Browse Source

first commit

felixyin 7 months ago
commit
7ecc86406c
100 changed files with 6169 additions and 0 deletions
  1. 33 0
      .gitignore
  2. 9 0
      Dockerfile
  3. 10 0
      jzo2o-foundations-startup.bat
  4. 106 0
      pom.xml
  5. 25 0
      src/main/java/com/jzo2o/foundations/FoundationsApplication.java
  6. 23 0
      src/main/java/com/jzo2o/foundations/config/JwtConfiguration.java
  7. 19 0
      src/main/java/com/jzo2o/foundations/config/SecurityConfig.java
  8. 8 0
      src/main/java/com/jzo2o/foundations/constants/IndexConstants.java
  9. 67 0
      src/main/java/com/jzo2o/foundations/constants/RedisConstants.java
  10. 35 0
      src/main/java/com/jzo2o/foundations/controller/agency/RegionController.java
  11. 90 0
      src/main/java/com/jzo2o/foundations/controller/consumer/FirstPageServeController.java
  12. 40 0
      src/main/java/com/jzo2o/foundations/controller/consumer/RegionController.java
  13. 57 0
      src/main/java/com/jzo2o/foundations/controller/inner/InnerRegionController.java
  14. 37 0
      src/main/java/com/jzo2o/foundations/controller/inner/InnerServeController.java
  15. 56 0
      src/main/java/com/jzo2o/foundations/controller/inner/InnerServeItemController.java
  16. 40 0
      src/main/java/com/jzo2o/foundations/controller/inner/InnerServeTypeController.java
  17. 32 0
      src/main/java/com/jzo2o/foundations/controller/open/LoginController.java
  18. 44 0
      src/main/java/com/jzo2o/foundations/controller/operation/ConfigRegionController.java
  19. 115 0
      src/main/java/com/jzo2o/foundations/controller/operation/RegionController.java
  20. 111 0
      src/main/java/com/jzo2o/foundations/controller/operation/ServeController.java
  21. 92 0
      src/main/java/com/jzo2o/foundations/controller/operation/ServeItemController.java
  22. 90 0
      src/main/java/com/jzo2o/foundations/controller/operation/ServeTypeController.java
  23. 35 0
      src/main/java/com/jzo2o/foundations/controller/worker/RegionController.java
  24. 38 0
      src/main/java/com/jzo2o/foundations/controller/worker/ServeTypeController.java
  25. 22 0
      src/main/java/com/jzo2o/foundations/enums/FoundationStatusEnum.java
  26. 55 0
      src/main/java/com/jzo2o/foundations/handler/ServeCanalDataSyncHandler.java
  27. 123 0
      src/main/java/com/jzo2o/foundations/handler/SpringCacheSyncHandler.java
  28. 16 0
      src/main/java/com/jzo2o/foundations/mapper/CityDirectoryMapper.java
  29. 16 0
      src/main/java/com/jzo2o/foundations/mapper/ConfigRegionMapper.java
  30. 21 0
      src/main/java/com/jzo2o/foundations/mapper/OperatorMapper.java
  31. 16 0
      src/main/java/com/jzo2o/foundations/mapper/RegionMapper.java
  32. 60 0
      src/main/java/com/jzo2o/foundations/mapper/ServeItemMapper.java
  33. 63 0
      src/main/java/com/jzo2o/foundations/mapper/ServeMapper.java
  34. 16 0
      src/main/java/com/jzo2o/foundations/mapper/ServeSyncMapper.java
  35. 16 0
      src/main/java/com/jzo2o/foundations/mapper/ServeTypeMapper.java
  36. 59 0
      src/main/java/com/jzo2o/foundations/model/domain/CityDirectory.java
  37. 89 0
      src/main/java/com/jzo2o/foundations/model/domain/ConfigRegion.java
  38. 89 0
      src/main/java/com/jzo2o/foundations/model/domain/Operator.java
  39. 80 0
      src/main/java/com/jzo2o/foundations/model/domain/Region.java
  40. 86 0
      src/main/java/com/jzo2o/foundations/model/domain/Serve.java
  41. 96 0
      src/main/java/com/jzo2o/foundations/model/domain/ServeAggregation.java
  42. 108 0
      src/main/java/com/jzo2o/foundations/model/domain/ServeItem.java
  43. 115 0
      src/main/java/com/jzo2o/foundations/model/domain/ServeSync.java
  44. 80 0
      src/main/java/com/jzo2o/foundations/model/domain/ServeType.java
  45. 21 0
      src/main/java/com/jzo2o/foundations/model/dto/OperatorAddDTO.java
  46. 69 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ConfigRegionSetReqDTO.java
  47. 21 0
      src/main/java/com/jzo2o/foundations/model/dto/request/LoginReqDTO.java
  48. 16 0
      src/main/java/com/jzo2o/foundations/model/dto/request/RegionPageQueryReqDTO.java
  49. 40 0
      src/main/java/com/jzo2o/foundations/model/dto/request/RegionUpsertReqDTO.java
  50. 26 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ServeItemPageQueryReqDTO.java
  51. 72 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ServeItemUpsertReqDTO.java
  52. 19 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ServePageQueryReqDTO.java
  53. 58 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ServeSyncUpdateReqDTO.java
  54. 16 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ServeTypePageQueryReqDTO.java
  55. 40 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ServeTypeUpsertReqDTO.java
  56. 36 0
      src/main/java/com/jzo2o/foundations/model/dto/request/ServeUpsertReqDTO.java
  57. 27 0
      src/main/java/com/jzo2o/foundations/model/dto/response/CityResDTO.java
  58. 69 0
      src/main/java/com/jzo2o/foundations/model/dto/response/ConfigRegionResDTO.java
  59. 17 0
      src/main/java/com/jzo2o/foundations/model/dto/response/LoginResDTO.java
  60. 45 0
      src/main/java/com/jzo2o/foundations/model/dto/response/RegionDisplayResDTO.java
  61. 65 0
      src/main/java/com/jzo2o/foundations/model/dto/response/RegionResDTO.java
  62. 33 0
      src/main/java/com/jzo2o/foundations/model/dto/response/RegionSimpleResDTO.java
  63. 70 0
      src/main/java/com/jzo2o/foundations/model/dto/response/ServeAggregationSimpleResDTO.java
  64. 46 0
      src/main/java/com/jzo2o/foundations/model/dto/response/ServeAggregationTypeSimpleResDTO.java
  65. 53 0
      src/main/java/com/jzo2o/foundations/model/dto/response/ServeCategoryResDTO.java
  66. 90 0
      src/main/java/com/jzo2o/foundations/model/dto/response/ServeResDTO.java
  67. 46 0
      src/main/java/com/jzo2o/foundations/model/dto/response/ServeSimpleResDTO.java
  68. 71 0
      src/main/java/com/jzo2o/foundations/model/dto/response/ServeTypeResDTO.java
  69. 19 0
      src/main/java/com/jzo2o/foundations/properties/ApplicaitonProperties.java
  70. 73 0
      src/main/java/com/jzo2o/foundations/service/HomeService.java
  71. 58 0
      src/main/java/com/jzo2o/foundations/service/IConfigRegionService.java
  72. 17 0
      src/main/java/com/jzo2o/foundations/service/ILoginService.java
  73. 31 0
      src/main/java/com/jzo2o/foundations/service/IOperatorService.java
  74. 75 0
      src/main/java/com/jzo2o/foundations/service/IRegionService.java
  75. 100 0
      src/main/java/com/jzo2o/foundations/service/IServeItemService.java
  76. 144 0
      src/main/java/com/jzo2o/foundations/service/IServeService.java
  77. 31 0
      src/main/java/com/jzo2o/foundations/service/IServeSyncService.java
  78. 70 0
      src/main/java/com/jzo2o/foundations/service/IServeTypeService.java
  79. 21 0
      src/main/java/com/jzo2o/foundations/service/ServeAggregationService.java
  80. 77 0
      src/main/java/com/jzo2o/foundations/service/impl/ConfigRegionServiceImpl.java
  81. 208 0
      src/main/java/com/jzo2o/foundations/service/impl/HomeServiceImpl.java
  82. 47 0
      src/main/java/com/jzo2o/foundations/service/impl/LoginServiceImpl.java
  83. 58 0
      src/main/java/com/jzo2o/foundations/service/impl/OperatorServiceImpl.java
  84. 224 0
      src/main/java/com/jzo2o/foundations/service/impl/RegionServiceImpl.java
  85. 106 0
      src/main/java/com/jzo2o/foundations/service/impl/ServeAggregationServiceImpl.java
  86. 261 0
      src/main/java/com/jzo2o/foundations/service/impl/ServeItemServiceImpl.java
  87. 394 0
      src/main/java/com/jzo2o/foundations/service/impl/ServeServiceImpl.java
  88. 56 0
      src/main/java/com/jzo2o/foundations/service/impl/ServeSyncServiceImpl.java
  89. 195 0
      src/main/java/com/jzo2o/foundations/service/impl/ServeTypeServiceImpl.java
  90. 18 0
      src/main/resources/bootstrap-dev.yml
  91. 14 0
      src/main/resources/bootstrap-prod.yml
  92. 14 0
      src/main/resources/bootstrap-test.yml
  93. 76 0
      src/main/resources/bootstrap.yml
  94. 5 0
      src/main/resources/mapper/CityDirectoryMapper.xml
  95. 5 0
      src/main/resources/mapper/ConfigRegionMapper.xml
  96. 21 0
      src/main/resources/mapper/OperatorMapper.xml
  97. 5 0
      src/main/resources/mapper/RegionMapper.xml
  98. 96 0
      src/main/resources/mapper/ServeItemMapper.xml
  99. 141 0
      src/main/resources/mapper/ServeMapper.xml
  100. 5 0
      src/main/resources/mapper/ServeSyncMapper.xml

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 9 - 0
Dockerfile

@@ -0,0 +1,9 @@
+FROM openjdk:11-jdk
+LABEL maintainer="研究院研发组 <research-maint@itcast.cn>"
+RUN echo "Asia/Shanghai" > /etc/timezone
+ARG PACKAGE_PATH=./target/jzo2o-foundations.jar
+
+ADD ${PACKAGE_PATH:-./} app.jar
+EXPOSE 8080
+EXPOSE 9999
+ENTRYPOINT ["sh","-c","java  -jar $JAVA_OPTS app.jar"]

+ 10 - 0
jzo2o-foundations-startup.bat

@@ -0,0 +1,10 @@
+@echo off
+chcp 65001
+echo.
+echo [信息] 打包运营基础工程。
+echo.
+call  mvn  package -DskipTests=true
+echo.
+echo [信息] 启动运营基础工程。
+echo.
+java -Dfile.encoding=utf-8 -Xmx256m -jar target/jzo2o-foundations.jar

+ 106 - 0
pom.xml

@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.jzo2o</groupId>
+    <artifactId>jzo2o-foundations</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <parent>
+        <artifactId>jzo2o-parent</artifactId>
+        <groupId>com.jzo2o</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <properties>
+        <maven.compiler.source>11</maven.compiler.source>
+        <maven.compiler.target>11</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-mvc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-knife4j-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-es</artifactId>
+        </dependency>
+
+        <!--单元测试-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-canal-sync</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-mysql</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.jzo2o</groupId>
+            <artifactId>jzo2o-xxl-job</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>build-info</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <mainClass>com.jzo2o.foundations.FoundationsApplication</mainClass>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 25 - 0
src/main/java/com/jzo2o/foundations/FoundationsApplication.java

@@ -0,0 +1,25 @@
+package com.jzo2o.foundations;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+/**
+ * @author itcast
+ */
+@Slf4j
+@EnableCaching
+@MapperScan("com.jzo2o.foundations.mapper")
+@SpringBootApplication
+@EnableAspectJAutoProxy
+public class FoundationsApplication {
+    public static void main(String[] args) {
+        new SpringApplicationBuilder(FoundationsApplication.class)
+                .build(args)
+                .run(args);
+        log.info("家政服务-运营基础服务启动");
+    }
+}

+ 23 - 0
src/main/java/com/jzo2o/foundations/config/JwtConfiguration.java

@@ -0,0 +1,23 @@
+package com.jzo2o.foundations.config;
+
+import com.jzo2o.common.utils.JwtTool;
+import com.jzo2o.foundations.properties.ApplicaitonProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.Resource;
+
+/**
+ * @author itcast
+ */
+@Configuration
+public class JwtConfiguration {
+
+    @Resource
+    private ApplicaitonProperties applicaitonProperties;
+
+    @Bean
+    public JwtTool jwtTool() {
+        return new JwtTool(applicaitonProperties.getJwtKey());
+    }
+}

+ 19 - 0
src/main/java/com/jzo2o/foundations/config/SecurityConfig.java

@@ -0,0 +1,19 @@
+package com.jzo2o.foundations.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+/**
+ * @author itcast
+ */
+@Configuration
+public class SecurityConfig {
+
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
+}

+ 8 - 0
src/main/java/com/jzo2o/foundations/constants/IndexConstants.java

@@ -0,0 +1,8 @@
+package com.jzo2o.foundations.constants;
+
+public class IndexConstants {
+    /**
+     * 服务信息索引
+     */
+    public static final String SERVE = "serve_aggregation";
+}

+ 67 - 0
src/main/java/com/jzo2o/foundations/constants/RedisConstants.java

@@ -0,0 +1,67 @@
+package com.jzo2o.foundations.constants;
+
+/**
+ * redis相关常量
+ *
+ * @author itcast
+ * @create 2023/8/15 14:58
+ **/
+public class RedisConstants {
+
+    public static final class CacheName {
+        /**
+         * 家政服务缓存
+         */
+        public static final String JZ_CACHE = "JZ_CACHE";
+
+        /**
+         * 用户端首页服务图标
+         */
+        public static final String SERVE_ICON = "JZ_CACHE:SERVE_ICON";
+
+        /**
+         * 用户端首页热门服务
+         */
+        public static final String HOT_SERVE = "JZ_CACHE:HOT_SERVE";
+
+        /**
+         * 用户端已开通服务分类
+         */
+        public static final String SERVE_TYPE = "JZ_CACHE:SERVE_TYPE";
+
+        /**
+         * 服务项
+         */
+        public static final String SERVE_ITEM = "JZ_CACHE:SERVE_ITEM";
+
+        /**
+         * 服务
+         */
+        public static final String SERVE = "JZ_CACHE:SERVE_RECORD";
+    }
+
+    public static final class CacheManager {
+        /**
+         * 缓存时间永久
+         */
+        public static final String FOREVER = "cacheManagerForever";
+
+        /**
+         * 缓存时间永久
+         */
+        public static final String THIRTY_MINUTES = "cacheManager30Minutes";
+
+        /**
+         * 缓存时间1天
+         */
+        public static final String ONE_DAY = "cacheManagerOneDay";
+    }
+
+    public static final class Ttl {
+        /**
+         * 缓存时间30分钟
+         */
+        public static final int THIRTY = 30;
+    }
+
+}

+ 35 - 0
src/main/java/com/jzo2o/foundations/controller/agency/RegionController.java

@@ -0,0 +1,35 @@
+package com.jzo2o.foundations.controller.agency;
+
+
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.foundations.service.IRegionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 区域表 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@RestController("agencyRegionController")
+@RequestMapping("/agency/region")
+@Api(tags = "机构端 - 区域相关接口")
+public class RegionController {
+    @Resource
+    private IRegionService regionService;
+
+    @GetMapping("/activeRegionList")
+    @ApiOperation("已开通服务区域列表")
+    public List<RegionSimpleResDTO> activeRegionList() {
+        return regionService.queryActiveRegionList();
+    }
+}

+ 90 - 0
src/main/java/com/jzo2o/foundations/controller/consumer/FirstPageServeController.java

@@ -0,0 +1,90 @@
+package com.jzo2o.foundations.controller.consumer;
+
+
+import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
+import com.jzo2o.foundations.service.HomeService;
+import com.jzo2o.foundations.service.IServeService;
+import com.jzo2o.foundations.service.ServeAggregationService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * <p>
+ * 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Validated
+@RestController("consumerServeController")
+@RequestMapping("/customer/serve")
+@Api(tags = "用户端 - 首页服务查询接口")
+public class FirstPageServeController {
+    @Resource
+    private IServeService serveService;
+    @Resource
+    private ServeAggregationService serveAggregationService;
+    @Resource
+    private HomeService homeService;
+
+    @GetMapping("/firstPageServeList")
+    @ApiOperation("首页服务列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "regionId", value = "区域id", required = true, dataTypeClass = Long.class)
+    })
+    public List<ServeCategoryResDTO> serveCategory(@RequestParam("regionId") Long regionId) {
+        return homeService.queryServeIconCategoryByRegionIdCache(regionId);
+    }
+
+    @GetMapping("/hotServeList")
+    @ApiOperation("首页热门服务列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "regionId", value = "区域id", required = true, dataTypeClass = Long.class)
+    })
+    public List<ServeAggregationSimpleResDTO> listHotServe(@NotNull(message = "regionId不能为空") @RequestParam("regionId") Long regionId) {
+        return homeService.findHotServeListByRegionIdCache(regionId);
+    }
+
+    @GetMapping("/serveTypeList")
+    @ApiOperation("服务分类列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "regionId", value = "区域id", required = true, dataTypeClass = Long.class)
+    })
+    public List<ServeAggregationTypeSimpleResDTO> serveTypeList(@RequestParam("regionId") Long regionId) {
+        return homeService.queryServeTypeListByRegionIdCache(regionId);
+    }
+
+    @GetMapping("/search")
+    @ApiOperation("首页服务搜索")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "cityCode", value = "城市编码", required = true, dataTypeClass = String.class),
+            @ApiImplicitParam(name = "serveTypeId", value = "服务类型id", dataTypeClass = Long.class),
+            @ApiImplicitParam(name = "keyword", value = "关键词", dataTypeClass = String.class)
+    })
+    public List<ServeSimpleResDTO> findServeList(@RequestParam("cityCode") String cityCode,
+                                                 @RequestParam(value = "serveTypeId", required = false) Long serveTypeId,
+                                                 @RequestParam(value = "keyword", required = false) String keyword) {
+        return serveAggregationService.findServeList(cityCode, serveTypeId, keyword);
+    }
+
+    @GetMapping("/{id}")
+    @ApiOperation("根据id查询服务")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class)
+    })
+    public ServeAggregationSimpleResDTO findById(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        return serveService.findDetailById(id);
+    }
+}

+ 40 - 0
src/main/java/com/jzo2o/foundations/controller/consumer/RegionController.java

@@ -0,0 +1,40 @@
+package com.jzo2o.foundations.controller.consumer;
+
+
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.RegionDisplayResDTO;
+import com.jzo2o.foundations.service.HomeService;
+import com.jzo2o.foundations.service.IRegionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 区域表 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@RestController("consumerRegionController")
+@RequestMapping("/consumer/region")
+@Api(tags = "用户端 - 区域相关接口")
+public class RegionController {
+    @Resource
+    private HomeService homeService;
+    @Resource
+    private IRegionService regionService;
+
+    @GetMapping("/activeRegionList")
+    @ApiOperation("已开通服务区域列表")
+    public List<RegionSimpleResDTO> activeRegionList() {
+        return homeService.queryActiveRegionListCache();
+    }
+
+}

+ 57 - 0
src/main/java/com/jzo2o/foundations/controller/inner/InnerRegionController.java

@@ -0,0 +1,57 @@
+package com.jzo2o.foundations.controller.inner;
+
+
+import com.jzo2o.api.foundations.RegionApi;
+import com.jzo2o.api.foundations.dto.response.ConfigRegionInnerResDTO;
+import com.jzo2o.api.foundations.dto.response.RegionServeInfoResDTO;
+import com.jzo2o.common.utils.BeanUtils;
+import com.jzo2o.foundations.model.dto.response.ConfigRegionResDTO;
+import com.jzo2o.foundations.service.IConfigRegionService;
+import com.jzo2o.foundations.service.IRegionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 区域表 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@RestController
+@RequestMapping("/inner/region")
+@Api(tags = "内部接口 - 区域相关接口")
+public class InnerRegionController implements RegionApi {
+    @Resource
+    private IConfigRegionService configRegionService;
+
+    @Override
+    @GetMapping("/findAllConfigRegion")
+    @ApiOperation("查询所有区域配置")
+    public List<ConfigRegionInnerResDTO> findAll() {
+        return configRegionService.queryAll();
+    }
+
+    @Override
+    @GetMapping("/findConfigRegionById/{id}")
+    @ApiOperation("根据区域id查询区域配置")
+    @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class)
+    public ConfigRegionInnerResDTO findConfigRegionById(@PathVariable("id") Long id) {
+        ConfigRegionResDTO configRegionResDTO = configRegionService.queryById(id);
+        return BeanUtils.toBean(configRegionResDTO, ConfigRegionInnerResDTO.class);
+    }
+
+    @Override
+    @GetMapping("/findConfigRegionByCityCode")
+    @ApiOperation("根据城市编码获取区域配置信息")
+    @ApiImplicitParam(name = "cityCode", value = "城市编码", required = true, dataTypeClass = String.class)
+    public ConfigRegionInnerResDTO findConfigRegionByCityCode(@RequestParam("cityCode") String cityCode) {
+        return configRegionService.queryByCityCode(cityCode);
+    }
+}

+ 37 - 0
src/main/java/com/jzo2o/foundations/controller/inner/InnerServeController.java

@@ -0,0 +1,37 @@
+package com.jzo2o.foundations.controller.inner;
+
+import com.jzo2o.api.foundations.ServeApi;
+import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
+import com.jzo2o.foundations.service.IServeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author itcast
+ */
+@RestController
+@RequestMapping("/inner/serve")
+@Api(tags = "内部接口 - 服务相关接口")
+public class InnerServeController implements ServeApi {
+    @Resource
+    private IServeService serveService;
+
+    @Override
+    @GetMapping("/{id}")
+    @ApiOperation("根据id查询服务")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务项id", required = true, dataTypeClass = Long.class)
+    })
+    public ServeAggregationResDTO findById(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        return serveService.findServeDetailById(id);
+    }
+}

+ 56 - 0
src/main/java/com/jzo2o/foundations/controller/inner/InnerServeItemController.java

@@ -0,0 +1,56 @@
+package com.jzo2o.foundations.controller.inner;
+
+
+import com.jzo2o.api.foundations.ServeItemApi;
+import com.jzo2o.api.foundations.dto.response.ServeItemResDTO;
+import com.jzo2o.api.foundations.dto.response.ServeItemSimpleResDTO;
+import com.jzo2o.api.foundations.dto.response.ServeTypeCategoryResDTO;
+import com.jzo2o.foundations.service.IServeItemService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 内部接口 - 服务项相关接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@RestController
+@RequestMapping("/inner/serve-item")
+@Api(tags = "内部接口 - 服务项相关接口")
+public class InnerServeItemController implements ServeItemApi {
+    @Resource
+    private IServeItemService serveItemService;
+
+    @Override
+    @GetMapping("/{id}")
+    @ApiOperation("根据id查询服务项")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务项id", required = true, dataTypeClass = Long.class)
+    })
+    public ServeItemResDTO findById(@PathVariable("id") Long id) {
+        return serveItemService.queryServeItemAndTypeById(id);
+    }
+
+    @Override
+    @GetMapping("/listByIds")
+    @ApiOperation("根据id列表查询服务项")
+    public List<ServeItemSimpleResDTO> listByIds(@RequestParam("ids") List<Long> ids) {
+        return serveItemService.queryServeItemListByIds(ids);
+    }
+
+    @Override
+    @GetMapping("/queryActiveServeItemCategory")
+    @ApiOperation("查询启用状态的服务项目录")
+    public List<ServeTypeCategoryResDTO> queryActiveServeItemCategory() {
+        return serveItemService.queryActiveServeItemCategory();
+    }
+}

+ 40 - 0
src/main/java/com/jzo2o/foundations/controller/inner/InnerServeTypeController.java

@@ -0,0 +1,40 @@
+package com.jzo2o.foundations.controller.inner;
+
+
+import cn.hutool.core.bean.BeanUtil;
+import com.jzo2o.api.foundations.ServeTypeApi;
+import com.jzo2o.api.foundations.dto.response.ServeTypeSimpleResDTO;
+import com.jzo2o.foundations.enums.FoundationStatusEnum;
+import com.jzo2o.foundations.service.IServeTypeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 内部接口 - 服务类型相关接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@RestController
+@RequestMapping("/inner/serve-type")
+@Api(tags = "内部接口 - 服务类型相关接口")
+public class InnerServeTypeController implements ServeTypeApi {
+    @Resource
+    private IServeTypeService serveTypeService;
+
+    @Override
+    @GetMapping("/listByIds")
+    @ApiOperation("根据id列表查询服务类型")
+    public List<ServeTypeSimpleResDTO> listByIds(@RequestParam("ids") List<Long> ids) {
+        return BeanUtil.copyToList(serveTypeService.listByIds(ids), ServeTypeSimpleResDTO.class);
+    }
+}

+ 32 - 0
src/main/java/com/jzo2o/foundations/controller/open/LoginController.java

@@ -0,0 +1,32 @@
+package com.jzo2o.foundations.controller.open;
+
+import com.jzo2o.foundations.model.dto.request.LoginReqDTO;
+import com.jzo2o.foundations.model.dto.response.LoginResDTO;
+import com.jzo2o.foundations.service.ILoginService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * @author itcast
+ */
+@RestController("openLoginController")
+@RequestMapping("/open/login")
+@Api(tags = "白名单接口 - 运营人员登录相关接口")
+public class LoginController {
+
+    @Resource
+    private ILoginService loginService;
+
+    @PostMapping
+    @ApiOperation("运营人员登录")
+    public LoginResDTO login(@RequestBody LoginReqDTO loginReqDTO) {
+        String token = loginService.login(loginReqDTO);
+        return new LoginResDTO(token);
+    }
+}

+ 44 - 0
src/main/java/com/jzo2o/foundations/controller/operation/ConfigRegionController.java

@@ -0,0 +1,44 @@
+package com.jzo2o.foundations.controller.operation;
+
+
+import com.jzo2o.foundations.model.dto.request.ConfigRegionSetReqDTO;
+import com.jzo2o.foundations.model.dto.response.ConfigRegionResDTO;
+import com.jzo2o.foundations.service.IConfigRegionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * <p>
+ * 区域表 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Validated
+@RestController("operationConfigRegionController")
+@RequestMapping("/operation/config-region")
+@Api(tags = "运营端 - 区域配置相关接口")
+public class ConfigRegionController {
+    @Resource
+    private IConfigRegionService configRegionService;
+
+    @GetMapping("/{id}")
+    @ApiOperation("获取区域配置")
+    @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class)
+    public ConfigRegionResDTO queryById(@PathVariable(value = "id") Long id) {
+        return configRegionService.queryById(id);
+    }
+
+    @PutMapping("/{id}")
+    @ApiOperation("区域配置设置")
+    @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class)
+    public void putById(@PathVariable(value = "id") Long id, @Validated @RequestBody ConfigRegionSetReqDTO configRegionSetReqDTO) {
+        configRegionService.setConfigRegionById(id, configRegionSetReqDTO);
+    }
+}

+ 115 - 0
src/main/java/com/jzo2o/foundations/controller/operation/RegionController.java

@@ -0,0 +1,115 @@
+package com.jzo2o.foundations.controller.operation;
+
+
+import cn.hutool.core.bean.BeanUtil;
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.domain.Region;
+import com.jzo2o.foundations.model.dto.request.RegionPageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.RegionUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.RegionResDTO;
+import com.jzo2o.foundations.service.HomeService;
+import com.jzo2o.foundations.service.IRegionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * <p>
+ * 区域表 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Validated
+@RestController("operationRegionController")
+@RequestMapping("/operation/region")
+@Api(tags = "运营端 - 区域相关接口")
+public class RegionController {
+    @Resource
+    private IRegionService regionService;
+    @Resource
+    private HomeService homeService;
+
+    @GetMapping("/activeRegionList")
+    @ApiOperation("已开通服务区域列表")
+    public List<RegionSimpleResDTO> activeRegionList() {
+        return regionService.queryActiveRegionList();
+    }
+
+    @PostMapping
+    @ApiOperation("区域新增")
+    public void add(@RequestBody RegionUpsertReqDTO regionUpsertReqDTO) {
+        regionService.add(regionUpsertReqDTO);
+    }
+
+    @PutMapping("/{id}")
+    @ApiOperation("区域修改")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class),
+            @ApiImplicitParam(name = "managerName", value = "负责人名称", required = true, dataTypeClass = String.class),
+            @ApiImplicitParam(name = "managerPhone", value = "负责人电话", required = true, dataTypeClass = String.class)
+    })
+    public void update(@NotNull(message = "id不能为空") @PathVariable("id") Long id,
+                       @RequestParam("managerName") String managerName,
+                       @RequestParam("managerPhone") String managerPhone) {
+        regionService.update(id, managerName, managerPhone);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation("区域删除")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class)
+    })
+    public void delete(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        regionService.deleteById(id);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("区域分页查询")
+    public PageResult<RegionResDTO> page(RegionPageQueryReqDTO regionPageQueryReqDTO) {
+        return regionService.page(regionPageQueryReqDTO);
+    }
+
+    @GetMapping("/{id}")
+    @ApiOperation("根据id查询")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class)
+    })
+    public RegionResDTO findById(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        Region region = regionService.getById(id);
+        return BeanUtil.toBean(region, RegionResDTO.class);
+    }
+
+    @PutMapping("/activate/{id}")
+    @ApiOperation("区域启用")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class),
+    })
+    public void activate(@PathVariable("id") Long id) {
+        regionService.active(id);
+    }
+
+    @PutMapping("/deactivate/{id}")
+    @ApiOperation("区域禁用")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "区域id", required = true, dataTypeClass = Long.class),
+    })
+    public void deactivate(@PathVariable("id") Long id) {
+        regionService.deactivate(id);
+    }
+
+    @PutMapping("/refreshRegionRelateCaches/{id}")
+    @ApiOperation("刷新区域相关缓存")
+    public void refreshRegionRelateCaches(@PathVariable("id") Long id) {
+        homeService.refreshRegionRelateCaches(id);
+    }
+}

+ 111 - 0
src/main/java/com/jzo2o/foundations/controller/operation/ServeController.java

@@ -0,0 +1,111 @@
+package com.jzo2o.foundations.controller.operation;
+
+
+import com.jzo2o.common.enums.EnableStatusEnum;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
+import com.jzo2o.foundations.service.IServeService;
+import com.jzo2o.foundations.service.ServeAggregationService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * <p>
+ * 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Validated
+@RestController("operationServeController")
+@RequestMapping("/operation/serve")
+@Api(tags = "运营端 - 区域服务相关接口")
+public class ServeController {
+    @Resource
+    private IServeService serveService;
+    @Resource
+    private ServeAggregationService serveAggregationService;
+
+    @PostMapping("/batch")
+    @ApiOperation("区域服务批量新增")
+    public void add(@RequestBody List<ServeUpsertReqDTO> serveUpsertReqDTOList) {
+        serveService.batchAdd(serveUpsertReqDTOList);
+    }
+
+    @PutMapping("/{id}")
+    @ApiOperation("区域服务价格修改")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class),
+            @ApiImplicitParam(name = "price", value = "价格", required = true, dataTypeClass = Double.class)
+    })
+    public void update(@NotNull(message = "id不能为空") @PathVariable("id") Long id,
+                       @NotNull(message = "价格不能为空") @RequestParam("price") Double price) {
+        serveService.update(id, BigDecimal.valueOf(price));
+    }
+
+    @PutMapping("/onHot/{id}")
+    @ApiOperation("区域服务设置热门")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class)
+    })
+    public void onHot(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        serveService.changeHotStatus(id, EnableStatusEnum.ENABLE.getStatus());
+    }
+
+    @PutMapping("/offHot/{id}")
+    @ApiOperation("区域服务取消热门")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class)
+    })
+    public void offHot(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        serveService.changeHotStatus(id, EnableStatusEnum.DISABLE.getStatus());
+    }
+
+    @PutMapping("/onSale/{id}")
+    @ApiOperation("区域服务上架")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class),
+    })
+    public void onSale(@PathVariable("id") Long id) {
+        serveService.onSale(id);
+
+    }
+
+    @PutMapping("/offSale/{id}")
+    @ApiOperation("区域服务下架")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class),
+    })
+    public void offSale(@PathVariable("id") Long id) {
+        serveService.offSale(id);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation("区域服务删除")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class)
+    })
+    public void delete(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        serveService.deleteById(id);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("区域服务分页查询")
+    public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {
+        return serveService.page(servePageQueryReqDTO);
+    }
+}

+ 92 - 0
src/main/java/com/jzo2o/foundations/controller/operation/ServeItemController.java

@@ -0,0 +1,92 @@
+package com.jzo2o.foundations.controller.operation;
+
+
+import com.jzo2o.api.foundations.dto.response.ServeItemResDTO;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.dto.request.ServeItemPageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeItemUpsertReqDTO;
+import com.jzo2o.foundations.service.IServeItemService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
+
+/**
+ * <p>
+ * 服务表 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Validated
+@RestController("operationServeItemController")
+@RequestMapping("/operation/serve-item")
+@Api(tags = "运营端 - 服务项相关接口")
+public class ServeItemController {
+    @Resource
+    private IServeItemService serveItemService;
+
+    @PostMapping
+    @ApiOperation("服务项新增")
+    public void add(@RequestBody ServeItemUpsertReqDTO serveItemUpsertReqDTO) {
+        serveItemService.add(serveItemUpsertReqDTO);
+    }
+
+    @PutMapping("/{id}")
+    @ApiOperation("服务项修改")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务项id", required = true, dataTypeClass = Long.class)
+    })
+    public void update(@NotNull(message = "id不能为空") @PathVariable("id") Long id, @RequestBody ServeItemUpsertReqDTO serveItemUpsertReqDTO) {
+        serveItemService.update(id, serveItemUpsertReqDTO);
+    }
+
+
+    @PutMapping("/activate/{id}")    //启用状态,1:禁用,:2:启用
+    @ApiOperation("服务项启用")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class),
+    })
+    public void activate(@PathVariable("id") Long id) {
+        serveItemService.activate(id);
+    }
+
+    @PutMapping("/deactivate/{id}")
+    @ApiOperation("服务项禁用")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务id", required = true, dataTypeClass = Long.class),
+    })
+    public void deactivate(@PathVariable("id") Long id) {
+        serveItemService.deactivate(id);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation("服务项删除")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务项id", required = true, dataTypeClass = Long.class),
+    })
+    public void delete(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        serveItemService.deleteById(id);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("服务项分页查询")
+    public PageResult<ServeItemResDTO> page(ServeItemPageQueryReqDTO serveItemPageQueryReqDTO) {
+        return serveItemService.page(serveItemPageQueryReqDTO);
+    }
+
+    @GetMapping("/{id}")
+    @ApiOperation("根据id查询服务项")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务项id", required = true, dataTypeClass = Long.class)
+    })
+    public ServeItemResDTO findById(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        return serveItemService.queryServeItemAndTypeById(id);
+    }
+}

+ 90 - 0
src/main/java/com/jzo2o/foundations/controller/operation/ServeTypeController.java

@@ -0,0 +1,90 @@
+package com.jzo2o.foundations.controller.operation;
+
+import com.jzo2o.api.foundations.dto.response.ServeTypeSimpleResDTO;
+import com.jzo2o.common.enums.EnableStatusEnum;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.dto.request.ServeTypePageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeTypeUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.ServeTypeResDTO;
+import com.jzo2o.foundations.service.IServeTypeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 服务类型相关接口
+ *
+ * @author itcast
+ * @create 2023/7/26 14:16
+ **/
+@RestController("operationServeTypeController")
+@RequestMapping("/operation/serve-type")
+@Api(tags = "运营端 - 服务类型相关接口")
+public class ServeTypeController {
+    @Resource
+    private IServeTypeService serveTypeService;
+
+    @GetMapping("/queryServeTypeListByActiveStatus")
+    @ApiOperation("根据活动状态查询服务类型")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "activeStatus", value = "活动状态,0:草稿,1:禁用,:2:启用", dataTypeClass = Integer.class)
+    })
+    public List<ServeTypeSimpleResDTO> queryServeTypeListByActiveStatus(@RequestParam(value = "activeStatus", required = false) Integer activeStatus) {
+        return serveTypeService.queryServeTypeListByActiveStatus(activeStatus);
+    }
+
+    @PostMapping
+    @ApiOperation("服务类型新增")
+    public void add(@RequestBody ServeTypeUpsertReqDTO serveTypeUpsertReqDTO) {
+        serveTypeService.add(serveTypeUpsertReqDTO);
+    }
+
+    @PutMapping("/{id}")
+    @ApiOperation("服务类型修改")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务类型id", required = true, dataTypeClass = Long.class)
+    })
+    public void update(@NotNull(message = "id不能为空") @PathVariable("id") Long id,
+                       @RequestBody ServeTypeUpsertReqDTO serveTypeUpsertReqDTO) {
+        serveTypeService.update(id, serveTypeUpsertReqDTO);
+    }
+
+    @PutMapping("/activate/{id}")
+    @ApiOperation("服务类型启用")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务类型id", required = true, dataTypeClass = Long.class),
+    })
+    public void activate(@PathVariable("id") Long id) {
+        serveTypeService.activate(id);
+    }
+
+    @PutMapping("/deactivate/{id}")
+    @ApiOperation("服务类型禁用")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务类型id", required = true, dataTypeClass = Long.class),
+    })
+    public void deactivate(@PathVariable("id") Long id) {
+        serveTypeService.deactivate(id);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation("服务类型删除")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "服务类型id", required = true, dataTypeClass = Long.class)
+    })
+    public void delete(@NotNull(message = "id不能为空") @PathVariable("id") Long id) {
+        serveTypeService.deleteById(id);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("服务类型分页查询")
+    public PageResult<ServeTypeResDTO> page(ServeTypePageQueryReqDTO serveTypePageQueryReqDTO) {
+        return serveTypeService.page(serveTypePageQueryReqDTO);
+    }
+}

+ 35 - 0
src/main/java/com/jzo2o/foundations/controller/worker/RegionController.java

@@ -0,0 +1,35 @@
+package com.jzo2o.foundations.controller.worker;
+
+
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.foundations.service.IRegionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 区域表 前端控制器
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@RestController("workerRegionController")
+@RequestMapping("/worker/region")
+@Api(tags = "服务端 - 区域相关接口")
+public class RegionController {
+    @Resource
+    private IRegionService regionService;
+
+    @GetMapping("/activeRegionList")
+    @ApiOperation("已开通服务区域列表")
+    public List<RegionSimpleResDTO> activeRegionList() {
+        return regionService.queryActiveRegionList();
+    }
+}

+ 38 - 0
src/main/java/com/jzo2o/foundations/controller/worker/ServeTypeController.java

@@ -0,0 +1,38 @@
+package com.jzo2o.foundations.controller.worker;
+
+import com.jzo2o.api.foundations.dto.response.ServeTypeSimpleResDTO;
+import com.jzo2o.foundations.service.IServeTypeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 服务类型相关接口
+ *
+ * @author itcast
+ * @create 2023/7/26 14:16
+ **/
+@RestController("workerServeTypeController")
+@RequestMapping("/worker/serve-type")
+@Api(tags = "服务端 - 服务类型相关接口")
+public class ServeTypeController {
+    @Resource
+    private IServeTypeService serveTypeService;
+
+    @GetMapping("/queryServeTypeListByActiveStatus")
+    @ApiOperation("根据活动状态查询服务类型")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "activeStatus", value = "活动状态,0:草稿,1:禁用,:2:启用", dataTypeClass = Integer.class)
+    })
+    public List<ServeTypeSimpleResDTO> queryServeTypeListByActiveStatus(@RequestParam(value = "activeStatus", required = false) Integer activeStatus) {
+        return serveTypeService.queryServeTypeListByActiveStatus(activeStatus);
+    }
+}

+ 22 - 0
src/main/java/com/jzo2o/foundations/enums/FoundationStatusEnum.java

@@ -0,0 +1,22 @@
+package com.jzo2o.foundations.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum FoundationStatusEnum {
+    INIT(0,"草稿"),
+    ENABLE(2,"启用"),
+    DISABLE(1, "禁用");
+    private int status;
+    private String description;
+
+    public boolean equals(Integer status) {
+        return this.status == status;
+    }
+
+    public boolean equals(FoundationStatusEnum enableStatusEnum) {
+        return enableStatusEnum != null && enableStatusEnum.status == this.getStatus();
+    }
+}

+ 55 - 0
src/main/java/com/jzo2o/foundations/handler/ServeCanalDataSyncHandler.java

@@ -0,0 +1,55 @@
+package com.jzo2o.foundations.handler;
+
+import com.jzo2o.canal.listeners.AbstractCanalRabbitMqMsgListener;
+import com.jzo2o.es.core.ElasticSearchTemplate;
+import com.jzo2o.foundations.constants.IndexConstants;
+import com.jzo2o.foundations.model.domain.ServeSync;
+import org.springframework.amqp.core.ExchangeTypes;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.Exchange;
+import org.springframework.amqp.rabbit.annotation.Queue;
+import org.springframework.amqp.rabbit.annotation.QueueBinding;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author 86188
+ */
+@Component
+public class ServeCanalDataSyncHandler extends AbstractCanalRabbitMqMsgListener<ServeSync> {
+
+    @Resource
+    private ElasticSearchTemplate elasticSearchTemplate;
+
+    @RabbitListener(bindings = @QueueBinding(
+            value = @Queue(name = "canal-mq-jzo2o-foundations"),
+            exchange = @Exchange(name = "exchange.canal-jzo2o", type = ExchangeTypes.TOPIC),
+            key = "canal-mq-jzo2o-foundations"),
+            concurrency = "1"
+    )
+    public void onMessage(Message message) throws Exception {
+        parseMsg(message);
+    }
+
+    @Override
+    public void batchSave(List<ServeSync> data) {
+        Boolean aBoolean = elasticSearchTemplate.opsForDoc().batchInsert(IndexConstants.SERVE, data);
+        if(!aBoolean){
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+            throw new RuntimeException("同步失败");
+        }
+    }
+
+    @Override
+    public void batchDelete(List<Long> ids) {
+        Boolean aBoolean = elasticSearchTemplate.opsForDoc().batchDelete(IndexConstants.SERVE, ids);
+
+    }
+}

+ 123 - 0
src/main/java/com/jzo2o/foundations/handler/SpringCacheSyncHandler.java

@@ -0,0 +1,123 @@
+package com.jzo2o.foundations.handler;
+
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.foundations.constants.RedisConstants;
+import com.jzo2o.foundations.model.domain.Serve;
+import com.jzo2o.foundations.service.HomeService;
+import com.jzo2o.foundations.service.IRegionService;
+import com.jzo2o.foundations.service.IServeService;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * springCache缓存同步任务
+ *
+ * @author itcast
+ * @create 2023/8/15 18:14
+ **/
+@Slf4j
+@Component
+public class SpringCacheSyncHandler {
+
+    @Resource
+    private IRegionService regionService;
+    @Resource
+    private IServeService serveService;
+    @Resource
+    private RedisTemplate redisTemplate;
+    @Resource
+    private HomeService homeService;
+
+    /**
+     * 已启用区域缓存更新
+     * 每日凌晨1点执行
+     */
+    @XxlJob(value = "activeRegionCacheSync")
+    public void activeRegionCacheSync() {
+        log.info(">>>>>>>>开始进行缓存同步,更新已启用区域");
+        //1.清理缓存
+        String key = RedisConstants.CacheName.JZ_CACHE + "::ACTIVE_REGIONS";
+        redisTemplate.delete(key);
+
+        //2.刷新缓存
+        homeService.queryActiveRegionListCache();
+        log.info(">>>>>>>>更新已启用区域完成");
+    }
+
+    /**
+     * 用户端首页所选城市服务缓存更新
+     * 每日凌晨1点执行
+     */
+    @XxlJob(value = "cityServeCacheSync")
+    public void cityServeCacheSync() {
+        log.info(">>>>>>>>开始进行缓存同步,更新用户端首页所选城市服务");
+        //1.清理所有城市服务缓存
+        Set serveIconCacheKeys = redisTemplate.keys(RedisConstants.CacheName.SERVE_ICON.concat("*"));
+        Set hotServeCacheKeys = redisTemplate.keys(RedisConstants.CacheName.HOT_SERVE.concat("*"));
+        Set serveTypeCacheKeys = redisTemplate.keys(RedisConstants.CacheName.SERVE_TYPE.concat("*"));
+        Set cacheKeys = new HashSet<>();
+        cacheKeys.addAll(serveIconCacheKeys);
+        cacheKeys.addAll(hotServeCacheKeys);
+        cacheKeys.addAll(serveTypeCacheKeys);
+        redisTemplate.delete(cacheKeys);
+
+        //2.获取所有已启用的区域,提取区域id
+        List<RegionSimpleResDTO> regionSimpleResDTOList = regionService.queryActiveRegionList();
+        List<Long> activeRegionIdList = regionSimpleResDTOList.stream().map(RegionSimpleResDTO::getId).collect(Collectors.toList());
+
+        //3.循环对每个已启用城市相关服务缓存更新
+        for (Long regionId : activeRegionIdList) {
+            homeService.queryServeIconCategoryByRegionIdCache(regionId);
+            homeService.findHotServeListByRegionIdCache(regionId);
+            homeService.queryServeTypeListByRegionIdCache(regionId);
+        }
+
+        log.info(">>>>>>>>更新用户端首页所选城市服务完成");
+    }
+
+
+    /**
+     * 热门服务详情缓存更新
+     * 每3小时执行
+     */
+    @XxlJob(value = "hotServeCacheSync")
+    public void hotServeCacheSync() {
+        log.info(">>>>>>>>开始进行缓存同步,更新热门服务详情");
+
+        //1.查询热门且上架状态的服务
+        List<Serve> hotAndOnSaleServeList = serveService.queryHotAndOnSaleServeList();
+        Set<Long> hotServeItemIds=new HashSet<>();
+
+        //2.热门服务缓存续期
+        for (Serve serve : hotAndOnSaleServeList) {
+            //2.1删除热门服务缓存
+            String serveKey=RedisConstants.CacheName.SERVE+"::"+serve.getId();
+            redisTemplate.delete(serveKey);
+
+            //2.2重置热门服务缓存
+            homeService.queryServeByIdCache(serve.getId());
+
+            //2.2提取热门服务对应的服务项id
+            hotServeItemIds.add(serve.getServeItemId());
+        }
+
+        //3.对热门服务项更新缓存
+        for (Long serveItemId : hotServeItemIds) {
+            //3.1删除热门服务项缓存
+            String serveKey=RedisConstants.CacheName.SERVE_ITEM+"::"+serveItemId;
+            redisTemplate.delete(serveKey);
+
+            //3.2重置热门服务项缓存
+            homeService.queryServeItemByIdCache(serveItemId);
+        }
+        log.info(">>>>>>>>更新热门服务详情完成");
+    }
+}

+ 16 - 0
src/main/java/com/jzo2o/foundations/mapper/CityDirectoryMapper.java

@@ -0,0 +1,16 @@
+package com.jzo2o.foundations.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jzo2o.foundations.model.domain.CityDirectory;
+
+/**
+ * <p>
+ * 城市编码表 Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-04
+ */
+public interface CityDirectoryMapper extends BaseMapper<CityDirectory> {
+
+}

+ 16 - 0
src/main/java/com/jzo2o/foundations/mapper/ConfigRegionMapper.java

@@ -0,0 +1,16 @@
+package com.jzo2o.foundations.mapper;
+
+import com.jzo2o.foundations.model.domain.ConfigRegion;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 区域业务配置 Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-08-21
+ */
+public interface ConfigRegionMapper extends BaseMapper<ConfigRegion> {
+
+}

+ 21 - 0
src/main/java/com/jzo2o/foundations/mapper/OperatorMapper.java

@@ -0,0 +1,21 @@
+package com.jzo2o.foundations.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jzo2o.foundations.model.domain.Operator;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 运营人员 Mapper 接口
+ * </p>
+ *
+ * @author author
+ * @since 2023-07-03
+ */
+public interface OperatorMapper extends BaseMapper<Operator> {
+
+    @Select("select * from operator")
+    List<Operator> queryAll();
+}

+ 16 - 0
src/main/java/com/jzo2o/foundations/mapper/RegionMapper.java

@@ -0,0 +1,16 @@
+package com.jzo2o.foundations.mapper;
+
+import com.jzo2o.foundations.model.domain.Region;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 区域表 Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+public interface RegionMapper extends BaseMapper<Region> {
+}

+ 60 - 0
src/main/java/com/jzo2o/foundations/mapper/ServeItemMapper.java

@@ -0,0 +1,60 @@
+package com.jzo2o.foundations.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jzo2o.api.foundations.dto.response.ServeItemResDTO;
+import com.jzo2o.api.foundations.dto.response.ServeTypeCategoryResDTO;
+import com.jzo2o.foundations.model.domain.ServeItem;
+import com.jzo2o.foundations.model.domain.ServeType;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 服务表 Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+public interface ServeItemMapper extends BaseMapper<ServeItem> {
+
+//    @Select("SELECT type.*  FROM serve_type AS type \n" +
+//            "LEFT JOIN serve_item AS item ON type.id = item.serve_type_id \n" +
+//            "WHERE item.id = #{id}")
+//    ServeType findServeTypeById(@Param("id") Long id);
+
+    /**
+     * 根据条件查询服务项列表
+     *
+     * @param serveTypeId  服务类型id
+     * @param name         服务项名称
+     * @param activeStatus 活动状态,0:草稿,1禁用,2启用
+     * @return 服务项列表
+     */
+    List<ServeItemResDTO> queryList(@Param("serveTypeId") Long serveTypeId, @Param("name") String name, @Param("activeStatus") Integer activeStatus);
+
+    /**
+     * 根据id查询服务项和服务类型信息
+     *
+     * @param id 服务项id
+     * @return 服务项和服务类型信息
+     */
+    ServeItemResDTO queryServeItemAndTypeById(@Param("id") Long id);
+
+    /**
+     * 根据服务id查询服务项
+     *
+     * @param id 服务id
+     * @return 服务项
+     */
+    ServeItem queryServeItemByServeId(@Param("id") Long id);
+
+    /**
+     * 查询启用状态的服务项目录
+     *
+     * @return 服务项目录
+     */
+    List<ServeTypeCategoryResDTO> queryActiveServeItemCategory();
+}

+ 63 - 0
src/main/java/com/jzo2o/foundations/mapper/ServeMapper.java

@@ -0,0 +1,63 @@
+package com.jzo2o.foundations.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
+import com.jzo2o.foundations.model.domain.Serve;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeResDTO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+public interface ServeMapper extends BaseMapper<Serve> {
+
+    /**
+     * 根据区域id查询服务列表
+     *
+     * @param regionId 区域id
+     * @return 服务列表
+     */
+    List<ServeResDTO> queryServeListByRegionId(@Param("regionId") Long regionId);
+
+    /**
+     * 根据区域id查询热门服务列表
+     *
+     * @param regionId 区域id
+     * @return 热门服务列表
+     */
+    List<ServeAggregationSimpleResDTO> findHotServeListByRegionId(@Param("regionId")Long regionId);
+
+    /**
+     * 根据区域id查询服务类型列表
+     *
+     * @param regionId 区域id
+     * @return 服务类型列表
+     */
+    List<ServeAggregationTypeSimpleResDTO> findServeTypeListByRegionId(@Param("regionId")Long regionId);
+
+    /**
+     * 根据区域id查询服务图标
+     *
+     * @param regionId 区域id
+     * @return 服务图标
+     */
+    List<ServeCategoryResDTO> findServeIconCategoryByRegionId(@Param("regionId")Long regionId);
+
+    /**
+     * 根据id查询详情
+     *
+     * @param id 服务id
+     * @return 服务详情
+     */
+    ServeAggregationResDTO findServeDetailById(@Param("id") Long id);
+}

+ 16 - 0
src/main/java/com/jzo2o/foundations/mapper/ServeSyncMapper.java

@@ -0,0 +1,16 @@
+package com.jzo2o.foundations.mapper;
+
+import com.jzo2o.foundations.model.domain.ServeSync;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 服务同步表 Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-10
+ */
+public interface ServeSyncMapper extends BaseMapper<ServeSync> {
+}

+ 16 - 0
src/main/java/com/jzo2o/foundations/mapper/ServeTypeMapper.java

@@ -0,0 +1,16 @@
+package com.jzo2o.foundations.mapper;
+
+import com.jzo2o.foundations.model.domain.ServeType;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 服务类型表 Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+public interface ServeTypeMapper extends BaseMapper<ServeType> {
+}

+ 59 - 0
src/main/java/com/jzo2o/foundations/model/domain/CityDirectory.java

@@ -0,0 +1,59 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 城市编码表
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("city_directory")
+public class CityDirectory implements Serializable {
+    private static final long serialVersionUID = -1543919563486396187L;
+
+    @TableId(value = "id", type = IdType.INPUT)
+    private String id;
+
+    /**
+     * 父级城市编码
+     */
+    private String parentCode;
+
+    /**
+     * 城市类型,1:省份。2:市级
+     */
+    private String type;
+
+    /**
+     * 城市名称
+     */
+    private String cityName;
+
+    /**
+     * 城市编码
+     */
+    private String cityCode;
+
+    /**
+     * 排序字段
+     */
+    private Integer sortNum;
+
+    /**
+     * 城市名称拼音首字母
+     */
+    private String pinyinInitial;
+}

+ 89 - 0
src/main/java/com/jzo2o/foundations/model/domain/ConfigRegion.java

@@ -0,0 +1,89 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.io.Serializable;
+
+import lombok.*;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 区域业务配置
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-08-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ConfigRegion implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 区域id
+     */
+    @TableId(value = "id", type = IdType.NONE)
+    private Long id;
+
+    /**
+     * 城市编码
+     */
+    private String cityCode;
+
+    /**
+     * (个体)接单量限制
+     */
+    private Integer staffReceiveOrderMax;
+
+    /**
+     * (企业)接单量限制值
+     */
+    private Integer institutionReceiveOrderMax;
+
+    /**
+     * (个体)服务范围半径
+     */
+    private Integer staffServeRadius;
+
+    /**
+     * (企业)服务范围半径
+     */
+    private Integer institutionServeRadius;
+
+    /**
+     * 分流间隔(单位分钟),即下单时间与服务预计开始时间的间隔
+     */
+    private Integer diversionInterval;
+
+    /**
+     * 抢单超时时间间隔(单位分钟),从支付成功进入抢单后超过当前时间抢单派单同步进行
+     */
+    private Integer seizeTimeoutInterval;
+
+    /**
+     * 派单策略,1:距离优先策略,2:评分优先策略,3:接单量优先策略
+     */
+    private Integer dispatchStrategy;
+
+    /**
+     * 派单每轮时间间隔
+     */
+    private Integer dispatchPerRoundInterval;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    private Long createBy;
+
+    private Long updateBy;
+
+
+}

+ 89 - 0
src/main/java/com/jzo2o/foundations/model/domain/Operator.java

@@ -0,0 +1,89 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 运营人员
+ * </p>
+ *
+ * @author author
+ * @since 2023-07-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("operator")
+public class Operator implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.NONE)
+    private Long id;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 头像
+     */
+    private String avatar;
+
+    /**
+     * 运营人员姓名
+     */
+    private String name;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 账户状态:0-禁用 1-正常
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 创建者id
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createBy;
+
+    /**
+     * 更新者id
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updateBy;
+
+    /**
+     * 逻辑删除,默认0
+     */
+    private Integer isDeleted;
+}

+ 80 - 0
src/main/java/com/jzo2o/foundations/model/domain/Region.java

@@ -0,0 +1,80 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 区域表
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("region")
+public class Region implements Serializable {
+    private static final long serialVersionUID = -6475795569304770481L;
+
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 城市编码
+     */
+    private String cityCode;
+
+    /**
+     * 区域名称
+     */
+    private String name;
+
+    /**
+     * 负责人名称
+     */
+    private String managerName;
+
+    /**
+     * 负责人电话
+     */
+    private String managerPhone;
+
+    /**
+     * 活动状态,0:草稿,1:禁用,:2:启用
+     */
+    private Integer activeStatus;
+
+    /**
+     * 排序字段
+     */
+    private Integer sortNum;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 创建者
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createBy;
+
+    /**
+     * 更新者
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updateBy;
+}

+ 86 - 0
src/main/java/com/jzo2o/foundations/model/domain/Serve.java

@@ -0,0 +1,86 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("serve")
+public class Serve implements Serializable {
+    private static final long serialVersionUID = -283112689446411326L;
+
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 服务id
+     */
+    private Long serveItemId;
+
+    /**
+     * 区域id
+     */
+    private Long regionId;
+
+    /**
+     * 城市编码
+     */
+    private String cityCode;
+
+    /**
+     * 售卖状态,0:草稿,1下架,2上架
+     */
+    private Integer saleStatus;
+
+    /**
+     * 价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 是否为热门,0非热门,1热门
+     */
+    private Integer isHot;
+
+    /**
+     * 更新为热门的时间戳
+     */
+    private Long hotTimeStamp;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 创建者
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createBy;
+
+    /**
+     * 更新者
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updateBy;
+}

+ 96 - 0
src/main/java/com/jzo2o/foundations/model/domain/ServeAggregation.java

@@ -0,0 +1,96 @@
+package com.jzo2o.foundations.model.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class ServeAggregation implements Serializable {
+    private static final long serialVersionUID = -1655955421320957958L;
+    /**
+     * 服务id
+     */
+    private Long id;
+
+    /**
+     * 服务项名称
+     */
+    private String serveItemName;
+
+    /**
+     * 服务类型id
+     */
+    private Long serveTypeId;
+
+    /**
+     * 服务项id
+     */
+    private Long serveItemId;
+
+    /**
+     * 城市代码
+     */
+    private String cityCode;
+
+    /**
+     * 价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 是否是热门
+     */
+    private Integer isHot;
+
+    /**
+     * 更新为热门的时间戳
+     */
+    private Long hotTimeStamp;
+
+    /**
+     * 服务项排序字段
+     */
+    private Integer serveItemSortNum;
+
+    /**
+     * 服务类型排序字段
+     */
+    private Integer serveTypeSortNum;
+
+    /**
+     * 服务类型名称
+     */
+    private String serveTypeName;
+
+    /**
+     * 服务类型图片
+     */
+    private String serveTypeImg;
+
+    /**
+     * 服务类型icon
+     */
+    private String serveTypeIcon;
+
+    /**
+     * 服务收费价格单位
+     */
+    private Integer unit;
+
+    /**
+     * 服务详情图片
+     */
+    private String detailImg;
+
+    /**
+     * 服务项图片
+     */
+    private String serveItemImg;
+
+    /**
+     * 服务图标
+     */
+    private String serveItemIcon;
+
+}

+ 108 - 0
src/main/java/com/jzo2o/foundations/model/domain/ServeItem.java

@@ -0,0 +1,108 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 服务表
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("serve_item")
+public class ServeItem implements Serializable {
+    private static final long serialVersionUID = -6558310077509611789L;
+
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 服务编码
+     */
+    private String code;
+
+    /**
+     * 服务类型id
+     */
+    private Long serveTypeId;
+
+    /**
+     * 服务名称
+     */
+    private String name;
+
+    /**
+     * 服务图标
+     */
+    private String serveItemIcon;
+
+    /**
+     * 服务图片
+     */
+    private String img;
+
+    /**
+     * 服务单位
+     */
+    private Integer unit;
+
+    /**
+     * 服务描述
+     */
+    private String description;
+
+    /**
+     * 服务详图
+     */
+    private String detailImg;
+
+    /**
+     * 参考价格
+     */
+    private BigDecimal referencePrice;
+
+    /**
+     * 排序字段
+     */
+    private Integer sortNum;
+
+    /**
+     * 活动状态,0:草稿,1禁用,2启用
+     */
+    private Integer activeStatus;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 创建者
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createBy;
+
+    /**
+     * 更新者
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updateBy;
+
+
+}

+ 115 - 0
src/main/java/com/jzo2o/foundations/model/domain/ServeSync.java

@@ -0,0 +1,115 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * <p>
+ * 服务同步表
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("serve_sync")
+public class ServeSync implements Serializable {
+    private static final long serialVersionUID = 7506867018480258143L;
+
+    /**
+     * 服务id
+     */
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 服务项名称
+     */
+    private String serveItemName;
+
+    /**
+     * 服务类型id
+     */
+    private Long serveTypeId;
+
+    /**
+     * 服务项id
+     */
+    private Long serveItemId;
+
+    /**
+     * 城市代码
+     */
+    private String cityCode;
+
+    /**
+     * 价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 是否是热门
+     */
+    private Integer isHot;
+
+    /**
+     * 更新为热门的时间戳
+     */
+    private Long hotTimeStamp;
+
+    /**
+     * 服务项排序字段
+     */
+    private Integer serveItemSortNum;
+
+    /**
+     * 服务类型排序字段
+     */
+    private Integer serveTypeSortNum;
+
+    /**
+     * 服务类型名称
+     */
+    private String serveTypeName;
+
+    /**
+     * 服务类型图片
+     */
+    private String serveTypeImg;
+
+    /**
+     * 服务类型icon
+     */
+    private String serveTypeIcon;
+
+    /**
+     * 服务收费价格单位
+     */
+    private Integer unit;
+
+    /**
+     * 服务详情图片
+     */
+    private String detailImg;
+
+    /**
+     * 服务项图片
+     */
+    private String serveItemImg;
+
+    /**
+     * 服务图标
+     */
+    private String serveItemIcon;
+
+
+}

+ 80 - 0
src/main/java/com/jzo2o/foundations/model/domain/ServeType.java

@@ -0,0 +1,80 @@
+package com.jzo2o.foundations.model.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 服务类型表
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("serve_type")
+public class ServeType implements Serializable {
+    private static final long serialVersionUID = 9096692500357281141L;
+
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 服务类型编码
+     */
+    private String code;
+
+    /**
+     * 服务类型名称
+     */
+    private String name;
+
+    /**
+     * 服务类型图标
+     */
+    private String serveTypeIcon;
+
+    /**
+     * 服务类型图片
+     */
+    private String img;
+
+    /**
+     * 排序字段
+     */
+    private Integer sortNum;
+
+    /**
+     * 活动状态,0:草稿,1:禁用,:2:启用
+     */
+    private Integer activeStatus;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 创建者
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createBy;
+
+    /**
+     * 更新者
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updateBy;
+}

+ 21 - 0
src/main/java/com/jzo2o/foundations/model/dto/OperatorAddDTO.java

@@ -0,0 +1,21 @@
+package com.jzo2o.foundations.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author itcast
+ */
+@Data
+@ApiModel("运营人员新增模型")
+public class OperatorAddDTO {
+    @ApiModelProperty("账号")
+    private String username;
+
+    @ApiModelProperty("运营人员姓名")
+    private String name;
+
+    @ApiModelProperty("密码")
+    private String password;
+}

+ 69 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ConfigRegionSetReqDTO.java

@@ -0,0 +1,69 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel("区域配置")
+@Data
+public class ConfigRegionSetReqDTO {
+
+    /**
+     * 区域id
+     */
+    @ApiModelProperty(value = "区域id",required = true)
+    private Long id;
+    /**
+     * 城市编码
+     */
+    @ApiModelProperty(value = "区域编码",required = true)
+    private String cityCode;
+
+    /**
+     * (个体)接单量限制
+     */
+    @ApiModelProperty(value = "区域个人接单数量限制(单位个)",required = true)
+    private Integer staffReceiveOrderMax;
+
+    /**
+     * (企业)接单量限制值
+     */
+    @ApiModelProperty(value = "区域企业接单数量限制,(单位个)",required = true)
+    private Integer institutionReceiveOrderMax;
+
+    /**
+     * (个体)服务范围半径
+     */
+    @ApiModelProperty(value = "个人服务半径,(单位km)",required = true)
+    private Integer staffServeRadius;
+
+    /**
+     * (企业)服务范围半径
+     */
+    @ApiModelProperty(value = "企业服务半径(单位km)",required = true)
+    private Integer institutionServeRadius;
+
+    /**
+     * 分流间隔(单位分钟),即下单时间与服务预计开始时间的间隔
+     */
+    @ApiModelProperty(value = "分流间隔(单位分钟),即下单时间与服务预计开始时间的间隔",required = true)
+    private Integer diversionInterval;
+
+    /**
+     * 抢单超时时间间隔(单位分钟),从支付成功进入抢单后超过当前时间抢单派单同步进行
+     */
+    @ApiModelProperty(value = "抢单超时时间间隔(单位分钟)",required = true)
+    private Integer seizeTimeoutInterval;
+
+    /**
+     * 派单策略,1:距离优先策略,2:评分优先策略,3:接单量优先策略
+     */
+    @ApiModelProperty(value = "派单策略,1:距离优先策略,2:评分优先策略,3:接单量优先策略",required = true)
+    private Integer dispatchStrategy;
+
+    /**
+     * 派单每轮时间间隔,(单位s)
+     */
+    @ApiModelProperty(value = "派单每轮时间间隔,(单位s)",required = true)
+    private Integer dispatchPerRoundInterval;
+}

+ 21 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/LoginReqDTO.java

@@ -0,0 +1,21 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel("运营人员登录模型")
+@Data
+public class LoginReqDTO {
+
+    /**
+     * 运营人员账号
+     */
+    @ApiModelProperty("运营人员账号")
+    private String username;
+    /**
+     * 登录密码
+     */
+    @ApiModelProperty("登录密码")
+    private String password;
+}

+ 16 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/RegionPageQueryReqDTO.java

@@ -0,0 +1,16 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import com.jzo2o.common.model.dto.PageQueryDTO;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * 区域分页查询类
+ *
+ * @author itcast
+ * @create 2023/7/4 12:43
+ **/
+@Data
+@ApiModel("区域分页查询类")
+public class RegionPageQueryReqDTO extends PageQueryDTO {
+}

+ 40 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/RegionUpsertReqDTO.java

@@ -0,0 +1,40 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 区域新增更新
+ *
+ * @author itcast
+ * @create 2023/7/3 14:43
+ **/
+@Data
+@ApiModel("区域新增更新")
+public class RegionUpsertReqDTO {
+
+    /**
+     * 城市编码
+     */
+    @ApiModelProperty(value = "城市编码", required = true)
+    private String cityCode;
+
+    /**
+     * 区域名称
+     */
+    @ApiModelProperty(value = "区域名称", required = true)
+    private String name;
+
+    /**
+     * 负责人名称
+     */
+    @ApiModelProperty(value = "负责人名称", required = true)
+    private String managerName;
+
+    /**
+     * 负责人电话
+     */
+    @ApiModelProperty(value = "负责人电话", required = true)
+    private String managerPhone;
+}

+ 26 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ServeItemPageQueryReqDTO.java

@@ -0,0 +1,26 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import com.jzo2o.common.model.dto.PageQueryDTO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 服务项分页查询类
+ *
+ * @author itcast
+ * @create 2023/7/4 12:43
+ **/
+@Data
+@ApiModel("服务项分页查询类")
+public class ServeItemPageQueryReqDTO extends PageQueryDTO {
+
+    @ApiModelProperty("服务项名称")
+    private String name;
+
+    @ApiModelProperty("服务类型id")
+    private Long serveTypeId;
+
+    @ApiModelProperty("活动状态,0:草稿,1禁用,2启用")
+    private Integer activeStatus;
+}

+ 72 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ServeItemUpsertReqDTO.java

@@ -0,0 +1,72 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 服务项新增更新
+ *
+ * @author itcast
+ * @create 2023/7/3 14:43
+ **/
+@Data
+@ApiModel("服务项新增更新")
+public class ServeItemUpsertReqDTO {
+
+    /**
+     * 服务类型id
+     */
+    @ApiModelProperty(value = "服务类型id", required = true)
+    private Long serveTypeId;
+
+    /**
+     * 服务名称
+     */
+    @ApiModelProperty(value = "服务名称", required = true)
+    private String name;
+
+    /**
+     * 服务图标
+     */
+    @ApiModelProperty(value = "服务图标", required = true)
+    private String serveItemIcon;
+
+    /**
+     * 服务图片
+     */
+    @ApiModelProperty(value = "服务图片", required = true)
+    private String img;
+
+    /**
+     * 服务单位
+     */
+    @ApiModelProperty(value = "服务单位", required = true)
+    private Integer unit;
+
+    /**
+     * 服务描述
+     */
+    @ApiModelProperty(value = "服务描述", required = true)
+    private String description;
+
+    /**
+     * 服务详图
+     */
+    @ApiModelProperty(value = "服务详图", required = true)
+    private String detailImg;
+
+    /**
+     * 参考价格
+     */
+    @ApiModelProperty(value = "参考价格", required = true)
+    private BigDecimal referencePrice;
+
+    /**
+     * 排序字段
+     */
+    @ApiModelProperty(value = "排序字段", required = true)
+    private Integer sortNum;
+}

+ 19 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ServePageQueryReqDTO.java

@@ -0,0 +1,19 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import com.jzo2o.common.model.dto.PageQueryDTO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 服务分页查询类
+ *
+ * @author itcast
+ * @create 2023/7/4 12:43
+ **/
+@Data
+@ApiModel("服务分页查询类")
+public class ServePageQueryReqDTO extends PageQueryDTO {
+    @ApiModelProperty(value = "区域id", required = true)
+    private Long regionId;
+}

+ 58 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ServeSyncUpdateReqDTO.java

@@ -0,0 +1,58 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import lombok.Data;
+
+/**
+ * 服务同步表更新
+ *
+ * @author itcast
+ * @create 2023/8/1 19:06
+ **/
+@Data
+public class ServeSyncUpdateReqDTO {
+    /**
+     * 服务类型名称
+     */
+    private String serveTypeName;
+
+    /**
+     * 服务类型图片
+     */
+    private String serveTypeImg;
+
+    /**
+     * 服务类型图标
+     */
+    private String serveTypeIcon;
+
+    /**
+     * 服务类型排序
+     */
+    private Integer serveTypeSortNum;
+
+    /**
+     * 服务项名称
+     */
+    private String serveItemName;
+
+    /**
+     * 服务项图片
+     */
+    private String serveItemImg;
+
+    /**
+     * 服务项图标
+     */
+    private String serveItemIcon;
+
+    /**
+     * 服务项排序
+     */
+    private Integer serveItemSortNum;
+
+    /**
+     * 服务收费价格单位
+     */
+    private Integer unit;
+
+}

+ 16 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ServeTypePageQueryReqDTO.java

@@ -0,0 +1,16 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import com.jzo2o.common.model.dto.PageQueryDTO;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * 服务类型分页查询类
+ *
+ * @author itcast
+ * @create 2023/7/4 12:43
+ **/
+@Data
+@ApiModel("服务类型分页查询类")
+public class ServeTypePageQueryReqDTO extends PageQueryDTO {
+}

+ 40 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ServeTypeUpsertReqDTO.java

@@ -0,0 +1,40 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+ * 服务类型新增更新
+ *
+ * @author itcast
+ * @create 2023/7/3 14:43
+ **/
+@Data
+@ApiModel("服务类型新增更新")
+public class ServeTypeUpsertReqDTO {
+    /**
+     * 服务类型名称
+     */
+    @ApiModelProperty(value = "服务类型名称", required = true)
+    private String name;
+
+    /**
+     * 服务类型图标
+     */
+    @ApiModelProperty(value = "服务类型图标", required = true)
+    private String serveTypeIcon;
+
+    /**
+     * 服务类型图片
+     */
+    @ApiModelProperty(value = "服务类型图片", required = true)
+    private String img;
+
+    /**
+     * 排序字段
+     */
+    @ApiModelProperty(value = "排序字段", required = true)
+    private Integer sortNum;
+}

+ 36 - 0
src/main/java/com/jzo2o/foundations/model/dto/request/ServeUpsertReqDTO.java

@@ -0,0 +1,36 @@
+package com.jzo2o.foundations.model.dto.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 服务新增更新
+ *
+ * @author itcast
+ * @create 2023/7/3 14:43
+ **/
+@Data
+@ApiModel("服务新增更新")
+public class ServeUpsertReqDTO {
+
+    /**
+     * 服务id
+     */
+    @ApiModelProperty(value = "服务id", required = true)
+    private Long serveItemId;
+
+    /**
+     * 区域id
+     */
+    @ApiModelProperty(value = "区域id", required = true)
+    private Long regionId;
+
+    /**
+     * 价格
+     */
+    @ApiModelProperty(value = "价格", required = true)
+    private BigDecimal price;
+}

+ 27 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/CityResDTO.java

@@ -0,0 +1,27 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 城市响应信息
+ *
+ * @author itcast
+ * @create 2023/7/12 10:12
+ **/
+@Data
+@ApiModel("城市响应信息")
+public class CityResDTO {
+    /**
+     * 城市名称
+     */
+    @ApiModelProperty("城市名称")
+    private String cityName;
+
+    /**
+     * 城市编码
+     */
+    @ApiModelProperty("城市编码")
+    private String cityCode;
+}

+ 69 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/ConfigRegionResDTO.java

@@ -0,0 +1,69 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel("区域配置")
+@Data
+public class ConfigRegionResDTO {
+
+    /**
+     * 区域id
+     */
+    @ApiModelProperty(value = "区域id",required = true)
+    private Long id;
+    /**
+     * 城市编码
+     */
+    @ApiModelProperty(value = "区域编码",required = true)
+    private String cityCode;
+
+    /**
+     * (个体)接单量限制
+     */
+    @ApiModelProperty(value = "区域个人接单数量限制(单位个)",required = true)
+    private Integer staffReceiveOrderMax;
+
+    /**
+     * (企业)接单量限制值
+     */
+    @ApiModelProperty(value = "区域企业接单数量限制,(单位个)",required = true)
+    private Integer institutionReceiveOrderMax;
+
+    /**
+     * (个体)服务范围半径
+     */
+    @ApiModelProperty(value = "个人服务半径,(单位km)",required = true)
+    private Integer staffServeRadius;
+
+    /**
+     * (企业)服务范围半径
+     */
+    @ApiModelProperty(value = "企业服务半径(单位km)",required = true)
+    private Integer institutionServeRadius;
+
+    /**
+     * 分流间隔(单位分钟),即下单时间与服务预计开始时间的间隔
+     */
+    @ApiModelProperty(value = "分流间隔(单位分钟),即下单时间与服务预计开始时间的间隔",required = true)
+    private Integer diversionInterval;
+
+    /**
+     * 抢单超时时间间隔(单位分钟),从支付成功进入抢单后超过当前时间抢单派单同步进行
+     */
+    @ApiModelProperty(value = "抢单超时时间间隔(单位分钟)",required = true)
+    private Integer seizeTimeoutInterval;
+
+    /**
+     * 派单策略,1:距离优先策略,2:评分优先策略,3:接单量优先策略
+     */
+    @ApiModelProperty(value = "派单策略,1:距离优先策略,2:评分优先策略,3:接单量优先策略",required = true)
+    private Integer dispatchStrategy;
+
+    /**
+     * 派单每轮时间间隔,(单位s)
+     */
+    @ApiModelProperty(value = "派单每轮时间间隔,(单位s)",required = true)
+    private Integer dispatchPerRoundInterval;
+}

+ 17 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/LoginResDTO.java

@@ -0,0 +1,17 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@ApiModel("登录结果")
+@NoArgsConstructor
+@AllArgsConstructor
+public class LoginResDTO {
+
+    @ApiModelProperty("运营端访问token")
+    private String token;
+}

+ 45 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/RegionDisplayResDTO.java

@@ -0,0 +1,45 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 用户端-区域展示响应模型
+ *
+ * @author itcast
+ * @create 2023/8/28 15:54
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("区域展示响应模型")
+public class RegionDisplayResDTO {
+    /**
+     * 区域id
+     */
+    @ApiModelProperty("区域id")
+    private Long id;
+
+    /**
+     * 区域编码
+     */
+    @ApiModelProperty("区域编码")
+    private String cityCode;
+
+    /**
+     * 区域名称
+     */
+    @ApiModelProperty("区域名称")
+    private String name;
+
+    /**
+     * 活动状态,0:草稿,1:禁用,:2:启用
+     */
+    @ApiModelProperty("活动状态,0:草稿,1:禁用,:2:启用")
+    private Integer activeStatus;
+}

+ 65 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/RegionResDTO.java

@@ -0,0 +1,65 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 区域响应值
+ *
+ * @author itcast
+ * @create 2023/7/4 11:53
+ **/
+@Data
+@ApiModel("区域响应值")
+public class RegionResDTO {
+    /**
+     * 主键
+     */
+    @ApiModelProperty("主键")
+    private Long id;
+
+    /**
+     * 城市编码
+     */
+    @ApiModelProperty("城市编码")
+    private String cityCode;
+
+    /**
+     * 区域名称
+     */
+    @ApiModelProperty("区域名称")
+    private String name;
+
+    /**
+     * 负责人名称
+     */
+    @ApiModelProperty("负责人名称")
+    private String managerName;
+
+    /**
+     * 负责人电话
+     */
+    @ApiModelProperty("负责人电话")
+    private String managerPhone;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty("更新时间")
+    private LocalDateTime updateTime;
+
+    /**
+     * 活动状态,0:草稿,1:禁用,:2:启用
+     */
+    @ApiModelProperty("活动状态,0:草稿,1:禁用,:2:启用")
+    private Integer activeStatus;
+}

+ 33 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/RegionSimpleResDTO.java

@@ -0,0 +1,33 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 区域简略响应值
+ *
+ * @author itcast
+ * @create 2023/7/4 11:53
+ **/
+@Data
+@ApiModel("区域简略响应值")
+public class RegionSimpleResDTO {
+    /**
+     * 主键
+     */
+    @ApiModelProperty("主键")
+    private Long id;
+
+    /**
+     * 区域名称
+     */
+    @ApiModelProperty("区域名称")
+    private String name;
+
+    /**
+     * 城市编码
+     */
+    @ApiModelProperty("城市编码")
+    private String cityCode;
+}

+ 70 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/ServeAggregationSimpleResDTO.java

@@ -0,0 +1,70 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+/**
+ * 服务响应值
+ *
+ * @author itcast
+ * @create 2023/7/4 11:53
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ServeAggregationSimpleResDTO {
+    /**
+     * 主键
+     */
+    @ApiModelProperty("主键")
+    private Long id;
+
+    /**
+     * 服务id
+     */
+    @ApiModelProperty("服务项id")
+    private Long serveItemId;
+
+    /**
+     * 服务项名称
+     */
+    @ApiModelProperty("服务项名称")
+    private String serveItemName;
+
+    /**
+     * 服务项图片
+     */
+    @ApiModelProperty("服务项图片")
+    private String serveItemImg;
+
+    /**
+     * 服务单位
+     */
+    @ApiModelProperty("服务单位")
+    private Integer unit;
+
+    /**
+     * 价格
+     */
+    @ApiModelProperty("价格")
+    private BigDecimal price;
+
+    /**
+     * 服务详图
+     */
+    @ApiModelProperty("服务详图")
+    private String detailImg;
+
+    /**
+     * 城市编码
+     */
+    @ApiModelProperty("城市编码")
+    private String cityCode;
+}

+ 46 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/ServeAggregationTypeSimpleResDTO.java

@@ -0,0 +1,46 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 服务分类响应信息
+ *
+ * @author itcast
+ * @create 2023/7/7 14:50
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("服务分类响应信息")
+public class ServeAggregationTypeSimpleResDTO {
+
+    /**
+     * 服务类型id
+     */
+    @ApiModelProperty("服务类型id")
+    private Long serveTypeId;
+
+    /**
+     * 服务类型名称
+     */
+    @ApiModelProperty("服务类型名称")
+    private String serveTypeName;
+
+    /**
+     * 服务类型图片
+     */
+    @ApiModelProperty("服务类型图片")
+    private String serveTypeImg;
+
+    /**
+     * 服务类型排序字段
+     */
+    @ApiModelProperty("服务类型排序字段")
+    private Integer serveTypeSortNum;
+}

+ 53 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/ServeCategoryResDTO.java

@@ -0,0 +1,53 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 首页服务图标
+ *
+ * @author itcast
+ * @create 2023/7/7 14:50
+ **/
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("首页服务图标")
+public class ServeCategoryResDTO {
+
+    /**
+     * 服务类型id
+     */
+    @ApiModelProperty("服务类型id")
+    private Long serveTypeId;
+
+    /**
+     * 服务类型名称
+     */
+    @ApiModelProperty("服务类型名称")
+    private String serveTypeName;
+
+    /**
+     * 服务类型图标
+     */
+    @ApiModelProperty("服务类型图标")
+    private String serveTypeIcon;
+    private String cityCode;
+
+    /**
+     * 服务类型排序字段
+     */
+    @ApiModelProperty("服务类型排序字段")
+    private Integer serveTypeSortNum;
+
+    /**
+     * 服务项图标列表
+     */
+    @ApiModelProperty("服务项图标列表")
+    private List<ServeSimpleResDTO> serveResDTOList;
+}

+ 90 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/ServeResDTO.java

@@ -0,0 +1,90 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 服务响应值
+ *
+ * @author itcast
+ * @create 2023/7/4 11:53
+ **/
+@Data
+@ApiModel("服务响应值")
+public class ServeResDTO {
+    /**
+     * 主键
+     */
+    @ApiModelProperty("主键")
+    private Long id;
+
+    /**
+     * 售卖状态,0:草稿,1下架,2上架
+     */
+    @ApiModelProperty("售卖状态,0:草稿,1下架,2上架")
+    private Integer saleStatus;
+
+    /**
+     * 服务id
+     */
+    @ApiModelProperty("服务项id")
+    private Long serveItemId;
+
+    /**
+     * 服务名称
+     */
+    @ApiModelProperty("服务项名称")
+    private String serveItemName;
+
+    /**
+     * 服务类型id
+     */
+    @ApiModelProperty("服务类型id")
+    private Long serveTypeId;
+
+    /**
+     * 服务名称
+     */
+    @ApiModelProperty("服务类型名称")
+    private String serveTypeName;
+
+    /**
+     * 区域id
+     */
+    @ApiModelProperty("区域id")
+    private Long regionId;
+
+    /**
+     * 参考价格
+     */
+    @ApiModelProperty("参考价格")
+    private BigDecimal referencePrice;
+
+    /**
+     * 价格
+     */
+    @ApiModelProperty("价格")
+    private BigDecimal price;
+
+    /**
+     * 是否为热门,0非热门,1热门
+     */
+    @ApiModelProperty("是否为热门,0非热门,1热门")
+    private Integer isHot;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty("更新时间")
+    private LocalDateTime updateTime;
+}

+ 46 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/ServeSimpleResDTO.java

@@ -0,0 +1,46 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 服务简略响应信息
+ *
+ * @author itcast
+ * @create 2023/7/7 14:50
+ **/
+@Data
+@ApiModel("服务简略响应信息")
+public class ServeSimpleResDTO {
+
+    /**
+     * 服务id
+     */
+    @ApiModelProperty("服务id")
+    private Long id;
+
+    /**
+     * 服务项id
+     */
+    @ApiModelProperty("服务项id")
+    private Long serveItemId;
+
+    /**
+     * 服务项名称
+     */
+    @ApiModelProperty("服务项名称")
+    private String serveItemName;
+
+    /**
+     * 服务项图标
+     */
+    @ApiModelProperty("服务项图标")
+    private String serveItemIcon;
+
+    /**
+     * 服务项排序字段
+     */
+    @ApiModelProperty("服务项排序字段")
+    private Integer serveItemSortNum;
+}

+ 71 - 0
src/main/java/com/jzo2o/foundations/model/dto/response/ServeTypeResDTO.java

@@ -0,0 +1,71 @@
+package com.jzo2o.foundations.model.dto.response;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 服务类型响应值
+ *
+ * @author itcast
+ * @create 2023/7/4 11:53
+ **/
+@Data
+@ApiModel("服务类型响应值")
+public class ServeTypeResDTO {
+    /**
+     * 主键
+     */
+    @ApiModelProperty("主键")
+    private Long id;
+
+    /**
+     * 服务类型编码
+     */
+    @ApiModelProperty("服务类型编码")
+    private String code;
+
+    /**
+     * 服务类型名称
+     */
+    @ApiModelProperty("服务类型名称")
+    private String name;
+
+    /**
+     * 服务类型图标
+     */
+    @ApiModelProperty("服务类型图标")
+    private String serveTypeIcon;
+
+    /**
+     * 服务类型图片
+     */
+    @ApiModelProperty("服务类型图片")
+    private String img;
+
+    /**
+     * 排序字段
+     */
+    @ApiModelProperty("排序字段")
+    private Integer sortNum;
+
+    /**
+     * 活动状态,0:草稿,1:禁用,:2:启用
+     */
+    @ApiModelProperty("活动状态,0:草稿,1:禁用,:2:启用")
+    private Integer activeStatus;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty("更新时间")
+    private LocalDateTime updateTime;
+}

+ 19 - 0
src/main/java/com/jzo2o/foundations/properties/ApplicaitonProperties.java

@@ -0,0 +1,19 @@
+package com.jzo2o.foundations.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 应用配置,没有明确分类的系统配置
+ */
+@Configuration
+@ConfigurationProperties(prefix = "jzo2o")
+@Data
+public class ApplicaitonProperties {
+
+    /**
+     * jwt 加密秘钥
+     */
+    private String jwtKey;
+}

+ 73 - 0
src/main/java/com/jzo2o/foundations/service/HomeService.java

@@ -0,0 +1,73 @@
+package com.jzo2o.foundations.service;
+
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.foundations.model.domain.Serve;
+import com.jzo2o.foundations.model.domain.ServeItem;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
+
+import java.util.List;
+
+/**
+ * 首页查询相关功能
+ *
+ * @author itcast
+ * @create 2023/8/21 10:55
+ **/
+public interface HomeService {
+
+    /**
+     * 已开通服务区域列表
+     *
+     * @return 区域简略列表
+     */
+    List<RegionSimpleResDTO> queryActiveRegionListCache();
+
+    /**
+     * 根据区域id获取服务图标信息
+     *
+     * @param regionId 区域id
+     * @return 服务图标列表
+     */
+    List<ServeCategoryResDTO> queryServeIconCategoryByRegionIdCache(Long regionId);
+
+    /**
+     * 根据区域id查询热门服务列表
+     *
+     * @param regionId 区域id
+     * @return 服务列表
+     */
+    List<ServeAggregationSimpleResDTO> findHotServeListByRegionIdCache(Long regionId);
+
+    /**
+     * 根据区域id查询已开通的服务类型
+     *
+     * @param regionId 区域id
+     * @return 已开通的服务类型
+     */
+    List<ServeAggregationTypeSimpleResDTO> queryServeTypeListByRegionIdCache(Long regionId);
+
+    /**
+     * 根据id查询区域服务信息
+     *
+     * @param id 服务id
+     * @return 服务
+     */
+    Serve queryServeByIdCache(Long id);
+
+    /**
+     * 根据id查询服务项
+     *
+     * @param id 服务项id
+     * @return 服务项
+     */
+    ServeItem queryServeItemByIdCache(Long id);
+
+    /**
+     * 刷新区域id相关缓存:首页图标、热门服务、服务分类
+     *
+     * @param regionId 区域id
+     */
+    void refreshRegionRelateCaches(Long regionId);
+}

+ 58 - 0
src/main/java/com/jzo2o/foundations/service/IConfigRegionService.java

@@ -0,0 +1,58 @@
+package com.jzo2o.foundations.service;
+
+import com.jzo2o.api.foundations.dto.response.ConfigRegionInnerResDTO;
+import com.jzo2o.foundations.model.domain.ConfigRegion;
+import com.jzo2o.foundations.model.dto.request.ConfigRegionSetReqDTO;
+import com.jzo2o.foundations.model.dto.response.ConfigRegionResDTO;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 区域业务配置 服务类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-08-21
+ */
+public interface IConfigRegionService extends IService<ConfigRegion> {
+
+    /**
+     * 获取区域配置
+     *
+     * @param id 区域id
+     * @return 区域配置信息
+     */
+    ConfigRegionResDTO queryById(Long id);
+
+    /**
+     * 设置区域业务配置
+     *
+     * @param id 区域id
+     * @param configRegionSetReqDTO 区域配置
+     */
+    void setConfigRegionById(Long id, ConfigRegionSetReqDTO configRegionSetReqDTO);
+
+    /**
+     * 初始化区域配置
+     * @param id
+     * @param cityCode
+     */
+    void init(Long id, String cityCode);
+
+    /**
+     * 查询所有的区域配置
+     *
+     * @return
+     */
+    List<ConfigRegionInnerResDTO> queryAll();
+
+    /**
+     * 根据城市编码获取区域配置
+     *
+     * @param cityCode 城市编码
+     * @return 区域配置
+     */
+    ConfigRegionInnerResDTO queryByCityCode(String cityCode);
+}

+ 17 - 0
src/main/java/com/jzo2o/foundations/service/ILoginService.java

@@ -0,0 +1,17 @@
+package com.jzo2o.foundations.service;
+
+import com.jzo2o.foundations.model.dto.request.LoginReqDTO;
+
+/**
+ * 登录相关业务
+ * @author itcast
+ */
+public interface ILoginService {
+    /**
+     * 运营员登录
+     *
+     * @param loginReqDTO 运营人员登录请求模型
+     * @return token
+     */
+    String login(LoginReqDTO loginReqDTO);
+}

+ 31 - 0
src/main/java/com/jzo2o/foundations/service/IOperatorService.java

@@ -0,0 +1,31 @@
+package com.jzo2o.foundations.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jzo2o.foundations.model.domain.Operator;
+import com.jzo2o.foundations.model.dto.OperatorAddDTO;
+
+/**
+ * <p>
+ * 运营人员 服务类
+ * </p>
+ *
+ * @author author
+ * @since 2023-06-29
+ */
+public interface IOperatorService extends IService<Operator> {
+
+    /**
+     * 根据名称查询运营人员
+     *
+     * @param username 名称
+     * @return 运营人员
+     */
+    Operator findByUsername(String username);
+
+    /**
+     * 新增运营人员
+     *
+     * @param operatorAddDTO 运营人员新增模型
+     */
+    void add(OperatorAddDTO operatorAddDTO);
+}

+ 75 - 0
src/main/java/com/jzo2o/foundations/service/IRegionService.java

@@ -0,0 +1,75 @@
+package com.jzo2o.foundations.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.domain.Region;
+import com.jzo2o.foundations.model.dto.request.RegionPageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.RegionUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.RegionDisplayResDTO;
+import com.jzo2o.foundations.model.dto.response.RegionResDTO;
+
+import java.util.List;
+
+/**
+ * 区域管理
+ *
+ * @author itcast
+ * @create 2023/7/17 16:49
+ **/
+public interface IRegionService extends IService<Region> {
+
+    /**
+     * 区域新增
+     *
+     * @param regionUpsertReqDTO 插入更新区域
+     */
+    void add(RegionUpsertReqDTO regionUpsertReqDTO);
+
+    /**
+     * 区域修改
+     *
+     * @param id           区域id
+     * @param managerName  负责人姓名
+     * @param managerPhone 负责人电话
+     */
+    void update(Long id, String managerName, String managerPhone);
+
+    /**
+     * 区域删除
+     *
+     * @param id 区域id
+     */
+    void deleteById(Long id);
+
+    /**
+     * 分页查询
+     *
+     * @param regionPageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    PageResult<RegionResDTO> page(RegionPageQueryReqDTO regionPageQueryReqDTO);
+
+    /**
+     * 已开通服务区域列表
+     *
+     * @return 区域列表
+     */
+    List<RegionSimpleResDTO> queryActiveRegionList();
+
+    /**
+     * 区域启用
+     *
+     * @param id 区域id
+     */
+    void active(Long id);
+
+    /**
+     * 区域禁用
+     *
+     * @param id 区域id
+     */
+    void deactivate(Long id);
+
+
+}

+ 100 - 0
src/main/java/com/jzo2o/foundations/service/IServeItemService.java

@@ -0,0 +1,100 @@
+package com.jzo2o.foundations.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jzo2o.api.foundations.dto.response.ServeItemResDTO;
+import com.jzo2o.api.foundations.dto.response.ServeItemSimpleResDTO;
+import com.jzo2o.api.foundations.dto.response.ServeTypeCategoryResDTO;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.domain.ServeItem;
+import com.jzo2o.foundations.model.dto.request.ServeItemPageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeItemUpsertReqDTO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 服务表 服务类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+public interface IServeItemService extends IService<ServeItem> {
+    /**
+     * 服务项新增
+     *
+     * @param serveItemUpsertReqDTO 插入更新服务项
+     */
+    void add(ServeItemUpsertReqDTO serveItemUpsertReqDTO);
+
+    /**
+     * 服务项修改
+     *
+     * @param id                    服务项id
+     * @param serveItemUpsertReqDTO 插入更新服务项
+     * @return 服务项
+     */
+    ServeItem update(Long id, ServeItemUpsertReqDTO serveItemUpsertReqDTO);
+
+    /**
+     * 启用服务项
+     *
+     * @param id 服务项id
+     * @return
+     */
+    ServeItem activate(Long id);
+
+    /**
+     * 禁用服务项
+     *
+     * @param id 服务项id
+     * @return
+     */
+    void deactivate(Long id);
+
+    /**
+     * 服务项删除
+     *
+     * @param id 服务项id
+     */
+    void deleteById(Long id);
+
+    /**
+     * 根据服务类型id查询关联的启用状态服务项数量
+     *
+     * @param serveTypeId 服务类型id
+     * @return 服务项数量
+     */
+    int queryActiveServeItemCountByServeTypeId(Long serveTypeId);
+
+    /**
+     * 分页查询
+     *
+     * @param serveItemPageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    PageResult<ServeItemResDTO> page(ServeItemPageQueryReqDTO serveItemPageQueryReqDTO);
+
+    /**
+     * 根据id查询详情
+     *
+     * @param id 服务项id
+     * @return 服务项详细信息
+     */
+    ServeItemResDTO queryServeItemAndTypeById(Long id);
+
+    /**
+     * 根据id列表批量查询
+     *
+     * @param ids 服务项id列表
+     * @return 服务项简略列表
+     */
+    List<ServeItemSimpleResDTO> queryServeItemListByIds(List<Long> ids);
+
+    /**
+     * 查询启用状态的服务项目录
+     *
+     * @return 服务项目录
+     */
+    List<ServeTypeCategoryResDTO> queryActiveServeItemCategory();
+}

+ 144 - 0
src/main/java/com/jzo2o/foundations/service/IServeService.java

@@ -0,0 +1,144 @@
+package com.jzo2o.foundations.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.domain.Serve;
+import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeResDTO;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * <p>
+ * 服务类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+public interface IServeService extends IService<Serve> {
+
+    /**
+     * 根据城市编码查询服务项id列表
+     *
+     * @param cityCode 城市编码
+     * @return 服务项id列表
+     */
+    List<Long> queryServeItemIdListByCityCode(String cityCode);
+
+    /**
+     * 批量新增
+     *
+     * @param serveUpsertReqDTOList 批量新增数据
+     */
+    void batchAdd(List<ServeUpsertReqDTO> serveUpsertReqDTOList);
+
+    /**
+     * 服务修改
+     *
+     * @param id    服务id
+     * @param price 价格
+     * @return 服务
+     */
+    Serve update(Long id, BigDecimal price);
+
+    /**
+     * 服务设置热门/取消
+     *
+     * @param id   服务id
+     * @param flag 是否为热门,0:非热门,1:热门
+     */
+    void changeHotStatus(Long id, Integer flag);
+
+    /**
+     * 根据区域id和售卖状态查询关联服务数量
+     *
+     * @param regionId   区域id
+     * @param saleStatus 售卖状态,0:草稿,1下架,2上架。可传null,即查询所有状态
+     * @return 服务数量
+     */
+    int queryServeCountByRegionIdAndSaleStatus(Long regionId, Integer saleStatus);
+
+    /**
+     * 根据服务项id和售卖状态查询关联服务数量
+     *
+     * @param  serveItemId  服务项id
+     * @param saleStatus 售卖状态,0:草稿,1下架,2上架。可传null,即查询所有状态
+     * @return 服务数量
+     */
+     int queryServeCountByServeItemIdAndSaleStatus(Long serveItemId, Integer saleStatus);
+
+    /**
+     * 分页查询
+     *
+     * @param servePageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO);
+
+    /**
+     * 删除服务
+     *
+     * @param id 服务id
+     */
+    void deleteById(Long id);
+
+    /**
+     * 查询热门服务列表
+     *
+     * @return 热门服务列表
+     */
+    List<Serve> queryHotAndOnSaleServeList();
+
+    /**
+     * 根据id查询服务详情
+     *
+     * @param id 服务id
+     * @return 服务详情
+     */
+    ServeAggregationSimpleResDTO findDetailById(Long id);
+
+
+    /**
+     * 根据区域id查询热门服务列表
+     *
+     * @param regionId 区域id
+     * @return 热门服务列表
+     */
+    List<ServeAggregationSimpleResDTO> findHotServeListByRegionId(Long regionId);
+
+    /**
+     * 根据区域id查询服务类型列表
+     *
+     * @param regionId 区域id
+     * @return 服务类型列表
+     */
+    List<ServeAggregationTypeSimpleResDTO> findServeTypeListByRegionId(Long regionId);
+
+    /**
+     * 上架
+     *
+     * @param id         服务id
+     */
+    Serve onSale(Long id);
+    /**
+     * 下架
+     *
+     * @param id         服务id
+     */
+    Serve offSale(Long id);
+
+    /**
+     * 根据id查询详情
+     *
+     * @param id 服务id
+     * @return 服务详情
+     */
+    ServeAggregationResDTO findServeDetailById(Long id);
+}

+ 31 - 0
src/main/java/com/jzo2o/foundations/service/IServeSyncService.java

@@ -0,0 +1,31 @@
+package com.jzo2o.foundations.service;
+
+import com.jzo2o.foundations.model.domain.ServeSync;
+import com.jzo2o.foundations.model.dto.request.ServeSyncUpdateReqDTO;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 服务同步表 服务类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-10
+ */
+public interface IServeSyncService extends IService<ServeSync> {
+    /**
+     * 根据服务项id更新
+     *
+     * @param serveItemId           服务项id
+     * @param serveSyncUpdateReqDTO 服务同步更新数据
+     */
+    void updateByServeItemId(Long serveItemId, ServeSyncUpdateReqDTO serveSyncUpdateReqDTO);
+
+    /**
+     * 根据服务类型id更新
+     *
+     * @param serveTypeId           服务类型id
+     * @param serveSyncUpdateReqDTO 服务同步更新数据
+     */
+    void updateByServeTypeId(Long serveTypeId, ServeSyncUpdateReqDTO serveSyncUpdateReqDTO);
+}

+ 70 - 0
src/main/java/com/jzo2o/foundations/service/IServeTypeService.java

@@ -0,0 +1,70 @@
+package com.jzo2o.foundations.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jzo2o.api.foundations.dto.response.ServeTypeSimpleResDTO;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.model.domain.ServeType;
+import com.jzo2o.foundations.model.dto.request.ServeTypePageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeTypeUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.ServeTypeResDTO;
+
+import java.util.List;
+
+/**
+ * @author itcast
+ */
+public interface IServeTypeService extends IService<ServeType> {
+
+    /**
+     * 服务类型新增
+     *
+     * @param serveTypeUpsertReqDTO 插入更新服务类型
+     */
+    void add(ServeTypeUpsertReqDTO serveTypeUpsertReqDTO);
+
+    /**
+     * 服务类型修改
+     *
+     * @param id                    服务类型id
+     * @param serveTypeUpsertReqDTO 插入更新服务类型
+     */
+    void update(Long id, ServeTypeUpsertReqDTO serveTypeUpsertReqDTO);
+
+
+    /**
+     * 服务类型启用/禁用
+     *
+     * @param id 服务类型id
+     */
+    void activate(Long id);
+
+    /**
+     * 服务类型启用/禁用
+     *
+     * @param id 服务类型id
+     */
+    void deactivate(Long id);
+
+    /**
+     * 根据id删除服务类型
+     *
+     * @param id 服务类型id
+     */
+    void deleteById(Long id);
+
+    /**
+     * 分页查询
+     *
+     * @param serveTypePageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    PageResult<ServeTypeResDTO> page(ServeTypePageQueryReqDTO serveTypePageQueryReqDTO);
+
+    /**
+     * 根据活动状态查询简略列表
+     *
+     * @param activeStatus 活动状态,0:草稿,1:禁用,:2:启用
+     * @return 服务类型列表
+     */
+    List<ServeTypeSimpleResDTO> queryServeTypeListByActiveStatus(Integer activeStatus);
+}

+ 21 - 0
src/main/java/com/jzo2o/foundations/service/ServeAggregationService.java

@@ -0,0 +1,21 @@
+package com.jzo2o.foundations.service;
+
+import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
+
+import java.util.List;
+
+/**
+ * @author itcast
+ */
+public interface ServeAggregationService {
+
+    /**
+     * 查询服务列表
+     *
+     * @param cityCode    城市编码
+     * @param serveTypeId 服务类型id
+     * @param keyword     关键词
+     * @return 服务列表
+     */
+    List<ServeSimpleResDTO> findServeList(String cityCode, Long serveTypeId, String keyword);
+}

+ 77 - 0
src/main/java/com/jzo2o/foundations/service/impl/ConfigRegionServiceImpl.java

@@ -0,0 +1,77 @@
+package com.jzo2o.foundations.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzo2o.api.foundations.dto.response.ConfigRegionInnerResDTO;
+import com.jzo2o.common.utils.BeanUtils;
+import com.jzo2o.foundations.mapper.ConfigRegionMapper;
+import com.jzo2o.foundations.model.domain.ConfigRegion;
+import com.jzo2o.foundations.model.dto.request.ConfigRegionSetReqDTO;
+import com.jzo2o.foundations.model.dto.response.ConfigRegionResDTO;
+import com.jzo2o.foundations.service.IConfigRegionService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 区域业务配置 服务实现类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-08-21
+ */
+@Service
+public class ConfigRegionServiceImpl extends ServiceImpl<ConfigRegionMapper, ConfigRegion> implements IConfigRegionService {
+
+    @Override
+    public ConfigRegionResDTO queryById(Long id) {
+        ConfigRegion configRegion = baseMapper.selectById(id);
+        return BeanUtils.toBean(configRegion, ConfigRegionResDTO.class);
+    }
+
+    @Override
+    public void setConfigRegionById(Long id, ConfigRegionSetReqDTO configRegionSetReqDTO) {
+        ConfigRegion configRegion = BeanUtils.toBean(configRegionSetReqDTO, ConfigRegion.class);
+        configRegion.setId(id);
+        baseMapper.updateById(configRegion);
+    }
+
+    @Override
+    public void init(Long id, String cityCode) {
+        ConfigRegion configRegion = ConfigRegion.builder()
+                .id(id)
+                .cityCode(cityCode)
+                // 个人接单数量限制,默认10个
+                .staffReceiveOrderMax(10)
+                // 机构接单数量限制,默认100个
+                .institutionReceiveOrderMax(100)
+                // 个人接单范围半径 50公里
+                .staffServeRadius(50)
+                // 机构接单范围半径200公里
+                .institutionServeRadius(200)
+                // 分流时间间隔120分钟,即下单时间与服务预计开始时间的间隔
+                .diversionInterval(120)
+                // 抢单超时时间,默认60分钟
+                .seizeTimeoutInterval(60)
+                // 派单策略默认距离优先策略
+                .dispatchStrategy(1)
+                // 派单每轮时间间隔,默认180s
+                .dispatchPerRoundInterval(180)
+                .build();
+        baseMapper.insert(configRegion);
+    }
+
+    @Override
+    public List<ConfigRegionInnerResDTO> queryAll() {
+        List<ConfigRegion> list = lambdaQuery().list();
+        return BeanUtils.copyToList(list, ConfigRegionInnerResDTO.class);
+    }
+
+    @Override
+    public ConfigRegionInnerResDTO queryByCityCode(String cityCode) {
+        ConfigRegion configRegion = lambdaQuery()
+                .eq(ConfigRegion::getCityCode, cityCode)
+                .one();
+        return BeanUtils.toBean(configRegion, ConfigRegionInnerResDTO.class);
+    }
+}

+ 208 - 0
src/main/java/com/jzo2o/foundations/service/impl/HomeServiceImpl.java

@@ -0,0 +1,208 @@
+package com.jzo2o.foundations.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.foundations.constants.RedisConstants;
+import com.jzo2o.foundations.enums.FoundationStatusEnum;
+import com.jzo2o.foundations.mapper.ServeMapper;
+import com.jzo2o.foundations.model.domain.Region;
+import com.jzo2o.foundations.model.domain.Serve;
+import com.jzo2o.foundations.model.domain.ServeItem;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
+import com.jzo2o.foundations.service.HomeService;
+import com.jzo2o.foundations.service.IRegionService;
+import com.jzo2o.foundations.service.IServeItemService;
+import com.jzo2o.foundations.service.IServeService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 首页查询相关功能
+ *
+ * @author itcast
+ * @create 2023/8/21 10:57
+ **/
+@Slf4j
+@Service
+public class HomeServiceImpl implements HomeService {
+    @Resource
+    private IRegionService regionService;
+    @Resource
+    private IServeService serveService;
+    @Resource
+    private ServeMapper serveMapper;
+    @Resource
+    private IServeItemService serveItemService;
+    //解决springCache同级方法调用失效问题
+    @Resource
+    private HomeService homeService;
+
+
+    /**
+     * 已开通服务区域列表
+     *
+     * @return 区域简略列表
+     */
+    @Override
+    @Cacheable(value = RedisConstants.CacheName.JZ_CACHE, key = "'ACTIVE_REGIONS'", cacheManager = RedisConstants.CacheManager.FOREVER)
+    public List<RegionSimpleResDTO> queryActiveRegionListCache() {
+        return regionService.queryActiveRegionList();
+    }
+
+    /**
+     * 根据区域id获取服务图标信息
+     *
+     * @param regionId 区域id
+     * @return 服务图标列表
+     */
+    @Override
+    @Caching(
+            cacheable = {
+                    //result为null时,属于缓存穿透情况,缓存时间30分钟
+                    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId", unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
+                    //result不为null时,永久缓存
+                    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId", unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
+            }
+    )
+    public List<ServeCategoryResDTO> queryServeIconCategoryByRegionIdCache(Long regionId) {
+        //1.校验当前城市是否为启用状态
+        Region region = regionService.getById(regionId);
+        if (ObjectUtil.isEmpty(region) || ObjectUtil.equal(FoundationStatusEnum.DISABLE.getStatus(), region.getActiveStatus())) {
+            return Collections.emptyList();
+        }
+
+        //2.根据城市编码查询所有的服务图标
+        List<ServeCategoryResDTO> list = serveMapper.findServeIconCategoryByRegionId(regionId);
+        if (ObjectUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+
+        //3.服务类型取前两个,每个类型下服务项取前4个
+        //list的截止下标
+        int endIndex = list.size() >= 2 ? 2 : list.size();
+        List<ServeCategoryResDTO> serveCategoryResDTOS = new ArrayList<>(list.subList(0, endIndex));
+        serveCategoryResDTOS.forEach(v -> {
+            List<ServeSimpleResDTO> serveResDTOList = v.getServeResDTOList();
+            //serveResDTOList的截止下标
+            int endIndex2 = serveResDTOList.size() >= 4 ? 4 : serveResDTOList.size();
+            List<ServeSimpleResDTO> serveSimpleResDTOS = new ArrayList<>(serveResDTOList.subList(0, endIndex2));
+            v.setServeResDTOList(serveSimpleResDTOS);
+        });
+
+        return serveCategoryResDTOS;
+    }
+
+
+    /**
+     * 根据区域id查询热门服务列表
+     *
+     * @param regionId 区域id
+     * @return 服务列表
+     */
+    @Override
+    @Caching(
+            cacheable = {
+                    //result为null时,属于缓存穿透情况,缓存时间30分钟
+                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
+                    //result不为null时,永久缓存
+                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
+            }
+    )
+    public List<ServeAggregationSimpleResDTO> findHotServeListByRegionIdCache(Long regionId) {
+        //1.校验当前城市是否为启用状态
+        Region region = regionService.getById(regionId);
+        if (ObjectUtil.equal(FoundationStatusEnum.DISABLE.getStatus(), region.getActiveStatus())) {
+            return Collections.emptyList();
+        }
+
+        //2.根据城市编码查询热门服务
+        List<ServeAggregationSimpleResDTO> list = serveService.findHotServeListByRegionId(regionId);
+        if (ObjectUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        return list;
+    }
+
+    /**
+     * 根据区域id查询已开通的服务类型
+     *
+     * @param regionId 区域id
+     * @return 已开通的服务类型
+     */
+    @Override
+    @Caching(
+            cacheable = {
+                    //result为null时,属于缓存穿透情况,缓存时间30分钟
+                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
+                    //result不为null时,永久缓存
+                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
+            }
+    )
+    public List<ServeAggregationTypeSimpleResDTO> queryServeTypeListByRegionIdCache(Long regionId) {
+        //1.校验当前城市是否为启用状态
+        Region region = regionService.getById(regionId);
+        if (ObjectUtil.equal(FoundationStatusEnum.DISABLE.getStatus(), region.getActiveStatus())) {
+            return Collections.emptyList();
+        }
+
+        //2.根据城市编码查询服务对应的服务分类
+        List<ServeAggregationTypeSimpleResDTO> list = serveService.findServeTypeListByRegionId(regionId);
+        if (ObjectUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        return list;
+    }
+
+    /**
+     * 根据id查询区域服务信息
+     *
+     * @param id 服务id
+     * @return 服务
+     */
+    @Override
+    @Cacheable(value = RedisConstants.CacheName.SERVE, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
+    public Serve queryServeByIdCache(Long id) {
+        return serveService.getById(id);
+    }
+
+    /**
+     * 根据id查询服务项
+     *
+     * @param id 服务项id
+     * @return 服务项
+     */
+    @Override
+    @Cacheable(value = RedisConstants.CacheName.SERVE_ITEM, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
+    public ServeItem queryServeItemByIdCache(Long id) {
+        return serveItemService.getById(id);
+    }
+
+    /**
+     * 刷新区域id相关缓存:首页图标、热门服务、服务分类
+     *
+     * @param regionId 区域id
+     */
+    @Override
+    @Caching(evict = {
+            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", beforeInvocation = true)
+    })
+    public void refreshRegionRelateCaches(Long regionId) {
+        //刷新缓存:首页图标、热门服务、服务类型
+        homeService.queryServeIconCategoryByRegionIdCache(regionId);
+        homeService.findHotServeListByRegionIdCache(regionId);
+        homeService.queryServeTypeListByRegionIdCache(regionId);
+    }
+}

+ 47 - 0
src/main/java/com/jzo2o/foundations/service/impl/LoginServiceImpl.java

@@ -0,0 +1,47 @@
+package com.jzo2o.foundations.service.impl;
+
+import com.jzo2o.common.constants.UserType;
+import com.jzo2o.common.expcetions.RequestForbiddenException;
+import com.jzo2o.common.utils.JwtTool;
+import com.jzo2o.foundations.model.domain.Operator;
+import com.jzo2o.foundations.model.dto.request.LoginReqDTO;
+import com.jzo2o.foundations.service.ILoginService;
+import com.jzo2o.foundations.service.IOperatorService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * @author itcast
+ */
+@Service
+public class LoginServiceImpl implements ILoginService {
+
+    @Resource
+    private IOperatorService operatorService;
+    @Resource
+    private JwtTool jwtTool;
+    @Resource
+    private PasswordEncoder passwordEncoder;
+
+    /**
+     * 运营员登录
+     *
+     * @param loginReqDTO 运营人员登录请求模型
+     * @return token
+     */
+    @Override
+    public String login(LoginReqDTO loginReqDTO) {
+
+        Operator operator = operatorService.findByUsername(loginReqDTO.getUsername());
+        if (operator == null) {
+            throw new RequestForbiddenException("账号或密码错误,请重新输入");
+        }
+        // 比对密码
+        if (!passwordEncoder.matches(loginReqDTO.getPassword(), operator.getPassword())) {
+            throw new RequestForbiddenException("账号或密码错误,请重新输入");
+        }
+        return jwtTool.createToken(operator.getId(), operator.getName(), operator.getAvatar(), UserType.OPERATION);
+    }
+}

+ 58 - 0
src/main/java/com/jzo2o/foundations/service/impl/OperatorServiceImpl.java

@@ -0,0 +1,58 @@
+package com.jzo2o.foundations.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzo2o.common.enums.EnableStatusEnum;
+import com.jzo2o.common.expcetions.BadRequestException;
+import com.jzo2o.common.utils.BeanUtils;
+import com.jzo2o.foundations.mapper.OperatorMapper;
+import com.jzo2o.foundations.model.domain.Operator;
+import com.jzo2o.foundations.model.dto.OperatorAddDTO;
+import com.jzo2o.foundations.service.IOperatorService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * <p>
+ * 运营人员 服务实现类
+ * </p>
+ *
+ * @author author
+ * @since 2023-06-29
+ */
+@Service
+public class OperatorServiceImpl extends ServiceImpl<OperatorMapper, Operator> implements IOperatorService {
+
+    @Resource
+    private PasswordEncoder passwordEncoder;
+
+    /**
+     * 根据名称查询运营人员
+     *
+     * @param username 名称
+     * @return 运营人员
+     */
+    @Override
+    public Operator findByUsername(String username) {
+        return lambdaQuery().eq(Operator::getUsername, username).one();
+    }
+
+    /**
+     * 新增运营人员
+     *
+     * @param operatorAddDTO 运营人员新增模型
+     */
+    @Override
+    public void add(OperatorAddDTO operatorAddDTO) {
+        Integer operatorNumExists = lambdaQuery().eq(Operator::getUsername, operatorAddDTO.getUsername())
+                .count();
+        if (operatorNumExists > 0) {
+            throw new BadRequestException("账号已经存在,请勿重复添加");
+        }
+        Operator operator = BeanUtils.copyBean(operatorAddDTO, Operator.class);
+        operator.setPassword(passwordEncoder.encode(operatorAddDTO.getPassword()));
+        operator.setStatus(EnableStatusEnum.ENABLE.getStatus());
+        baseMapper.insert(operator);
+    }
+}

+ 224 - 0
src/main/java/com/jzo2o/foundations/service/impl/RegionServiceImpl.java

@@ -0,0 +1,224 @@
+package com.jzo2o.foundations.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzo2o.api.foundations.dto.response.RegionSimpleResDTO;
+import com.jzo2o.common.expcetions.ForbiddenOperationException;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.constants.RedisConstants;
+import com.jzo2o.foundations.enums.FoundationStatusEnum;
+import com.jzo2o.foundations.mapper.CityDirectoryMapper;
+import com.jzo2o.foundations.mapper.RegionMapper;
+import com.jzo2o.foundations.model.domain.CityDirectory;
+import com.jzo2o.foundations.model.domain.Region;
+import com.jzo2o.foundations.model.dto.request.RegionPageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.RegionUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.RegionDisplayResDTO;
+import com.jzo2o.foundations.model.dto.response.RegionResDTO;
+import com.jzo2o.foundations.service.HomeService;
+import com.jzo2o.foundations.service.IConfigRegionService;
+import com.jzo2o.foundations.service.IRegionService;
+import com.jzo2o.foundations.service.IServeService;
+import com.jzo2o.mysql.utils.PageUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Caching;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 区域管理
+ *
+ * @author itcast
+ * @create 2023/7/17 16:50
+ **/
+@Service
+public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> implements IRegionService {
+    @Resource
+    private IServeService serveService;
+    @Resource
+    private IConfigRegionService configRegionService;
+    @Resource
+    private CityDirectoryMapper cityDirectoryMapper;
+    @Resource
+    private HomeService homeService;
+
+
+    /**
+     * 区域新增
+     *
+     * @param regionUpsertReqDTO 插入更新区域
+     */
+    @Override
+    @Transactional
+    public void add(RegionUpsertReqDTO regionUpsertReqDTO) {
+        //1.校验城市编码是否重复
+        LambdaQueryWrapper<Region> queryWrapper = Wrappers.<Region>lambdaQuery().eq(Region::getCityCode, regionUpsertReqDTO.getCityCode());
+        Integer count = baseMapper.selectCount(queryWrapper);
+        if (count > 0) {
+            throw new ForbiddenOperationException("城市提交重复");
+        }
+
+        //查询城市
+        CityDirectory cityDirectory = cityDirectoryMapper.selectById(regionUpsertReqDTO.getCityCode());
+        //查询城市的排序位
+        int sotNum = cityDirectory.getSortNum();
+
+        //2.新增区域
+        Region region = BeanUtil.toBean(regionUpsertReqDTO, Region.class);
+        region.setSortNum(sotNum);
+        baseMapper.insert(region);
+
+        //3.初始化区域配置
+        configRegionService.init(region.getId(), region.getCityCode());
+    }
+
+    /**
+     * 区域修改
+     *
+     * @param id           区域id
+     * @param managerName  负责人姓名
+     * @param managerPhone 负责人电话
+     */
+    @Override
+    public void update(Long id, String managerName, String managerPhone) {
+        Region region = new Region();
+        region.setId(id);
+        region.setManagerName(managerName);
+        region.setManagerPhone(managerPhone);
+        baseMapper.updateById(region);
+    }
+
+    /**
+     * 区域删除
+     *
+     * @param id 区域id
+     */
+    @Override
+    @Transactional
+    public void deleteById(Long id) {
+        //区域信息
+        Region region = baseMapper.selectById(id);
+        //启用状态
+        Integer activeStatus = region.getActiveStatus();
+        //草稿状态方可删除
+        if (!(FoundationStatusEnum.INIT.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("草稿状态方可删除");
+        }
+        //删除
+        baseMapper.deleteById(id);
+
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param regionPageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    @Override
+    public PageResult<RegionResDTO> page(RegionPageQueryReqDTO regionPageQueryReqDTO) {
+        Page<Region> page = PageUtils.parsePageQuery(regionPageQueryReqDTO, Region.class);
+        Page<Region> serveTypePage = baseMapper.selectPage(page, new QueryWrapper<>());
+        return PageUtils.toPage(serveTypePage, RegionResDTO.class);
+    }
+
+    /**
+     * 已开通服务区域列表
+     *
+     * @return 区域列表
+     */
+    @Override
+    public List<RegionSimpleResDTO> queryActiveRegionList() {
+        LambdaQueryWrapper<Region> queryWrapper = Wrappers.<Region>lambdaQuery()
+                .eq(Region::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus())
+                .orderByAsc(Region::getSortNum);
+        List<Region> regionList = baseMapper.selectList(queryWrapper);
+        return BeanUtil.copyToList(regionList, RegionSimpleResDTO.class);
+    }
+
+    /**
+     * 区域启用
+     *
+     * @param id 区域id
+     */
+    @Override
+    @Caching(evict = {
+            @CacheEvict(value = RedisConstants.CacheName.JZ_CACHE, key = "'ACTIVE_REGIONS'", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#id", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#id", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)
+    })
+    public void active(Long id) {
+        //区域信息
+        Region region = baseMapper.selectById(id);
+        //启用状态
+        Integer activeStatus = region.getActiveStatus();
+        //草稿或禁用状态方可启用
+        if (!(FoundationStatusEnum.INIT.getStatus() == activeStatus || FoundationStatusEnum.DISABLE.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("草稿或禁用状态方可启用");
+        }
+        //如果需要启用区域,需要校验该区域下是否有上架的服务
+        int count = serveService.queryServeCountByRegionIdAndSaleStatus(id, FoundationStatusEnum.ENABLE.getStatus());
+        if (count <= 0) {
+            //如果区域下不存在上架的服务,不允许启用
+            throw new ForbiddenOperationException("区域下不存在上架的服务,不允许启用");
+        }
+
+        //更新启用状态
+        LambdaUpdateWrapper<Region> updateWrapper = Wrappers.<Region>lambdaUpdate()
+                .eq(Region::getId, id)
+                .set(Region::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus());
+        update(updateWrapper);
+
+        //3.如果是启用操作,刷新缓存:启用区域列表、首页图标、热门服务、服务类型
+        homeService.queryActiveRegionListCache();
+        homeService.queryServeIconCategoryByRegionIdCache(id);
+        homeService.findHotServeListByRegionIdCache(id);
+        homeService.queryServeTypeListByRegionIdCache(id);
+    }
+
+    /**
+     * 区域禁用
+     *
+     * @param id 区域id
+     */
+    @Override
+    @Caching(evict = {
+            @CacheEvict(value = RedisConstants.CacheName.JZ_CACHE, key = "'ACTIVE_REGIONS'", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#id", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#id", beforeInvocation = true),
+            @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id", beforeInvocation = true)
+    })
+    public void deactivate(Long id) {
+        //区域信息
+        Region region = baseMapper.selectById(id);
+        //启用状态
+        Integer activeStatus = region.getActiveStatus();
+        //启用状态方可禁用
+        if (!(FoundationStatusEnum.ENABLE.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("启用状态方可禁用");
+        }
+
+        //1.如果禁用区域下有上架的服务则无法禁用
+        int count = serveService.queryServeCountByRegionIdAndSaleStatus(id, FoundationStatusEnum.ENABLE.getStatus());
+        if (count > 0) {
+            throw new ForbiddenOperationException("区域下有上架的服务无法禁用");
+        }
+
+        //更新禁用状态
+        LambdaUpdateWrapper<Region> updateWrapper = Wrappers.<Region>lambdaUpdate()
+                .eq(Region::getId, id)
+                .set(Region::getActiveStatus, FoundationStatusEnum.DISABLE.getStatus());
+        update(updateWrapper);
+    }
+
+
+}

+ 106 - 0
src/main/java/com/jzo2o/foundations/service/impl/ServeAggregationServiceImpl.java

@@ -0,0 +1,106 @@
+package com.jzo2o.foundations.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import co.elastic.clients.elasticsearch.ElasticsearchClient;
+import co.elastic.clients.elasticsearch._types.SortOptions;
+import co.elastic.clients.elasticsearch._types.SortOrder;
+import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
+import co.elastic.clients.elasticsearch._types.query_dsl.MultiMatchQuery;
+import co.elastic.clients.elasticsearch._types.query_dsl.Query;
+import co.elastic.clients.elasticsearch.core.SearchRequest;
+import co.elastic.clients.elasticsearch.core.SearchResponse;
+import co.elastic.clients.elasticsearch.core.search.Hit;
+import com.jzo2o.common.expcetions.ElasticSearchException;
+import com.jzo2o.common.utils.LambdaUtils;
+import com.jzo2o.es.core.ElasticSearchTemplate;
+import com.jzo2o.es.utils.SearchResponseUtils;
+import com.jzo2o.foundations.constants.IndexConstants;
+import com.jzo2o.foundations.model.domain.ServeAggregation;
+import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
+import com.jzo2o.foundations.service.ServeAggregationService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 服务相关
+ *
+ * @author itcast
+ * @create 2023/7/9 14:42
+ **/
+@Slf4j
+@Service
+public class ServeAggregationServiceImpl implements ServeAggregationService {
+    @Resource
+    private ElasticsearchClient client;
+
+    @Resource
+    private ElasticSearchTemplate elasticSearchTemplate;
+
+
+    /**
+     * 查询服务列表
+     *
+     * @param cityCode    城市编码
+     * @param serveTypeId 服务类型id
+     * @param keyword     关键词
+     * @return 服务列表
+     */
+    @Override
+    public List<ServeSimpleResDTO> findServeList(String cityCode, Long serveTypeId, String keyword) {
+        // 构造查询条件
+        SearchRequest.Builder builder = new SearchRequest.Builder();
+
+        builder.query(query->query.bool(bool->{
+            //匹配citycode
+            bool.must(must->
+                    must.term(term->
+                            term.field(LambdaUtils.getUnderLineFieldName(ServeAggregation::getCityCode)).value(cityCode)));
+            //匹配服务类型
+            if (ObjectUtil.isNotEmpty(serveTypeId)) {
+                bool.must(must->
+                        must.term(term->
+                                term.field(LambdaUtils.getUnderLineFieldName(ServeAggregation::getServeTypeId)).value(serveTypeId)));
+            }
+            //匹配关键字
+            if (ObjectUtil.isNotEmpty(keyword)) {
+                String serveItemNameField = LambdaUtils.getUnderLineFieldName(ServeAggregation::getServeItemName);
+                String serveTypeNameField = LambdaUtils.getUnderLineFieldName(ServeAggregation::getServeTypeName);
+
+                bool.must(must->
+                        must.multiMatch(multiMatch->multiMatch.fields(serveItemNameField,serveTypeNameField).query(keyword)));
+            }
+
+            return bool;
+        }));
+        // 排序 按服务项的serveItemSortNum排序(升序)
+        List<SortOptions> sortOptions = new ArrayList<>();
+        sortOptions.add(SortOptions.of(sortOption -> sortOption.field(field->field.field("serve_item_sort_num").order(SortOrder.Asc))));
+        builder.sort(sortOptions);
+        // 索引
+        builder.index(IndexConstants.SERVE);
+        // 检索数据
+        SearchResponse<ServeAggregation> searchResponse = elasticSearchTemplate.opsForDoc().search(builder.build(), ServeAggregation.class);
+        //如果搜索成功返回结果集
+        if (SearchResponseUtils.isSuccess(searchResponse)) {
+            List<ServeAggregation> collect = searchResponse.hits().hits()
+                    .stream().map(hit -> {
+                        ServeAggregation serve = hit.source();
+                        return serve;
+                    })
+                    .collect(Collectors.toList());
+            List<ServeSimpleResDTO> serveSimpleResDTOS = BeanUtil.copyToList(collect, ServeSimpleResDTO.class);
+            return serveSimpleResDTOS;
+        }
+        return  Collections.emptyList();
+
+    }
+}

+ 261 - 0
src/main/java/com/jzo2o/foundations/service/impl/ServeItemServiceImpl.java

@@ -0,0 +1,261 @@
+package com.jzo2o.foundations.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzo2o.api.foundations.dto.response.ServeItemResDTO;
+import com.jzo2o.api.foundations.dto.response.ServeItemSimpleResDTO;
+import com.jzo2o.api.foundations.dto.response.ServeTypeCategoryResDTO;
+import com.jzo2o.common.expcetions.ForbiddenOperationException;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.constants.RedisConstants;
+import com.jzo2o.foundations.enums.FoundationStatusEnum;
+import com.jzo2o.foundations.mapper.ServeItemMapper;
+import com.jzo2o.foundations.mapper.ServeTypeMapper;
+import com.jzo2o.foundations.model.domain.ServeItem;
+import com.jzo2o.foundations.model.domain.ServeType;
+import com.jzo2o.foundations.model.dto.request.ServeItemPageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeItemUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeSyncUpdateReqDTO;
+import com.jzo2o.foundations.service.IServeItemService;
+import com.jzo2o.foundations.service.IServeService;
+import com.jzo2o.foundations.service.IServeSyncService;
+import com.jzo2o.mysql.utils.PageHelperUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 服务表 服务实现类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Service
+public class ServeItemServiceImpl extends ServiceImpl<ServeItemMapper, ServeItem> implements IServeItemService {
+    @Resource
+    private IServeSyncService serveSyncService;
+    @Resource
+    private IServeService serveService;
+
+    @Resource
+    private ServeTypeMapper serveTypeMapper;
+
+    /**
+     * 服务项新增
+     *
+     * @param serveItemUpsertReqDTO 新增服务项
+     */
+    @Override
+    public void add(ServeItemUpsertReqDTO serveItemUpsertReqDTO) {
+        //校验名称是否重复
+        LambdaQueryWrapper<ServeItem> queryWrapper = Wrappers.<ServeItem>lambdaQuery().eq(ServeItem::getName, serveItemUpsertReqDTO.getName());
+        Integer count = baseMapper.selectCount(queryWrapper);
+        if (count > 0) {
+            throw new ForbiddenOperationException("服务项名称不可重复");
+        }
+
+        ServeItem serveItem = BeanUtil.toBean(serveItemUpsertReqDTO, ServeItem.class);
+        serveItem.setCode(IdUtil.getSnowflakeNextIdStr());
+        baseMapper.insert(serveItem);
+    }
+
+    /**
+     * 服务项修改
+     *
+     * @param id                    服务项id
+     * @param serveItemUpsertReqDTO 插入更新服务项
+     * @return 服务项
+     */
+    @Override
+    @CachePut(value = RedisConstants.CacheName.SERVE_ITEM, key = "#id", unless = "#result.activeStatus != 2", cacheManager = RedisConstants.CacheManager.ONE_DAY)
+    public ServeItem update(Long id, ServeItemUpsertReqDTO serveItemUpsertReqDTO) {
+        //1.更新服务项
+        ServeItem serveItem = BeanUtil.toBean(serveItemUpsertReqDTO, ServeItem.class);
+        serveItem.setId(id);
+        baseMapper.updateById(serveItem);
+
+        //2.同步数据到es
+        ServeSyncUpdateReqDTO serveSyncUpdateReqDTO = BeanUtil.toBean(serveItemUpsertReqDTO, ServeSyncUpdateReqDTO.class);
+        serveSyncUpdateReqDTO.setServeItemName(serveItemUpsertReqDTO.getName());
+        serveSyncUpdateReqDTO.setServeItemImg(serveItemUpsertReqDTO.getImg());
+        serveSyncUpdateReqDTO.setServeItemIcon(serveItemUpsertReqDTO.getServeItemIcon());
+        serveSyncUpdateReqDTO.setServeItemSortNum(serveItemUpsertReqDTO.getSortNum());
+        serveSyncService.updateByServeItemId(id, serveSyncUpdateReqDTO);
+
+        //用于更新缓存
+        return baseMapper.selectById(id);
+    }
+
+
+    /**
+     * 启用服务项
+     *
+     * @param id 服务项id
+     * @return
+     */
+    @Override
+    @Transactional
+    @CachePut(value = RedisConstants.CacheName.SERVE_ITEM, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
+    public ServeItem activate(Long id) {
+
+        //查询服务项
+        ServeItem serveItem = baseMapper.selectById(id);
+        if (ObjectUtil.isNull(serveItem)) {
+            throw new ForbiddenOperationException("服务项不存在");
+        }
+        //启用状态
+        Integer activeStatus = serveItem.getActiveStatus();
+        //草稿或禁用状态方可启用
+        if (!(FoundationStatusEnum.INIT.getStatus() == activeStatus || FoundationStatusEnum.DISABLE.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("草稿或禁用状态方可启用");
+        }
+        //服务类型id
+        Long serveTypeId = serveItem.getServeTypeId();
+        //服务类型信息
+        ServeType serveType = serveTypeMapper.selectById(serveTypeId);
+        if (ObjectUtil.isNull(serveType)) {
+            throw new ForbiddenOperationException("所属服务类型不存在");
+        }
+        //所属服务类型为启用状态时方可启用
+        if (!(FoundationStatusEnum.ENABLE.getStatus() == serveType.getActiveStatus())) {
+            throw new ForbiddenOperationException("所属服务类型为启用状态时方可启用");
+        }
+
+        if (ObjectUtil.equal(FoundationStatusEnum.DISABLE.getStatus(), serveType.getActiveStatus())) {
+            throw new ForbiddenOperationException("服务所属的服务类型已禁用,启用后方可操作。");
+        }
+        //更新启用状态
+        LambdaUpdateWrapper<ServeItem> updateWrapper = Wrappers.<ServeItem>lambdaUpdate().eq(ServeItem::getId, id).set(ServeItem::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus());
+        update(updateWrapper);
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 禁用服务项
+     *
+     * @param id 服务项id
+     * @return
+     */
+    @Override
+    @Transactional
+    @CacheEvict(value = RedisConstants.CacheName.SERVE_ITEM, key = "#id", beforeInvocation = true)
+    public void deactivate(Long id) {
+        //查询服务项
+        ServeItem serveItem = baseMapper.selectById(id);
+        if (ObjectUtil.isNull(serveItem)) {
+            throw new ForbiddenOperationException("服务项不存在");
+        }
+        //启用状态
+        Integer activeStatus = serveItem.getActiveStatus();
+        //启用状态方可禁用
+        if (!(FoundationStatusEnum.ENABLE.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("启用状态方可禁用");
+        }
+        //有区域在使用该服务将无法禁用(存在关联的区域服务且状态为上架表示有区域在使用该服务项)
+        int count = serveService.queryServeCountByServeItemIdAndSaleStatus(id, FoundationStatusEnum.ENABLE.getStatus());
+        if (count > 0) {
+            throw new ForbiddenOperationException("该服务有区域正在使用,无法进行禁用,请先将区域内的服务下架。");
+        }
+
+        //更新禁用状态
+        LambdaUpdateWrapper<ServeItem> updateWrapper = Wrappers.<ServeItem>lambdaUpdate().eq(ServeItem::getId, id).set(ServeItem::getActiveStatus, FoundationStatusEnum.DISABLE.getStatus());
+        update(updateWrapper);
+    }
+
+
+    /**
+     * 服务项删除
+     *
+     * @param id 服务项id
+     */
+    @Override
+    @Transactional
+    public void deleteById(Long id) {
+        ServeItem serveItem = baseMapper.selectById(id);
+        if (ObjectUtil.isNull(serveItem)) {
+            throw new ForbiddenOperationException("服务项不存在");
+        }
+        //启用状态
+        Integer activeStatus = serveItem.getActiveStatus();
+
+        //1.删除校验:只有草稿状态方可删除
+        if (!(FoundationStatusEnum.INIT.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("只有草稿状态方可删除");
+        }
+
+        //2.根据id删除
+        baseMapper.deleteById(id);
+    }
+
+    /**
+     * 根据服务类型id查询关联的启用状态服务项数量
+     *
+     * @param serveTypeId 服务类型id
+     * @return 服务项数量
+     */
+    @Override
+    public int queryActiveServeItemCountByServeTypeId(Long serveTypeId) {
+        LambdaQueryWrapper<ServeItem> queryWrapper = Wrappers.<ServeItem>lambdaQuery()
+                .eq(ServeItem::getServeTypeId, serveTypeId)
+                .eq(ServeItem::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus());
+        return baseMapper.selectCount(queryWrapper);
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param serveItemPageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    @Override
+    public PageResult<ServeItemResDTO> page(ServeItemPageQueryReqDTO serveItemPageQueryReqDTO) {
+        return PageHelperUtils.selectPage(serveItemPageQueryReqDTO,
+                () -> baseMapper.queryList(serveItemPageQueryReqDTO.getServeTypeId(), serveItemPageQueryReqDTO.getName(), serveItemPageQueryReqDTO.getActiveStatus()));
+    }
+
+    /**
+     * 根据id查询
+     *
+     * @param id 服务项id
+     * @return 服务项详细信息
+     */
+    @Override
+    public ServeItemResDTO queryServeItemAndTypeById(Long id) {
+        return baseMapper.queryServeItemAndTypeById(id);
+    }
+
+    /**
+     * 根据id列表批量查询
+     *
+     * @param ids 服务项id列表
+     * @return 服务项简略列表
+     */
+    @Override
+    public List<ServeItemSimpleResDTO> queryServeItemListByIds(List<Long> ids) {
+        List<ServeItem> list = lambdaQuery().in(ServeItem::getId, ids).orderByAsc(ServeItem::getCreateTime).list();
+        return BeanUtil.copyToList(list, ServeItemSimpleResDTO.class);
+    }
+
+
+    /**
+     * 查询启用状态的服务项目录
+     *
+     * @return 服务项目录
+     */
+    @Override
+    public List<ServeTypeCategoryResDTO> queryActiveServeItemCategory() {
+        return baseMapper.queryActiveServeItemCategory();
+    }
+}

+ 394 - 0
src/main/java/com/jzo2o/foundations/service/impl/ServeServiceImpl.java

@@ -0,0 +1,394 @@
+package com.jzo2o.foundations.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
+import com.jzo2o.common.enums.EnableStatusEnum;
+import com.jzo2o.common.expcetions.ForbiddenOperationException;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.constants.RedisConstants;
+import com.jzo2o.foundations.enums.FoundationStatusEnum;
+import com.jzo2o.foundations.mapper.*;
+import com.jzo2o.foundations.model.domain.*;
+import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
+import com.jzo2o.foundations.model.dto.response.ServeResDTO;
+import com.jzo2o.foundations.service.HomeService;
+import com.jzo2o.foundations.service.IServeService;
+import com.jzo2o.mysql.utils.PageHelperUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 服务实现类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-03
+ */
+@Service
+public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {
+    @Resource
+    private ServeTypeMapper serveTypeMapper;
+    @Resource
+    private RegionMapper regionMapper;
+    @Resource
+    private ServeSyncMapper serveSyncMapper;
+    @Resource
+    private ServeItemMapper serveItemMapper;
+    @Resource
+    private HomeService homeService;
+
+    /**
+     * 批量新增
+     * @param serveUpsertReqDTOList 批量新增数据
+     */
+    @Override
+    @Transactional
+    public void batchAdd(List<ServeUpsertReqDTO> serveUpsertReqDTOList) {
+        for (ServeUpsertReqDTO serveUpsertReqDTO : serveUpsertReqDTOList) {
+            //1.校验服务项是否为启用状态,不是启用状态不能新增
+            ServeItem serveItem = serveItemMapper.selectById(serveUpsertReqDTO.getServeItemId());
+            if(!(serveItem.getActiveStatus() == FoundationStatusEnum.ENABLE.getStatus())){
+                throw new ForbiddenOperationException("该服务未启用无法添加到区域下使用");
+            }
+
+            //2.校验是否重复新增
+            LambdaQueryWrapper<Serve> queryWrapper = Wrappers.<Serve>lambdaQuery()
+                    .eq(Serve::getRegionId, serveUpsertReqDTO.getRegionId())
+                    .eq(Serve::getServeItemId, serveUpsertReqDTO.getServeItemId());
+            Integer count = baseMapper.selectCount(queryWrapper);
+            if(count>0){
+                throw new ForbiddenOperationException("服务存在重复新增");
+            }
+
+            //3.新增服务
+            Serve serve = BeanUtil.toBean(serveUpsertReqDTO, Serve.class);
+            Region region = regionMapper.selectById(serveUpsertReqDTO.getRegionId());
+            serve.setCityCode(region.getCityCode());
+            baseMapper.insert(serve);
+        }
+    }
+
+    /**
+     * 服务修改
+     *
+     * @param id    服务id
+     * @param price 价格
+     * @return 服务
+     */
+    @Override
+    @Transactional
+    @CachePut(value = RedisConstants.CacheName.SERVE, key = "#id", unless = "#result.saleStatus != 2", cacheManager = RedisConstants.CacheManager.ONE_DAY)
+    public Serve update(Long id, BigDecimal price) {
+        //1.更新服务价格
+        LambdaUpdateWrapper<Serve> updateWrapper = Wrappers.<Serve>lambdaUpdate()
+                .eq(Serve::getId, id)
+                .set(Serve::getPrice, price);
+        super.update(updateWrapper);
+
+        //2.同步数据
+        ServeSync serveSync = new ServeSync();
+        serveSync.setId(id);
+        serveSync.setPrice(price);
+        serveSyncMapper.updateById(serveSync);
+
+        //用于缓存更新
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 服务设置热门/取消
+     *
+     * @param id   服务id
+     * @param flag 是否为热门,0:非热门,1:热门
+     */
+    @Override
+    @Transactional
+    public void changeHotStatus(Long id, Integer flag) {
+        //1.设置热门
+        LambdaUpdateWrapper<Serve> updateWrapper = Wrappers.<Serve>lambdaUpdate()
+                .eq(Serve::getId, id)
+                .set(Serve::getIsHot, flag)
+                .set(Serve::getHotTimeStamp, System.currentTimeMillis());
+        super.update(updateWrapper);
+
+        //2.同步数据
+        ServeSync serveSync = new ServeSync();
+        serveSync.setId(id);
+        serveSync.setIsHot(flag);
+        serveSync.setHotTimeStamp(System.currentTimeMillis());
+        serveSyncMapper.updateById(serveSync);
+    }
+
+    /**
+     * 根据区域id和售卖状态查询关联服务数量
+     *
+     * @param regionId   区域id
+     * @param saleStatus 售卖状态,0:草稿,1下架,2上架。可传null,即查询所有状态
+     * @return 服务数量
+     */
+    @Override
+    public int queryServeCountByRegionIdAndSaleStatus(Long regionId, Integer saleStatus) {
+        LambdaQueryWrapper<Serve> queryWrapper = Wrappers.<Serve>lambdaQuery()
+                .eq(Serve::getRegionId, regionId)
+                .eq(ObjectUtil.isNotEmpty(saleStatus), Serve::getSaleStatus, saleStatus);
+        return baseMapper.selectCount(queryWrapper);
+    }
+    /**
+     * 根据服务项id和售卖状态查询关联服务数量
+     *
+     * @param  serveItemId  服务项id
+     * @param saleStatus 售卖状态,0:草稿,1下架,2上架。可传null,即查询所有状态
+     * @return 服务数量
+     */
+    @Override
+    public int queryServeCountByServeItemIdAndSaleStatus(Long serveItemId, Integer saleStatus) {
+        LambdaQueryWrapper<Serve> queryWrapper = Wrappers.<Serve>lambdaQuery()
+                .eq(Serve::getServeItemId, serveItemId)
+                .eq(ObjectUtil.isNotEmpty(saleStatus), Serve::getSaleStatus, saleStatus);
+        return baseMapper.selectCount(queryWrapper);
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param servePageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    @Override
+    public PageResult<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {
+        return PageHelperUtils.selectPage(servePageQueryReqDTO, () -> baseMapper.queryServeListByRegionId(servePageQueryReqDTO.getRegionId()));
+    }
+
+    /**
+     * 删除服务
+     *
+     * @param id 服务id
+     */
+    @Override
+    @Transactional
+    public void deleteById(Long id) {
+        Serve serve = baseMapper.selectById(id);
+        if(ObjectUtil.isNull(serve)){
+            throw new ForbiddenOperationException("区域服务不存在");
+        }
+        //草稿状态方可删除
+        if (!(serve.getSaleStatus()==FoundationStatusEnum.INIT.getStatus())) {
+            throw new ForbiddenOperationException("草稿状态方可删除");
+        }
+
+        //删除服务
+        baseMapper.deleteById(id);
+
+        //同步数据
+        serveSyncMapper.deleteById(id);
+    }
+
+    /**
+     * 根据城市编码查询服务项id列表
+     *
+     * @param cityCode 城市编码
+     * @return 服务项id列表
+     */
+    @Override
+    public List<Long> queryServeItemIdListByCityCode(String cityCode) {
+        LambdaQueryWrapper<Serve> queryWrapper = Wrappers.<Serve>lambdaQuery().eq(Serve::getCityCode, cityCode).select(Serve::getServeItemId);
+        List<Serve> serveList = baseMapper.selectList(queryWrapper);
+        return serveList.stream().map(Serve::getServeItemId).distinct().collect(Collectors.toList());
+    }
+
+    /**
+     * 查询热门服务列表
+     *
+     * @return 热门服务列表
+     */
+    @Override
+    public List<Serve> queryHotAndOnSaleServeList() {
+        LambdaQueryWrapper<Serve> queryWrapper = Wrappers.<Serve>lambdaQuery()
+                .eq(Serve::getIsHot, EnableStatusEnum.ENABLE.getStatus())
+                .eq(Serve::getSaleStatus, FoundationStatusEnum.ENABLE.getStatus());
+        return baseMapper.selectList(queryWrapper);
+    }
+
+    /**
+     * 根据id查询服务详情
+     *
+     * @param id 服务id
+     * @return 服务详情
+     */
+    @Override
+    public ServeAggregationSimpleResDTO findDetailById(Long id) {
+        //1.查询服务信息
+        Serve serve = homeService.queryServeByIdCache(id);
+
+        //2.查询服务项信息
+        ServeItem serveItem = homeService.queryServeItemByIdCache(serve.getServeItemId());
+
+        //3.封装数据
+        ServeAggregationSimpleResDTO serveAggregationSimpleResDTO = BeanUtil.toBean(serve, ServeAggregationSimpleResDTO.class);
+        serveAggregationSimpleResDTO.setServeItemName(serveItem.getName());
+        serveAggregationSimpleResDTO.setServeItemImg(serveItem.getImg());
+        serveAggregationSimpleResDTO.setDetailImg(serveItem.getDetailImg());
+        serveAggregationSimpleResDTO.setUnit(serveItem.getUnit());
+        return serveAggregationSimpleResDTO;
+    }
+
+    /**
+     * 根据区域id查询热门服务列表
+     *
+     * @param regionId 区域id
+     * @return 热门服务列表
+     */
+    @Override
+    public List<ServeAggregationSimpleResDTO> findHotServeListByRegionId(Long regionId) {
+        return baseMapper.findHotServeListByRegionId(regionId);
+    }
+
+    /**
+     * 根据区域id查询服务类型列表
+     *
+     * @param regionId 区域id
+     * @return 服务类型列表
+     */
+    @Override
+    public List<ServeAggregationTypeSimpleResDTO> findServeTypeListByRegionId(Long regionId) {
+        return baseMapper.findServeTypeListByRegionId(regionId);
+    }
+
+
+    /**
+     * 上架
+     *
+     * @param id         服务id
+     */
+    @Override
+    @Transactional
+    @CachePut(value = RedisConstants.CacheName.SERVE, key = "#id",  cacheManager = RedisConstants.CacheManager.ONE_DAY)
+    public Serve onSale(Long id){
+        Serve serve = baseMapper.selectById(id);
+        if(ObjectUtil.isNull(serve)){
+            throw new ForbiddenOperationException("区域服务不存在");
+        }
+        //上架状态
+        Integer saleStatus = serve.getSaleStatus();
+        //草稿或下架状态方可上架
+        if (!(saleStatus==FoundationStatusEnum.INIT.getStatus() || saleStatus==FoundationStatusEnum.DISABLE.getStatus())) {
+            throw new ForbiddenOperationException("草稿或下架状态方可上架");
+        }
+        //服务项id
+        Long serveItemId = serve.getServeItemId();
+        ServeItem serveItem = serveItemMapper.selectById(serveItemId);
+        if(ObjectUtil.isNull(serveItem)){
+            throw new ForbiddenOperationException("所属服务项不存在");
+        }
+        //服务项的启用状态
+        Integer activeStatus = serveItem.getActiveStatus();
+        //服务项为启用状态方可上架
+        if (!(FoundationStatusEnum.ENABLE.getStatus()==activeStatus)) {
+            throw new ForbiddenOperationException("服务项为启用状态方可上架");
+         }
+
+       //更新上架状态
+        LambdaUpdateWrapper<Serve> updateWrapper = Wrappers.<Serve>lambdaUpdate()
+                .eq(Serve::getId, id)
+                .set(Serve::getSaleStatus, FoundationStatusEnum.ENABLE.getStatus());
+        update(updateWrapper);
+        //添加同步表
+        addServeSync(id);
+        return baseMapper.selectById(id);
+
+    }
+    /**
+     * 下架
+     *
+     * @param id         服务id
+     */
+    @Override
+    @Transactional
+    @CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id", beforeInvocation = true)
+    public Serve offSale(Long id){
+        Serve serve = baseMapper.selectById(id);
+        if(ObjectUtil.isNull(serve)){
+            throw new ForbiddenOperationException("区域服务不存在");
+        }
+        //上架状态
+        Integer saleStatus = serve.getSaleStatus();
+        //上架状态方可下架
+        if (!(saleStatus==FoundationStatusEnum.ENABLE.getStatus())) {
+            throw new ForbiddenOperationException("上架状态方可下架");
+        }
+        //更新下架状态
+        LambdaUpdateWrapper<Serve> updateWrapper = Wrappers.<Serve>lambdaUpdate()
+                .eq(Serve::getId, id)
+                .set(Serve::getSaleStatus, FoundationStatusEnum.DISABLE.getStatus());
+        update(updateWrapper);
+        //删除同步表的数据
+        serveSyncMapper.deleteById(id);
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 新增服务同步数据
+     *
+     * @param serveId 服务id
+     */
+    private void addServeSync(Long serveId) {
+        //服务信息
+        Serve serve = baseMapper.selectById(serveId);
+        //区域信息
+        Region region = regionMapper.selectById(serve.getRegionId());
+        //服务项信息
+        ServeItem serveItem = serveItemMapper.selectById(serve.getServeItemId());
+        //服务类型
+        ServeType serveType = serveTypeMapper.selectById(serveItem.getServeTypeId());
+
+        ServeSync serveSync = new ServeSync();
+        serveSync.setServeTypeId(serveType.getId());
+        serveSync.setServeTypeName(serveType.getName());
+        serveSync.setServeTypeIcon(serveType.getServeTypeIcon());
+        serveSync.setServeTypeImg(serveType.getImg());
+        serveSync.setServeTypeSortNum(serveType.getSortNum());
+
+        serveSync.setServeItemId(serveItem.getId());
+        serveSync.setServeItemIcon(serveItem.getServeItemIcon());
+        serveSync.setServeItemName(serveItem.getName());
+        serveSync.setServeItemImg(serveItem.getImg());
+        serveSync.setServeItemSortNum(serveItem.getSortNum());
+        serveSync.setUnit(serveItem.getUnit());
+        serveSync.setDetailImg(serveItem.getDetailImg());
+        serveSync.setPrice(serve.getPrice());
+
+        serveSync.setCityCode(region.getCityCode());
+        serveSync.setId(serve.getId());
+        serveSync.setIsHot(serve.getIsHot());
+        serveSyncMapper.insert(serveSync);
+    }
+
+    /**
+     * 根据id查询详情
+     *
+     * @param id 服务id
+     * @return 服务详情
+     */
+    @Override
+    public ServeAggregationResDTO findServeDetailById(Long id) {
+        return baseMapper.findServeDetailById(id);
+    }
+
+
+}

+ 56 - 0
src/main/java/com/jzo2o/foundations/service/impl/ServeSyncServiceImpl.java

@@ -0,0 +1,56 @@
+package com.jzo2o.foundations.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzo2o.foundations.mapper.ServeSyncMapper;
+import com.jzo2o.foundations.model.domain.ServeSync;
+import com.jzo2o.foundations.model.dto.request.ServeSyncUpdateReqDTO;
+import com.jzo2o.foundations.service.IServeSyncService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 服务同步表 服务实现类
+ * </p>
+ *
+ * @author itcast
+ * @since 2023-07-10
+ */
+@Service
+public class ServeSyncServiceImpl extends ServiceImpl<ServeSyncMapper, ServeSync> implements IServeSyncService {
+    /**
+     * 根据服务项id更新
+     *
+     * @param serveItemId           服务项id
+     * @param serveSyncUpdateReqDTO 服务同步更新数据
+     */
+    @Override
+    public void updateByServeItemId(Long serveItemId, ServeSyncUpdateReqDTO serveSyncUpdateReqDTO) {
+        LambdaUpdateWrapper<ServeSync> updateWrapper = Wrappers.<ServeSync>lambdaUpdate()
+                .eq(ServeSync::getServeItemId, serveItemId)
+                .set(ServeSync::getServeItemName, serveSyncUpdateReqDTO.getServeItemName())
+                .set(ServeSync::getServeItemSortNum, serveSyncUpdateReqDTO.getServeItemSortNum())
+                .set(ServeSync::getUnit, serveSyncUpdateReqDTO.getUnit())
+                .set(ServeSync::getServeItemImg, serveSyncUpdateReqDTO.getServeItemImg())
+                .set(ServeSync::getServeItemIcon, serveSyncUpdateReqDTO.getServeItemIcon());
+        super.update(updateWrapper);
+    }
+
+    /**
+     * 根据服务类型id更新
+     *
+     * @param serveTypeId           服务类型id
+     * @param serveSyncUpdateReqDTO 服务同步更新数据
+     */
+    @Override
+    public void updateByServeTypeId(Long serveTypeId, ServeSyncUpdateReqDTO serveSyncUpdateReqDTO) {
+        LambdaUpdateWrapper<ServeSync> updateWrapper = Wrappers.<ServeSync>lambdaUpdate()
+                .eq(ServeSync::getServeTypeId, serveTypeId)
+                .set(ServeSync::getServeTypeName, serveSyncUpdateReqDTO.getServeTypeName())
+                .set(ServeSync::getServeTypeImg, serveSyncUpdateReqDTO.getServeTypeImg())
+                .set(ServeSync::getServeTypeIcon, serveSyncUpdateReqDTO.getServeTypeIcon())
+                .set(ServeSync::getServeTypeSortNum, serveSyncUpdateReqDTO.getServeTypeSortNum());
+        super.update(updateWrapper);
+    }
+}

+ 195 - 0
src/main/java/com/jzo2o/foundations/service/impl/ServeTypeServiceImpl.java

@@ -0,0 +1,195 @@
+package com.jzo2o.foundations.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzo2o.api.foundations.dto.response.ServeTypeSimpleResDTO;
+import com.jzo2o.common.expcetions.ForbiddenOperationException;
+import com.jzo2o.common.model.PageResult;
+import com.jzo2o.foundations.enums.FoundationStatusEnum;
+import com.jzo2o.foundations.mapper.ServeTypeMapper;
+import com.jzo2o.foundations.model.domain.ServeType;
+import com.jzo2o.foundations.model.dto.request.ServeSyncUpdateReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeTypePageQueryReqDTO;
+import com.jzo2o.foundations.model.dto.request.ServeTypeUpsertReqDTO;
+import com.jzo2o.foundations.model.dto.response.ServeTypeResDTO;
+import com.jzo2o.foundations.service.IServeItemService;
+import com.jzo2o.foundations.service.IServeSyncService;
+import com.jzo2o.foundations.service.IServeTypeService;
+import com.jzo2o.mysql.utils.PageUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 服务类型
+ *
+ * @author itcast
+ * @create 2023/7/26 14:18
+ **/
+@Service
+public class ServeTypeServiceImpl extends ServiceImpl<ServeTypeMapper, ServeType> implements IServeTypeService {
+    @Resource
+    private IServeItemService serveItemService;
+    @Resource
+    private IServeSyncService serveSyncService;
+
+    /**
+     * 服务类型新增
+     *
+     * @param serveTypeUpsertReqDTO 插入更新服务类型
+     */
+    @Override
+    public void add(ServeTypeUpsertReqDTO serveTypeUpsertReqDTO) {
+        //校验名称是否重复
+        LambdaQueryWrapper<ServeType> queryWrapper = Wrappers.<ServeType>lambdaQuery().eq(ServeType::getName, serveTypeUpsertReqDTO.getName());
+        Integer count = baseMapper.selectCount(queryWrapper);
+        if(count>0){
+            throw new ForbiddenOperationException("服务类型名称不可重复");
+        }
+
+        //新增服务类型
+        ServeType serveType = BeanUtil.toBean(serveTypeUpsertReqDTO, ServeType.class);
+        serveType.setCode(IdUtil.getSnowflakeNextIdStr());
+        baseMapper.insert(serveType);
+    }
+
+    /**
+     * 服务类型修改
+     *
+     * @param id                    服务类型id
+     * @param serveTypeUpsertReqDTO 插入更新服务类型
+     */
+    @Override
+    public void update(Long id, ServeTypeUpsertReqDTO serveTypeUpsertReqDTO) {
+        //1.更新服务类型
+        ServeType serveType = BeanUtil.toBean(serveTypeUpsertReqDTO, ServeType.class);
+        serveType.setId(id);
+        baseMapper.updateById(serveType);
+
+        //2.同步数据到es
+        ServeSyncUpdateReqDTO serveSyncUpdateReqDTO = new ServeSyncUpdateReqDTO();
+        serveSyncUpdateReqDTO.setServeTypeName(serveTypeUpsertReqDTO.getName());
+        serveSyncUpdateReqDTO.setServeTypeImg(serveTypeUpsertReqDTO.getImg());
+        serveSyncUpdateReqDTO.setServeTypeIcon(serveTypeUpsertReqDTO.getServeTypeIcon());
+        serveSyncUpdateReqDTO.setServeTypeSortNum(serveTypeUpsertReqDTO.getSortNum());
+        serveSyncService.updateByServeTypeId(id, serveSyncUpdateReqDTO);
+    }
+
+
+    /**
+     * 服务类型启用/禁用
+     *
+     * @param id 服务类型id
+     */
+    @Override
+    @Transactional
+    public void activate(Long id) {
+        //查询服务类型
+        ServeType serveType = baseMapper.selectById(id);
+        if (ObjectUtil.isNull(serveType)) {
+            throw new ForbiddenOperationException("服务类型不存在");
+        }
+        //启用状态
+        Integer activeStatus = serveType.getActiveStatus();
+        //草稿或禁用状态方可启用
+        if (!(FoundationStatusEnum.INIT.getStatus() == activeStatus || FoundationStatusEnum.DISABLE.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("草稿或禁用状态方可启用");
+        }
+        //更新状态为启用
+        LambdaUpdateWrapper<ServeType> updateWrapper = Wrappers.<ServeType>lambdaUpdate()
+                .eq(ServeType::getId, id)
+                .set(ServeType::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus());
+        update(updateWrapper);
+    }
+
+    /**
+     * 服务类型启用/禁用
+     *
+     * @param id 服务类型id
+     */
+    @Override
+    @Transactional
+    public void deactivate(Long id) {
+        //查询服务类型
+        ServeType serveType = baseMapper.selectById(id);
+        if (ObjectUtil.isNull(serveType)) {
+            throw new ForbiddenOperationException("服务类型不存在");
+        }
+        //启用状态
+        Integer activeStatus = serveType.getActiveStatus();
+        //启用状态方可禁用
+        if (!(FoundationStatusEnum.ENABLE.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("启用状态方可禁用");
+        }
+        //下属服务项全部为非启用方可禁用
+        int count = serveItemService.queryActiveServeItemCountByServeTypeId(id);
+        if (count > 0) {
+            throw new ForbiddenOperationException("禁用失败,该服务类型下有启用状态的服务项");
+        }
+        //更新状态为禁用
+        LambdaUpdateWrapper<ServeType> updateWrapper = Wrappers.<ServeType>lambdaUpdate()
+                .eq(ServeType::getId, id)
+                .set(ServeType::getActiveStatus, FoundationStatusEnum.DISABLE.getStatus());
+        update(updateWrapper);
+    }
+
+    /**
+     * 根据id删除服务类型
+     *
+     * @param id 服务类型id
+     */
+    @Override
+    @Transactional
+    public void deleteById(Long id) {
+        //查询服务类型
+        ServeType serveType = baseMapper.selectById(id);
+        if (ObjectUtil.isNull(serveType)) {
+            throw new ForbiddenOperationException("服务类型不存在");
+        }
+        //启用状态
+        Integer activeStatus = serveType.getActiveStatus();
+        //草稿状态方可删除
+        if (!(FoundationStatusEnum.INIT.getStatus() == activeStatus)) {
+            throw new ForbiddenOperationException("草稿状态方可删除");
+        }
+        baseMapper.deleteById(id);
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param serveTypePageQueryReqDTO 查询条件
+     * @return 分页结果
+     */
+    @Override
+    public PageResult<ServeTypeResDTO> page(ServeTypePageQueryReqDTO serveTypePageQueryReqDTO) {
+        Page<ServeType> page = PageUtils.parsePageQuery(serveTypePageQueryReqDTO, ServeType.class);
+        Page<ServeType> serveTypePage = baseMapper.selectPage(page, new QueryWrapper<>());
+        return PageUtils.toPage(serveTypePage, ServeTypeResDTO.class);
+    }
+
+    /**
+     * 根据活动状态查询简略列表
+     *
+     * @param activeStatus 活动状态,0:草稿,1:禁用,:2:启用
+     * @return 服务类型列表
+     */
+    @Override
+    public List<ServeTypeSimpleResDTO> queryServeTypeListByActiveStatus(Integer activeStatus) {
+        LambdaQueryWrapper<ServeType> queryWrapper = Wrappers.<ServeType>lambdaQuery()
+                .eq(ObjectUtil.isNotEmpty(activeStatus), ServeType::getActiveStatus, activeStatus)
+                .orderByAsc(ServeType::getSortNum)
+                .orderByDesc(ServeType::getUpdateTime);
+        List<ServeType> serveTypeList = baseMapper.selectList(queryWrapper);
+        return BeanUtil.copyToList(serveTypeList, ServeTypeSimpleResDTO.class);
+    }
+}

+ 18 - 0
src/main/resources/bootstrap-dev.yml

@@ -0,0 +1,18 @@
+spring:
+  cloud:
+    nacos:
+      username: nacos
+      password: nacos
+      server-addr: 192.168.101.68:8848
+      config:
+        namespace: 75a593f5-33e6-4c65-b2a0-18c403d20f63
+        file-extension: yaml
+      discovery:
+        namespace: 75a593f5-33e6-4c65-b2a0-18c403d20f63
+        ip: ${ACCESS_IP:}
+
+
+#################     日志配置     #################
+logging:
+  level:
+    com.jzo2o: debug

+ 14 - 0
src/main/resources/bootstrap-prod.yml

@@ -0,0 +1,14 @@
+spring:
+  cloud:
+    nacos:
+      username: ${NACOS_USERNAME}
+      password: ${NACOS_PASSWORD}
+      server-addr: ${NACOS_ADDR}
+      config:
+        namespace: ${NACOS_NAMESPACE}
+        file-extension: yaml
+      discovery:
+        namespace: ${NACOS_NAMESPACE}
+logging:
+  level:
+    com.jzo2o: debug

+ 14 - 0
src/main/resources/bootstrap-test.yml

@@ -0,0 +1,14 @@
+spring:
+  cloud:
+    nacos:
+      username: ${NACOS_USERNAME}
+      password: ${NACOS_PASSWORD}
+      server-addr: ${NACOS_ADDR}
+      config:
+        namespace: ${NACOS_NAMESPACE}
+        file-extension: yaml
+      discovery:
+        namespace: ${NACOS_NAMESPACE}
+logging:
+  level:
+    com.jzo2o: debug

+ 76 - 0
src/main/resources/bootstrap.yml

@@ -0,0 +1,76 @@
+#################     服务器配置     #################
+server:
+  port: 11509
+  undertow:
+    accesslog:
+      enabled: true
+      pattern: "%t %a &quot;%r&quot; %s (%D ms)"
+      dir: /data/logs/undertow/${spring.application.name}/access-logs/
+  servlet:
+    context-path: /foundations
+
+#################     spring公共配置     #################
+spring:
+  mvc:
+    path-match:
+      matching-strategy: ant_path_matcher
+    format:
+      date: yyyy-MM-dd HH:mm:ss
+  jackson:
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+  profiles:
+    active: dev
+  application:
+    name: jzo2o-foundations
+  main:
+    # 支持循环依赖注入
+    allow-circular-references: true
+    # bean名相同覆盖
+    allow-bean-definition-overriding: true
+  cloud:
+    nacos:
+      username: ${NACOS_USERNAME}
+      password: ${NACOS_PASSWORD}
+      server-addr: ${NACOS_ADDR}
+      discovery:
+        namespace: ${NACOS_NAMESPACE}
+      config:
+        namespace: ${NACOS_NAMESPACE}
+        file-extension: yaml
+        shared-configs: # 共享配置
+          - data-id: shared-redis-cluster.yaml # 共享redis配置
+            refresh: false
+          - data-id: shared-xxl-job.yaml # xxl-job配置
+            refresh: false
+          - data-id: shared-rabbitmq.yaml # rabbitmq配置
+            refresh: false
+          - data-id: shared-es.yaml # rabbitmq配置
+            refresh: false
+          - data-id: shared-mysql.yaml # mysql配置
+            refresh: false
+
+#################     项目独有配置     #################
+mysql:
+  db-name: jzo2o-foundations
+mybatis:
+  mapper-locations: mapper/*.xml
+  type-aliases-package: com.jzo2o.foundations.mapper
+swagger:
+  enable: true
+  package-path: com.jzo2o.foundations.controller
+  title: 家政服务-运营基础服务接口文档
+  description: 用于服务、区域进行管理
+  contact-name: 传智教育·研究院
+  contact-url: http://www.itcast.cn/
+  contact-email: yjy@itcast.cn
+  version: v1.0
+
+
+#################     日志配置     #################
+logging:
+  level:
+    com.jzo2o: debug
+    org.apache.http: info #es请求日志
+feign:
+  enable: true

+ 5 - 0
src/main/resources/mapper/CityDirectoryMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzo2o.foundations.mapper.CityDirectoryMapper">
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/ConfigRegionMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzo2o.foundations.mapper.ConfigRegionMapper">
+
+</mapper>

+ 21 - 0
src/main/resources/mapper/OperatorMapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzo2o.foundations.mapper.OperatorMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.jzo2o.foundations.model.domain.Operator">
+        <id column="id" property="id" />
+        <result column="username" property="username" />
+        <result column="avatar" property="avatar" />
+        <result column="name" property="name" />
+        <result column="phone" property="phone" />
+        <result column="password" property="password" />
+        <result column="status" property="status" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+        <result column="create_by" property="createBy" />
+        <result column="update_by" property="updateBy" />
+        <result column="is_deleted" property="isDeleted" />
+    </resultMap>
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/RegionMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzo2o.foundations.mapper.RegionMapper">
+
+</mapper>

+ 96 - 0
src/main/resources/mapper/ServeItemMapper.xml

@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzo2o.foundations.mapper.ServeItemMapper">
+
+    <select id="queryList" resultType="com.jzo2o.api.foundations.dto.response.ServeItemResDTO">
+        SELECT
+        item.id,
+        item.code,
+        item.serve_type_id,
+        type.name AS serve_type_name,
+        item.name,
+        item.serve_item_icon,
+        item.img,
+        item.unit,
+        item.description,
+        item.detail_img,
+        item.reference_price,
+        item.sort_num,
+        item.active_status,
+        item.create_time,
+        item.update_time
+        FROM
+        serve_item AS item
+        LEFT JOIN serve_type AS type ON item.serve_type_id = type.id
+        <where>
+            <if test="serveTypeId != null">
+                and item.serve_type_id=#{serveTypeId}
+            </if>
+            <if test="name != null and name != ''">
+                and item.name like concat('%',#{name},'%')
+            </if>
+            <if test="activeStatus != null">
+                and item.active_status=#{activeStatus}
+            </if>
+        </where>
+    </select>
+
+
+    <select id="queryServeItemAndTypeById" resultType="com.jzo2o.api.foundations.dto.response.ServeItemResDTO">
+        SELECT
+            item.id,
+            item.code,
+            item.serve_type_id,
+            type.name AS serve_type_name,
+            item.name,
+            item.serve_item_icon,
+            item.img,
+            item.unit,
+            item.description,
+            item.detail_img,
+            item.reference_price,
+            item.sort_num,
+            item.active_status,
+            item.create_time,
+            item.update_time
+        FROM
+            serve_item AS item
+                LEFT JOIN serve_type AS type ON item.serve_type_id = type.id
+        WHERE
+            item.id = #{id}
+    </select>
+
+
+
+    <select id="queryActiveServeItemCategory" resultMap="ServeItemCategoryMap">
+        SELECT
+            type.id AS serve_type_id,
+            type.`name` AS serve_type_name,
+            item.id AS serve_item_id,
+            item.`name` AS serve_item_name
+        FROM
+            serve_item AS item
+                LEFT JOIN serve_type AS type ON item.serve_type_id = type.id
+        WHERE
+            item.active_status = 2
+        ORDER BY
+            type.sort_num,
+            item.sort_num
+    </select>
+
+    <!--手动的映射-->
+    <resultMap id="ServeItemCategoryMap" type="com.jzo2o.api.foundations.dto.response.ServeTypeCategoryResDTO">
+        <!--id映射主键字段-->
+        <id column="serve_type_id" property="serveTypeId"></id>
+        <!--result映射普通字段-->
+        <result column="serve_type_name" property="serveTypeName"></result>
+
+        <!--column 数据库中的字段名-->
+        <!--property 实体类中对应的属性 该关键字可以省略... -->
+        <!--ofType 是javaType中的单个对象类型-->
+        <collection property="serveItemList" ofType="com.jzo2o.api.foundations.dto.ServeItemSimpleDTO">
+            <id column="serve_item_id" property="serveItemId"></id>
+            <result column="serve_item_name" property="serveItemName"></result>
+        </collection>
+    </resultMap>
+</mapper>

+ 141 - 0
src/main/resources/mapper/ServeMapper.xml

@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzo2o.foundations.mapper.ServeMapper">
+
+    <select id="queryServeListByRegionId" resultType="com.jzo2o.foundations.model.dto.response.ServeResDTO">
+        SELECT
+            serve.id,
+            serve.sale_status,
+            serve.serve_item_id,
+            item.name AS serve_item_name,
+            item.serve_type_id,
+            serve.region_id,
+            item.reference_price,
+            serve.price,
+            serve.is_hot,
+            serve.create_time,
+            serve.update_time,
+            type.name AS serve_type_name
+        FROM
+            serve
+                inner JOIN serve_item AS item ON serve.serve_item_id = item.id
+                inner JOIN serve_type AS type ON item.serve_type_id = type.id
+        WHERE
+            serve.region_id = #{regionId}
+    </select>
+
+    <select id="findHotServeListByRegionId" resultType="com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO">
+        SELECT
+            serve.id,
+            serve.serve_item_id,
+            serve.price,
+            serve.city_code,
+            item.name AS serve_item_name,
+            item.img AS serve_item_img,
+            item.detail_img,
+            item.unit
+        FROM
+            serve
+                inner JOIN serve_item AS item ON serve.serve_item_id = item.id
+        WHERE
+            serve.is_hot = 1
+          AND serve.sale_status = 2
+          AND serve.region_id = #{regionId}
+        ORDER BY serve.update_time DESC
+    </select>
+
+    <select id="findServeTypeListByRegionId" resultType="com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO">
+        SELECT
+            type.id as serve_type_id,
+            type.name as serve_type_name,
+            type.img as serve_type_img
+        FROM
+            serve
+                inner JOIN serve_item AS item ON serve.serve_item_id = item.id
+                inner JOIN serve_type AS type ON type.id = item.serve_type_id
+        WHERE
+            serve.region_id = #{regionId}
+          AND serve.sale_status = 2
+        GROUP BY
+            type.id
+        ORDER BY
+            type.sort_num ASC,
+            type.create_time DESC;
+    </select>
+
+    <select id="findServeIconCategoryByRegionId" resultMap="ServeCategoryMap">
+        SELECT
+            type.id as serve_type_id,
+            type.name as serve_type_name,
+            type.serve_type_icon,
+            serve.city_code,
+            serve.id as serve_id,
+            item.id as serve_item_id,
+            item.name as serve_item_name,
+            item.serve_item_icon,
+            item.sort_num as serve_item_sort_num
+        FROM
+            serve
+                inner JOIN serve_item AS item ON item.id = serve.serve_item_id
+                inner JOIN serve_type AS type ON type.id = item.serve_type_id
+        WHERE
+            serve.region_id = #{regionId}
+          AND serve.sale_status = 2
+        ORDER BY
+            type.sort_num,
+            type.update_time desc,
+            item.sort_num,
+            item.update_time desc
+    </select>
+
+    <!--手动的映射-->
+    <resultMap id="ServeCategoryMap" type="com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO">
+        <!--id映射主键字段-->
+        <id column="serve_type_id" property="serveTypeId"></id>
+        <!--result映射普通字段-->
+        <result column="serve_type_name" property="serveTypeName"></result>
+        <result column="serve_type_icon" property="serveTypeIcon"></result>
+        <result column="city_code" property="cityCode"></result>
+
+        <!--column 数据库中的字段名-->
+        <!--property 实体类中对应的属性 该关键字可以省略... -->
+        <!--ofType 是javaType中的单个对象类型-->
+        <collection property="serveResDTOList" ofType="com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO">
+            <id column="serve_id" property="id"></id>
+            <result column="serve_item_id" property="serveItemId"></result>
+            <result column="serve_item_name" property="serveItemName"></result>
+            <result column="serve_item_icon" property="serveItemIcon"></result>
+            <result column="serve_item_sort_num" property="serveItemSortNum"></result>
+        </collection>
+    </resultMap>
+
+
+    <select id="findServeDetailById" resultType="com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO">
+        SELECT
+            serve.id,
+            serve.city_code,
+            serve.price,
+            serve.is_hot,
+            serve.hot_time_stamp,
+            serve.sale_status,
+            item.id AS serve_item_id,
+            item.`name` AS serve_item_name,
+            item.img AS serve_item_img,
+            item.detail_img,
+            item.serve_item_icon,
+            item.unit,
+            item.sort_num AS serve_item_sort_num,
+            item.serve_type_id AS serve_type_id,
+            type.`name` AS serve_type_name,
+            type.img AS serve_type_img,
+            type.serve_type_icon,
+            type.sort_num AS serve_type_sort_num
+        FROM
+            serve
+                inner JOIN serve_item AS item ON item.id = serve.serve_item_id
+                inner JOIN serve_type AS type ON type.id = item.serve_type_id
+        WHERE
+            serve.id = #{id}
+    </select>
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/ServeSyncMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzo2o.foundations.mapper.ServeSyncMapper">
+
+</mapper>

Some files were not shown because too many files changed in this diff