flowerpig 1 an în urmă
comite
14ac5e3426
100 a modificat fișierele cu 7596 adăugiri și 0 ștergeri
  1. 34 0
      .gitignore
  2. 10 0
      README.txt
  3. 12 0
      dockerfiles/backstage/DockerUse.txt
  4. 35 0
      dockerfiles/backstage/Dockerfile
  5. 26 0
      dockerfiles/game/DockerUse.txt
  6. 30 0
      dockerfiles/game/Dockerfile
  7. 30 0
      dockerfiles/game/Dockerfile.1
  8. 8 0
      fastpack.bat
  9. 34 0
      fullpack.bat
  10. 47 0
      fullpack.sh
  11. 79 0
      pom.xml
  12. 4 0
      x1-backstage/.gitignore
  13. 30 0
      x1-backstage/config/application.properties.temp
  14. 2 0
      x1-backstage/config/database.db.temp
  15. 71 0
      x1-backstage/config/log4j2.xml
  16. 71 0
      x1-backstage/config/log4j2.xml.temp
  17. 93 0
      x1-backstage/pom.xml
  18. 26 0
      x1-backstage/restart-backstage.sh
  19. 38 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/X1BackStage.java
  20. 100 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ApplicationSettings.java
  21. 19 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ApplicationSettingsTool.java
  22. 40 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/BeanRegister.java
  23. 71 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/DatabaseLifecycle.java
  24. 36 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ProjectBooter.java
  25. 36 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ScheduleLifecycle.java
  26. 165 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/MenuController.java
  27. 77 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/TipsCode.java
  28. 64 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/ClientLogController.java
  29. 85 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/model/ClientLog.java
  30. 79 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/service/ClientLogService.java
  31. 31 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/service/ClientLogTimer.java
  32. 96 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/ClientVersionController.java
  33. 134 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/model/ClientVersion.java
  34. 43 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/service/ClientVersionService.java
  35. 74 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/struct/ClientVersionForm.java
  36. 22 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/struct/ClientVersionQuery.java
  37. 41 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/command/ServerCommandController.java
  38. 103 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/BossDotDataController.java
  39. 106 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/FogDotDataController.java
  40. 113 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/GuideDotDataController.java
  41. 112 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/LoginDotDataController.java
  42. 112 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/RecruitDotDataController.java
  43. 113 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/RecruitRefreshDotDataController.java
  44. 81 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/TaskDotDataController.java
  45. 85 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/model/LoginDotData.java
  46. 209 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/model/LoginDotDataStatistic.java
  47. 47 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/model/TaskDotDataStatistic.java
  48. 41 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/service/DotDataTimer.java
  49. 138 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/service/LoginDotDataService.java
  50. 70 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/service/LoginDotDataStatisticService.java
  51. 27 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/struct/LoginDotQuery.java
  52. 78 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/BossDotDataResultVo.java
  53. 60 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/BossDotDataVo.java
  54. 48 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/FogDotDataResultVo.java
  55. 39 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/FogDotDataVo.java
  56. 53 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/GuideDotDataResultVo.java
  57. 39 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/GuideDotDataVo.java
  58. 39 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/LoginDotDataStatisticVo.java
  59. 25 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/PlayerLevelNumVo.java
  60. 34 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitDotDataQuery.java
  61. 53 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitDotDataResultVo.java
  62. 32 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitDotDataVo.java
  63. 53 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitRefreshDotDataResultVo.java
  64. 32 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitRefreshDotDataVo.java
  65. 46 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/TaskDotDataResultVo.java
  66. 39 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/TaskDotDataVo.java
  67. 87 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamecause/GameCauseController.java
  68. 37 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamecause/model/GameCause.java
  69. 38 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamecause/service/GameCauseService.java
  70. 117 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamelog/GameLogController.java
  71. 78 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamelog/service/LogTableService.java
  72. 54 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamelog/struct/LogQuery.java
  73. 104 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/BulletinController.java
  74. 208 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameChannelController.java
  75. 176 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameChannelServerController.java
  76. 60 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameDbController.java
  77. 118 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GamePlatformController.java
  78. 131 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameRegionController.java
  79. 425 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameServerController.java
  80. 215 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameServerMaintainController.java
  81. 158 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/ServerOpenController.java
  82. 209 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/UserChannelController.java
  83. 32 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/BulletinForm.java
  84. 28 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/ChannelServerRelationForm.java
  85. 54 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameChannelForm.java
  86. 25 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GamePlatformForm.java
  87. 46 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameRegionForm.java
  88. 152 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameServerForm.java
  89. 27 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameServerMaintainForm.java
  90. 32 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/ServerToRegionForm.java
  91. 27 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/UserChannelForm.java
  92. 53 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/Bulletin.java
  93. 102 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameChannel.java
  94. 123 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameChannelServer.java
  95. 121 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameDb.java
  96. 62 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GamePlatform.java
  97. 81 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameRegion.java
  98. 256 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameServer.java
  99. 136 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameServerRuntime.java
  100. 104 0
      x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/UserChannel.java

+ 34 - 0
.gitignore

@@ -0,0 +1,34 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# Package Files #
+*.jar
+*.war
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+.idea
+*.iml
+.idea/compiler.xml
+.idea/encodings.xml
+.idea/misc.xml
+.idea/modules.xml
+.idea/vcs.xml
+
+
+*.project
+*.classpath
+
+.settings/
+logs/
+target/
+uploadfiles/
+common-libs/*

+ 10 - 0
README.txt

@@ -0,0 +1,10 @@
+端口占用
+后台占用:10000
+
+游戏服N Tcp端口:1xxxx,从10001开始,一般遵循xxxx=N的设定
+游戏服N Http端口:2xxxx,从20001开始,一般遵循xxxx=N的设定
+游戏服N Dubbo端口:3xxxx,从30001开始,一般遵循xxxx=N的设定
+
+跨服1 	
+		tcp端口41001
+		http端口42001

+ 12 - 0
dockerfiles/backstage/DockerUse.txt

@@ -0,0 +1,12 @@
+
+通过镜像运行一个服务器容器
+docker run \
+	-d \
+	--name x1-backstage \
+	-p 9001:9001 \
+	-v /game/x1/backstage/config:/game/x1/config \
+	-v /game/x1/backstage/logs:/game/x1/logs \
+	x1-backstage:202408011000
+
+进入到容器内部
+docker exec -it 容器名 bash	

+ 35 - 0
dockerfiles/backstage/Dockerfile

@@ -0,0 +1,35 @@
+#构建镜像初始的依赖镜像(镜像名:版本号,缺省版本号时为latest)
+FROM yy-jdk8
+
+#指定镜像创建者信息
+Maintainer YY
+
+#设置语言
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+
+#设置时区
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+#在容器中创建目录
+RUN mkdir /game
+RUN mkdir /game/x1
+RUN mkdir /game/x1/common-libs
+RUN mkdir /game/x1/jar
+RUN mkdir /game/x1/config
+RUN mkdir /game/x1/logs
+
+#COPY 当前目录下的文件 目标文件夹
+COPY ./common-libs/* /game/x1/common-libs
+RUN rm -rf /game/x1/common-libs/jdk.tools-1.8.jar
+COPY ./jar/* /game/x1/jar
+RUN cp /usr/local/java/jdk1.8.0_231/lib/tools.jar /game/x1/common-libs
+
+#设置进行容器时的工作目录,也是程序启动的目录,如果不进行此设置,会影响到springboot无法正常加载config配置
+WORKDIR /game/x1
+
+ENTRYPOINT ["java", "-server", "-XX:+HeapDumpOnOutOfMemoryError", "-Xms1024M", "-Xmx2048M", "-classpath", "./config/*:./common-libs/*:./jar/*:", "com.xiugou.x1.backstage.X1BackStage", ">", "./log_console.log", "&"]
+
+#使用如下命令进行构建
+#docker build -t x1-backstage:202408011000 .

+ 26 - 0
dockerfiles/game/DockerUse.txt

@@ -0,0 +1,26 @@
+
+通过镜像运行一个服务器容器
+docker run \
+	-d \
+	--name x1-game-server4 \
+	-p 10004:10004 \
+	-p 20004:20004 \
+	-v /game/x1/game-server-4/config:/game/x1/config \
+	-v /game/x1/game-server-4/csv:/game/x1/csv \
+	-v /game/x1/game-server-4/mapdata:/game/x1/mapdata \
+	-v /game/x1/game-server-4/uploadfiles:/game/x1/uploadfiles \
+	x1-game-server:202408021600
+	
+docker run \
+	-d \
+	--name x1-game-server5 \
+	-p 10005:10005 \
+	-p 20005:20005 \
+	-v /game/x1/game-server-5/config:/game/x1/config \
+	-v /game/x1/game-server-5/csv:/game/x1/csv \
+	-v /game/x1/game-server-5/mapdata:/game/x1/mapdata \
+	-v /game/x1/game-server-4/uploadfiles:/game/x1/uploadfiles \
+	x1-game-server:202408021600
+
+进入到容器内部
+docker exec -it 容器名 bash	

+ 30 - 0
dockerfiles/game/Dockerfile

@@ -0,0 +1,30 @@
+# 构建镜像初始的依赖镜像(镜像名:版本号,缺省版本号时为latest)
+FROM openjdk:8-jdk-alpine
+
+# 指定镜像创建者信息
+LABEL maintainer="YY"
+
+# 设置语言
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+
+# 设置时区
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+# 在容器中创建目录
+RUN mkdir -p /game/x1/common-libs /game/x1/jar /game/x1/config /game/x1/csv /game/x1/mapdata /game/x1/uploadfiles
+
+# 复制文件
+COPY ../common-libs/* /game/x1/common-libs
+RUN rm -rf /game/x1/common-libs/jdk.tools-1.8.jar
+COPY ../x1-game-server/target/jar/* /game/x1/jar
+
+# 复制 tools.jar
+RUN find /usr -name "tools.jar" -exec cp {} /game/x1/common-libs \;
+
+# 设置进行容器时的工作目录,也是程序启动的目录,如果不进行此设置,会影响到springboot无法正常加载config配置
+WORKDIR /game/x1
+
+# 启动命令
+ENTRYPOINT java -server -javaagent:./jar/gaming-agent-0.0.1.jar -XX:+HeapDumpOnOutOfMemoryError -Xms1024M -Xmx2048M -classpath "./config/*:./common-libs/*:./jar/*:" com.xiugou.x1.game.server.X1GameServer > ./log_console.log &

+ 30 - 0
dockerfiles/game/Dockerfile.1

@@ -0,0 +1,30 @@
+# 构建镜像初始的依赖镜像(镜像名:版本号,缺省版本号时为latest)
+FROM openjdk:8
+
+# 指定镜像创建者信息
+LABEL maintainer="YY"
+
+# 设置语言
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+
+# 设置时区
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+# 在容器中创建目录
+RUN mkdir -p /game/x1/common-libs /game/x1/jar /game/x1/config /game/x1/csv /game/x1/mapdata /game/x1/uploadfiles
+
+# 复制文件
+COPY ../common-libs/* /game/x1/common-libs
+RUN rm -rf /game/x1/common-libs/jdk.tools-1.8.jar
+COPY ../x1-game-server/target/jar/* /game/x1/jar
+
+# 复制 tools.jar
+RUN find /usr -name "tools.jar" -exec cp {} /game/x1/common-libs \;
+
+# 设置进行容器时的工作目录,也是程序启动的目录,如果不进行此设置,会影响到springboot无法正常加载config配置
+WORKDIR /game/x1
+
+# 启动命令
+ENTRYPOINT java -server -javaagent:./jar/gaming-agent-0.0.1.jar -XX:+HeapDumpOnOutOfMemoryError -Xms1024M -Xmx2048M -classpath "./config/*:./common-libs/*:./jar/*:" com.xiugou.x1.game.server.X1GameServer > ./log_console.log &

+ 8 - 0
fastpack.bat

@@ -0,0 +1,8 @@
+::基础模块目录
+
+cd %~dp0
+call mvn clean install
+
+::call ./copydeploy.bat
+@pause
+::此bat文件需要GBK的编码格式

+ 34 - 0
fullpack.bat

@@ -0,0 +1,34 @@
+::基础模块目录
+set gamingspace=D:\Git\gaming\
+set gamingprospace=D:\Git\gaming-project-branch\
+
+cd %gamingspace%gaming-agent
+call mvn clean install
+
+cd %gamingspace%gaming-tool
+call mvn clean install
+
+cd %gamingspace%gaming-db
+call mvn clean install
+
+cd %gamingspace%gaming-fakecmd
+call mvn clean install
+
+cd %gamingspace%gaming-design
+call mvn clean install
+
+cd %gamingspace%gaming-ruler
+call mvn clean install
+
+cd %gamingprospace%gaming-prefab
+call mvn clean install
+
+cd %gamingprospace%gaming-backstage
+call mvn clean install
+
+cd %~dp0
+call mvn clean install
+
+::call ./copydeploy.bat
+@pause
+::此bat文件需要GBK的编码格式

+ 47 - 0
fullpack.sh

@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# 基础模块目录
+gamingspace="/Users/pigflower/Code/server/gaming"
+gamingprospace="/Users/pigflower/Code/server/gaming"
+
+# 进入 gaming-agent 目录并执行 mvn clean install
+cd "$gamingspace/gaming-agent"
+mvn clean install
+
+# 进入 gaming-tool 目录并执行 mvn clean install
+cd "$gamingspace/gaming-tool"
+mvn clean install
+
+# 进入 gaming-db 目录并执行 mvn clean install
+cd "$gamingspace/gaming-db"
+mvn clean install
+
+# 进入 gaming-fakecmd 目录并执行 mvn clean install
+cd "$gamingspace/gaming-fakecmd"
+mvn clean install
+
+# 进入 gaming-design 目录并执行 mvn clean install
+cd "$gamingspace/gaming-design"
+mvn clean install
+
+# 进入 gaming-ruler 目录并执行 mvn clean install
+cd "$gamingspace/gaming-ruler"
+mvn clean install
+
+# 进入 gaming-prefab 目录并执行 mvn clean install
+cd "$gamingprospace/gaming-prefab"
+mvn clean install
+
+# 进入 gaming-backstage 目录并执行 mvn clean install
+cd "$gamingprospace/gaming-backstage"
+mvn clean install
+
+# 回到脚本所在目录并执行 mvn clean install
+cd "$(dirname "$0")"
+mvn clean install
+
+# 调用 copydeploy.bat(这里注释掉的部分,在 Shell 中应该调用对应的 Shell 脚本)
+#./copydeploy.sh
+
+# 暂停,等待用户输入
+read -p "Press any key to continue..."

+ 79 - 0
pom.xml

@@ -0,0 +1,79 @@
+<?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>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.1.0.RELEASE</version>
+		<relativePath/>
+	</parent>
+
+	<groupId>xiugou</groupId>
+	<artifactId>x1-project</artifactId>
+	<packaging>pom</packaging>
+	<version>0.0.1</version>
+
+	<modules>
+		<module>x1-protobuf</module>
+		<module>x1-battle</module>
+		<module>x1-design</module>
+		<module>x1-pojo</module>
+		<module>x1-game-server</module>
+		<module>x1-backstage</module>
+    <module>x1-cross-server</module>
+  </modules>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.build.jdk>1.8</project.build.jdk>
+		<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
+		<maven.compiler.source>1.8</maven.compiler.source>
+		<maven.compiler.target>1.8</maven.compiler.target>
+
+		<gaming.version>0.0.1</gaming.version>
+		<xiugou.x1.version>0.0.1</xiugou.x1.version>
+	</properties>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>game</groupId>
+				<artifactId>gaming-agent</artifactId>
+				<version>${gaming.version}</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>copy-thirds</id>
+						<phase>package</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<!-- 把第三方的jar拷贝在common-libs目录下 -->
+						<configuration>
+							<echo message="${project.build.directory}"/>
+						    <outputDirectory>${project.build.directory}/common-libs</outputDirectory>
+							<outputDirectory>../common-libs</outputDirectory>
+							<excludeGroupIds>game,xiugou,gaming-project</excludeGroupIds>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 4 - 0
x1-backstage/.gitignore

@@ -0,0 +1,4 @@
+target
+config/application.properties
+config/database.db
+.idea

+ 30 - 0
x1-backstage/config/application.properties.temp

@@ -0,0 +1,30 @@
+#后台服务器的tomcat端口
+server.port=9001
+#服务器是否调试模式
+server.debug.mode=true
+
+#是否为后台主服务器
+server.backstage.main=true
+
+#热更配置文件夹
+fix.upload.design.folder=/uploadfiles/design/
+#热更代码文件夹
+fix.upload.clazzs.folder=/uploadfiles/clazzs/
+
+#后台加密秘钥
+backstage.key=xiugouyouxi2023
+#主后台的地址
+backstage.main.url=http://127.0.0.1:9001
+
+#数据库配置
+database.config.file=file:./config/database.db
+#日志输出格式配置
+logging.config=file:./config/log4j2.xml
+
+#===================redis基础配置===================
+spring.redis.database=1
+spring.redis.host=127.0.0.1
+spring.redis.password=yy2024
+spring.redis.port=6379
+# 连接超时时间 单位 ms(毫秒)
+spring.redis.timeout=3000

+ 2 - 0
x1-backstage/config/database.db.temp

@@ -0,0 +1,2 @@
+{"id":1,"alias":"backstage","ipPort":"127.0.0.1:3306","dbName":"x1_backstage","user":"root","password":"123456","minIdle":1,"maxActive":5,"maxWaitMillis":60000}
+{"id":1,"alias":"backlog","ipPort":"127.0.0.1:3306","dbName":"x1_backlog","user":"root","password":"123456","minIdle":1,"maxActive":5,"maxWaitMillis":60000}

+ 71 - 0
x1-backstage/config/log4j2.xml

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN" monitorInterval="600" shutdownHook="disable">
+    <Properties>
+        <Property name="LOG_HOME">logs</Property>
+        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss:SSS} %-5p [%10.10t] %-25.25C{1.}.%-15.15M:%-4.4L | %X{user} %m%n
+        </Property>
+    </Properties>
+
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+        	<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+        </Console>
+        
+        <RollingRandomAccessFile name="ServiceInfoAppender" fileName="${sys:logPath:-logs}/info.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log.gz">
+            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+            <Policies>
+                <TimeBasedTriggeringPolicy/>
+                <SizeBasedTriggeringPolicy size="128 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="9999"/>
+        </RollingRandomAccessFile>
+
+        <RollingRandomAccessFile name="ServiceDebufAppender" fileName="${sys:logPath:-logs}/debug.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/debug-%d{yyyy-MM-dd HH}-%i.log.gz">
+            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+            <Policies>
+                <TimeBasedTriggeringPolicy/>
+                <SizeBasedTriggeringPolicy size="512 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="9999"/>
+        </RollingRandomAccessFile>
+
+        <RollingRandomAccessFile name="ServiceErrorAppender" fileName="${sys:logPath:-logs}/error.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/error-%d{yyyy-MM-dd}-%i.log.gz">
+            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+            <Policies>
+                <TimeBasedTriggeringPolicy/>
+                <SizeBasedTriggeringPolicy size="128 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="9999"/>
+        </RollingRandomAccessFile>
+
+    </Appenders>
+
+    <Loggers>
+        <root level="DEBUG">
+            <appender-ref ref="Console"/>
+            <appender-ref ref="ServiceInfoAppender"/>
+            <appender-ref ref="ServiceDebufAppender"/>
+            <appender-ref ref="ServiceErrorAppender"/>
+        </root>
+
+        <logger name="org.springframework" level="info"/>
+        <logger name="io.netty" level="info"/>
+        <logger name="io.lettuce" level="info"/>
+        <logger name="org.eclipse.jetty" level="info"/>
+    </Loggers>
+</Configuration>

+ 71 - 0
x1-backstage/config/log4j2.xml.temp

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN" monitorInterval="600" shutdownHook="disable">
+    <Properties>
+        <Property name="LOG_HOME">logs</Property>
+        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss:SSS} %-5p [%10.10t] %-25.25C{1.}.%-15.15M:%-4.4L | %X{user} %m%n
+        </Property>
+    </Properties>
+
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+        	<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+        </Console>
+        
+        <RollingRandomAccessFile name="ServiceInfoAppender" fileName="${sys:logPath:-logs}/info.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log.gz">
+            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+            <Policies>
+                <TimeBasedTriggeringPolicy/>
+                <SizeBasedTriggeringPolicy size="128 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="9999"/>
+        </RollingRandomAccessFile>
+
+        <RollingRandomAccessFile name="ServiceDebufAppender" fileName="${sys:logPath:-logs}/debug.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/debug-%d{yyyy-MM-dd HH}-%i.log.gz">
+            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+            <Policies>
+                <TimeBasedTriggeringPolicy/>
+                <SizeBasedTriggeringPolicy size="512 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="9999"/>
+        </RollingRandomAccessFile>
+
+        <RollingRandomAccessFile name="ServiceErrorAppender" fileName="${sys:logPath:-logs}/error.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM-dd}/error-%d{yyyy-MM-dd}-%i.log.gz">
+            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
+            <PatternLayout>
+                <Pattern>${LOG_PATTERN}</Pattern>
+            </PatternLayout>
+            <Policies>
+                <TimeBasedTriggeringPolicy/>
+                <SizeBasedTriggeringPolicy size="128 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="9999"/>
+        </RollingRandomAccessFile>
+
+    </Appenders>
+
+    <Loggers>
+        <root level="DEBUG">
+            <appender-ref ref="Console"/>
+            <appender-ref ref="ServiceInfoAppender"/>
+            <appender-ref ref="ServiceDebufAppender"/>
+            <appender-ref ref="ServiceErrorAppender"/>
+        </root>
+
+        <logger name="org.springframework" level="info"/>
+        <logger name="io.netty" level="info"/>
+        <logger name="io.lettuce" level="info"/>
+        <logger name="org.eclipse.jetty" level="info"/>
+    </Loggers>
+</Configuration>

+ 93 - 0
x1-backstage/pom.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<project
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>xiugou</groupId>
+		<artifactId>x1-project</artifactId>
+		<version>0.0.1</version>
+	</parent>
+	<artifactId>x1-backstage</artifactId>
+
+	<dependencies>
+		<dependency>
+			<groupId>xiugou</groupId>
+			<artifactId>x1-pojo</artifactId>
+			<version>${xiugou.x1.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>gaming-project</groupId>
+			<artifactId>gaming-backstage</artifactId>
+			<version>${gaming.version}</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>copy-main</id>
+						<phase>package</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<!-- 把游戏与框架分组的jar拷贝到jar目录下 -->
+						<configuration>
+							<outputDirectory>${project.build.directory}/jar</outputDirectory>
+							<includeGroupIds>game,xiugou,gaming-project</includeGroupIds>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-resources-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>copy-config</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>copy-resources</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/config</outputDirectory>
+							<resources>
+								<resource>
+									<directory>config</directory>
+									<filtering>false</filtering>
+								</resource>
+							</resources>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<outputDirectory>${project.build.directory}/jar</outputDirectory>
+					<archive>
+						<manifest>
+							<addClasspath>false</addClasspath>
+							<mainClass>com.xiugou.x1.backstage.X1BackStage</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 26 - 0
x1-backstage/restart-backstage.sh

@@ -0,0 +1,26 @@
+#!/bin/bash
+
+server_path=$(cd "$(dirname "$0")"/; pwd)
+
+echo -e "\nstop $server_path "
+
+for (( i=1; i<=100; i++))
+do
+        process=`ps -ef |grep -v 'grep' | grep "java" | grep $server_path/ | awk '{print $2}'`
+        if [[ $process -gt 0 ]];then
+            kill -15 $process
+            echo "process lenght:${#process[*]} kill -15 $process "
+        else 
+            echo "not java process"
+            break
+        fi
+        sleep 2
+done
+
+echo "stop $server_path end"
+
+echo "start $server_path"
+
+#nohup java -server -XX:+HeapDumpOnOutOfMemoryError -Xms512M -Xmx1024M -classpath $server_path/config/*:/game/x1/common-libs/*:$server_path/jar/*: com.xiugou.x1.backstage.X1BackStage > ./log_console.log &
+
+ java -server -XX:+HeapDumpOnOutOfMemoryError -Xms512M -Xmx1024M -classpath $server_path/config/*:/Users/pigflower/Code/server/x1-project/common-libs/*:$server_path/jar/*: com.xiugou.x1.backstage.X1BackStage

+ 38 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/X1BackStage.java

@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package com.xiugou.x1.backstage;
+
+import java.util.Collections;
+
+import org.gaming.ruler.eventbus.EventBus;
+import org.gaming.ruler.schedule.ScheduleManager;
+import org.gaming.tool.ConsoleUtil;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+import com.xiugou.x1.backstage.foundation.starting.ProjectBooter;
+
+/**
+ * @author YY
+ */
+@ComponentScan(basePackages = { "com.xiugou", "org.gaming" })
+@SpringBootApplication
+public class X1BackStage {
+
+	public static void main(String[] args) {
+		SpringApplication springApplication = new SpringApplication();
+		// 服务器启动引导
+		springApplication.addListeners(new ProjectBooter());
+
+		springApplication.addPrimarySources(Collections.singletonList(X1BackStage.class));
+		springApplication.run(args);
+
+		ConsoleUtil.addFunction("stop", () -> { System.exit(0); });
+		ConsoleUtil.addFunction("printConsoleFunction", ConsoleUtil::printFunction);
+		ConsoleUtil.addFunction("printEventTrace", EventBus::printTrace);
+		ConsoleUtil.addFunction("printSchedule", () -> { ScheduleManager.print();});
+		ConsoleUtil.inputListening();
+	}
+}

+ 100 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ApplicationSettings.java

@@ -0,0 +1,100 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.foundation.starting;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author YY
+ *
+ */
+@Configuration
+public class ApplicationSettings {
+
+
+	//#后台服务器的tomcat端口
+	@Value("${server.port:9001}")
+	protected int serverPort;
+	//#服务器是否调试模式
+	@Value("${server.debug.mode:true}")
+	protected boolean serverDebugMode;
+	//#是否为后台主服务器
+	@Value("${server.backstage.main:true}")
+	protected boolean serverBackstageMain;
+	//#热更配置文件夹
+	@Value("${fix.upload.design.folder:/uploadfiles/design/}")
+	protected String fixUploadDesignFolder;
+	//#热更代码文件夹
+	@Value("${fix.upload.clazzs.folder:/uploadfiles/clazzs/}")
+	protected String fixUploadClazzsFolder;
+	//#后台加密秘钥
+	@Value("${backstage.key:xiugouyouxi2023}")
+	protected String backstageKey;
+	//#主后台的地址
+	@Value("${backstage.main.url:http://127.0.0.1:9001}")
+	protected String backstageMainUrl;
+	//#数据库配置
+	@Value("${database.config.file:file:./config/database.db}")
+	protected String databaseConfigFile;
+	//#日志输出格式配置
+	@Value("${logging.config:file:./config/log4j2.xml}")
+	protected String loggingConfig;
+	//#===================redis基础配置===================
+	@Value("${spring.redis.database:3}")
+	protected int springRedisDatabase;
+	@Value("${spring.redis.host:192.168.1.47}")
+	protected String springRedisHost;
+	@Value("${spring.redis.password:xiugou2023}")
+	protected String springRedisPassword;
+	@Value("${spring.redis.port:6379}")
+	protected int springRedisPort;
+	//# 连接超时时间 单位 ms(毫秒)
+	@Value("${spring.redis.timeout:3000}")
+	protected int springRedisTimeout;
+
+
+	public int getServerPort() {
+		return serverPort;
+	}
+	public boolean isServerDebugMode() {
+		return serverDebugMode;
+	}
+	public boolean isServerBackstageMain() {
+		return serverBackstageMain;
+	}
+	public String getDatabaseConfigFile() {
+		return databaseConfigFile;
+	}
+	public String getLoggingConfig() {
+		return loggingConfig;
+	}
+	public int getSpringRedisDatabase() {
+		return springRedisDatabase;
+	}
+	public String getSpringRedisHost() {
+		return springRedisHost;
+	}
+	public String getSpringRedisPassword() {
+		return springRedisPassword;
+	}
+	public int getSpringRedisPort() {
+		return springRedisPort;
+	}
+	public int getSpringRedisTimeout() {
+		return springRedisTimeout;
+	}
+	public String getFixUploadDesignFolder() {
+		return fixUploadDesignFolder;
+	}
+	public String getFixUploadClazzsFolder() {
+		return fixUploadClazzsFolder;
+	}
+	public String getBackstageKey() {
+		return backstageKey;
+	}
+	public String getBackstageMainUrl() {
+		return backstageMainUrl;
+	}
+}

+ 19 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ApplicationSettingsTool.java

@@ -0,0 +1,19 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.foundation.starting;
+
+import org.gaming.ruler.util.ApplicationPropertiesGenerator;
+
+/**
+ * @author YY
+ *
+ */
+public class ApplicationSettingsTool {
+	
+	public static void main(String[] args) {
+		String projectDir = System.getProperty("user.dir");
+		String game = projectDir + "/config/application.properties";
+		ApplicationPropertiesGenerator.readPropertiesFile(game);
+	}
+}

+ 40 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/BeanRegister.java

@@ -0,0 +1,40 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.foundation.starting;
+
+import org.gaming.ruler.eventbus.EventBus;
+import org.gaming.ruler.lifecycle.Lifecycle;
+import org.gaming.ruler.lifecycle.LifecycleSupport;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author YY
+ *
+ */
+@Component
+public class BeanRegister implements BeanPostProcessor {
+	
+	@Override
+	public Object postProcessBeforeInitialization(Object bean, String beanName)
+			throws BeansException {
+		if(bean instanceof Lifecycle) {
+			//生命周期服务注册
+			LifecycleSupport.registerBean((Lifecycle)bean);
+		}
+		Service service = bean.getClass().getAnnotation(Service.class);
+		if(service != null) {
+			EventBus.register(bean);
+		}
+		return bean;
+	}
+
+	@Override
+	public Object postProcessAfterInitialization(Object bean, String beanName)
+			throws BeansException {
+		return bean;
+	}
+}

+ 71 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/DatabaseLifecycle.java

@@ -0,0 +1,71 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.foundation.starting;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.gaming.db.annotation.LogTable;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.mysql.database.DBConfig;
+import org.gaming.db.mysql.table.TableBuilder;
+import org.gaming.db.orm.AbstractEntity;
+import org.gaming.db.usecase.SlimDao;
+import org.gaming.ruler.lifecycle.Lifecycle;
+import org.gaming.ruler.lifecycle.LifecycleInfo;
+import org.gaming.ruler.lifecycle.Ordinal;
+import org.gaming.ruler.lifecycle.Priority;
+import org.gaming.ruler.spring.Spring;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author YY
+ *
+ */
+@Component
+public class DatabaseLifecycle implements Lifecycle {
+
+	@Autowired
+	private ApplicationSettings applicationSettings;
+	
+	@Override
+	public LifecycleInfo getInfo() {
+		return LifecycleInfo.valueOf(this.getClass().getSimpleName(), Priority.INITIALIZATION, Ordinal.MIN);
+	}
+
+	@Override
+	public void start() throws Exception {
+		String dbFilePath = "";
+		if(applicationSettings.getDatabaseConfigFile().startsWith("file")) {
+			ResourceLoader loader = new DefaultResourceLoader();
+	        Resource resource = loader.getResource(applicationSettings.getDatabaseConfigFile());
+	        dbFilePath = resource.getFile().getPath();
+		} else {
+			dbFilePath = applicationSettings.getDatabaseConfigFile();
+		}
+		TableBuilder.SERVER_IDENTITY = 1;
+		List<DBConfig> dbConfigs = DBConfig.loadConfigs(dbFilePath);
+		
+		Collection<Object> entitySamples = Spring.getBeansWithAnnotation(Table.class);
+		Collection<Object> logSamples = Spring.getBeansWithAnnotation(LogTable.class);
+		
+		List<Class<?>> classList = new ArrayList<>();
+		for(Object bean : entitySamples) {
+			if (bean instanceof AbstractEntity) {
+				classList.add(Spring.getBeanRealClass(bean));
+			}
+		}
+		for(Object bean : logSamples) {
+			if (bean instanceof AbstractEntity) {
+				classList.add(Spring.getBeanRealClass(bean));
+			}
+		}
+		SlimDao.build(dbConfigs, classList);
+	}
+}

+ 36 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ProjectBooter.java

@@ -0,0 +1,36 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.foundation.starting;
+
+import org.gaming.ruler.lifecycle.LifecycleSupport;
+import org.gaming.ruler.spring.Spring;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ApplicationContextEvent;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+/**
+ * @author YY
+ *
+ */
+public class ProjectBooter implements ApplicationListener<ApplicationContextEvent> {
+
+	private static Logger logger = LoggerFactory.getLogger(ProjectBooter.class);
+	
+	@Override
+	public void onApplicationEvent(ApplicationContextEvent event) {
+		if(event instanceof ContextRefreshedEvent) {
+			Spring.setContext(event.getApplicationContext());
+
+			logger.info("执行服务器启动逻辑");
+			LifecycleSupport.start();
+		} else if(event instanceof ContextClosedEvent) {
+			logger.info("执行服务器关停逻辑");
+			LifecycleSupport.stop();
+		}
+	}
+
+}

+ 36 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/foundation/starting/ScheduleLifecycle.java

@@ -0,0 +1,36 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.foundation.starting;
+
+import org.gaming.ruler.lifecycle.Lifecycle;
+import org.gaming.ruler.lifecycle.LifecycleInfo;
+import org.gaming.ruler.lifecycle.Ordinal;
+import org.gaming.ruler.lifecycle.Priority;
+import org.gaming.ruler.schedule.ScheduleManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author YY
+ *
+ */
+@Component
+public class ScheduleLifecycle implements Lifecycle {
+	
+	@Autowired
+	private ApplicationSettings applicationSettings;
+	
+	@Override
+	public LifecycleInfo getInfo() {
+		return LifecycleInfo.valueOf(this.getClass().getSimpleName(), Priority.LOW, Ordinal.MAX);
+	}
+
+	@Override
+	public void start() throws Exception {
+		//只在主后台跑定时器
+		if(applicationSettings.isServerBackstageMain()) {
+			ScheduleManager.setup(Runtime.getRuntime().availableProcessors());
+		}
+	}
+}

+ 165 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/MenuController.java

@@ -0,0 +1,165 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module;
+
+import org.gaming.backstage.module.menu.annotation.FunctionPage;
+import org.gaming.backstage.module.menu.annotation.ModulePage;
+import org.gaming.backstage.module.menu.annotation.SystemPage;
+import org.springframework.stereotype.Controller;
+
+import com.xiugou.x1.backstage.module.clientlog.ClientLogController;
+import com.xiugou.x1.backstage.module.clientversion.ClientVersionController;
+import com.xiugou.x1.backstage.module.dotdata.BossDotDataController;
+import com.xiugou.x1.backstage.module.dotdata.FogDotDataController;
+import com.xiugou.x1.backstage.module.dotdata.GuideDotDataController;
+import com.xiugou.x1.backstage.module.dotdata.LoginDotDataController;
+import com.xiugou.x1.backstage.module.dotdata.RecruitDotDataController;
+import com.xiugou.x1.backstage.module.dotdata.RecruitRefreshDotDataController;
+import com.xiugou.x1.backstage.module.dotdata.TaskDotDataController;
+import com.xiugou.x1.backstage.module.gamecause.GameCauseController;
+import com.xiugou.x1.backstage.module.gamelog.GameLogController;
+import com.xiugou.x1.backstage.module.gameserver.BulletinController;
+import com.xiugou.x1.backstage.module.gameserver.GameChannelController;
+import com.xiugou.x1.backstage.module.gameserver.GameChannelServerController;
+import com.xiugou.x1.backstage.module.gameserver.GamePlatformController;
+import com.xiugou.x1.backstage.module.gameserver.GameRegionController;
+import com.xiugou.x1.backstage.module.gameserver.GameServerController;
+import com.xiugou.x1.backstage.module.gameserver.GameServerMaintainController;
+import com.xiugou.x1.backstage.module.gameserver.ServerOpenController;
+import com.xiugou.x1.backstage.module.gameserver.UserChannelController;
+import com.xiugou.x1.backstage.module.giftcode.GiftCodeCfgController;
+import com.xiugou.x1.backstage.module.giftcode.GiftCodeController;
+import com.xiugou.x1.backstage.module.giftcode.GiftCodeShareLogController;
+import com.xiugou.x1.backstage.module.godfinger.GodFingerController;
+import com.xiugou.x1.backstage.module.hotfix.FixCodeController;
+import com.xiugou.x1.backstage.module.hotfix.FixDesignController;
+import com.xiugou.x1.backstage.module.item.ItemCfgController;
+import com.xiugou.x1.backstage.module.mail.MailSystemController;
+import com.xiugou.x1.backstage.module.mail.PlayerMailController;
+import com.xiugou.x1.backstage.module.player.ConsumeController;
+import com.xiugou.x1.backstage.module.player.ForbidListController;
+import com.xiugou.x1.backstage.module.player.PlayerController;
+import com.xiugou.x1.backstage.module.player.PlayerLTVController;
+import com.xiugou.x1.backstage.module.player.PlayerOnlineLogController;
+import com.xiugou.x1.backstage.module.player.PlayerPayRemainController;
+import com.xiugou.x1.backstage.module.player.PlayerRemainController;
+import com.xiugou.x1.backstage.module.player.PlayerScatterLogController;
+import com.xiugou.x1.backstage.module.player.PlayerTimeLogController;
+import com.xiugou.x1.backstage.module.player.ServerResumeController;
+import com.xiugou.x1.backstage.module.player.WhiteListController;
+import com.xiugou.x1.backstage.module.recharge.RechargeCallbackController;
+import com.xiugou.x1.backstage.module.recharge.RechargeProductCountController;
+import com.xiugou.x1.backstage.module.recharge.RechargeRankController;
+import com.xiugou.x1.backstage.module.recharge.RechargeVirtualController;
+import com.xiugou.x1.backstage.module.rechargeproduct.RechargeProductCfgController;
+
+/**
+ * @author YY
+ *
+ */
+@SystemPage(id = 2, name = "游戏管理", sort = 2, routeName = "gameSettings", routeComponent = "Layout")
+@ModulePage(id = 10001, name = "服务器管理", systemId = 2, routeName = "serverSettings", routeComponent = "layout/secondaryLayout")
+	@FunctionPage(moduleId = 10001, name = "平台管理", routeName = "gamePlatform", sort = 1, authClass = GamePlatformController.class)
+	@FunctionPage(moduleId = 10001, name = "渠道管理", routeName = "gameChannel", sort = 2, authClass = GameChannelController.class)
+	@FunctionPage(moduleId = 10001, name = "服务器管理", routeName = "gameServer", sort = 3, authClass = GameServerController.class)
+	@FunctionPage(moduleId = 10001, name = "渠道与服务器关系", routeName = "gameChannelServer", sort = 4, authClass = GameChannelServerController.class)
+	@FunctionPage(moduleId = 10001, name = "渠道大区管理", routeName = "gameRegion", sort = 5, authClass = GameRegionController.class)
+	@FunctionPage(moduleId = 10001, name = "开服管理", routeName = "serverOpen", sort = 6, authClass = ServerOpenController.class)
+	@FunctionPage(moduleId = 10001, name = "渠道权限管理", routeName = "userChannel", sort = 7, authClass = UserChannelController.class)
+	@FunctionPage(moduleId = 10001, name = "游戏公告管理", routeName = "bulletin", sort = 8, authClass = BulletinController.class)
+	@FunctionPage(moduleId = 10001, name = "服务器维护管理", routeName = "gameServerMaintain", sort = 9, authClass = GameServerMaintainController.class)
+	@FunctionPage(moduleId = 10001, name = "客户端版本管理", routeName = "clientVersion", sort = 10, authClass = ClientVersionController.class)
+@ModulePage(id = 10002, name = "玩家管理", systemId = 2, routeName = "loginSettings", routeComponent = "layout/secondaryLayout")
+	@FunctionPage(moduleId = 10002, name = "玩家信息管理", routeName = "player", sort = 1, authClass = PlayerController.class)
+	@FunctionPage(moduleId = 10002, name = "白名单管理", routeName = "whiteList", sort = 2, authClass = WhiteListController.class)
+	@FunctionPage(moduleId = 10002, name = "金手指名单", routeName = "godFinger", sort = 3, authClass = GodFingerController.class)
+	@FunctionPage(moduleId = 10002, name = "封禁账号", routeName = "forbidList", sort = 4, authClass = ForbidListController.class)
+@ModulePage(id = 10003, name = "游戏统计数据", systemId = 2, routeName = "censusSettings", routeComponent = "layout/secondaryLayout")
+	@FunctionPage(moduleId = 10003, name = "注册分时", routeName = "playerTimeLog", sort = 1, authClass = PlayerTimeLogController.class)
+	@FunctionPage(moduleId = 10003, name = "在线人数", routeName = "playerOnlineLog", sort = 2, authClass = PlayerOnlineLogController.class)
+	@FunctionPage(moduleId = 10003, name = "在线时长占比", routeName = "playerScatterLog", sort = 3, authClass = PlayerScatterLogController.class)
+	@FunctionPage(moduleId = 10003, name = "玩家留存", routeName = "playerRemain", sort = 4, authClass = PlayerRemainController.class)
+	@FunctionPage(moduleId = 10003, name = "付费留存", routeName = "playerPayRemain", sort = 5, authClass = PlayerPayRemainController.class)
+	@FunctionPage(moduleId = 10003, name = "付费LTV", routeName = "playerLTV", sort = 6, authClass = PlayerLTVController.class)
+	@FunctionPage(moduleId = 10003, name = "游戏汇总", routeName = "serverResume", sort = 7, authClass = ServerResumeController.class)
+	@FunctionPage(moduleId = 10003, name = "货币消费统计", routeName = "consume", sort = 8, authClass = ConsumeController.class)
+	@FunctionPage(moduleId = 10003, name = "登录数据打点", routeName = "loginDotData", sort = 9, authClass = LoginDotDataController.class)
+	@FunctionPage(moduleId = 10003, name = "任务数据打点", routeName = "taskDotData", sort = 10, authClass = TaskDotDataController.class)
+	@FunctionPage(moduleId = 10003, name = "引导数据打点", routeName = "guideDotData", sort = 11, authClass = GuideDotDataController.class)
+	@FunctionPage(moduleId = 10003, name = "招募数据打点", routeName = "recruitDotData", sort = 11, authClass = RecruitDotDataController.class)
+	@FunctionPage(moduleId = 10003, name = "招募刷新数据打点", routeName = "recruitRefreshDotData", sort = 12, authClass = RecruitRefreshDotDataController.class)
+	@FunctionPage(moduleId = 10003, name = "BOSS击杀数据打点", routeName = "bossDotData", sort = 13, authClass = BossDotDataController.class)
+	@FunctionPage(moduleId = 10003, name = "场景区域解锁数据打点", routeName = "fogDotData", sort = 14, authClass = FogDotDataController.class)
+@ModulePage(id = 10004, name = "邮件相关", systemId = 2, routeName = "mailSettings", routeComponent = "layout/secondaryLayout")
+	@FunctionPage(moduleId = 10004, name = "系统邮件", routeName = "mailSystem", sort = 1, authClass = MailSystemController.class)
+	@FunctionPage(moduleId = 10004, name = "玩家邮件", routeName = "playerMail", sort = 2, authClass = PlayerMailController.class)
+@ModulePage(id = 10005, name = "玩家流水查询", systemId = 2, routeName = "logSettings", routeComponent = "layout/secondaryLayout")
+	@FunctionPage(moduleId = 10005, name = "钻石日志", routeName = "diamondLogs", sort = 1, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "金币日志", routeName = "goldLogs", sort = 2, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "道具日志", routeName = "itemLogs", sort = 3, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "肉日志", routeName = "meatLogs", sort = 4, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "木日志", routeName = "woodLogs", sort = 5, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "矿日志", routeName = "mineLogs", sort = 6, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "英雄日志", routeName = "heroLogs", sort = 7, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "装备日志", routeName = "equipLogs", sort = 8, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "角色经验日志", routeName = "playerExpLogs", sort = 9, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "英雄战力日志", routeName = "heroFightingLogs", sort = 10, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "已删邮件日志", routeName = "mailLogs", sort = 11, authClass = GameLogController.class)
+	@FunctionPage(moduleId = 10005, name = "玩家战力日志", routeName = "playerFightingLogs", sort = 12, authClass = GameLogController.class)
+@ModulePage(id = 10006, name = "特殊操作", systemId = 2, routeName = "fixSettings", routeComponent = "layout/secondaryLayout")
+	@FunctionPage(moduleId = 10006, name = "热更配置", routeName = "fixDesign", sort = 1, authClass = FixDesignController.class)
+	@FunctionPage(moduleId = 10006, name = "热更代码", routeName = "fixCode", sort = 2, authClass = FixCodeController.class)
+	@FunctionPage(moduleId = 10006, name = "流水事件", routeName = "gameCause", sort = 3, authClass = GameCauseController.class)
+	@FunctionPage(moduleId = 10006, name = "道具配置", routeName = "itemCfg", sort = 4, authClass = ItemCfgController.class)
+	@FunctionPage(moduleId = 10006, name = "兑换码礼包配置", routeName = "giftCodeCfg", sort = 5, authClass = GiftCodeCfgController.class)
+	@FunctionPage(moduleId = 10006, name = "兑换码生成", routeName = "giftCode", sort = 6, authClass = GiftCodeController.class)
+	@FunctionPage(moduleId = 10006, name = "通用兑换码日志", routeName = "giftCodeShareLog", sort = 7, authClass = GiftCodeShareLogController.class)
+	@FunctionPage(moduleId = 10006, name = "客户端日志", routeName = "clientLog", sort = 8, authClass = ClientLogController.class)
+	@FunctionPage(moduleId = 10006, name = "充值商品配置", routeName = "rechargeProductCfg", sort = 9, authClass = RechargeProductCfgController.class)
+@ModulePage(id = 10007, name = "充值相关", systemId = 2, routeName = "rechargeSettings", routeComponent = "layout/secondaryLayout")
+	@FunctionPage(moduleId = 10007, name = "充值回调查询", routeName = "recharge", sort = 1, authClass = RechargeCallbackController.class)
+	@FunctionPage(moduleId = 10007, name = "充值排名", routeName = "rechargeRank", sort = 2, authClass = RechargeRankController.class)
+	@FunctionPage(moduleId = 10007, name = "充值项目统计", routeName = "rechargeProductCount", sort = 3, authClass = RechargeProductCountController.class)
+	@FunctionPage(moduleId = 10007, name = "虚拟充值(内部充值)", routeName = "rechargeVirtual", sort = 4, authClass = RechargeVirtualController.class)
+//@ModulePage(id = 10008, name = "37互娱相关", systemId = 2, routeName = "sanQiHuYu", routeComponent = "layout/secondaryLayout")
+//	@FunctionPage(moduleId = 10008, name = "37互娱渠道参数设置", routeName = "sanQiHuYuSetting", sort = 1, authClass = SanQiHuYuSettingController.class)
+//	@FunctionPage(moduleId = 10008, name = "37互娱IP白名单", routeName = "sanQiHuYuWhiteIp", sort = 2, authClass = SanQiHuYuWhiteIpController.class)
+//	@FunctionPage(moduleId = 10008, name = "37互娱发放礼包配置", routeName = "sanQiHuYuGiftCfg", sort = 3, authClass = SanQiHuYuGiftCfgController.class)
+
+@Controller
+public class MenuController {
+	//5.1	角色查询			OK
+	//5.2	玩家封禁			OK
+	//5.3	注册分时			OK		后OK
+	//5.4	在线人数			OK		后OK
+	//5.5	在线玩家列表		OK		后OK
+	//5.6	在线时长占比		OK		后OK
+	//5.7	玩家流水查询		OK		后OK
+	//5.8	登陆流失			暂时先不做
+	//5.9	用户留存			OK
+	//5.10	付费用户留存统计	OK
+	//5.11	付费LTV			OK
+	//5.12	游戏汇总			OK		后OK
+	//5.13	充值排名			OK		后OK
+	//5.14	充值记录			OK
+	//5.15	充值项目统计		OK		后OK
+	//5.16	货币消耗统计		OK		后OK
+	//5.17	渠道配置			OK
+	//5.18	服务器配置			OK
+	//5.19	开服设置			OK
+	//5.20	单服邮件			OK		后OK
+	//5.21	单服公告			OK
+	//5.22	维护白名单			OK		后OK
+	//5.23	绿色通道			暂时先不做
+	//5.24	金手指名单			OK
+	//5.25	账号权限管理		OK
+	//5.xx	热更配置			OK		后OK
+	//5.xx	热更代码			OK		后OK
+	//5.xx	用户与渠道			OK		后OK
+	//5.xx	流水事件			OK
+	//5.xx	道具配置			OK
+	//5.xx	兑换码配置					后OK
+	//5.xx	兑换码生成					后OK
+	//5.xx	通用兑换码日志				后OK
+}

+ 77 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/TipsCode.java

@@ -0,0 +1,77 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module;
+
+import org.gaming.backstage.advice.IResultTips;
+
+/**
+ * @author YY
+ *
+ */
+public enum TipsCode implements IResultTips {
+
+	POST_NO_RESPONSE(100001, "通过%s请求无法得到游戏服的响应"),
+	POST_FAIL(100002, "请求%s未能返回成功结果"),
+	ERROR_PARAM(100003, "参数错误"),
+	WHAT_DO_YOU_WANT_TO_DO(100004, "(╯‵□′)╯︵┻━┻"),
+	
+	GAME_SERVER_MISS(200001, "未找到UID为%s的服务器信息"),
+	SERVER_ID_NOT_ZERO(200002, "服务器ID不能为0"),
+	CHANNEL_MISS(200003, "未找到ID为%s的渠道信息"),
+	REGION_MISS(200004, "未找到渠道%s下的大区%s信息"),
+	CHANNEL_SERVER_MISS(200005, "渠道%s服务器%s关系未找到"),
+	CHANNEL_NOT_CHOOSE(200006, "还没有选择渠道"),
+	SERVER_OPENED(200007, "该服务器已经开服,不能再修改预期开服时间"),
+	SERVER_OPENTIME_NEED_FUTURE(200008, "开服时间必须是未来的时间"),
+	REGION_EXIST(200009, "渠道%s下的大区%s信息已经存在,不能重复添加"),
+	CHANNEL_GAMESERVER_MISS(200010, "渠道%s下未找到服务器UID%s"),
+	BULLETIN_MISS(200011, "未找到ID为%s的公告信息"),
+	BULLETIN_USING_IN_CHANNEL(200012, "该公告还在渠道[%s]下使用,请先修改引用关系"),
+	PLATFORM_MISS(200013, "未找到ID为%s的平台信息"),
+	PLATFORM_SERVER_REPEAT(200014, "该平台下已经有ID为%s的服务器"),
+	CLIENT_VERSION_MISS(200015, "未找到ID为%s的客户端版本信息数据"),
+	CLIENT_VERSION_DELETE_CURR(200016, "不能删除正在对外使用的版本信息"),
+	CLIENT_VERSION_TYPE_ERROR(200017, "版本类型参数错误"),
+	CLIENT_VERSION_CHANNEL_MISS(200018, "未找到渠道%s下版本编号为%s的版本信息"),
+	SERVER_REGION_TYPE_UNMATCH(200019, "服务器与大区的类型不一致"),
+	
+	MAIL_MISS(300001, "未找到ID为%s的系统邮件"),
+	MAIL_HAS_CHECK(300002, "系统邮件%s已经审核,无法修改"),
+	MAIL_EDIT_NEED_CREATOR(300003, "系统邮件只能由创建人修改"),
+	MAIL_NOT_CHECK_PASS(300004, "该系统邮件还没有审核通过"),
+	MAIL_RESEND_NEED_CHECKER(300005, "只有审核员才能对该系统邮件进行重发"),
+	MAIL_DELETE_PLAYER_ERROR(300006, "删除玩家邮件出现异常"),
+	MAIL_ITEM_MISS(300007, "邮件附件未找到道具%s,请更新道具配置"),
+	MAIL_DELETE_AFTER_PASS(300008, "审核通过的系统邮件才有必要通知删除"),
+	MAIL_SERVER_EMPTY(300009, "服务器列表不能为空"),
+	
+	PLAYER_NOT_EXIST(400001, "未找到玩家%s"),
+	PLAYER_NOT_EXIST_IN_CHANNEL(400002, "未找到渠道%s下的玩家%s"),
+	PLAYER_FORBID_FAIL(400003, "玩家封号失败"),
+	PLAYER_FORCED_OFFLINE_FAIL(400004, "玩家强制下线失败"),
+	PLAYER_NOT_IN_CHANNEL(400005, "该玩家不在你的授权渠道中"),
+	RECHARGE_FAIL(400006, "充值回调处理失败"),
+	
+	GOD_FINGER_PLAYER_WRONG(500001, "修改金手指玩家数据未匹配"),
+	GOD_FINGER_BIGGER_ZERO(500002, "金手指金额必须大于0"),
+	GOD_FINGER_NOT_EXIST(500003, "未找到ID为%s的金手指"),
+	
+	FIX_DESIGN_MISS(600001, "未找到ID为%s的热更配制记录"),
+	FIX_DESIGN_SERVER_WRONG(600002, "选中的服务器不在当前渠道下"),
+	
+	CONSUME_TYPE_NOT_FOUND(700001, "未找到对应的资源日志"),
+	;
+	private final int code;
+	private final String message;
+	private TipsCode(int code, String message) {
+		this.code = code;
+		this.message = message;
+	}
+	public int getCode() {
+		return code;
+	}
+	public String getMessage() {
+		return message;
+	}
+}

+ 64 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/ClientLogController.java

@@ -0,0 +1,64 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientlog;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.PageQuery;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.clientlog.model.ClientLog;
+import com.xiugou.x1.backstage.module.clientlog.service.ClientLogService;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class ClientLogController {
+
+	@Autowired
+	private ClientLogService clientLogService;
+	
+	@ApiDocument("请求客户端日志数据")
+	@RequestMapping(value = "/clientLog/data.auth")
+	@ResponseBody
+	public PageData<ClientLog> data(PageQuery query) {
+		QuerySet querySet = new QuerySet();
+		querySet.limit(query.getPage(), query.getLimit());
+		querySet.orderBy("order by id desc");
+		querySet.formWhere();
+		
+		return clientLogService.query(querySet);
+	}
+	
+	/**
+	 * level分为:fatal、error、warn,其中fatal会发送邮件至管理员邮箱
+	 * title为邮件标题
+	 * content为邮件内容
+	 * http://120.79.34.46:10000的地址后续需要替换
+	 * http://120.79.34.46:10000/api/clientLog?level=zzzz&title=yyyyy&content=xxxxxxx
+	 * @return
+	 */
+	@ApiDocument("记录客户端日志,给游戏客户端请求用的")
+	@RequestMapping(value = "/api/clientLog")
+	@ResponseBody
+	public void addLog(@RequestParam("level") String level, @RequestParam("title") String title,
+			@RequestParam("content") String content, @RequestParam("playerId") String playerId,
+			@RequestParam("name") String name, @RequestParam("data") String data) {
+		ClientLog log = new ClientLog();
+		log.setLevel(level);
+		log.setTitle(title);
+		log.setContent(content);
+		log.setPlayerId(playerId);
+		log.setName(name);
+		log.setData(data);
+		clientLogService.insert(log);
+	}
+}

+ 85 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/model/ClientLog.java

@@ -0,0 +1,85 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientlog.model;
+
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.orm.AbstractEntity;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "client_log", comment = "客户端日志", dbAlias = "backstage")
+public class ClientLog extends AbstractEntity {
+	@Id(strategy = Strategy.AUTO, autoBase = 1)
+	@Column(comment = "日志ID")
+	private long id;
+	@Column(comment = "日志级别")
+	private String level;
+	@Column(comment = "标题、类别")
+	private String title;
+	@Column(comment = "日志信息", extra = "text")
+	private String content;
+	@Column(name = "player_id", comment = "玩家ID")
+	private String playerId;
+	@Column(comment = "玩家名称")
+	private String name;
+	@Column(comment = "日志内容", extra = "text")
+	private String data;
+	@Column(comment = "是否已发送给管理员")
+	private boolean send;
+	public String getTitle() {
+		return title;
+	}
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	public boolean isSend() {
+		return send;
+	}
+	public void setSend(boolean send) {
+		this.send = send;
+	}
+	public String getLevel() {
+		return level;
+	}
+	public void setLevel(String level) {
+		this.level = level;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getContent() {
+		return content;
+	}
+	public void setContent(String content) {
+		this.content = content;
+	}
+	public String getPlayerId() {
+		return playerId;
+	}
+	public void setPlayerId(String playerId) {
+		this.playerId = playerId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getData() {
+		return data;
+	}
+	public void setData(String data) {
+		this.data = data;
+	}
+}

+ 79 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/service/ClientLogService.java

@@ -0,0 +1,79 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientlog.service;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.service.AbstractService;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.ConsoleUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.xiugou.x1.backstage.module.clientlog.model.ClientLog;
+import com.xiugou.x1.backstage.module.mailsetting.service.MailSettingService;
+
+/**
+ * @author YY
+ *
+ */
+@Service
+public class ClientLogService extends AbstractService<ClientLog> {
+
+	@Autowired
+	private MailSettingService mailSettingService;
+	
+	public PageData<ClientLog> query(QuerySet querySet) {
+		List<ClientLog> list = this.repository().getBaseDao().queryListWhere(querySet.getWhere(), querySet.getParams());
+		
+		PageData<ClientLog> pageData = new PageData<>();
+		pageData.setCount(this.repository().getBaseDao().count(querySet.getCountWhere(), querySet.getCountParams()));
+		pageData.setData(list);
+		return pageData;
+	}
+	
+	public void runInSchedule() {
+		QuerySet querySet = new QuerySet();
+		querySet.addCondition("level = ?", "fatal");
+		querySet.addCondition("send = ?", "false");
+		querySet.formWhere();
+		List<ClientLog> list = this.repository().getBaseDao().queryListWhere(querySet.getWhere(), querySet.getParams());
+		if(list.isEmpty()) {
+			return;
+		}
+		for(ClientLog log : list) {
+			try {
+				mailSettingService.sendMail(log);
+				
+				log.setSend(true);
+			} catch (Exception e) {
+				logger.error("发送告警邮件" + log.getId() + "时发生异常", e);
+			}
+		}
+		this.updateAll(list);
+	}
+	
+	@PostConstruct
+	public void test() {
+		ConsoleUtil.addFunction("test_mail", () -> {
+			sendMail();
+		});
+	}
+	
+	public void sendMail() {
+		logger.info("发送");
+		ClientLog log = new ClientLog();
+		log.setTitle("ABC");
+		log.setContent("大条了大条了");
+		try {
+			mailSettingService.sendMail(log);
+			logger.info("发送成功");
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+}

+ 31 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientlog/service/ClientLogTimer.java

@@ -0,0 +1,31 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientlog.service;
+
+import org.gaming.ruler.schedule.AbstractScheduler;
+import org.gaming.ruler.schedule.IScheduleTask;
+import org.gaming.ruler.schedule.LoopTask;
+import org.gaming.tool.DateTimeUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author YY
+ *
+ */
+@Component
+public class ClientLogTimer extends AbstractScheduler {
+
+	@Autowired
+	private ClientLogService clientLogService;
+	
+	@Override
+	protected IScheduleTask[] tasks() {
+		IScheduleTask task = new LoopTask("ClientLogTimer", DateTimeUtil.ONE_MINUTE_MILLIS, 5, () -> {
+			clientLogService.runInSchedule();
+		});
+		return new IScheduleTask[] { task };
+	}
+
+}

+ 96 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/ClientVersionController.java

@@ -0,0 +1,96 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientversion;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.clientversion.model.ClientVersion;
+import com.xiugou.x1.backstage.module.clientversion.service.ClientVersionService;
+import com.xiugou.x1.backstage.module.clientversion.struct.ClientVersionForm;
+import com.xiugou.x1.backstage.module.clientversion.struct.ClientVersionQuery;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class ClientVersionController {
+
+	@Autowired
+	private ClientVersionService clientVersionService;
+	@Autowired
+	private GameChannelService gameChannelService;
+	
+	@ApiDocument("请求客户端版本信息数据")
+	@RequestMapping(value = "/clientVersion/data.auth")
+	@ResponseBody
+	public PageData<ClientVersion> data(ClientVersionQuery query) {
+		QuerySet querySet = new QuerySet();
+		querySet.limit(query.getPage(), query.getLimit());
+		if(query.getChannelId() > 0) {
+			querySet.addCondition("channel_id = ?", query.getChannelId());
+		}
+		querySet.formWhere();
+		
+		return clientVersionService.query(querySet);
+	}
+	
+	@ApiDocument("保存版本信息数据,数据ID小于等于0时插入数据,大于0时更新对应数据")
+	@RequestMapping(value = "/clientVersion/save.authw")
+	@ResponseBody
+	public ClientVersion save(ClientVersionForm form) {
+//		Asserts.isTrue(form.getServerType() != 0, TipsCode.CLIENT_VERSION_TYPE_ERROR);
+		
+		ClientVersion clientVersion = null;
+		if(form.getId() <= 0) {
+			GameChannel gameChannel = gameChannelService.getEntity(form.getChannelId());
+			Asserts.isTrue(gameChannel != null, TipsCode.CHANNEL_MISS, form.getChannelId());
+			
+			clientVersion = new ClientVersion();
+			clientVersion.setChannelId(gameChannel.getId());
+			clientVersion.setChannelName(gameChannel.getName());
+			clientVersion.setVersionCode(form.getVersionCode());
+			clientVersion.setServerType(form.getServerType());
+			clientVersion.setRemoteUrl(form.getRemoteUrl());
+			clientVersion.setResourceVersion(form.getResourceVersion());
+			clientVersion.setRemark(form.getRemark());
+			clientVersion.setPcResourceVersion(form.getPcResourceVersion());
+			clientVersion.setQuickUrl(form.getQuickUrl());
+			clientVersionService.insert(clientVersion);
+		} else {
+			clientVersion = clientVersionService.getById(form.getId());
+			Asserts.isTrue(clientVersion != null, TipsCode.CLIENT_VERSION_MISS, form.getId());
+			
+			clientVersion.setServerType(form.getServerType());
+			clientVersion.setRemoteUrl(form.getRemoteUrl());
+			clientVersion.setResourceVersion(form.getResourceVersion());
+			clientVersion.setRemark(form.getRemark());
+			clientVersion.setPcResourceVersion(form.getPcResourceVersion());
+			clientVersion.setQuickUrl(form.getQuickUrl());
+			clientVersionService.update(clientVersion);
+		}
+		return clientVersion;
+	}
+	
+	@ApiDocument("删除版本信息数据,数据ID小于等于0时插入数据,大于0时更新对应数据")
+	@RequestMapping(value = "/clientVersion/delete.authw")
+	@ResponseBody
+	public void delete(@RequestParam("id") long id) {
+		ClientVersion clientVersion = clientVersionService.getById(id);
+		Asserts.isTrue(clientVersion != null, TipsCode.CLIENT_VERSION_MISS, id);
+		
+		clientVersionService.delete(clientVersion);
+	}
+}

+ 134 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/model/ClientVersion.java

@@ -0,0 +1,134 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientversion.model;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.enuma.IndexType;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "client_version", comment = "客户端版本控制", dbAlias = "backstage", indexs = {
+		@Index(name = "channel_version", columns = { "channel_id", "version_code" }, type = IndexType.UNIQUE) })
+public class ClientVersion extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO)
+	@Column(comment = "数据ID")
+	private long id;
+	@Column(name = "channel_id", comment = "渠道ID", readonly = true)
+	private long channelId;
+	@Column(name = "channel_name", comment = "渠道名字")
+	private String channelName;
+	@Column(name = "version_code", comment = "版本编号", readonly = true)
+	private int versionCode;
+	@Column(name = "server_type", comment = "服务器类型,1测试,2审核,3正式")
+	private int serverType;
+	@Column(name = "remote_url", comment = "远程地址")
+	private String remoteUrl;
+	@Column(name = "resource_version", comment = "客户端资源版本号")
+	private String resourceVersion;
+	@Column(comment = "备注")
+	private String remark;
+	@Column(name = "pc_resource_version", comment = "PC客户端资源版本号")
+	private String pcResourceVersion;
+	@Column(name = "quick_url", comment = "快速通道地址")
+	private String quickUrl;
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	public int getVersionCode() {
+		return versionCode;
+	}
+
+	public void setVersionCode(int versionCode) {
+		this.versionCode = versionCode;
+	}
+
+	public long getChannelId() {
+		return channelId;
+	}
+
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+
+	@Override
+	public Long redisOwnerKey() {
+		return channelId;
+	}
+
+	@Override
+	public Long redisHashKey() {
+		return (long)versionCode;
+	}
+
+	public String getChannelName() {
+		return channelName;
+	}
+
+	public void setChannelName(String channelName) {
+		this.channelName = channelName;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public String getRemoteUrl() {
+		return remoteUrl;
+	}
+
+	public void setRemoteUrl(String remoteUrl) {
+		this.remoteUrl = remoteUrl;
+	}
+
+	public String getResourceVersion() {
+		return resourceVersion;
+	}
+
+	public void setResourceVersion(String resourceVersion) {
+		this.resourceVersion = resourceVersion;
+	}
+
+	public int getServerType() {
+		return serverType;
+	}
+
+	public void setServerType(int serverType) {
+		this.serverType = serverType;
+	}
+
+	public String getPcResourceVersion() {
+		return pcResourceVersion;
+	}
+
+	public void setPcResourceVersion(String pcResourceVersion) {
+		this.pcResourceVersion = pcResourceVersion;
+	}
+
+	public String getQuickUrl() {
+		return quickUrl;
+	}
+
+	public void setQuickUrl(String quickUrl) {
+		this.quickUrl = quickUrl;
+	}
+}

+ 43 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/service/ClientVersionService.java

@@ -0,0 +1,43 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientversion.service;
+
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.service.OneToManyRedisService;
+import org.gaming.db.repository.QueryOptions;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.springframework.stereotype.Service;
+
+import com.xiugou.x1.backstage.module.clientversion.model.ClientVersion;
+
+/**
+ * @author YY
+ *
+ */
+@Service
+public class ClientVersionService extends OneToManyRedisService<ClientVersion> {
+	
+	public PageData<ClientVersion> query(QuerySet querySet) {
+		List<ClientVersion> list = this.repository().getBaseDao().queryListWhere(querySet.getWhere(), querySet.getParams());
+		
+		PageData<ClientVersion> pageData = new PageData<>();
+		pageData.setCount(this.repository().getBaseDao().count(querySet.getCountWhere(), querySet.getCountParams()));
+		pageData.setData(list);
+		return pageData;
+	}
+
+	@Override
+	protected String cacheContext() {
+		return "game_channel";
+	}
+
+	@Override
+	protected QueryOptions queryForOwner(long ownerId) {
+		QueryOptions options = new QueryOptions();
+		options.put("channelId", ownerId);
+		return options;
+	}
+}

+ 74 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/struct/ClientVersionForm.java

@@ -0,0 +1,74 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientversion.struct;
+
+/**
+ * @author YY
+ *
+ */
+public class ClientVersionForm {
+	private long id;
+	private long channelId;
+	private int versionCode;
+	private int serverType;
+	private String remark;
+	private String remoteUrl;
+	private String resourceVersion;
+	private String pcResourceVersion;
+	private String quickUrl;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public int getVersionCode() {
+		return versionCode;
+	}
+	public void setVersionCode(int versionCode) {
+		this.versionCode = versionCode;
+	}
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public String getRemark() {
+		return remark;
+	}
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+	public String getRemoteUrl() {
+		return remoteUrl;
+	}
+	public void setRemoteUrl(String remoteUrl) {
+		this.remoteUrl = remoteUrl;
+	}
+	public String getResourceVersion() {
+		return resourceVersion;
+	}
+	public void setResourceVersion(String resourceVersion) {
+		this.resourceVersion = resourceVersion;
+	}
+	public int getServerType() {
+		return serverType;
+	}
+	public void setServerType(int serverType) {
+		this.serverType = serverType;
+	}
+	public String getPcResourceVersion() {
+		return pcResourceVersion;
+	}
+	public void setPcResourceVersion(String pcResourceVersion) {
+		this.pcResourceVersion = pcResourceVersion;
+	}
+	public String getQuickUrl() {
+		return quickUrl;
+	}
+	public void setQuickUrl(String quickUrl) {
+		this.quickUrl = quickUrl;
+	}
+}

+ 22 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/clientversion/struct/ClientVersionQuery.java

@@ -0,0 +1,22 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.clientversion.struct;
+
+import org.gaming.backstage.PageQuery;
+
+/**
+ * @author YY
+ *
+ */
+public class ClientVersionQuery extends PageQuery {
+	private long channelId;
+
+	public long getChannelId() {
+		return channelId;
+	}
+
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+}

+ 41 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/command/ServerCommandController.java

@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.command;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+import com.xiugou.x1.backstage.util.X1HttpUtil;
+
+import pojo.xiugou.x1.pojo.GameApi;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class ServerCommandController {
+
+	@Autowired
+	private GameServerService gameServerService;
+	
+	@ApiDocument("发送服务器指令")
+	@RequestMapping(value = "/serverCommand/send.authw")
+	@ResponseBody
+	public void send(@RequestParam("serverUid") long serverUid, @RequestParam("command") String command) {
+		GameServer gameServer = gameServerService.getEntity(serverUid);
+		Map<String, Object> parameter = new HashMap<>();
+		parameter.put("command", command);
+		X1HttpUtil.formPost(gameServer, GameApi.serverRunCommand, parameter);
+	}
+}

+ 103 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/BossDotDataController.java

@@ -0,0 +1,103 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.mysql.dao.ReadOnlyDao;
+import org.gaming.db.mysql.database.DataBase;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.dotdata.vo.BossDotDataResultVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.BossDotDataVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.PlayerLevelNumVo;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.DataBaseManager;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+
+import pojo.xiugou.x1.pojo.log.mainline.MainlineBossTiming;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class BossDotDataController {
+
+	@Autowired
+	private DataBaseManager dataBaseManager;
+	@Autowired
+	private GameServerService gameServerService;
+	
+	//用于缓存查询结果
+	private PageData<BossDotDataResultVo> resultData;
+	private long refreshTime;
+	
+	@ApiDocument("引导打点数据")
+	@RequestMapping(value = "/bossDotData/data.auth")
+	@ResponseBody
+	public PageData<BossDotDataResultVo> data(@RequestParam("serverUid") int serverUid) {
+		DataBase dataBase = dataBaseManager.getLogDb(serverUid);
+		GameServer gameServer = gameServerService.getEntity(serverUid);
+		
+		String querySql = "SELECT boss_id as bossId,max(boss_name) as bossName,`level`,count(1) as challengeNum,"
+				+ "count(DISTINCT player_id) as playerNum,MIN(fighting) as minFighting,timing "
+				+ "FROM `mainline_boss_dot` GROUP BY boss_id,`level`,timing";
+		List<BossDotDataVo> groupedVos = ReadOnlyDao.queryAliasObjects(dataBase, BossDotDataVo.class, querySql);
+		
+		QuerySet querySet = new QuerySet();
+		querySet.addCondition("platform_id = ?", gameServer.getPlatformId());
+		querySet.addCondition("server_id = ?", gameServer.getServerId());
+		querySet.groupBy("GROUP BY `level`");
+		querySet.formWhere();
+		String playerSql = "SELECT `level`,count(1) as num FROM `player` " + querySet.getWhere();
+		List<PlayerLevelNumVo> levelVos = ReadOnlyDao.queryAliasObjects(dataBase, PlayerLevelNumVo.class, playerSql, querySet.getParams());
+		
+		Map<Integer, BossDotDataResultVo> resultMap = new HashMap<>();
+		for(BossDotDataVo bossVo : groupedVos) {
+			int canNum = 0;
+			if(bossVo.getTiming() == MainlineBossTiming.CHALLENGE.getValue()) {
+				for(PlayerLevelNumVo playerNum : levelVos) {
+					if(playerNum.getLevel() >= bossVo.getLevel()) {
+						canNum += playerNum.getNum();
+					}
+				}
+			}
+			
+			BossDotDataResultVo resultVo = resultMap.get(bossVo.getBossId());
+			if(resultVo == null) {
+				resultVo = new BossDotDataResultVo();
+				resultVo.setBossId(bossVo.getBossId());
+				resultVo.setBossName(bossVo.getBossName());
+				resultMap.put(resultVo.getBossId(), resultVo);
+			}
+			if(bossVo.getTiming() == MainlineBossTiming.CHALLENGE.getValue()) {
+				resultVo.setCanChallengeNum(canNum);
+				resultVo.setChallengeNum(bossVo.getChallengeNum());
+				resultVo.setPlayerNum(bossVo.getPlayerNum());
+			} else if(bossVo.getTiming() == MainlineBossTiming.KILL.getValue()) {
+				resultVo.setKillNum(bossVo.getChallengeNum());
+				resultVo.setMinFighting(bossVo.getMinFighting());
+			}
+		}
+		List<BossDotDataResultVo> resultList = new ArrayList<>(resultMap.values());
+		SortUtil.sortInt(resultList, BossDotDataResultVo::getBossId);
+		
+		PageData<BossDotDataResultVo> pageData = new PageData<>();
+		pageData.setData(resultList);
+		pageData.setCount(resultList.size());
+		return pageData;
+	}
+}

+ 106 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/FogDotDataController.java

@@ -0,0 +1,106 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.mysql.dao.ReadOnlyDao;
+import org.gaming.db.mysql.database.DataBase;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.GsonUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.dotdata.vo.FogDotDataResultVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.FogDotDataVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.PlayerLevelNumVo;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.DataBaseManager;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+
+import pojo.xiugou.x1.pojo.log.mainline.MainlineFogDot;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class FogDotDataController {
+
+	@Autowired
+	private DataBaseManager dataBaseManager;
+	@Autowired
+	private GameServerService gameServerService;
+	
+	public static void main(String[] args) {
+		String json = "[10016,10017,10018,10019,10020,10001,10002,10003,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,10014,10015,10021,10022,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,10049,10050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,10062,10063,10064,10065,10066,10067,10068,10069,10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080,10081,10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092,10093,10094,10095,10096,10097,10098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,10110,10111,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,10122,10123,10124,10125,10126,10127,10128,10129,10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,10141,10142,10143,10144,10145,10146,10147,10148,10149,10150,10151,10152,10153,10154,10155,10156,10157,10158,10159,10160,10161,10162,10163,10164,10165,10166,10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,10182,10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,10193,10194,10195,10196,10197,10198,10199,10200,10201]";
+		List<Integer> list = GsonUtil.getList(json, Integer.class);
+		Collections.sort(list);
+		for(int value : list) {
+			System.out.println(value);
+		}
+	}
+	
+	//用于缓存查询结果
+	private PageData<FogDotDataResultVo> resultData;
+	private long refreshTime;
+	
+	@ApiDocument("引导打点数据")
+	@RequestMapping(value = "/fogDotData/data.auth")
+	@ResponseBody
+	public PageData<FogDotDataResultVo> data(@RequestParam("serverUid") int serverUid) {
+		DataBase dataBase = dataBaseManager.getLogDb(serverUid);
+		GameServer gameServer = gameServerService.getEntity(serverUid);
+		
+		Table table = MainlineFogDot.class.getAnnotation(Table.class);
+		String querySql = "SELECT fog_id as fogId,count(1) as num,MIN(fighting) as minFighting,`level` FROM `" + table.name()
+				+ "` GROUP BY fog_id,`level`";
+		List<FogDotDataVo> groupedVos = ReadOnlyDao.queryAliasObjects(dataBase, FogDotDataVo.class, querySql);
+
+		QuerySet querySet = new QuerySet();
+		querySet.addCondition("platform_id = ?", gameServer.getPlatformId());
+		querySet.addCondition("server_id = ?", gameServer.getServerId());
+		querySet.groupBy("GROUP BY `level`");
+		querySet.formWhere();
+		String playerSql = "SELECT `level`,count(1) as num FROM `player` " + querySet.getWhere();
+		List<PlayerLevelNumVo> levelVos = ReadOnlyDao.queryAliasObjects(dataBase, PlayerLevelNumVo.class, playerSql, querySet.getParams());
+		
+		List<FogDotDataResultVo> resultList = new ArrayList<>();
+		for(FogDotDataVo fogVo : groupedVos) {
+			int canNum = 0;
+			for(PlayerLevelNumVo playerNum : levelVos) {
+				if(playerNum.getLevel() >= fogVo.getLevel()) {
+					canNum += playerNum.getNum();
+				}
+			}
+			FogDotDataResultVo resultVo = new FogDotDataResultVo();
+			resultVo.setFogId(fogVo.getFogId());
+			resultVo.setCanNum(canNum);
+			resultVo.setNum(fogVo.getNum());
+			resultVo.setMinFighting(fogVo.getMinFighting());
+			if(canNum > 0) {
+				BigDecimal rate = new BigDecimal(fogVo.getNum() * 1.0f / canNum * 100);
+				resultVo.setRate(rate.setScale(2).toString() + "%");
+			}
+			resultList.add(resultVo);
+		}
+		
+		SortUtil.sortInt(resultList, FogDotDataResultVo::getFogId);
+		
+		PageData<FogDotDataResultVo> pageData = new PageData<>();
+		pageData.setData(resultList);
+		pageData.setCount(resultList.size());
+		return pageData;
+	}
+}

+ 113 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/GuideDotDataController.java

@@ -0,0 +1,113 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.mysql.dao.ReadOnlyDao;
+import org.gaming.db.mysql.database.DataBase;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.dotdata.vo.GuideDotDataResultVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.GuideDotDataVo;
+import com.xiugou.x1.backstage.module.gameserver.service.DataBaseManager;
+
+import pojo.xiugou.x1.pojo.log.function.GuideDot;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GuideDotDataController {
+
+	@Autowired
+	private DataBaseManager dataBaseManager;
+	
+	
+	@ApiDocument("引导打点数据")
+	@RequestMapping(value = "/guideDotData/data.auth")
+	@ResponseBody
+	public PageData<GuideDotDataResultVo> data(@RequestParam("serverUid") int serverUid) {
+		DataBase dataBase = dataBaseManager.getLogDb(serverUid);
+		
+		Table table = GuideDot.class.getAnnotation(Table.class);
+		
+		String querySql = "SELECT guide_id as guideId, max(guide_name) as guideName, step, count(1) as num FROM `" + table.name()
+				+ "` group by guide_id, step";
+		List<GuideDotDataVo> groupedVos = ReadOnlyDao.queryAliasObjects(dataBase, GuideDotDataVo.class, querySql);
+		
+		Map<String, GuideDotDataResultVo> resultMap = new HashMap<>();
+		for(GuideDotDataVo vo : groupedVos) {
+			String key = vo.getGuideId() + "_" + vo.getStep();
+			GuideDotDataResultVo resultVo = resultMap.get(key);
+			if(resultVo == null) {
+				resultVo = new GuideDotDataResultVo();
+				resultVo.setGuideId(vo.getGuideId());
+				resultVo.setGuideName(vo.getGuideName());
+				resultVo.setStep(vo.getStep());
+				resultMap.put(key, resultVo);
+			}
+			resultVo.setNum(vo.getNum());
+		}
+		
+		List<GuideDotDataResultVo> resultList = new ArrayList<>(resultMap.values());
+		SortUtil.sortInt(resultList, GuideDotDataResultVo::getGuideId, GuideDotDataResultVo::getStep);
+		
+		int totalLose = 0;
+		for(int i = 0; i < resultList.size(); i++) {
+			GuideDotDataResultVo resultVo = resultList.get(i);
+			int loseNum = 0;
+			if(i > 0) {
+				GuideDotDataResultVo preResultVo = resultList.get(i - 1);
+				loseNum = preResultVo.getNum() - resultVo.getNum();
+				resultVo.setLoseNum(loseNum);
+				totalLose += loseNum;
+			} else {
+				resultVo.setLoseNum(0);
+			}
+			
+			if(resultVo.getNum() > 0) {
+				BigDecimal rate = new BigDecimal(loseNum * 1.0f / resultVo.getNum() * 100);
+				resultVo.setLoseRate(rate.setScale(2, RoundingMode.HALF_DOWN).toString() + "%");
+			} else {
+				resultVo.setLoseRate("");
+			}
+		}
+		int finishNum = 0;
+		if(!resultList.isEmpty()) {
+			finishNum = resultList.get(resultList.size() - 1).getNum();
+		}
+		
+		GuideDotDataResultVo totalVo = new GuideDotDataResultVo();
+		totalVo.setGuideName("流失汇总");
+		totalVo.setLoseNum(totalLose);
+		if(finishNum + totalLose > 0) {
+			BigDecimal rate = new BigDecimal(totalLose * 1.0f / (finishNum + totalLose) * 100);
+			totalVo.setLoseRate(rate.setScale(2, RoundingMode.HALF_DOWN).toString() + "%");
+		} else {
+			totalVo.setLoseRate("");
+		}
+		resultList.add(totalVo);
+		
+		PageData<GuideDotDataResultVo> pageData = new PageData<>();
+		pageData.setCount(resultList.size());
+		pageData.setData(resultList);
+		return pageData;
+	}
+	
+}

+ 112 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/LoginDotDataController.java

@@ -0,0 +1,112 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.ruler.util.HttpUtil;
+import org.gaming.tool.DateTimeUtil;
+import org.gaming.tool.LocalDateTimeUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.foundation.starting.ApplicationSettings;
+import com.xiugou.x1.backstage.module.dotdata.model.LoginDotData;
+import com.xiugou.x1.backstage.module.dotdata.model.LoginDotDataStatistic;
+import com.xiugou.x1.backstage.module.dotdata.service.LoginDotDataService;
+import com.xiugou.x1.backstage.module.dotdata.service.LoginDotDataStatisticService;
+import com.xiugou.x1.backstage.module.dotdata.struct.LoginDotQuery;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+
+import pojo.xiugou.x1.pojo.GameApi;
+import pojo.xiugou.x1.pojo.module.player.form.LoginTimingTable;
+import pojo.xiugou.x1.pojo.module.player.form.LoginTimingTable.LoginTiming;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class LoginDotDataController {
+
+	@Autowired
+	private LoginDotDataService loginDotDataService;
+	@Autowired
+	private ApplicationSettings applicationSettings;
+	@Autowired
+	private GameChannelService gameChannelService;
+	@Autowired
+	private LoginDotDataStatisticService loginDotDataStatisticService;
+
+	@ApiDocument("登录打点接口")
+	@RequestMapping(value = "/loginDotData/data.auth")
+	@ResponseBody
+	public PageData<LoginDotDataStatistic> data(LoginDotQuery query) {
+		long channelId = gameChannelService.currChannel();
+
+		QuerySet querySet = new QuerySet();
+		querySet.addCondition("channel_id = ?", channelId);
+		long startTime = query.getStartTime() * 1000L;
+		if (startTime > 0) {
+			String startBorn = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, startTime);
+			querySet.addCondition("date_str >= ?", startBorn);
+		}
+		long endTime = query.getEndTime() * 1000L;
+		if (endTime > 0) {
+			String endBorn = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, endTime);
+			querySet.addCondition("date_str <= ?", endBorn);
+		}
+		querySet.orderBy("order by date_str desc");
+		querySet.formWhere();
+
+		PageData<LoginDotDataStatistic> pageData = loginDotDataStatisticService.query(querySet);
+		return pageData;
+	}
+
+	// 因为非主后台不跑定时器,并且主后台不对外提供访问,客户端上报的打点数据都是在非主后台,
+	// 所以上报到非主后台的打点数据,需要转发到主后台中进行录入
+	// http://192.168.1.5:9001/api/loginDot?channelId=1&openId=AAA&timing=1
+	@ApiDocument("提供给游戏客户端使用,非主后台的登录打点接口")
+	@RequestMapping(value = GameApi.loginDot)
+	@ResponseBody
+	public void loginDot(@RequestParam("channelId") long channelId, @RequestParam("openId") String openId,
+			@RequestParam("timing") int timing) {
+		Map<String, Object> parameter = new HashMap<>();
+		parameter.put("channelId", channelId);
+		parameter.put("openId", openId);
+		parameter.put("timing", timing);
+		HttpUtil.formPost(applicationSettings.getBackstageMainUrl() + GameApi.loginDotMain, parameter);
+	}
+
+	@ApiDocument("主后台的登录打点接口")
+	@RequestMapping(value = GameApi.loginDotMain)
+	@ResponseBody
+	public void loginDotMain(@RequestParam("channelId") long channelId, @RequestParam("openId") String openId,
+			@RequestParam("timing") int timing) {
+		loginDotDataService.addLoginDot(channelId, openId, timing);
+	}
+	
+	@ApiDocument("提供给游戏服使用,上报登录打点接口")
+	@RequestMapping(value = GameApi.loginDotReport)
+	@ResponseBody
+	public void loginDotReport(@RequestBody LoginTimingTable loginTimingTable) {
+		for(LoginTiming loginTiming : loginTimingTable.getDatas()) {
+			LoginDotData loginDot = new LoginDotData();
+			loginDot.setChannelId(loginTiming.getChannelId());
+			loginDot.setOpenId(loginTiming.getOpenId());
+			loginDot.setTiming(loginTiming.getTiming());
+			loginDot.setDateStr(DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, loginTiming.getTime()));
+			loginDot.setTime(LocalDateTimeUtil.ofEpochMilli(loginTiming.getTime()));
+			loginDotDataService.addLoginDot(loginDot);
+		}
+	}
+}

+ 112 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/RecruitDotDataController.java

@@ -0,0 +1,112 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.mysql.dao.ReadOnlyDao;
+import org.gaming.db.mysql.database.DataBase;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.DateTimeUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.dotdata.vo.RecruitDotDataQuery;
+import com.xiugou.x1.backstage.module.dotdata.vo.RecruitDotDataResultVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.RecruitDotDataVo;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServerRuntime;
+import com.xiugou.x1.backstage.module.gameserver.service.DataBaseManager;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerRuntimeService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+
+import pojo.xiugou.x1.pojo.log.recruit.RecruitPrizeDrawLog;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class RecruitDotDataController {
+
+	@Autowired
+	private DataBaseManager dataBaseManager;
+	@Autowired
+	private GameServerService gameServerService;
+	@Autowired
+	private GameServerRuntimeService gameServerRuntimeService;
+	
+	@ApiDocument("招募打点数据")
+	@RequestMapping(value = "/recruitDotData/data.auth")
+	@ResponseBody
+	public PageData<RecruitDotDataResultVo> data(RecruitDotDataQuery query) {
+		DataBase dataBase = dataBaseManager.getLogDb(query.getServerUid());
+		GameServer gameServer = gameServerService.getEntity(query.getServerUid());
+		GameServerRuntime gameServerRuntime = gameServerRuntimeService.getEntity(gameServer.getId());
+
+		Table table = RecruitPrizeDrawLog.class.getAnnotation(Table.class);
+		
+		QuerySet querySet = new QuerySet();
+		long startTime = query.getStartTime() * 1000L;
+		if(startTime <= 0) {
+			startTime = DateTimeUtil.currMillis();
+		}
+		String startStr = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, startTime);
+		querySet.addCondition("date_str >= ?", startStr);
+		
+		long endTime = query.getEndTime() * 1000L;
+		if(endTime <= 0) {
+			endTime = DateTimeUtil.currMillis();
+		}
+		String endStr = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, endTime);
+		querySet.addCondition("date_str <= ?", endStr);
+		
+		querySet.groupBy("group by pid, date_str");
+		querySet.formWhere();
+		
+		String tableMonth = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMM, startTime);
+		String querySql = "SELECT pid, date_str as dateStr, count(1) as num FROM " + table.name() + "_" + tableMonth + " " + querySet.getWhere();
+		
+		List<RecruitDotDataVo> groupedVos = ReadOnlyDao.queryAliasObjects(dataBase, RecruitDotDataVo.class, querySql, querySet.getParams());
+		
+		Map<String, RecruitDotDataResultVo> resultMap = new HashMap<>();
+		for(RecruitDotDataVo vo : groupedVos) {
+			RecruitDotDataResultVo resultVo = resultMap.get(vo.getDateStr());
+			if(resultVo == null) {
+				resultVo = new RecruitDotDataResultVo();
+				resultVo.setDateStr(vo.getDateStr());
+				resultMap.put(resultVo.getDateStr(), resultVo);
+			}
+			if(vo.getNum() <= 10) {
+				resultVo.setNum0to10(resultVo.getNum0to10() + 1);
+			} else if(vo.getNum() <= 20) {
+				resultVo.setNum11to20(resultVo.getNum11to20() + 1);
+			} else {
+				resultVo.setNum21toMax(resultVo.getNum21toMax() + 1);
+			}
+		}
+		List<RecruitDotDataResultVo> resultList = new ArrayList<>(resultMap.values());
+		SortUtil.sortStr(resultList, RecruitDotDataResultVo::getDateStr);
+		for(RecruitDotDataResultVo resultVo : resultList) {
+			resultVo.setJoinNum(resultVo.getNum0to10() + resultVo.getNum11to20() + resultVo.getNum11to20());
+			if(gameServerRuntime != null) {
+				resultVo.setCreateNum(gameServerRuntime.getCreateNum());
+			}
+		}
+		
+		PageData<RecruitDotDataResultVo> pageData = new PageData<>();
+		pageData.setCount(resultList.size());
+		pageData.setData(resultList);
+		return pageData;
+	}
+}

+ 113 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/RecruitRefreshDotDataController.java

@@ -0,0 +1,113 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.mysql.dao.ReadOnlyDao;
+import org.gaming.db.mysql.database.DataBase;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.DateTimeUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.dotdata.vo.RecruitDotDataQuery;
+import com.xiugou.x1.backstage.module.dotdata.vo.RecruitRefreshDotDataResultVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.RecruitRefreshDotDataVo;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServerRuntime;
+import com.xiugou.x1.backstage.module.gameserver.service.DataBaseManager;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerRuntimeService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+
+import pojo.xiugou.x1.pojo.log.recruit.RecruitRefreshLog;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class RecruitRefreshDotDataController {
+
+	@Autowired
+	private DataBaseManager dataBaseManager;
+	@Autowired
+	private GameServerService gameServerService;
+	@Autowired
+	private GameServerRuntimeService gameServerRuntimeService;
+	
+	@ApiDocument("招募刷新打点数据")
+	@RequestMapping(value = "/recruitRefreshDotData/data.auth")
+	@ResponseBody
+	public PageData<RecruitRefreshDotDataResultVo> data(RecruitDotDataQuery query) {
+		DataBase dataBase = dataBaseManager.getLogDb(query.getServerUid());
+		GameServer gameServer = gameServerService.getEntity(query.getServerUid());
+		GameServerRuntime gameServerRuntime = gameServerRuntimeService.getEntity(gameServer.getId());
+		
+		Table table = RecruitRefreshLog.class.getAnnotation(Table.class);
+		
+		QuerySet querySet = new QuerySet();
+		long startTime = query.getStartTime() * 1000L;
+		if(startTime <= 0) {
+			startTime = DateTimeUtil.currMillis();
+		}
+		String startStr = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, startTime);
+		querySet.addCondition("date_str >= ?", startStr);
+		
+		long endTime = query.getEndTime() * 1000L;
+		if(endTime <= 0) {
+			endTime = DateTimeUtil.currMillis();
+		}
+		String endStr = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, endTime);
+		querySet.addCondition("date_str <= ?", endStr);
+		
+		querySet.groupBy("group by pid, date_str");
+		querySet.formWhere();
+		
+		String tableMonth = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMM, startTime);
+		String querySql = "SELECT pid, date_str as dateStr, count(1) as num FROM " + table.name() + "_" + tableMonth + " " + querySet.getWhere();
+		
+		List<RecruitRefreshDotDataVo> groupedVos = ReadOnlyDao.queryAliasObjects(dataBase, RecruitRefreshDotDataVo.class, querySql, querySet.getParams());
+		
+		Map<String, RecruitRefreshDotDataResultVo> resultMap = new HashMap<>();
+		for(RecruitRefreshDotDataVo vo : groupedVos) {
+			RecruitRefreshDotDataResultVo resultVo = resultMap.get(vo.getDateStr());
+			if(resultVo == null) {
+				resultVo = new RecruitRefreshDotDataResultVo();
+				resultVo.setDateStr(vo.getDateStr());
+				resultMap.put(resultVo.getDateStr(), resultVo);
+			}
+			if(vo.getNum() <= 10) {
+				resultVo.setNum0to10(resultVo.getNum0to10() + 1);
+			} else if(vo.getNum() <= 20) {
+				resultVo.setNum11to20(resultVo.getNum11to20() + 1);
+			} else {
+				resultVo.setNum21toMax(resultVo.getNum21toMax() + 1);
+			}
+		}
+		List<RecruitRefreshDotDataResultVo> resultList = new ArrayList<>(resultMap.values());
+		SortUtil.sortStr(resultList, RecruitRefreshDotDataResultVo::getDateStr);
+		for(RecruitRefreshDotDataResultVo resultVo : resultList) {
+			resultVo.setJoinNum(resultVo.getNum0to10() + resultVo.getNum11to20() + resultVo.getNum11to20());
+			if(gameServerRuntime != null) {
+				resultVo.setCreateNum(gameServerRuntime.getCreateNum());
+			}
+			
+		}
+		
+		PageData<RecruitRefreshDotDataResultVo> pageData = new PageData<>();
+		pageData.setCount(resultList.size());
+		pageData.setData(resultList);
+		return pageData;
+	}
+}

+ 81 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/TaskDotDataController.java

@@ -0,0 +1,81 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.mysql.dao.ReadOnlyDao;
+import org.gaming.db.mysql.database.DataBase;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.dotdata.vo.TaskDotDataResultVo;
+import com.xiugou.x1.backstage.module.dotdata.vo.TaskDotDataVo;
+import com.xiugou.x1.backstage.module.gameserver.service.DataBaseManager;
+
+import pojo.xiugou.x1.pojo.log.mainline.MainlineTaskDot;
+import pojo.xiugou.x1.pojo.log.mainline.MainlineTaskTiming;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class TaskDotDataController {
+
+	@Autowired
+	private DataBaseManager dataBaseManager;
+	
+	@ApiDocument("任务打点数据")
+	@RequestMapping(value = "/taskDotData/data.auth")
+	@ResponseBody
+	public PageData<TaskDotDataResultVo> data(@RequestParam("serverUid") int serverUid) {
+		DataBase dataBase = dataBaseManager.getLogDb(serverUid);
+		
+		Table table = MainlineTaskDot.class.getAnnotation(Table.class);
+		String querySql = "SELECT task_id as taskId, max(task_name) as taskName, timing, count(1) as num FROM `" + table.name() + "` group by task_id, timing";
+		List<TaskDotDataVo> groupedVos = ReadOnlyDao.queryAliasObjects(dataBase, TaskDotDataVo.class, querySql);
+		
+		Map<Integer, TaskDotDataResultVo> taskMap = new HashMap<>();
+		for(TaskDotDataVo vo : groupedVos) {
+			TaskDotDataResultVo resultVo = taskMap.get(vo.getTaskId());
+			if(resultVo == null) {
+				resultVo = new TaskDotDataResultVo();
+				resultVo.setTaskId(vo.getTaskId());
+				resultVo.setTaskName(vo.getTaskName());
+				taskMap.put(resultVo.getTaskId(), resultVo);
+			}
+			if(vo.getTiming() == MainlineTaskTiming.START.getValue()) {
+				resultVo.setStartNum(resultVo.getStartNum() + vo.getNum());
+			} else if(vo.getTiming() == MainlineTaskTiming.FINISH.getValue()) {
+				resultVo.setFinishNum(resultVo.getFinishNum() + vo.getNum());
+			}
+		}
+		
+		List<TaskDotDataResultVo> resultList = new ArrayList<>(taskMap.values());
+		SortUtil.sortInt(resultList, TaskDotDataResultVo::getTaskId);
+		
+		for(TaskDotDataResultVo resultVo : resultList) {
+			if(resultVo.getStartNum() <= 0) {
+				continue;
+			}
+			resultVo.setFinishRate(resultVo.getFinishNum() * 1.0f / resultVo.getStartNum());
+		}
+		
+		PageData<TaskDotDataResultVo> pageData = new PageData<>();
+		pageData.setCount(resultList.size());
+		pageData.setData(resultList);
+		return pageData;
+	}
+}

+ 85 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/model/LoginDotData.java

@@ -0,0 +1,85 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.model;
+
+import java.time.LocalDateTime;
+
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.LogTable;
+import org.gaming.db.orm.AbstractEntity;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@LogTable(name = "dot_data_login", comment = "登录打点数据", dbAlias = "backlog", indexs = {
+		@Index(name = "channelid_datestr", columns = { "channel_id", "date_str" }) }, byColumn = "time")
+public class LoginDotData extends AbstractEntity {
+	@Id(strategy = Strategy.AUTO)
+	@Column(comment = "数据ID")
+	private long id;
+	@Column(name = "channel_id", comment = "渠道ID")
+	private long channelId;
+	@Column(name = "open_id", comment = "账号ID")
+	private String openId;
+	@Column(name = "date_str", comment = "日期字符串,yyyyMMdd")
+	private String dateStr;
+	@Column(comment = "打点时机")
+	private int timing;
+	@Column(comment = "发生时间")
+	private LocalDateTime time = LocalDateTime.now();
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	public String getOpenId() {
+		return openId;
+	}
+
+	public void setOpenId(String openId) {
+		this.openId = openId;
+	}
+
+	public String getDateStr() {
+		return dateStr;
+	}
+
+	public void setDateStr(String dateStr) {
+		this.dateStr = dateStr;
+	}
+
+	public long getChannelId() {
+		return channelId;
+	}
+
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+
+	public int getTiming() {
+		return timing;
+	}
+
+	public void setTiming(int timing) {
+		this.timing = timing;
+	}
+
+	public LocalDateTime getTime() {
+		return time;
+	}
+
+	public void setTime(LocalDateTime time) {
+		this.time = time;
+	}
+}

+ 209 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/model/LoginDotDataStatistic.java

@@ -0,0 +1,209 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.model;
+
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.enuma.IndexType;
+import org.gaming.db.orm.AbstractEntity;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "dot_data_login_statistic", comment = "登录打点数据统计", dbAlias = "backstage", indexs = {
+		@Index(name = "channelid_datastr", columns = { "channel_id", "date_str" }, type = IndexType.UNIQUE) })
+public class LoginDotDataStatistic extends AbstractEntity {
+	@Id(strategy = Strategy.AUTO)
+	@Column(comment = "数据ID")
+	private long id;
+	@Column(name = "channel_id", comment = "渠道ID", readonly = true)
+	private long channelId;
+	@Column(name = "date_str", comment = "日期字符串,yyyyMMdd", readonly = true)
+	private String dateStr;
+
+	@Column(name = "req_res_url_begin", comment = "根据版本号请求资源路径")
+	private int reqResUrlBegin;
+	@Column(name = "req_res_url_sucess", comment = "根据版本号请求资源路径成功")
+	private int reqResUrlSucess;
+	@Column(name = "req_res_url_fail", comment = "根据版本号请求资源路径成功")
+	private int reqResUrlFail;
+	@Column(name = "sdk_login_begin", comment = "SDK开始登陆")
+	private int sdkLoginBegin;
+	@Column(name = "sdk_login_sucess", comment = "SDK的登录成功")
+	private int sdkLoginSucess;
+	@Column(name = "sdk_login_fail", comment = "SDK的登录失败")
+	private int sdkLoginFail;
+	@Column(name = "req_server_verify_begin", comment = "请求服务器账号验证")
+	private int reqServerVerifyBegin;
+	@Column(name = "req_server_verify_sucess", comment = "请求服务器账号验证成功")
+	private int reqServerVerifySucess;
+	@Column(name = "req_server_verify_fail", comment = "请求服务器账号验证失败")
+	private int reqServerVerifyFail;
+	@Column(name = "req_server_list_begin", comment = "请求服务器列表")
+	private int reqServerListBegin;
+	@Column(name = "req_server_list_sucess", comment = "请求服务器列表成功")
+	private int reqServerListSucess;
+	@Column(name = "req_server_list_fail", comment = "请求服务器列表失败")
+	private int reqServerListFail;
+	@Column(name = "start_game", comment = "点击开始游戏")
+	private int startGame;
+	@Column(name = "req_socket_connect_sucess", comment = "向服务器socket连接成功")
+	private int reqSocketConnectSucess;
+	@Column(name = "req_socket_login_begin", comment = "向服务器发送登陆请求协议")
+	private int reqSocketLoginBegin;
+	@Column(name = "req_socket_login_sucess", comment = "向服务器发送登陆请求协议成功")
+	private int reqSocketLoginSucess;
+	@Column(name = "req_socket_login_fail", comment = "向服务器发送登陆请求协议失败")
+	private int reqSocketLoginFail;
+	@Column(name = "create_succ", comment = "创号成功")
+	private int createSucc;
+	@Column(name = "req_server_push_data_end", comment = "服务器推送数据结束")
+	private int reqServerPushDataEnd;
+	@Column(name = "in_game", comment = "进入游戏")
+	private int inGame;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public String getDateStr() {
+		return dateStr;
+	}
+	public void setDateStr(String dateStr) {
+		this.dateStr = dateStr;
+	}
+	public int getReqResUrlBegin() {
+		return reqResUrlBegin;
+	}
+	public void setReqResUrlBegin(int reqResUrlBegin) {
+		this.reqResUrlBegin = reqResUrlBegin;
+	}
+	public int getReqResUrlSucess() {
+		return reqResUrlSucess;
+	}
+	public void setReqResUrlSucess(int reqResUrlSucess) {
+		this.reqResUrlSucess = reqResUrlSucess;
+	}
+	public int getReqResUrlFail() {
+		return reqResUrlFail;
+	}
+	public void setReqResUrlFail(int reqResUrlFail) {
+		this.reqResUrlFail = reqResUrlFail;
+	}
+	public int getSdkLoginBegin() {
+		return sdkLoginBegin;
+	}
+	public void setSdkLoginBegin(int sdkLoginBegin) {
+		this.sdkLoginBegin = sdkLoginBegin;
+	}
+	public int getSdkLoginSucess() {
+		return sdkLoginSucess;
+	}
+	public void setSdkLoginSucess(int sdkLoginSucess) {
+		this.sdkLoginSucess = sdkLoginSucess;
+	}
+	public int getSdkLoginFail() {
+		return sdkLoginFail;
+	}
+	public void setSdkLoginFail(int sdkLoginFail) {
+		this.sdkLoginFail = sdkLoginFail;
+	}
+	public int getReqServerVerifyBegin() {
+		return reqServerVerifyBegin;
+	}
+	public void setReqServerVerifyBegin(int reqServerVerifyBegin) {
+		this.reqServerVerifyBegin = reqServerVerifyBegin;
+	}
+	public int getReqServerVerifySucess() {
+		return reqServerVerifySucess;
+	}
+	public void setReqServerVerifySucess(int reqServerVerifySucess) {
+		this.reqServerVerifySucess = reqServerVerifySucess;
+	}
+	public int getReqServerVerifyFail() {
+		return reqServerVerifyFail;
+	}
+	public void setReqServerVerifyFail(int reqServerVerifyFail) {
+		this.reqServerVerifyFail = reqServerVerifyFail;
+	}
+	public int getReqServerListBegin() {
+		return reqServerListBegin;
+	}
+	public void setReqServerListBegin(int reqServerListBegin) {
+		this.reqServerListBegin = reqServerListBegin;
+	}
+	public int getReqServerListSucess() {
+		return reqServerListSucess;
+	}
+	public void setReqServerListSucess(int reqServerListSucess) {
+		this.reqServerListSucess = reqServerListSucess;
+	}
+	public int getReqServerListFail() {
+		return reqServerListFail;
+	}
+	public void setReqServerListFail(int reqServerListFail) {
+		this.reqServerListFail = reqServerListFail;
+	}
+	public int getStartGame() {
+		return startGame;
+	}
+	public void setStartGame(int startGame) {
+		this.startGame = startGame;
+	}
+	public int getReqSocketConnectSucess() {
+		return reqSocketConnectSucess;
+	}
+	public void setReqSocketConnectSucess(int reqSocketConnectSucess) {
+		this.reqSocketConnectSucess = reqSocketConnectSucess;
+	}
+	public int getReqSocketLoginBegin() {
+		return reqSocketLoginBegin;
+	}
+	public void setReqSocketLoginBegin(int reqSocketLoginBegin) {
+		this.reqSocketLoginBegin = reqSocketLoginBegin;
+	}
+	public int getReqSocketLoginSucess() {
+		return reqSocketLoginSucess;
+	}
+	public void setReqSocketLoginSucess(int reqSocketLoginSucess) {
+		this.reqSocketLoginSucess = reqSocketLoginSucess;
+	}
+	public int getReqSocketLoginFail() {
+		return reqSocketLoginFail;
+	}
+	public void setReqSocketLoginFail(int reqSocketLoginFail) {
+		this.reqSocketLoginFail = reqSocketLoginFail;
+	}
+	public int getCreateSucc() {
+		return createSucc;
+	}
+	public void setCreateSucc(int createSucc) {
+		this.createSucc = createSucc;
+	}
+	public int getReqServerPushDataEnd() {
+		return reqServerPushDataEnd;
+	}
+	public void setReqServerPushDataEnd(int reqServerPushDataEnd) {
+		this.reqServerPushDataEnd = reqServerPushDataEnd;
+	}
+	public int getInGame() {
+		return inGame;
+	}
+	public void setInGame(int inGame) {
+		this.inGame = inGame;
+	}
+}

+ 47 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/model/TaskDotDataStatistic.java

@@ -0,0 +1,47 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.model;
+
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.orm.AbstractEntity;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "dot_data_task_statistic", comment = "任务打点数据统计", dbAlias = "backstage", indexs = {
+		@Index(name = "channel_id", columns = { "channel_id"}) })
+public class TaskDotDataStatistic extends AbstractEntity {
+	@Id(strategy = Strategy.AUTO)
+	@Column(comment = "数据ID")
+	private long id;
+	@Column(name = "channel_id", comment = "渠道ID", readonly = true)
+	private long channelId;
+	@Column(name = "server_uid", comment = "服务器ID")
+	private long serverUid;
+	@Column(name = "task_id", comment = "任务ID")
+	private int taskId;
+	@Column(name = "task_name", comment = "任务名称")
+	private String taskName;
+	@Column(name = "start_num", comment = "接取人数")
+	private int startNum;
+	@Column(name = "finish_num", comment = "完成人数")
+	private int finishNum;
+	
+	//
+//	1月1日                                           1月2日
+//	taskId, num, timing   num, timing 
+//	10001   10   开始                   12 
+//	10001   8     完成                   10
+//	10002   7   开始                       9
+//	10002   6     完成                     7
+	
+	
+}

+ 41 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/service/DotDataTimer.java

@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.service;
+
+import org.gaming.ruler.schedule.AbstractScheduler;
+import org.gaming.ruler.schedule.IScheduleTask;
+import org.gaming.ruler.schedule.LoopTask;
+import org.gaming.tool.DateTimeUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author YY
+ *
+ */
+@Component
+public class DotDataTimer extends AbstractScheduler {
+
+	@Autowired
+	private LoginDotDataService loginDotDataService;
+	@Autowired
+	private LoginDotDataStatisticService loginDotDataStatisticService;
+	
+	@Override
+	protected IScheduleTask[] tasks() {
+		IScheduleTask task1 = new LoopTask("DotDataTimer-保存登录打点数据", DateTimeUtil.ONE_MINUTE_MILLIS * 1, 5, () -> {
+			loginDotDataService.runForSaveDot();
+		});
+		IScheduleTask task2 = new LoopTask("DotDataTimer-统计登录打点数据", DateTimeUtil.ONE_HOUR_MILLIS, 5, () -> {
+			loginDotDataStatisticService.runForSaveStatistic();
+		});
+//		IScheduleTask task3 = new LoopTask("DotDataTimer-统计任务打点数据", DateTimeUtil.ONE_HOUR_MILLIS, 5, () -> {
+//			
+//		});
+		
+		return new IScheduleTask[] {task1, task2};
+	}
+
+	
+}

+ 138 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/service/LoginDotDataService.java

@@ -0,0 +1,138 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.gaming.backstage.service.AbstractService;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.DateTimeUtil;
+import org.springframework.stereotype.Service;
+
+import com.xiugou.x1.backstage.module.dotdata.model.LoginDotData;
+import com.xiugou.x1.backstage.module.dotdata.model.LoginDotDataStatistic;
+import com.xiugou.x1.backstage.module.dotdata.vo.LoginDotDataStatisticVo;
+
+import pojo.xiugou.x1.pojo.module.player.form.LoginDotTiming;
+
+/**
+ * @author YY
+ *
+ */
+@Service
+public class LoginDotDataService extends AbstractService<LoginDotData> {
+
+	private Queue<LoginDotData> dotData = new ConcurrentLinkedQueue<>();
+
+	public void addLoginDot(long channelId, String openId, int timing) {
+		LoginDotData loginDot = new LoginDotData();
+		loginDot.setChannelId(channelId);
+		loginDot.setOpenId(openId);
+		loginDot.setTiming(timing);
+		loginDot.setDateStr(DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, DateTimeUtil.currMillis()));
+		dotData.add(loginDot);
+	}
+
+	public void addLoginDot(LoginDotData loginDot) {
+		dotData.add(loginDot);
+	}
+
+	/**
+	 * 保存打点数据记录
+	 */
+	protected void runForSaveDot() {
+		LoginDotData loginDot = dotData.poll();
+		List<LoginDotData> insertList = new ArrayList<>();
+		while (loginDot != null) {
+			insertList.add(loginDot);
+			if (insertList.size() >= 500) {
+				this.insertAll(insertList);
+				insertList.clear();
+			}
+			loginDot = dotData.poll();
+		}
+		if (!insertList.isEmpty()) {
+			this.insertAll(insertList);
+		}
+	}
+
+	public List<LoginDotDataStatistic> statistic(long millisTime) {
+		try {
+			String tableMonth = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMM, millisTime);
+			String dateStr = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, millisTime);
+
+			QuerySet querySet = new QuerySet();
+			querySet.addCondition("date_str = ?", dateStr);
+			querySet.groupBy("GROUP BY channel_id, date_str, timing");
+			querySet.formWhere();
+			String sql = "SELECT channel_id as channelId, date_str as dateStr, timing, count(DISTINCT open_id) as num FROM `dot_data_login_"
+					+ tableMonth + "`" + querySet.getWhere();
+			List<LoginDotDataStatisticVo> voList = this.repository().getBaseDao()
+					.queryAliasObjects(LoginDotDataStatisticVo.class, sql, querySet.getParams());
+
+			Map<Long, LoginDotDataStatistic> channelStatistic = new HashMap<>();
+
+			for (LoginDotDataStatisticVo vo : voList) {
+				LoginDotDataStatistic statistic = channelStatistic.get(vo.getChannelId());
+				if (statistic == null) {
+					statistic = new LoginDotDataStatistic();
+					statistic.setChannelId(vo.getChannelId());
+					statistic.setDateStr(dateStr);
+					channelStatistic.put(statistic.getChannelId(), statistic);
+				}
+				if (vo.getTiming() == LoginDotTiming.REQ_RES_URL_BEGIN.getValue()) {
+					statistic.setReqResUrlBegin((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_RES_URL_SUCESS.getValue()) {
+					statistic.setReqResUrlSucess((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_RES_URL_FAIL.getValue()) {
+					statistic.setReqResUrlFail((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.SDK_LOGIN_BEGIN.getValue()) {
+					statistic.setSdkLoginBegin((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.SDK_LOGIN_SUCESS.getValue()) {
+					statistic.setSdkLoginSucess((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.SDK_LOGIN_FAIL.getValue()) {
+					statistic.setSdkLoginFail((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SERVER_VERIFY_BEGIN.getValue()) {
+					statistic.setReqServerVerifyBegin((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SERVER_VERIFY_SUCESS.getValue()) {
+					statistic.setReqServerVerifySucess((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SERVER_VERIFY_FAIL.getValue()) {
+					statistic.setReqServerVerifyFail((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SERVER_LIST_BEGIN.getValue()) {
+					statistic.setReqServerListBegin((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SERVER_LIST_SUCESS.getValue()) {
+					statistic.setReqServerListSucess((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SERVER_LIST_FAIL.getValue()) {
+					statistic.setReqServerListFail((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.START_GAME.getValue()) {
+					statistic.setStartGame((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SOCKET_CONNECT_SUCESS.getValue()) {
+					statistic.setReqSocketConnectSucess((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SOCKET_LOGIN_BEGIN.getValue()) {
+					statistic.setReqSocketLoginBegin((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SOCKET_LOGIN_SUCESS.getValue()) {
+					statistic.setReqSocketLoginSucess((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SOCKET_LOGIN_FAIL.getValue()) {
+					statistic.setReqSocketLoginFail((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.CREATE_SUCC.getValue()) {
+					statistic.setCreateSucc((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.REQ_SERVER_PUSH_DATA_END.getValue()) {
+					statistic.setReqServerPushDataEnd((int) vo.getNum());
+				} else if (vo.getTiming() == LoginDotTiming.IN_GAME.getValue()) {
+					statistic.setInGame((int) vo.getNum());
+				}
+			}
+			return new ArrayList<>(channelStatistic.values());
+		} catch (Exception e) {
+			logger.error("统计登录打点异常", e);
+			return Collections.emptyList();
+		}
+	}
+}

+ 70 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/service/LoginDotDataStatisticService.java

@@ -0,0 +1,70 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.gaming.backstage.service.AbstractService;
+import org.gaming.tool.ConsoleUtil;
+import org.gaming.tool.DateTimeUtil;
+import org.gaming.tool.LocalDateTimeUtil;
+import org.gaming.tool.RandomUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.xiugou.x1.backstage.module.dotdata.model.LoginDotData;
+import com.xiugou.x1.backstage.module.dotdata.model.LoginDotDataStatistic;
+
+/**
+ * @author YY
+ *
+ */
+@Service
+public class LoginDotDataStatisticService extends AbstractService<LoginDotDataStatistic> {
+
+	@Autowired
+	private LoginDotDataService loginDotDataService;
+	
+	/**
+	 * 跑打点统计数据
+	 */
+	protected void runForSaveStatistic() {
+		logger.info("统计打点数据开始");
+		List<LoginDotDataStatistic> statisticList = loginDotDataService.statistic(DateTimeUtil.currMillis());
+		this.repository().getBaseDao().insertUpdate(statisticList);
+		logger.info("统计打点数据结束");
+	}
+	
+	@PostConstruct
+	public void console() {
+		ConsoleUtil.addFunction("loginDot", () -> {
+			test();
+		});
+	}
+
+	public void test() {
+		List<LoginDotData> insertList = new ArrayList<>();
+		for (int i = 0; i < 1000; i++) {
+			for (int j = 0; j < 30; j++) {
+				LoginDotData loginDotData = new LoginDotData();
+				loginDotData.setOpenId("AAA" + RandomUtil.closeClose(1, 500));
+				loginDotData.setChannelId(2);
+				long nowTime = DateTimeUtil.currMillis() - DateTimeUtil.ONE_DAY_MILLIS * j;
+				loginDotData.setDateStr(DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, nowTime));
+				loginDotData.setTime(LocalDateTimeUtil.ofEpochMilli(nowTime));
+				loginDotData.setTiming(RandomUtil.closeClose(1, 6));
+				insertList.add(loginDotData);
+			}
+		}
+		loginDotDataService.insertAll(insertList);
+		for (int j = 0; j < 30; j++) {
+			List<LoginDotDataStatistic> statisticList = loginDotDataService
+					.statistic(DateTimeUtil.currMillis() - DateTimeUtil.ONE_DAY_MILLIS * j);
+			this.repository().getBaseDao().insertUpdate(statisticList);
+		}
+	}
+}

+ 27 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/struct/LoginDotQuery.java

@@ -0,0 +1,27 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.struct;
+
+import org.gaming.backstage.PageQuery;
+
+/**
+ * @author YY
+ *
+ */
+public class LoginDotQuery extends PageQuery {
+	private int startTime;
+	private int endTime;
+	public int getStartTime() {
+		return startTime;
+	}
+	public void setStartTime(int startTime) {
+		this.startTime = startTime;
+	}
+	public int getEndTime() {
+		return endTime;
+	}
+	public void setEndTime(int endTime) {
+		this.endTime = endTime;
+	}
+}

+ 78 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/BossDotDataResultVo.java

@@ -0,0 +1,78 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class BossDotDataResultVo {
+	private int bossId;
+	private String bossName;
+	private int level;
+	//可参与人数
+	private long canChallengeNum;
+	//挑战数量
+	private long challengeNum;
+	//挑战人数
+	private long playerNum;
+	private long killNum;
+	private long minFighting;
+	//击杀率
+	private String killRate;
+	public int getBossId() {
+		return bossId;
+	}
+	public void setBossId(int bossId) {
+		this.bossId = bossId;
+	}
+	public String getBossName() {
+		return bossName;
+	}
+	public void setBossName(String bossName) {
+		this.bossName = bossName;
+	}
+	public int getLevel() {
+		return level;
+	}
+	public void setLevel(int level) {
+		this.level = level;
+	}
+	public long getChallengeNum() {
+		return challengeNum;
+	}
+	public void setChallengeNum(long challengeNum) {
+		this.challengeNum = challengeNum;
+	}
+	public long getPlayerNum() {
+		return playerNum;
+	}
+	public void setPlayerNum(long playerNum) {
+		this.playerNum = playerNum;
+	}
+	public long getKillNum() {
+		return killNum;
+	}
+	public void setKillNum(long killNum) {
+		this.killNum = killNum;
+	}
+	public long getMinFighting() {
+		return minFighting;
+	}
+	public void setMinFighting(long minFighting) {
+		this.minFighting = minFighting;
+	}
+	public String getKillRate() {
+		return killRate;
+	}
+	public void setKillRate(String killRate) {
+		this.killRate = killRate;
+	}
+	public long getCanChallengeNum() {
+		return canChallengeNum;
+	}
+	public void setCanChallengeNum(long canChallengeNum) {
+		this.canChallengeNum = canChallengeNum;
+	}
+}

+ 60 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/BossDotDataVo.java

@@ -0,0 +1,60 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class BossDotDataVo {
+	private int bossId;
+	private String bossName;
+	private int level;
+	private long challengeNum;
+	private long playerNum;
+	private long minFighting;
+	private int timing;
+	public int getBossId() {
+		return bossId;
+	}
+	public void setBossId(int bossId) {
+		this.bossId = bossId;
+	}
+	public String getBossName() {
+		return bossName;
+	}
+	public void setBossName(String bossName) {
+		this.bossName = bossName;
+	}
+	public int getLevel() {
+		return level;
+	}
+	public void setLevel(int level) {
+		this.level = level;
+	}
+	public long getChallengeNum() {
+		return challengeNum;
+	}
+	public void setChallengeNum(long challengeNum) {
+		this.challengeNum = challengeNum;
+	}
+	public long getPlayerNum() {
+		return playerNum;
+	}
+	public void setPlayerNum(long playerNum) {
+		this.playerNum = playerNum;
+	}
+	public long getMinFighting() {
+		return minFighting;
+	}
+	public void setMinFighting(long minFighting) {
+		this.minFighting = minFighting;
+	}
+	public int getTiming() {
+		return timing;
+	}
+	public void setTiming(int timing) {
+		this.timing = timing;
+	}
+}

+ 48 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/FogDotDataResultVo.java

@@ -0,0 +1,48 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class FogDotDataResultVo {
+	private int fogId;
+	private long minFighting;
+	private long num;
+	//可解锁人数
+	private long canNum;
+	private String rate;
+	
+	public int getFogId() {
+		return fogId;
+	}
+	public void setFogId(int fogId) {
+		this.fogId = fogId;
+	}
+	public long getMinFighting() {
+		return minFighting;
+	}
+	public void setMinFighting(long minFighting) {
+		this.minFighting = minFighting;
+	}
+	public long getNum() {
+		return num;
+	}
+	public void setNum(long num) {
+		this.num = num;
+	}
+	public long getCanNum() {
+		return canNum;
+	}
+	public void setCanNum(long canNum) {
+		this.canNum = canNum;
+	}
+	public String getRate() {
+		return rate;
+	}
+	public void setRate(String rate) {
+		this.rate = rate;
+	}
+}

+ 39 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/FogDotDataVo.java

@@ -0,0 +1,39 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class FogDotDataVo {
+	private int fogId;
+	private long minFighting;
+	private long num;
+	private int level;
+	public int getFogId() {
+		return fogId;
+	}
+	public void setFogId(int fogId) {
+		this.fogId = fogId;
+	}
+	public long getMinFighting() {
+		return minFighting;
+	}
+	public void setMinFighting(long minFighting) {
+		this.minFighting = minFighting;
+	}
+	public long getNum() {
+		return num;
+	}
+	public void setNum(long num) {
+		this.num = num;
+	}
+	public int getLevel() {
+		return level;
+	}
+	public void setLevel(int level) {
+		this.level = level;
+	}
+}

+ 53 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/GuideDotDataResultVo.java

@@ -0,0 +1,53 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class GuideDotDataResultVo {
+	private int guideId;
+	private String guideName;
+	private int step;
+	private int num;
+	private int loseNum;
+	private String loseRate;
+	public int getGuideId() {
+		return guideId;
+	}
+	public void setGuideId(int guideId) {
+		this.guideId = guideId;
+	}
+	public int getStep() {
+		return step;
+	}
+	public void setStep(int step) {
+		this.step = step;
+	}
+	public int getNum() {
+		return num;
+	}
+	public void setNum(int num) {
+		this.num = num;
+	}
+	public String getLoseRate() {
+		return loseRate;
+	}
+	public void setLoseRate(String loseRate) {
+		this.loseRate = loseRate;
+	}
+	public String getGuideName() {
+		return guideName;
+	}
+	public void setGuideName(String guideName) {
+		this.guideName = guideName;
+	}
+	public int getLoseNum() {
+		return loseNum;
+	}
+	public void setLoseNum(int loseNum) {
+		this.loseNum = loseNum;
+	}
+}

+ 39 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/GuideDotDataVo.java

@@ -0,0 +1,39 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class GuideDotDataVo {
+	private int guideId;
+	private String guideName;
+	private int step;
+	private int num;
+	public int getGuideId() {
+		return guideId;
+	}
+	public void setGuideId(int guideId) {
+		this.guideId = guideId;
+	}
+	public int getStep() {
+		return step;
+	}
+	public void setStep(int step) {
+		this.step = step;
+	}
+	public int getNum() {
+		return num;
+	}
+	public void setNum(int num) {
+		this.num = num;
+	}
+	public String getGuideName() {
+		return guideName;
+	}
+	public void setGuideName(String guideName) {
+		this.guideName = guideName;
+	}
+}

+ 39 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/LoginDotDataStatisticVo.java

@@ -0,0 +1,39 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class LoginDotDataStatisticVo {
+	private long channelId;
+	private String dateStr;
+	private int timing;
+	private long num;
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public String getDateStr() {
+		return dateStr;
+	}
+	public void setDateStr(String dateStr) {
+		this.dateStr = dateStr;
+	}
+	public int getTiming() {
+		return timing;
+	}
+	public void setTiming(int timing) {
+		this.timing = timing;
+	}
+	public long getNum() {
+		return num;
+	}
+	public void setNum(long num) {
+		this.num = num;
+	}
+}

+ 25 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/PlayerLevelNumVo.java

@@ -0,0 +1,25 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class PlayerLevelNumVo {
+	private int level;
+	private long num;
+	public int getLevel() {
+		return level;
+	}
+	public void setLevel(int level) {
+		this.level = level;
+	}
+	public long getNum() {
+		return num;
+	}
+	public void setNum(long num) {
+		this.num = num;
+	}
+}

+ 34 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitDotDataQuery.java

@@ -0,0 +1,34 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+import org.gaming.backstage.PageQuery;
+
+/**
+ * @author YY
+ *
+ */
+public class RecruitDotDataQuery extends PageQuery {
+	private int serverUid;
+	private int startTime;
+	private int endTime;
+	public int getServerUid() {
+		return serverUid;
+	}
+	public void setServerUid(int serverUid) {
+		this.serverUid = serverUid;
+	}
+	public int getStartTime() {
+		return startTime;
+	}
+	public void setStartTime(int startTime) {
+		this.startTime = startTime;
+	}
+	public int getEndTime() {
+		return endTime;
+	}
+	public void setEndTime(int endTime) {
+		this.endTime = endTime;
+	}
+}

+ 53 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitDotDataResultVo.java

@@ -0,0 +1,53 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class RecruitDotDataResultVo {
+	private String dateStr;
+	private int num0to10;
+	private int num11to20;
+	private int num21toMax;
+	private int joinNum;
+	private int createNum;
+	public String getDateStr() {
+		return dateStr;
+	}
+	public void setDateStr(String dateStr) {
+		this.dateStr = dateStr;
+	}
+	public int getNum0to10() {
+		return num0to10;
+	}
+	public void setNum0to10(int num0to10) {
+		this.num0to10 = num0to10;
+	}
+	public int getNum11to20() {
+		return num11to20;
+	}
+	public void setNum11to20(int num11to20) {
+		this.num11to20 = num11to20;
+	}
+	public int getNum21toMax() {
+		return num21toMax;
+	}
+	public void setNum21toMax(int num21toMax) {
+		this.num21toMax = num21toMax;
+	}
+	public int getJoinNum() {
+		return joinNum;
+	}
+	public void setJoinNum(int joinNum) {
+		this.joinNum = joinNum;
+	}
+	public int getCreateNum() {
+		return createNum;
+	}
+	public void setCreateNum(int createNum) {
+		this.createNum = createNum;
+	}
+}

+ 32 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitDotDataVo.java

@@ -0,0 +1,32 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class RecruitDotDataVo {
+	private String dateStr;
+	private long pid;
+	private long num;
+	public String getDateStr() {
+		return dateStr;
+	}
+	public void setDateStr(String dateStr) {
+		this.dateStr = dateStr;
+	}
+	public long getPid() {
+		return pid;
+	}
+	public void setPid(long pid) {
+		this.pid = pid;
+	}
+	public long getNum() {
+		return num;
+	}
+	public void setNum(long num) {
+		this.num = num;
+	}
+}

+ 53 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitRefreshDotDataResultVo.java

@@ -0,0 +1,53 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class RecruitRefreshDotDataResultVo {
+	private String dateStr;
+	private int num0to10;
+	private int num11to20;
+	private int num21toMax;
+	private int joinNum;
+	private int createNum;
+	public String getDateStr() {
+		return dateStr;
+	}
+	public void setDateStr(String dateStr) {
+		this.dateStr = dateStr;
+	}
+	public int getNum0to10() {
+		return num0to10;
+	}
+	public void setNum0to10(int num0to10) {
+		this.num0to10 = num0to10;
+	}
+	public int getNum11to20() {
+		return num11to20;
+	}
+	public void setNum11to20(int num11to20) {
+		this.num11to20 = num11to20;
+	}
+	public int getNum21toMax() {
+		return num21toMax;
+	}
+	public void setNum21toMax(int num21toMax) {
+		this.num21toMax = num21toMax;
+	}
+	public int getJoinNum() {
+		return joinNum;
+	}
+	public void setJoinNum(int joinNum) {
+		this.joinNum = joinNum;
+	}
+	public int getCreateNum() {
+		return createNum;
+	}
+	public void setCreateNum(int createNum) {
+		this.createNum = createNum;
+	}
+}

+ 32 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/RecruitRefreshDotDataVo.java

@@ -0,0 +1,32 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class RecruitRefreshDotDataVo {
+	private String dateStr;
+	private long pid;
+	private long num;
+	public String getDateStr() {
+		return dateStr;
+	}
+	public void setDateStr(String dateStr) {
+		this.dateStr = dateStr;
+	}
+	public long getPid() {
+		return pid;
+	}
+	public void setPid(long pid) {
+		this.pid = pid;
+	}
+	public long getNum() {
+		return num;
+	}
+	public void setNum(long num) {
+		this.num = num;
+	}
+}

+ 46 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/TaskDotDataResultVo.java

@@ -0,0 +1,46 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class TaskDotDataResultVo {
+	private int taskId;
+	private String taskName;
+	private long startNum;
+	private long finishNum;
+	private float finishRate;
+	public int getTaskId() {
+		return taskId;
+	}
+	public void setTaskId(int taskId) {
+		this.taskId = taskId;
+	}
+	public String getTaskName() {
+		return taskName;
+	}
+	public void setTaskName(String taskName) {
+		this.taskName = taskName;
+	}
+	public long getStartNum() {
+		return startNum;
+	}
+	public void setStartNum(long startNum) {
+		this.startNum = startNum;
+	}
+	public long getFinishNum() {
+		return finishNum;
+	}
+	public void setFinishNum(long finishNum) {
+		this.finishNum = finishNum;
+	}
+	public float getFinishRate() {
+		return finishRate;
+	}
+	public void setFinishRate(float finishRate) {
+		this.finishRate = finishRate;
+	}
+}

+ 39 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/dotdata/vo/TaskDotDataVo.java

@@ -0,0 +1,39 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.dotdata.vo;
+
+/**
+ * @author YY
+ *
+ */
+public class TaskDotDataVo {
+	private int taskId;
+	private String taskName;
+	private int timing;
+	private long num;
+	public int getTaskId() {
+		return taskId;
+	}
+	public void setTaskId(int taskId) {
+		this.taskId = taskId;
+	}
+	public int getTiming() {
+		return timing;
+	}
+	public void setTiming(int timing) {
+		this.timing = timing;
+	}
+	public long getNum() {
+		return num;
+	}
+	public void setNum(long num) {
+		this.num = num;
+	}
+	public String getTaskName() {
+		return taskName;
+	}
+	public void setTaskName(String taskName) {
+		this.taskName = taskName;
+	}
+}

+ 87 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamecause/GameCauseController.java

@@ -0,0 +1,87 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gamecause;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.GsonUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.gamecause.model.GameCause;
+import com.xiugou.x1.backstage.module.gamecause.service.GameCauseService;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions;
+import com.xiugou.x1.backstage.module.godfinger.struct.GodFingerQuery;
+import com.xiugou.x1.backstage.util.X1HttpUtil;
+
+import pojo.xiugou.x1.pojo.GameApi;
+import pojo.xiugou.x1.pojo.module.server.ServerResponse;
+import pojo.xiugou.x1.pojo.module.server.form.GameCauseForm;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameCauseController {
+
+	@Autowired
+	private GameCauseService gameCauseService;
+	@Autowired
+	private GameServerService gameServerService;
+	
+	
+	@ApiDocument("请求流水事件数据")
+	@RequestMapping(value = "/gameCause/data.auth")
+	@ResponseBody
+	public PageData<GameCause> data(GodFingerQuery query) {
+		QuerySet querySet = new QuerySet();
+		querySet.limit(query.getPage(), query.getLimit());
+		querySet.formWhere();
+		
+		return gameCauseService.query(querySet);
+	}
+	
+	@ApiDocument("更新流水事件数据")
+	@RequestMapping(value = "/gameCause/refresh.auth")
+	@ResponseBody
+	public void refresh() {
+		GameServer gameServer = gameServerService.getEntities().get(0);
+		
+		ServerResponse serverResponse = X1HttpUtil.formPost(gameServer, GameApi.gameCauseUpdate, Collections.emptyMap());
+
+		List<GameCauseForm> list = GsonUtil.getList(serverResponse.getData(), GameCauseForm.class);
+		
+		List<GameCause> updateList = new ArrayList<>();
+		for(GameCauseForm form : list) {
+			GameCause cause = new GameCause();
+			cause.setId(form.getId());
+			cause.setName(form.getName());
+			updateList.add(cause);
+		}
+		gameCauseService.insertUpdate(updateList);
+	}
+	
+	@ApiDocument("流水事件下拉菜单数据")
+	@RequestMapping(value = "/gameCause/options.do")
+	@ResponseBody
+	public DropDownOptions options() {
+		List<GameCause> list = gameCauseService.getAll();
+		
+		DropDownOptions options = new DropDownOptions();
+		for(GameCause gameCause : list) {
+			options.addOption(gameCause.getId(), gameCause.getName());
+		}
+		return options;
+	}
+}

+ 37 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamecause/model/GameCause.java

@@ -0,0 +1,37 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gamecause.model;
+
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.orm.AbstractEntity;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_cause", comment = "游戏流水事件表", dbAlias = "backstage")
+public class GameCause extends AbstractEntity {
+	@Id(strategy = Strategy.IDENTITY)
+	@Column(comment = "事件ID")
+	private long id;
+	@Column(comment = "事件名")
+	private String name;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}

+ 38 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamecause/service/GameCauseService.java

@@ -0,0 +1,38 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gamecause.service;
+
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.service.AbstractService;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.springframework.stereotype.Service;
+
+import com.xiugou.x1.backstage.module.gamecause.model.GameCause;
+
+/**
+ * @author YY
+ *
+ */
+@Service
+public class GameCauseService extends AbstractService<GameCause> {
+
+	public PageData<GameCause> query(QuerySet querySet) {
+		List<GameCause> list = this.repository().getBaseDao().queryListWhere(querySet.getWhere(), querySet.getParams());
+		
+		PageData<GameCause> pageData = new PageData<>();
+		pageData.setCount(this.repository().getBaseDao().count(querySet.getCountWhere(), querySet.getCountParams()));
+		pageData.setData(list);
+		return pageData;
+	}
+	
+	public void insertUpdate(List<GameCause> list) {
+		this.repository().getBaseDao().insertUpdate(list);
+	}
+	
+	public List<GameCause> getAll() {
+		return this.repository().getAllInDb();
+	}
+}

+ 117 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamelog/GameLogController.java

@@ -0,0 +1,117 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gamelog;
+
+import org.gaming.backstage.PageData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.gamelog.service.LogTableService;
+import com.xiugou.x1.backstage.module.gamelog.struct.LogQuery;
+
+import pojo.xiugou.x1.pojo.log.bag.ItemLog;
+import pojo.xiugou.x1.pojo.log.equip.EquipLog;
+import pojo.xiugou.x1.pojo.log.hero.HeroFightingLog;
+import pojo.xiugou.x1.pojo.log.hero.HeroLog;
+import pojo.xiugou.x1.pojo.log.home.MeatLog;
+import pojo.xiugou.x1.pojo.log.home.MineLog;
+import pojo.xiugou.x1.pojo.log.home.WoodLog;
+import pojo.xiugou.x1.pojo.log.mail.MailLog;
+import pojo.xiugou.x1.pojo.log.player.DiamondLog;
+import pojo.xiugou.x1.pojo.log.player.GoldLog;
+import pojo.xiugou.x1.pojo.log.player.PlayerExpLog;
+import pojo.xiugou.x1.pojo.log.player.PlayerFightingLog;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameLogController {
+
+	@Autowired
+	private LogTableService logTableService;
+	
+	@RequestMapping(value = "/gamelog/itemLogs.auth")
+	@ResponseBody
+	public PageData<ItemLog> itemLogs(LogQuery query) {
+		return logTableService.queryDatas(ItemLog.class, query);
+	}
+	
+	@RequestMapping(value = "/gamelog/equipLogs.auth")
+	@ResponseBody
+	public PageData<EquipLog> equipLogs(LogQuery query) {
+		return logTableService.queryDatas(EquipLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/goldLogs.auth")
+	@ResponseBody
+	public PageData<GoldLog> goldLogs(LogQuery query) {
+		return logTableService.queryDatas(GoldLog.class, query);
+	}
+	
+	@RequestMapping(value = "/gamelog/diamondLogs.auth")
+	@ResponseBody
+	public PageData<DiamondLog> diamondLogs(LogQuery query) {
+		return logTableService.queryDatas(DiamondLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/playerExpLogs.auth")
+	@ResponseBody
+	public PageData<PlayerExpLog> playerExpLogs(LogQuery query) {
+		return logTableService.queryDatas(PlayerExpLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/heroLogs.auth")
+	@ResponseBody
+	public PageData<HeroLog> heroLogs(LogQuery query) {
+		return logTableService.queryDatas(HeroLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/heroFightingLogs.auth")
+	@ResponseBody
+	public PageData<HeroFightingLog> heroFightingLogs(LogQuery query) {
+		return logTableService.queryDatas(HeroFightingLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/meatLogs.auth")
+	@ResponseBody
+	public PageData<MeatLog> meatLogs(LogQuery query) {
+		return logTableService.queryDatas(MeatLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/woodLogs.auth")
+	@ResponseBody
+	public PageData<WoodLog> woodLogs(LogQuery query) {
+		return logTableService.queryDatas(WoodLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/mineLogs.auth")
+	@ResponseBody
+	public PageData<MineLog> mineLogs(LogQuery query) {
+		return logTableService.queryDatas(MineLog.class, query);
+	}
+	
+	
+	@RequestMapping(value = "/gamelog/mailLogs.auth")
+	@ResponseBody
+	public PageData<MailLog> mailLogs(LogQuery query) {
+		return logTableService.queryDatas(MailLog.class, query);
+	}
+	
+	@RequestMapping(value = "/gamelog/playerFightingLogs.auth")
+	@ResponseBody
+	public PageData<PlayerFightingLog> playerFightingLogs(LogQuery query) {
+		return logTableService.queryDatas(PlayerFightingLog.class, query);
+	}
+}

+ 78 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamelog/service/LogTableService.java

@@ -0,0 +1,78 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gamelog.service;
+
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.db.annotation.LogTable;
+import org.gaming.db.mysql.dao.ReadOnlyDao;
+import org.gaming.db.mysql.database.DataBase;
+import org.gaming.db.orm.AbstractEntity;
+import org.gaming.db.util.QueryUtil.QuerySet;
+import org.gaming.tool.DateTimeUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gamelog.struct.LogQuery;
+import com.xiugou.x1.backstage.module.gameserver.service.DataBaseManager;
+
+/**
+ * @author YY
+ *
+ */
+@Service
+public class LogTableService {
+
+	@Autowired
+	private DataBaseManager dataBaseManager;
+	
+	public <T extends AbstractEntity> PageData<T> queryDatas(Class<T> clazz, LogQuery query) {
+		LogTable logTable = clazz.getAnnotation(LogTable.class);
+		if(logTable == null) {
+			return new PageData<>();
+		}
+		
+		int serverUid = query.getServerUid();
+		Asserts.isTrue(serverUid > 0, TipsCode.GAME_SERVER_MISS, serverUid);
+		
+		DataBase dataBase = dataBaseManager.getLogDb(serverUid);
+		int yearMonthTime = query.getStartTime();
+		if(yearMonthTime <= 0) {
+			yearMonthTime = DateTimeUtil.currSecond();
+		}
+		
+		String yearMonth = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMM, yearMonthTime * 1000L);
+		String tableName = logTable.name() + "_" + yearMonth;
+		
+		QuerySet querySet = new QuerySet();
+		if(query.getPlayerId() > 0) {
+			querySet.addCondition("owner_id = ?", query.getPlayerId());
+		}
+		if(query.getStartTime() > 0) {
+			String startTimeStr = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD_HH_MM_SS, query.getStartTime() * 1000L);
+			querySet.addCondition(logTable.byColumn() + " >= ?", startTimeStr);
+		}
+		if(query.getEndTime() > 0) {
+			String endTimeStr = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD_HH_MM_SS, query.getEndTime() * 1000L + DateTimeUtil.ONE_DAY_MILLIS);
+			querySet.addCondition(logTable.byColumn() + " <= ?", endTimeStr);
+		}
+		if(query.getCause() > 0) {
+			querySet.addCondition("game_cause = ?", query.getCause());
+		}
+		
+		querySet.orderBy("order by id desc");
+		querySet.limit(query.getPage(), query.getLimit());
+		querySet.formWhere();
+		
+		List<T> results = ReadOnlyDao.queryObjects(dataBase, clazz, tableName, querySet.getWhere(), querySet.getParams());
+
+		PageData<T> pageData = new PageData<>();
+		pageData.setCount(ReadOnlyDao.count(dataBase, tableName, querySet.getCountWhere(), querySet.getCountParams()));
+		pageData.setData(results);
+		return pageData;
+	}
+}

+ 54 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gamelog/struct/LogQuery.java

@@ -0,0 +1,54 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gamelog.struct;
+
+import org.gaming.backstage.PageQuery;
+
+/**
+ * @author YY
+ *
+ */
+public class LogQuery extends PageQuery {
+	//服务器ID
+	private int serverUid;
+	//开始时间戳
+	private int startTime;
+	//结束时间戳
+	private int endTime;
+	//玩家ID
+	private long playerId;
+	//流水事件
+	private int cause;
+	
+	public int getStartTime() {
+		return startTime;
+	}
+	public void setStartTime(int startTime) {
+		this.startTime = startTime;
+	}
+	public int getEndTime() {
+		return endTime;
+	}
+	public void setEndTime(int endTime) {
+		this.endTime = endTime;
+	}
+	public long getPlayerId() {
+		return playerId;
+	}
+	public void setPlayerId(long playerId) {
+		this.playerId = playerId;
+	}
+	public int getServerUid() {
+		return serverUid;
+	}
+	public void setServerUid(int serverUid) {
+		this.serverUid = serverUid;
+	}
+	public int getCause() {
+		return cause;
+	}
+	public void setCause(int cause) {
+		this.cause = cause;
+	}
+}

+ 104 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/BulletinController.java

@@ -0,0 +1,104 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.PageQuery;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.tool.PageUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gameserver.form.BulletinForm;
+import com.xiugou.x1.backstage.module.gameserver.model.Bulletin;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.service.BulletinService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions.DropDownOption;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class BulletinController {
+
+	@Autowired
+	private BulletinService bulletinService;
+	@Autowired
+	private GameChannelService gameChannelService;
+	
+	@ApiDocument("请求公告数据")
+	@RequestMapping(value = "/bulletin/data.auth")
+	@ResponseBody
+	public PageData<Bulletin> info(PageQuery query) {
+		List<Bulletin> list = bulletinService.getEntities();
+		SortUtil.sort(list, Bulletin::getId);
+		
+		PageData<Bulletin> pageData = new PageData<>();
+		pageData.setCount(list.size());
+		pageData.setData(PageUtil.pageN(list, query.getPage(), query.getLimit()));
+		return pageData;
+	}
+	
+	@ApiDocument("保存公告数据,数据ID小于等于0时插入数据,大于0时更新对应数据")
+	@RequestMapping(value = "/bulletin/save.authw")
+	@ResponseBody
+	public Bulletin save(BulletinForm form) {
+		Bulletin bulletin = null;
+		if(form.getId() <= 0) {
+			bulletin = new Bulletin();
+			bulletin.setTitle(form.getTitle());
+			bulletin.setContent(form.getContent());
+			bulletinService.insert(bulletin);
+		} else {
+			bulletin = bulletinService.getEntity(form.getId());
+			Asserts.isTrue(bulletin != null, TipsCode.BULLETIN_MISS, form.getId());
+			
+			bulletin.setTitle(form.getTitle());
+			bulletin.setContent(form.getContent());
+			bulletinService.update(bulletin);
+		}
+		return bulletin;
+	}
+	
+	@ApiDocument("删除渠道数据,并删除与之关联的服务器关系数据")
+	@RequestMapping(value = "/bulletin/delete.authw")
+	@ResponseBody
+	public void delete(@RequestParam("id") long id) {
+		Bulletin bulletin = bulletinService.getEntity(id);
+		Asserts.isTrue(bulletin != null, TipsCode.BULLETIN_MISS, id);
+		
+		for(GameChannel gameChannel : gameChannelService.getEntities()) {
+			if(gameChannel.getBulletinId() == id) {
+				Asserts.isTrue(false, TipsCode.BULLETIN_USING_IN_CHANNEL, gameChannel.getName());
+			}
+		}
+		bulletinService.delete(bulletin);
+	}
+	
+	@ApiDocument("请求公告下拉菜单数据")
+	@RequestMapping(value = "/bulletin/options.do")
+	@ResponseBody
+	public DropDownOptions bulletinOptions() {
+		List<Bulletin> list = bulletinService.getEntities();
+		SortUtil.sort(list, Bulletin::getId);
+		
+		DropDownOptions options = new DropDownOptions();
+		for(Bulletin bulletin : list) {
+			options.addOption(bulletin.getId(), bulletin.getTitle());
+		}
+		SortUtil.sort(options.getOptions(), DropDownOption::getValue);
+		return options;
+	}
+}

+ 208 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameChannelController.java

@@ -0,0 +1,208 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.PageQuery;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.interceptor.RoleContext;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.backstage.module.user.model.User;
+import org.gaming.backstage.module.user.service.UserService;
+import org.gaming.tool.PageUtil;
+import org.gaming.tool.SortUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gameserver.form.GameChannelForm;
+import com.xiugou.x1.backstage.module.gameserver.model.Bulletin;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannelServer;
+import com.xiugou.x1.backstage.module.gameserver.model.GamePlatform;
+import com.xiugou.x1.backstage.module.gameserver.model.GameRegion;
+import com.xiugou.x1.backstage.module.gameserver.model.UserChannel;
+import com.xiugou.x1.backstage.module.gameserver.service.BulletinService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelServerService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.service.GamePlatformService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameRegionService;
+import com.xiugou.x1.backstage.module.gameserver.service.UserChannelService;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions.DropDownOption;
+import com.xiugou.x1.backstage.module.gameserver.vo.GameChannelVo;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameChannelController {
+
+	private static Logger logger = LoggerFactory.getLogger(GameChannelController.class);
+	
+	@Autowired
+	private GameChannelService gameChannelService;
+	@Autowired
+	private GameChannelServerService gameChannelServerService;
+	@Autowired
+	private UserService userService;
+	@Autowired
+	private UserChannelService userChannelService;
+	@Autowired
+	private BulletinService bulletinService;
+	@Autowired
+	private GamePlatformService gamePlatformService;
+	@Autowired
+	private GameRegionService gameRegionService;
+	
+	@ApiDocument("请求渠道数据")
+	@RequestMapping(value = "/gameChannel/data.auth")
+	@ResponseBody
+	public PageData<GameChannel> info(PageQuery query) {
+		List<GameChannel> list = gameChannelService.getEntities();
+		SortUtil.sort(list, GameChannel::getId);
+		List<GameChannel> pageList = PageUtil.pageN(list, query.getPage(), query.getLimit());
+		
+		PageData<GameChannel> pageData = new PageData<>();
+		pageData.setCount(list.size());
+		pageData.setData(pageList);
+		return pageData;
+	}
+	
+	@ApiDocument("保存渠道数据,数据ID小于等于0时插入数据,大于0时更新对应数据")
+	@RequestMapping(value = "/gameChannel/save.authw")
+	@ResponseBody
+	public GameChannel save(GameChannelForm form) {
+		Bulletin bulletin = null;
+		if(form.getBulletinId() > 0) {
+			bulletin = bulletinService.getEntity(form.getBulletinId());
+		}
+		
+		GameChannel gameChannel = null;
+		if(form.getId() <= 0) {
+			GamePlatform gamePlatform = gamePlatformService.getEntity(form.getPlatformId());
+			Asserts.isTrue(gamePlatform != null, TipsCode.PLATFORM_MISS, form.getPlatformId());
+			
+			RoleContext roleContext = userService.getCurrUser();
+			
+			gameChannel = new GameChannel();
+			gameChannel.setName(form.getName());
+			gameChannel.setUserId(roleContext.getId());
+			gameChannel.setUserName(roleContext.getName());
+			gameChannel.setBulletinId(bulletin == null ? 0 : bulletin.getId());
+			gameChannel.setPlatformId(gamePlatform.getId());
+			gameChannel.setPlatformName(gamePlatform.getName());
+			gameChannel.setProgramVersion(form.getProgramVersion());
+			gameChannel.setResourceVersion(form.getResourceVersion());
+			gameChannelService.insert(gameChannel);
+		} else {
+			gameChannel = gameChannelService.getEntity(form.getId());
+			Asserts.isTrue(gameChannel != null, TipsCode.CHANNEL_MISS, form.getId());
+			
+			String oldName = gameChannel.getName();
+			gameChannel.setName(form.getName());
+			gameChannel.setBulletinId(bulletin == null ? 0 : bulletin.getId());
+			gameChannel.setProgramVersion(form.getProgramVersion());
+			gameChannel.setResourceVersion(form.getResourceVersion());
+			gameChannelService.update(gameChannel);
+			
+			if(oldName != null && form.getName() != null && !oldName.equals(form.getName())) {
+				List<GameChannelServer> list = gameChannelServerService.getEntityList(gameChannel.getId());
+				for(GameChannelServer entity : list) {
+					entity.setChannelName(gameChannel.getName());
+				}
+				gameChannelServerService.updateAll(list);
+				
+				List<GameRegion> regions = gameRegionService.getEntityList(gameChannel.getId());
+				for(GameRegion gameRegion : regions) {
+					gameRegion.setChannelName(gameChannel.getName());
+				}
+				gameRegionService.updateAll(regions);
+			}
+		}
+		return gameChannel;
+	}
+	
+	@ApiDocument("删除渠道数据,并删除与之关联的服务器关系数据")
+	@RequestMapping(value = "/gameChannel/delete.authw")
+	@ResponseBody
+	public void delete(@RequestParam("channelId") long channelId) {
+		GameChannel gameChannel = gameChannelService.getEntity(channelId);
+		Asserts.isTrue(gameChannel != null, TipsCode.CHANNEL_MISS, channelId);
+		
+		gameChannelService.delete(gameChannel);
+		gameChannelServerService.deleteAllInOwner(gameChannel.getId());
+	}
+	
+	@ApiDocument("请求渠道下拉菜单数据")
+	@RequestMapping(value = "/gameChannel/options.do")
+	@ResponseBody
+	public DropDownOptions channelOptions() {
+		RoleContext roleContext = userService.getCurrUser();
+		User user = userService.getById(roleContext.getId());
+		
+		DropDownOptions options = new DropDownOptions();
+		if(user.isSuperUser()) {
+			List<GameChannel> list = gameChannelService.getEntities();
+			for(GameChannel gameChannel : list) {
+				options.addOption(gameChannel.getId(), gameChannel.getName());
+			}
+		} else {
+			List<UserChannel> channels = userChannelService.getEntityList(user.getId());
+			for(UserChannel channel : channels) {
+				options.addOption(channel.getChannelId(), channel.getChannelName());
+			}
+		}
+		SortUtil.sort(options.getOptions(), DropDownOption::getValue);
+		return options;
+	}
+	
+	@ApiDocument("切换渠道")
+	@RequestMapping(value = "/gameChannel/change.do")
+	@ResponseBody
+	public void changeChannel(@RequestParam("channelId") long channelId) {
+		if(channelId <= 0) {
+			return;
+		}
+		
+		RoleContext roleContext = userService.getCurrUser();
+		User user = userService.getById(roleContext.getId());
+		if(user.isSuperUser()) {
+			GameChannel gameChannel = gameChannelService.getEntity(channelId);
+			
+			gameChannelService.changeChannel(roleContext.getId(), channelId);
+			logger.info("用户{}-{}切换渠道为{}-{}", roleContext.getId(), roleContext.getName(), gameChannel.getId(), gameChannel.getName());
+		} else {
+			List<UserChannel> channels = userChannelService.getEntityList(user.getId());
+			for(UserChannel channel : channels) {
+				if(channel.getChannelId() == channelId) {
+					gameChannelService.changeChannel(roleContext.getId(), channelId);
+					logger.info("用户{}-{}切换渠道为{}-{}", roleContext.getId(), roleContext.getName(), channel.getChannelId(), channel.getChannelName());
+					break;
+				}
+			}
+		}
+	}
+	
+	public GameChannelVo buildVo(GameChannel channel) {
+		GameChannelVo vo = new GameChannelVo();
+		vo.setId(channel.getId());
+		vo.setName(channel.getName());
+		vo.setBulletinId(channel.getBulletinId());
+		vo.setPlatformInfo(channel.getPlatformName() + "[" + channel.getPlatformId() + "]");
+		vo.setUserId(channel.getUserId());
+		vo.setUserName(channel.getUserName());
+		vo.setProgramVersion(channel.getProgramVersion());
+		vo.setResourceVersion(channel.getResourceVersion());
+		return vo;
+	}
+}

+ 176 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameChannelServerController.java

@@ -0,0 +1,176 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.interceptor.RoleContext;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.backstage.module.user.service.UserService;
+import org.gaming.tool.ListMapUtil;
+import org.gaming.tool.PageUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gameserver.form.ChannelServerRelationForm;
+import com.xiugou.x1.backstage.module.gameserver.form.ServerToRegionForm;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannelServer;
+import com.xiugou.x1.backstage.module.gameserver.model.GameRegion;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelServerService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameRegionService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+import com.xiugou.x1.backstage.module.gameserver.struct.GameChannelServerQuery;
+import com.xiugou.x1.backstage.module.gameserver.vo.ServerSelected;
+import com.xiugou.x1.backstage.module.gameserver.vo.ServerSelected.ServerSelectedData;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameChannelServerController {
+
+	@Autowired
+	private GameChannelServerService gameChannelServerService;
+	@Autowired
+	private GameChannelService gameChannelService;
+	@Autowired
+	private GameServerService gameServerService;
+	@Autowired
+	private GameRegionService gameRegionService;
+	@Autowired
+	private UserService userService;
+	
+	@ApiDocument("请求渠道与服务器关系数据")
+	@RequestMapping(value = "/gameChannelServer/data.auth")
+	@ResponseBody
+	public PageData<GameChannelServer> info(GameChannelServerQuery query) {
+		if(query.getChannelId() > 0) {
+			List<GameChannelServer> list = gameChannelServerService.getEntityList(query.getChannelId());
+			SortUtil.sortIntDesc(list, GameChannelServer::getServerId);
+			
+			PageData<GameChannelServer> pageData = new PageData<>();
+			pageData.setCount(list.size());
+			pageData.setData(PageUtil.pageN(list, query.getPage(), query.getLimit()));
+			return pageData;
+			
+		} else {
+			return gameChannelServerService.getList(query.getPage(), query.getLimit());
+		}
+	}
+	
+	@ApiDocument("编辑服务器归属大区")
+	@RequestMapping(value = "/gameChannelServer/saveToRegion.authw")
+	@ResponseBody
+	public GameChannelServer saveToRegion(ServerToRegionForm form) {
+		GameChannel gameChannel = gameChannelService.getEntity(form.getChannelId());
+		Asserts.isTrue(gameChannel != null, TipsCode.CHANNEL_MISS, form.getChannelId());
+		GameRegion gameRegion = gameRegionService.getEntity(form.getChannelId(), form.getRegionId());
+		Asserts.isTrue(gameRegion != null, TipsCode.REGION_MISS, form.getChannelId(), form.getRegionId());
+		GameServer gameServer = gameServerService.getEntity(form.getServerUid());
+		Asserts.isTrue(gameServer != null, TipsCode.GAME_SERVER_MISS, form.getServerUid());
+		
+		GameChannelServer gameChannelServer = gameChannelServerService.getEntity(form.getChannelId(), gameServer.getServerId());
+		Asserts.isTrue(gameChannelServer != null, TipsCode.CHANNEL_SERVER_MISS, form.getChannelId(), gameServer.getServerId());
+		
+		Asserts.isTrue(gameServer.getServerType() == gameRegion.getServerType(), TipsCode.SERVER_REGION_TYPE_UNMATCH);
+		
+		gameChannelServer.setRegionId(gameRegion.getRegionId());
+		gameChannelServer.setRegionName(gameRegion.getName());
+		gameChannelServerService.update(gameChannelServer);
+		return gameChannelServer;
+	}
+	
+	@ApiDocument("保存渠道与服务器关系数据")
+	@RequestMapping(value = "/gameChannelServer/save.authw")
+	@ResponseBody
+	public void save(ChannelServerRelationForm form) {
+		RoleContext roleContext = userService.getCurrUser();
+		
+		GameChannel gameChannel = gameChannelService.getEntity(form.getChannelId());
+		Asserts.isTrue(gameChannel != null, TipsCode.CHANNEL_MISS, form.getChannelId());
+		
+		List<GameChannelServer> relations = gameChannelServerService.getEntityList(form.getChannelId());
+		Map<Integer, GameChannelServer> relationMap = ListMapUtil.listToMap(relations, GameChannelServer::getServerUid);
+		
+		List<GameChannelServer> newRelations = new ArrayList<>();
+		
+		Set<Integer> serverUidSet = new HashSet<>(form.getServerUids());
+		for(Integer serverUid : serverUidSet) {
+			GameServer gameServer = gameServerService.getEntity(serverUid);
+			Asserts.isTrue(gameServer != null, TipsCode.GAME_SERVER_MISS, serverUid);
+			
+			GameChannelServer relation = relationMap.get(gameServer.getId());
+			if(relation != null) {
+				continue;
+			}
+			relation = new GameChannelServer();
+			relation.setChannelId(gameChannel.getId());
+			relation.setChannelName(gameChannel.getName());
+			relation.setServerUid(gameServer.getId());
+			relation.setServerId(gameServer.getServerId());
+			relation.setServerName(gameServer.getName());
+			relation.setUserId(roleContext.getId());
+			relation.setUserName(roleContext.getName());
+			relation.setRecommend(gameServer.isRecommend());
+			newRelations.add(relation);
+		}
+		gameChannelServerService.insertAll(newRelations);
+		
+		List<GameChannelServer> deleteList = new ArrayList<>();
+		for(GameChannelServer oriRelation : relations) {
+			if(serverUidSet.contains(oriRelation.getServerUid())) {
+				continue;
+			}
+			deleteList.add(oriRelation);
+		}
+		gameChannelServerService.deleteAll(deleteList);
+	}
+	
+	
+	@ApiDocument("请求渠道下当前的服务器")
+	@RequestMapping(value = "/gameChannelServer/currRelation.auth")
+	@ResponseBody
+	public ServerSelected currRelation(@RequestParam("channelId") long channelId) {
+		GameChannel gameChannel = gameChannelService.getEntity(channelId);
+		
+		List<GameChannelServer> list = gameChannelServerService.getEntityList(channelId);
+		Map<Integer, GameChannelServer> relations = ListMapUtil.listToMap(list, GameChannelServer::getServerUid);
+		
+		List<GameServer> servers = gameServerService.getEntities();
+		SortUtil.sortInt(servers, GameServer::getId);
+		
+		ServerSelected serverSelected = new ServerSelected();
+		for(GameServer gameServer : servers) {
+			if(gameServer.getPlatformId() != gameChannel.getPlatformId()) {
+				continue;
+			}
+			ServerSelectedData data = new ServerSelectedData();
+			data.setId(gameServer.getId());
+			data.setText(gameServer.getServerId() + "-" + gameServer.getName() + "(" + gameServer.getId() + ")");
+			GameChannelServer relation = relations.get(gameServer.getId());
+			if(relation != null) {
+				data.setSelect(true);
+			} else {
+				data.setSelect(false);
+			}
+			serverSelected.getDatas().add(data);
+		}
+		return serverSelected;
+	}
+}

+ 60 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameDbController.java

@@ -0,0 +1,60 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.foundation.starting.ApplicationSettings;
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gameserver.model.GameDb;
+import com.xiugou.x1.backstage.module.gameserver.service.GameDbService;
+import com.xiugou.x1.backstage.module.gameserver.vo.GameDbVo;
+
+import pojo.xiugou.x1.pojo.GameApi;
+import pojo.xiugou.x1.pojo.apiutil.ApiUtil;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameDbController {
+
+	@Autowired
+	private ApplicationSettings applicationSettings;
+	@Autowired
+	private GameDbService gameDbService;
+	
+	@ApiDocument("请求游戏服的数据库配置")
+	@RequestMapping(value = GameApi.dbs)
+	@ResponseBody
+	public List<GameDbVo> dbs(@RequestParam("platformId") int platformId, @RequestParam("serverId") int serverId,
+			@RequestParam("type") String type, @RequestParam("time") long time, @RequestParam("sign") String sign) {
+		Map<String, Object> map = new HashMap<>();
+		map.put("platformId", platformId);
+		map.put("serverId", serverId);
+		map.put("type", type);
+		map.put("time", time);
+		String signSource = ApiUtil.jointKeyValueToSource(map, applicationSettings.getBackstageKey(), "=", "&");
+		String localSign = ApiUtil.buildSign(signSource);
+		Asserts.isTrue(localSign.equals(sign), TipsCode.WHAT_DO_YOU_WANT_TO_DO);
+		List<GameDb> gameDbs = gameDbService.dbs(platformId, serverId, type);
+		List<GameDbVo> results = new ArrayList<>();
+		for(GameDb gameDb : gameDbs) {
+			results.add(new GameDbVo(gameDb));
+		}
+		return results;
+	}
+}

+ 118 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GamePlatformController.java

@@ -0,0 +1,118 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.PageQuery;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.interceptor.RoleContext;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.backstage.module.user.service.UserService;
+import org.gaming.tool.PageUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gameserver.form.GamePlatformForm;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.model.GamePlatform;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.service.GamePlatformService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions.DropDownOption;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GamePlatformController {
+	@Autowired
+	private GamePlatformService gamePlatformService;
+	@Autowired
+	private UserService userService;
+	@Autowired
+	private GameChannelService gameChannelService;
+	@Autowired
+	private GameServerService gameServerService;
+	
+	@ApiDocument("请求平台数据")
+	@RequestMapping(value = "/gamePlatform/data.auth")
+	@ResponseBody
+	public PageData<GamePlatform> info(PageQuery query) {
+		List<GamePlatform> list = gamePlatformService.getEntities();
+		SortUtil.sort(list, GamePlatform::getId);
+		
+		PageData<GamePlatform> pageData = new PageData<>();
+		pageData.setCount(list.size());
+		pageData.setData(PageUtil.pageN(list, query.getPage(), query.getLimit()));
+		return pageData;
+	}
+	
+	@ApiDocument("保存平台数据,数据ID小于等于0时插入数据,大于0时更新对应数据")
+	@RequestMapping(value = "/gamePlatform/save.authw")
+	@ResponseBody
+	public GamePlatform save(GamePlatformForm form) {
+		GamePlatform gamePlatform = null;
+		if(form.getId() <= 0) {
+			RoleContext roleContext = userService.getCurrUser();
+			
+			gamePlatform = new GamePlatform();
+			gamePlatform.setName(form.getName());
+			gamePlatform.setUserId(roleContext.getId());
+			gamePlatform.setUserName(roleContext.getName());
+			gamePlatformService.insert(gamePlatform);
+		} else {
+			gamePlatform = gamePlatformService.getEntity(form.getId());
+			Asserts.isTrue(gamePlatform != null, TipsCode.PLATFORM_MISS, form.getId());
+			
+			String oldName = gamePlatform.getName();
+			gamePlatform.setName(form.getName());
+			gamePlatformService.update(gamePlatform);
+			
+			if(oldName != null && form.getName() != null && !oldName.equals(form.getName())) {
+				List<GameChannel> updateChannels = new ArrayList<>();
+				for(GameChannel gameChannel : gameChannelService.getEntities()) {
+					if(gameChannel.getPlatformId() != gamePlatform.getId()) {
+						continue;
+					}
+					gameChannel.setPlatformName(gamePlatform.getName());
+					updateChannels.add(gameChannel);
+				}
+				gameChannelService.updateAll(updateChannels);
+				
+				List<GameServer> updateServers = new ArrayList<>();
+				for(GameServer gameServer : gameServerService.getEntities()) {
+					if(gameServer.getPlatformId() != gamePlatform.getId()) {
+						continue;
+					}
+					gameServer.setPlatformName(gamePlatform.getName());
+					updateServers.add(gameServer);
+				}
+				gameServerService.updateAll(updateServers);
+			}
+		}
+		return gamePlatform;
+	}
+	
+	@ApiDocument("请求平台下拉菜单数据")
+	@RequestMapping(value = "/gamePlatform/options.do")
+	@ResponseBody
+	public DropDownOptions channelOptions() {
+		DropDownOptions options = new DropDownOptions();
+		for(GamePlatform gamePlatform : gamePlatformService.getEntities()) {
+			options.addOption(gamePlatform.getId(), gamePlatform.getName() + "[" + gamePlatform.getId() + "]");
+		}
+		SortUtil.sort(options.getOptions(), DropDownOption::getValue);
+		return options;
+	}
+}

+ 131 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameRegionController.java

@@ -0,0 +1,131 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.tool.PageUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gameserver.form.GameRegionForm;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannelServer;
+import com.xiugou.x1.backstage.module.gameserver.model.GameRegion;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelServerService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameRegionService;
+import com.xiugou.x1.backstage.module.gameserver.struct.GameRegionQuery;
+import com.xiugou.x1.backstage.module.gameserver.struct.ServerType;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameRegionController {
+
+	@Autowired
+	private GameRegionService gameRegionService;
+	@Autowired
+	private GameChannelServerService gameChannelServerService;
+	@Autowired
+	private GameChannelService gameChannelService;
+	
+	@ApiDocument("请求渠道大区数据")
+	@RequestMapping(value = "/gameRegion/data.auth")
+	@ResponseBody
+	public PageData<GameRegion> info(GameRegionQuery query) {
+		if(query.getChannelId() > 0) {
+			List<GameRegion> list = gameRegionService.getEntityList(query.getChannelId());
+			SortUtil.sortInt(list, GameRegion::getRegionId);
+			
+			PageData<GameRegion> pageData = new PageData<>();
+			pageData.setCount(list.size());
+			pageData.setData(PageUtil.pageN(list, query.getPage(), query.getLimit()));
+			return pageData;
+		} else {
+			return gameRegionService.getList(query.getPage(), query.getLimit());
+		}
+	}
+	
+	@ApiDocument("保存渠道大区数据,ID小于等于0时新增,大于0时修改")
+	@RequestMapping(value = "/gameRegion/save.authw")
+	@ResponseBody
+	public GameRegion save(GameRegionForm form) {
+		GameChannel gameChannel = gameChannelService.getEntity(form.getChannelId());
+		Asserts.isTrue(gameChannel != null, TipsCode.CHANNEL_MISS, form.getChannelId());
+		GameRegion gameRegion = gameRegionService.getEntity(form.getChannelId(), form.getRegionId());
+		
+		if(form.getId() <= 0) {
+			Asserts.isTrue(gameRegion == null, TipsCode.REGION_EXIST, form.getChannelId(), form.getRegionId());
+		} else {
+			Asserts.isTrue(gameRegion.getId() == form.getId(), TipsCode.ERROR_PARAM);
+		}
+		if(gameRegion == null) {
+			gameRegion = new GameRegion();
+			gameRegion.setRegionId(form.getRegionId());
+			gameRegion.setName(form.getName());
+			gameRegion.setChannelId(gameChannel.getId());
+			gameRegion.setChannelName(gameChannel.getName());
+			gameRegion.setServerType(form.getServerType());
+			gameRegionService.insert(gameRegion);
+		} else {
+			gameRegion.setName(form.getName());
+			gameRegion.setServerType(form.getServerType());
+			gameRegionService.update(gameRegion);
+		}
+		return gameRegion;
+	}
+	
+	@ApiDocument("删除渠道大区数据")
+	@RequestMapping(value = "/gameRegion/delete.authw")
+	@ResponseBody
+	public void delete(@RequestParam("channelId") long channelId, @RequestParam("regionId") long regionId) {
+		GameRegion gameRegion = gameRegionService.getEntity(channelId, regionId);
+		Asserts.isTrue(gameRegion != null, TipsCode.REGION_MISS, channelId, regionId);
+		
+		gameRegionService.delete(gameRegion);
+		List<GameChannelServer> servers = gameChannelServerService.getEntityList(gameRegion.getChannelId());
+		List<GameChannelServer> updateList = new ArrayList<>();
+		for(GameChannelServer server : servers) {
+			if(server.getRegionId() == gameRegion.getRegionId()) {
+				server.setRegionId(0);
+				server.setRegionName("");
+				updateList.add(server);
+			}
+		}
+		gameChannelServerService.updateAll(updateList);
+	}
+	
+	@ApiDocument("渠道大区下拉菜单数据")
+	@RequestMapping(value = "/gameRegion/options.do")
+	@ResponseBody
+	public DropDownOptions regionOptions(@RequestParam("channelId") long channelId) {
+		List<GameRegion> list = gameRegionService.getEntityList(channelId);
+		SortUtil.sortInt(list, GameRegion::getRegionId);
+		
+		DropDownOptions options = new DropDownOptions();
+		for(GameRegion gameRegion : list) {
+			String serverDesc = ServerType.TEST.getDesc();
+			if(gameRegion.getServerType() == ServerType.REVIEW.getValue()) {
+				serverDesc = ServerType.REVIEW.getDesc();
+			} else if(gameRegion.getServerType() == ServerType.NORMAL.getValue()) {
+				serverDesc = ServerType.NORMAL.getDesc();
+			}
+			options.addOption(gameRegion.getRegionId(), gameRegion.getName() + "("+ serverDesc +")");
+		}
+		return options;
+	}
+}

+ 425 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameServerController.java

@@ -0,0 +1,425 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.tool.ListMapUtil;
+import org.gaming.tool.LocalDateTimeUtil;
+import org.gaming.tool.PageUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.clientversion.model.ClientVersion;
+import com.xiugou.x1.backstage.module.clientversion.service.ClientVersionService;
+import com.xiugou.x1.backstage.module.gameserver.form.GameServerForm;
+import com.xiugou.x1.backstage.module.gameserver.model.Bulletin;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannelServer;
+import com.xiugou.x1.backstage.module.gameserver.model.GamePlatform;
+import com.xiugou.x1.backstage.module.gameserver.model.GameRegion;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServerRuntime;
+import com.xiugou.x1.backstage.module.gameserver.service.BulletinService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelServerService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.service.GamePlatformService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameRegionService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerRuntimeService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+import com.xiugou.x1.backstage.module.gameserver.struct.GameServerQuery;
+import com.xiugou.x1.backstage.module.gameserver.struct.ServerType;
+import com.xiugou.x1.backstage.module.gameserver.vo.DropDownOptions;
+import com.xiugou.x1.backstage.module.gameserver.vo.GameRegionVo;
+import com.xiugou.x1.backstage.module.gameserver.vo.GameServerDetailVo;
+import com.xiugou.x1.backstage.module.gameserver.vo.GameServerVo;
+import com.xiugou.x1.backstage.module.gameserver.vo.PlayerVo;
+import com.xiugou.x1.backstage.module.gameserver.vo.ServerList;
+import com.xiugou.x1.backstage.module.gameserver.vo.VersionInfo;
+import com.xiugou.x1.backstage.module.player.model.Player;
+import com.xiugou.x1.backstage.module.player.service.PlayerService;
+
+import pojo.xiugou.x1.pojo.GameApi;
+import pojo.xiugou.x1.pojo.module.server.form.ServerRuntimeForm;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameServerController {
+
+	@Autowired
+	private GameServerService gameServerService;
+	@Autowired
+	private PlayerService playerService;
+	@Autowired
+	private GameRegionService gameRegionService;
+	@Autowired
+	private GameChannelServerService gameChannelServerService;
+	@Autowired
+	private GameChannelService gameChannelService;
+	@Autowired
+	private BulletinService bulletinService;
+	@Autowired
+	private GamePlatformService gamePlatformService;
+	@Autowired
+	private ClientVersionService clientVersionService;
+	@Autowired
+	private GameServerRuntimeService gameServerRuntimeService;
+	
+	
+	@ApiDocument("请求服务器数据")
+	@RequestMapping(value = "/gameServer/data.auth")
+	@ResponseBody
+	public PageData<GameServerDetailVo> data(GameServerQuery query) {
+		List<GameServer> list = gameServerService.getEntities();
+		Map<Integer, GameServerRuntime> runtimeMap = ListMapUtil.listToMap(gameServerRuntimeService.getEntities(), GameServerRuntime::getServerUid);
+		
+		List<GameServerDetailVo> pageList = new ArrayList<>();
+		for(GameServer server : list) {
+			if(query.getPlatformId() != 0 && server.getPlatformId() != query.getPlatformId()) {
+				continue;
+			}
+			if(query.getServerId() != 0 && server.getServerId() != query.getServerId()) {
+				continue;
+			}
+			GameServerRuntime runtime = runtimeMap.get(server.getId());
+			pageList.add(new GameServerDetailVo(server, runtime));
+		}
+		Collections.sort(pageList, comparator);
+		
+		PageData<GameServerDetailVo> pageData = new PageData<>();
+		pageData.setCount(pageList.size());
+		pageData.setData(PageUtil.pageN(pageList, query.getPage(), query.getLimit()));
+		return pageData;
+	}
+	
+	public static Comparator<GameServerDetailVo> comparator = new Comparator<GameServerDetailVo>() {
+		@Override
+		public int compare(GameServerDetailVo o1, GameServerDetailVo o2) {
+			int result = Long.compare(o1.getPlatformId(), o2.getPlatformId());
+			if(result != 0) {
+				return result;
+			}
+			return Integer.compare(o2.getServerId(), o1.getServerId());
+		}
+	};
+	
+	@ApiDocument("保存服务器数据,ID小于等于0时新增,大于0时修改")
+	@RequestMapping(value = "/gameServer/save.authw")
+	@ResponseBody
+	public GameServerDetailVo saveData(GameServerForm form) {
+		GamePlatform gamePlatform = gamePlatformService.getEntity(form.getPlatformId());
+		Asserts.isTrue(gamePlatform != null, TipsCode.PLATFORM_MISS, form.getPlatformId());
+		
+		List<GameServer> servers = gameServerService.getEntities();
+		Map<Integer, GameServer> serverMap = new HashMap<>();
+		for(GameServer server : servers) {
+			if(server.getPlatformId() != gamePlatform.getId()) {
+				continue;
+			}
+			serverMap.put(server.getServerId(), server);
+		}
+		
+		if(form.getId() <= 0) {
+			GameServer currServer = serverMap.get(form.getServerId());
+			Asserts.isTrue(currServer == null, TipsCode.PLATFORM_SERVER_REPEAT, form.getServerId());
+		}
+		
+		GameServer gameServer = serverMap.get(form.getServerId());
+		boolean insert = false;
+		if(gameServer == null) {
+			gameServer = new GameServer();
+			gameServer.setPlatformId(gamePlatform.getId());
+			gameServer.setPlatformName(gamePlatform.getName());
+			gameServer.setOpenTime(LocalDateTime.of(2099, 12, 31, 23, 59));
+			gameServer.setRealOpenTime(LocalDateTime.of(2099, 12, 31, 23, 59));
+			gameServer.setServerId(form.getServerId());
+			insert = true;
+		}
+		
+		gameServer.setName(form.getName());
+		gameServer.setSocketType(form.getSocketType());
+		gameServer.setExternalIp(form.getExternalIp());
+		gameServer.setInternalIp(form.getInternalIp());
+		gameServer.setTcpPort(form.getTcpPort());
+		gameServer.setHttpPort(form.getHttpPort());
+		gameServer.setDbGameName(form.getDbGameName());
+		gameServer.setDbLogName(form.getDbLogName());
+		gameServer.setStatus(form.getStatus());
+		gameServer.setRecommend(form.isRecommend());
+		gameServer.setServerType(form.getServerType());
+		gameServer.setHide(form.isHide());
+		
+		if(insert) {
+			gameServerService.insert(gameServer);
+		} else {
+			gameServerService.update(gameServer);
+		}
+		//更新渠道服务器关系数据
+		List<GameChannelServer> gameChannelServers = gameChannelServerService.getByServerUid(gameServer.getId());
+		for(GameChannelServer gameChannelServer : gameChannelServers) {
+			gameChannelServer.setRecommend(gameServer.isRecommend());
+		}
+		gameChannelServerService.updateAll(gameChannelServers);
+		
+		GameServerRuntime runtime = gameServerRuntimeService.getEntity(gameServer.getId());
+		return new GameServerDetailVo(gameServer, runtime);
+	}
+	
+	@ApiDocument("服务器下拉菜单数据")
+	@RequestMapping(value = "/gameServer/options.do")
+	@ResponseBody
+	public DropDownOptions options() {
+		List<GameServer> list = gameServerService.getEntities();
+		
+		DropDownOptions options = new DropDownOptions();
+		for(GameServer gameServer : list) {
+			options.addOption(gameServer.getId(),
+					gameServer.getName() + "-" + gameServer.getServerId() + "(" + gameServer.getId() + ")");
+		}
+		return options;
+	}
+	
+	@ApiDocument("根据当前渠道获取服务器下拉菜单数据")
+	@RequestMapping(value = "/gameServer/optionsInCurrChannel.do")
+	@ResponseBody
+	public DropDownOptions optionsInCurrChannel() {
+		long currChannel = gameChannelService.currChannel();
+		
+		DropDownOptions options = new DropDownOptions();
+		GameChannel gameChannel = gameChannelService.getEntity(currChannel);
+		if(gameChannel == null) {
+			return options;
+		}
+		List<GameChannelServer> relations = gameChannelServerService.getEntityList(gameChannel.getId());
+		for(GameChannelServer relation : relations) {
+			options.addOption(relation.getServerUid(),
+					relation.getServerName() + "-" + relation.getServerId() + "(" + relation.getServerUid() + ")");
+		}
+		return options;
+	}
+	
+	/**
+	 * http://192.168.1.5:9001/api/versionInfo?channelId=2&versionId=10001
+	 * http://127.0.0.1:9001/api/versionInfo?channelId=2&versionId=10001
+	 * https://2f895u5730.oicp.vip/api/versionInfo?channelId=2&versionId=10001
+	 * @param channelId
+	 * @param versionId
+	 * @return
+	 */
+	@ApiDocument("请求客户端版本信息,给游戏客户端请求用的")
+	@RequestMapping(value = "/api/versionInfo")
+	@ResponseBody
+	public VersionInfo versionInfo(@RequestParam("channelId") long channelId, @RequestParam("versionId") int versionId) {
+		ClientVersion clientVersion = clientVersionService.getEntity(channelId, versionId);
+		Asserts.isTrue(clientVersion != null, TipsCode.CLIENT_VERSION_CHANNEL_MISS, channelId, versionId);
+		
+		VersionInfo versionInfo = new VersionInfo();
+		versionInfo.setRemoteUrl(clientVersion.getRemoteUrl());
+		versionInfo.setResourceVersion(clientVersion.getResourceVersion());
+		versionInfo.setPcResourceVersion(clientVersion.getPcResourceVersion());
+		return versionInfo;
+	}
+	
+	/**
+	 * 微信请求服务器列表,http://120.79.34.46:10000/api/serversList?channelId=1&openId=AAA&versionId
+	 * http://192.168.1.5:9001/api/serversList?channelId=1&openId=AAA&versionId=0
+	 * https://www.xiugouchedui.cn/api/serversList?channelId=2&openId=45718870&versionId=10004
+	 * http://127.0.0.1:9001/api/serversList?channelId=2&openId=yy2&versionId=10001
+	 * https://2f895u5730.oicp.vip/api/serversList?channelId=2&openId=yy2&versionId=10001
+	 * @param channelId
+	 * @return
+	 */
+	@ApiDocument("请求服务器列表,给游戏客户端请求用的")
+	@RequestMapping(value = "/api/serversList")
+	@ResponseBody
+	public ServerList serversList(@RequestParam("channelId") long channelId, @RequestParam("openId") String openId,
+			@RequestParam(name = "versionId", required = false) Integer versionId) {
+		GameChannel gameChannel = gameChannelService.getEntity(channelId);
+		Asserts.isTrue(gameChannel != null, TipsCode.CHANNEL_MISS, channelId);
+		
+		Bulletin bulletin = bulletinService.getEntity(gameChannel.getBulletinId());
+		
+		ServerList serverList = new ServerList();
+		serverList.setTitle(bulletin == null ? "" : bulletin.getTitle());
+		serverList.setContent(bulletin == null ? "" : bulletin.getContent());
+		
+		if(versionId == null) {
+			versionId = 0;
+		}
+		ClientVersion clientVersion = clientVersionService.getEntity(channelId, versionId);
+		
+		ServerType serverType = null;
+		if(clientVersion != null) {
+			if(clientVersion.getServerType() == ServerType.TEST.getValue()) {
+				serverType = ServerType.TEST;
+			} else if(clientVersion.getServerType() == ServerType.REVIEW.getValue()) {
+				serverType = ServerType.REVIEW;
+			} else if(clientVersion.getServerType() == ServerType.NORMAL.getValue()) {
+				serverType = ServerType.NORMAL;
+			} else {
+				serverType = ServerType.TEST;
+			}
+		} else {
+			serverType = ServerType.TEST;
+		}
+		
+		//服务器列表包含两部分的数据,一部分是玩家创过号所登录的服务器,一部分是推荐服的服务器
+		
+		//我的区服
+		List<Player> players = playerService.getByOpenId(channelId, openId);
+		Collections.sort(players, LOGIN_SORTER);
+		Set<Integer> serverIds = new HashSet<>();
+		
+		for(Player player : players) {
+			GameServer server = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());
+			if(server.getServerType() != serverType.getValue()) {
+				continue;
+			}
+			
+			PlayerVo playerVo = new PlayerVo();
+			playerVo.setServerId(player.getServerId());
+			playerVo.setNick(player.getNick());
+			playerVo.setLevel(player.getLevel());
+			playerVo.setHead(player.getHead());
+			serverList.getPlayers().add(playerVo);
+			
+			serverList.getServers().add(new GameServerVo(server));
+			serverIds.add(server.getServerId());
+		}
+		
+		//推荐区服
+		List<GameServer> servers = gameChannelService.getRecommendServersUnderChannel(gameChannel.getId());
+		SortUtil.sortInt(servers, GameServer::getServerId);
+		
+		GameServer recommendServer = null;
+		for(GameServer server : servers) {
+			if(server.getServerType() != serverType.getValue()) {
+				continue;
+			}
+			if(serverIds.contains(server.getServerId())) {
+				continue;
+			}
+			if(server.isHide()) {
+				continue;
+			}
+			if(recommendServer == null) {
+				recommendServer = server;
+			} else {
+				if(server.getServerId() > recommendServer.getServerId()) {
+					recommendServer = server;
+				}
+			}
+		}
+		if(recommendServer != null) {
+			GameServerVo gameServerVo = new GameServerVo(recommendServer);
+			serverList.getServers().add(gameServerVo);
+		}
+		
+		//大区列表
+		List<GameRegion> regions = gameRegionService.getEntityList(channelId);
+		for(GameRegion region : regions) {
+			if(region.getServerType() != serverType.getValue()) {
+				continue;
+			}
+			GameRegionVo gameRegionVo = new GameRegionVo();
+			gameRegionVo.setId(region.getId());
+			gameRegionVo.setName(region.getName());
+			serverList.getRegions().add(gameRegionVo);
+		}
+		SortUtil.sort(serverList.getRegions(), GameRegionVo::getId);
+		return serverList;
+	}
+	
+	public static Comparator<Player> LOGIN_SORTER = new Comparator<Player>() {
+		@Override
+		public int compare(Player o1, Player o2) {
+			int result = Integer.compare(LocalDateTimeUtil.toEpochSecond(o2.getLastLoginTime()), LocalDateTimeUtil.toEpochSecond(o1.getLastLoginTime()));
+			if(result != 0) {
+				return result;
+			}
+			return Integer.compare(o2.getLevel(), o1.getLevel());
+		}
+	};
+	
+	/**
+	 * http://120.79.34.46:10000/api/serverInRegion?regionId=1
+	 * @param regionId
+	 * @return
+	 */
+	@ApiDocument("请求游戏大区下的服务器列表,给游戏客户端请求用的")
+	@RequestMapping(value = "/api/serverInRegion")
+	@ResponseBody
+	public List<GameServerVo> serverInRegion(@RequestParam("regionId") long regionId) {
+		GameRegion region = gameRegionService.getById(regionId);
+		
+		List<GameChannelServer> regionServers = gameChannelServerService.getEntityList(region.getChannelId());
+		List<GameServerVo> list = new ArrayList<>();
+		
+		for(GameChannelServer regionServer : regionServers) {
+			if(regionServer.getRegionId() != region.getRegionId()) {
+				continue;
+			}
+			GameServer server = gameServerService.getEntity(regionServer.getServerUid());
+			if(server.isHide()) {
+				continue;
+			}
+			GameServerVo gameServerVo = new GameServerVo(server);
+			list.add(gameServerVo);
+		}
+		SortUtil.sort(list, GameServerVo::getId);
+		return list;
+	}
+	
+	@ApiDocument("游戏服务器上报心跳")
+	@RequestMapping(value = GameApi.heartBeat)
+	@ResponseBody
+	public void heartBeat2(@RequestBody ServerRuntimeForm form) {
+		GameServer gameServer = gameServerService.getByPlatformAndServer(form.getPlatformId(), form.getServerId());
+		if (gameServer == null) {
+			return;
+		}
+		GameServerRuntime runtime = gameServerRuntimeService.getEntity(gameServer.getId());
+		if(runtime == null) {
+			runtime = new GameServerRuntime();
+			runtime.setServerUid(gameServer.getId());
+			gameServerRuntimeService.insert(runtime);
+		}
+		
+		runtime.setRunning(form.isRunning());
+		runtime.setHeartTime(LocalDateTime.now());
+		runtime.setCreateNum(form.getPlayerNum());
+		runtime.setRegisterNum(form.getPlayerNum());
+		runtime.setOnlineNum(form.getOnlineNum());
+		runtime.setBattleNum(form.getBattleNum());
+		runtime.setCurrBattleNum(form.getCurrBattleNum());
+		if(!"".equals(form.getMaxMemory())) {
+			runtime.setMaxMemory(form.getMaxMemory());
+			runtime.setFreeMemory(form.getFreeMemory());
+			runtime.setTotalMemory(form.getTotalMemory());
+			runtime.setLeftMemory(form.getLeftMemory());
+			runtime.setUsedMemory(form.getUsedMemory());
+		}
+		gameServerRuntimeService.update(runtime);
+	}
+}

+ 215 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/GameServerMaintainController.java

@@ -0,0 +1,215 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.gameserver.form.GameServerMaintainForm;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+import com.xiugou.x1.backstage.module.gameserver.vo.GameServerMaintainVo;
+import com.xiugou.x1.backstage.util.X1HttpUtil;
+
+import pojo.xiugou.x1.pojo.GameApi;
+import pojo.xiugou.x1.pojo.module.server.ServerResponse;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class GameServerMaintainController {
+
+	@Autowired
+	private GameServerService gameServerService;
+	
+	@ApiDocument("请求服务器维护数据")
+	@RequestMapping(value = "/gameServerMaintain/data.auth")
+	@ResponseBody
+	public PageData<GameServerMaintainVo> data(@RequestParam("platformId") long platformId) {
+		List<GameServer> list = gameServerService.getEntities();
+		
+		List<GameServer> pageList = new ArrayList<>();
+		for(GameServer server : list) {
+			if(server.getPlatformId() != platformId) {
+				continue;
+			}
+			if(server.isMerge()) {
+				continue;
+			}
+			pageList.add(server);
+		}
+		return buildMaintainVo(pageList);
+	}
+	
+	@ApiDocument("进行服务器维护")
+	@RequestMapping(value = "/gameServerMaintain/maintain.authw")
+	@ResponseBody
+	public PageData<GameServerMaintainVo> maintain(GameServerMaintainForm form) {
+		List<GameServer> list = gameServerService.getEntities();
+		
+		List<GameServer> updateList = new ArrayList<>();
+		for(GameServer gameServer : list) {
+			if(!form.getServerIds().contains(gameServer.getServerId())) {
+				continue;
+			}
+			if(gameServer.getPlatformId() != form.getPlatformId()) {
+				continue;
+			}
+			if(gameServer.isMerge()) {
+				continue;
+			}
+			gameServer.setStatus(0);
+			gameServer.setMaintain(true);
+			gameServer.setMaintainResponse(false);
+			updateList.add(gameServer);
+		}
+		for(GameServer gameServer : updateList) {
+			Map<String, Object> map = new HashMap<>();
+			map.put("maintain", true);
+			ServerResponse response = X1HttpUtil.formPost(gameServer, GameApi.serverMaintain, map);
+			if(response != null && response.getCode() == 0) {
+				gameServer.setMaintainResponse(true);
+			}
+		}
+		gameServerService.updateAll(updateList);
+		return buildMaintainVo(updateList);
+	}
+	
+	@ApiDocument("重新发送进行服务器维护")
+	@RequestMapping(value = "/gameServerMaintain/resendMaintain.authw")
+	@ResponseBody
+	public PageData<GameServerMaintainVo> resendMaintain(GameServerMaintainForm form) {
+		List<GameServer> list = gameServerService.getEntities();
+		
+		List<GameServer> updateList = new ArrayList<>();
+		for(GameServer gameServer : list) {
+			if(!form.getServerIds().contains(gameServer.getServerId())) {
+				continue;
+			}
+			if(gameServer.getPlatformId() != form.getPlatformId()) {
+				continue;
+			}
+			if(gameServer.isMerge()) {
+				continue;
+			}
+			if(gameServer.isMaintainResponse()) {
+				continue;
+			}
+			updateList.add(gameServer);
+		}
+		
+		for(GameServer gameServer : updateList) {
+			Map<String, Object> map = new HashMap<>();
+			map.put("maintain", true);
+			ServerResponse response = X1HttpUtil.formPost(gameServer, GameApi.serverMaintain, map);
+			if(response != null && response.getCode() == 0) {
+				gameServer.setMaintainResponse(true);
+			}
+		}
+		
+		gameServerService.updateAll(updateList);
+		return buildMaintainVo(updateList);
+	}
+	
+	@ApiDocument("结束服务器维护")
+	@RequestMapping(value = "/gameServerMaintain/endMaintain.authw")
+	@ResponseBody
+	public PageData<GameServerMaintainVo> endMaintain(GameServerMaintainForm form) {
+		List<GameServer> list = gameServerService.getEntities();
+		
+		List<GameServer> updateList = new ArrayList<>();
+		for(GameServer gameServer : list) {
+			if(!form.getServerIds().contains(gameServer.getServerId())) {
+				continue;
+			}
+			if(gameServer.getPlatformId() != form.getPlatformId()) {
+				continue;
+			}
+			if(gameServer.isMerge()) {
+				continue;
+			}
+			gameServer.setStatus(1);
+			gameServer.setMaintain(false);
+			gameServer.setMaintainResponse(false);
+			updateList.add(gameServer);
+		}
+		for(GameServer gameServer : updateList) {
+			Map<String, Object> map = new HashMap<>();
+			map.put("maintain", false);
+			ServerResponse response = X1HttpUtil.formPost(gameServer, GameApi.serverMaintain, map);
+			if(response != null && response.getCode() == 0) {
+				gameServer.setMaintainResponse(true);
+			}
+		}
+		gameServerService.updateAll(updateList);
+		return buildMaintainVo(updateList);
+	}
+	
+	@ApiDocument("重新发送结束服务器维护")
+	@RequestMapping(value = "/gameServerMaintain/resendEndMaintain.authw")
+	@ResponseBody
+	public PageData<GameServerMaintainVo> resendEndMaintain(GameServerMaintainForm form) {
+		List<GameServer> list = gameServerService.getEntities();
+		
+		List<GameServer> updateList = new ArrayList<>();
+		for(GameServer gameServer : list) {
+			if(!form.getServerIds().contains(gameServer.getServerId())) {
+				continue;
+			}
+			if(gameServer.getPlatformId() != form.getPlatformId()) {
+				continue;
+			}
+			if(gameServer.isMerge()) {
+				continue;
+			}
+			if(gameServer.isMaintainResponse()) {
+				continue;
+			}
+			updateList.add(gameServer);
+		}
+		
+		for(GameServer gameServer : updateList) {
+			Map<String, Object> map = new HashMap<>();
+			map.put("maintain", false);
+			ServerResponse response = X1HttpUtil.formPost(gameServer, GameApi.serverMaintain, map);
+			if(response != null && response.getCode() == 0) {
+				gameServer.setMaintainResponse(true);
+			}
+		}
+		gameServerService.updateAll(updateList);
+		return buildMaintainVo(updateList);
+	}
+	
+	public PageData<GameServerMaintainVo> buildMaintainVo(List<GameServer> servers) {
+		List<GameServerMaintainVo> pageList = new ArrayList<>();
+		for(GameServer server : servers) {
+			GameServerMaintainVo vo = new GameServerMaintainVo();
+			vo.setServerId(server.getServerId());
+			vo.setName(server.getName());
+			vo.setMaintain(server.isMaintain());
+			vo.setMaintainResponse(server.isMaintainResponse());
+			pageList.add(vo);
+		}
+		
+		SortUtil.sortInt(pageList, GameServerMaintainVo::getServerId);
+		
+		PageData<GameServerMaintainVo> pageData = new PageData<>();
+		pageData.setCount(pageList.size());
+		pageData.setData(pageList);
+		return pageData;
+	}
+}

+ 158 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/ServerOpenController.java

@@ -0,0 +1,158 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.PageQuery;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.interceptor.RoleContext;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.backstage.module.user.service.UserService;
+import org.gaming.tool.LocalDateTimeUtil;
+import org.gaming.tool.PageUtil;
+import org.gaming.tool.SortUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.TipsCode;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.model.GamePlatform;
+import com.xiugou.x1.backstage.module.gameserver.model.GameServer;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.service.GamePlatformService;
+import com.xiugou.x1.backstage.module.gameserver.service.GameServerService;
+import com.xiugou.x1.backstage.module.gameserver.vo.GameServerDetailVo;
+import com.xiugou.x1.backstage.util.X1HttpUtil;
+
+import pojo.xiugou.x1.pojo.GameApi;
+import pojo.xiugou.x1.pojo.module.server.ServerResponse;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class ServerOpenController {
+
+	private static Logger logger = LoggerFactory.getLogger(ServerOpenController.class);
+	
+	@Autowired
+	private GameChannelService gameChannelService;
+	@Autowired
+	private GameServerService gameServerService;
+	@Autowired
+	private UserService userService;
+	@Autowired
+	private GamePlatformService gamePlatformService;
+	
+	@ApiDocument("请求服务器开服数据")
+	@RequestMapping(value = "/serverOpen/data.auth")
+	@ResponseBody
+	public PageData<GameServerDetailVo> data(PageQuery query) {
+		long currChannel = gameChannelService.currChannel();
+		GameChannel gameChannel = gameChannelService.getEntity(currChannel);
+		
+		GamePlatform gamePlatform = gamePlatformService.getEntity(gameChannel.getPlatformId());
+		
+		List<GameServer> serverList = new ArrayList<>();
+		LocalDateTime now = LocalDateTime.now();
+		for(GameServer gameServer : gameServerService.getEntities()) {
+			if(gameServer.getPlatformId() != gamePlatform.getId()) {
+				continue;
+			}
+			if(gameServer.getRealOpenTime().isBefore(now)) {
+				continue;
+			}
+			serverList.add(gameServer);
+		}
+		SortUtil.sortInt(serverList, GameServer::getId);
+		List<GameServer> page = PageUtil.pageNDesc(serverList, query.getPage(), query.getLimit());
+		
+		List<GameServerDetailVo> list = new ArrayList<>();
+		for(GameServer gameServer : page) {
+			list.add(new GameServerDetailVo(gameServer));
+		}
+		
+		PageData<GameServerDetailVo> pageData = new PageData<>();
+		pageData.setCount(list.size());
+		pageData.setData(list);
+		return pageData;
+	}
+	
+	@ApiDocument("设置服务器预期开服时间")
+	@RequestMapping(value = "/serverOpen/editOpenTime.authw")
+	@ResponseBody
+	public GameServerDetailVo editOpenTime(@RequestParam("serverUid") int serverUid, @RequestParam("openTime") long openTime) {
+		GameServer gameServer = gameServerService.getEntity(serverUid);
+		Asserts.isTrue(gameServer != null, TipsCode.GAME_SERVER_MISS, serverUid);
+		Asserts.isTrue(gameServer.getOpenTime().isAfter(LocalDateTime.now()), TipsCode.SERVER_OPENED, serverUid);
+		Asserts.isTrue(gameServer.getRealOpenTime().isAfter(LocalDateTime.now()), TipsCode.SERVER_OPENED, serverUid);
+		
+		LocalDateTime openTime0 = LocalDateTimeUtil.ofEpochMilli(openTime);
+		Asserts.isTrue(openTime0.isAfter(LocalDateTime.now()), TipsCode.SERVER_OPENTIME_NEED_FUTURE);
+		
+		RoleContext roleContext = userService.getCurrUser();
+		logger.info("{}-{}操作修改服务器开服时间为{},目标服务器是{}-{}-{}", roleContext.getId(), roleContext.getName(), openTime0,
+				gameServer.getId(), gameServer.getServerId(), gameServer.getName());
+		
+		gameServer.setOpenTime(openTime0);
+		gameServer.setRealOpenTime(openTime0);
+		//先设置为未处理
+		gameServer.setSendOpenStatus(0);
+		gameServerService.update(gameServer);
+		
+		//发送给服务器
+		Map<String, Object> map = new HashMap<>();
+		map.put("openTime", openTime);
+		ServerResponse serverResponse = X1HttpUtil.formPost(gameServer, GameApi.serverSetOpenTime, map);
+		if(serverResponse != null && serverResponse.getCode() == 0) {
+			gameServer.setSendOpenStatus(1);
+		} else {
+			gameServer.setSendOpenStatus(2);
+		}
+		gameServerService.update(gameServer);
+		
+		return new GameServerDetailVo(gameServer);
+	}
+	
+	@ApiDocument("立刻开服")
+	@RequestMapping(value = "/serverOpen/openNow.authw")
+	@ResponseBody
+	public GameServerDetailVo openNow(@RequestParam("serverUid") int serverUid) {
+		GameServer gameServer = gameServerService.getEntity(serverUid);
+		Asserts.isTrue(gameServer != null, TipsCode.GAME_SERVER_MISS, serverUid);
+		Asserts.isTrue(gameServer.getOpenTime().isAfter(LocalDateTime.now()), TipsCode.SERVER_OPENED, serverUid);
+		
+		RoleContext roleContext = userService.getCurrUser();
+		logger.info("{}-{}操作立刻开服,目标服务器是{}-{}-{}", roleContext.getId(), roleContext.getName(), gameServer.getId(),
+				gameServer.getServerId(), gameServer.getName());
+		
+		gameServer.setSendOpenStatus(0);
+		gameServer.setRealOpenTime(LocalDateTime.now());
+		gameServer.setHide(false);
+		gameServer.setRecommend(true);
+		
+		ServerResponse serverResponse = X1HttpUtil.formPost(gameServer, GameApi.serverOpenNow, Collections.emptyMap());
+		if(serverResponse != null && serverResponse.getCode() == 0) {
+			gameServer.setSendOpenStatus(1);
+		} else {
+			gameServer.setSendOpenStatus(2);
+		}
+		gameServerService.update(gameServer);
+		
+		return new GameServerDetailVo(gameServer);
+	}
+}

+ 209 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/UserChannelController.java

@@ -0,0 +1,209 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.gaming.backstage.PageData;
+import org.gaming.backstage.WebCode;
+import org.gaming.backstage.advice.Asserts;
+import org.gaming.backstage.interceptor.RoleContext;
+import org.gaming.backstage.module.apidoc.annotation.ApiDocument;
+import org.gaming.backstage.module.user.model.User;
+import org.gaming.backstage.module.user.service.UserService;
+import org.gaming.tool.ListMapUtil;
+import org.gaming.tool.SortUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiugou.x1.backstage.module.gameserver.form.UserChannelForm;
+import com.xiugou.x1.backstage.module.gameserver.model.GameChannel;
+import com.xiugou.x1.backstage.module.gameserver.model.UserChannel;
+import com.xiugou.x1.backstage.module.gameserver.service.GameChannelService;
+import com.xiugou.x1.backstage.module.gameserver.service.UserChannelService;
+import com.xiugou.x1.backstage.module.gameserver.struct.UserChannelQuery;
+import com.xiugou.x1.backstage.module.gameserver.vo.ChannelGranting;
+import com.xiugou.x1.backstage.module.gameserver.vo.UserVo;
+
+/**
+ * @author YY
+ *
+ */
+@Controller
+public class UserChannelController {
+
+	@Autowired
+	private UserChannelService userChannelService;
+	@Autowired
+	private UserService userService;
+	@Autowired
+	private GameChannelService gameChannelService;
+	
+	@ApiDocument("请求用户与渠道关系数据")
+	@RequestMapping(value = "/userChannel/data.auth")
+	@ResponseBody
+	public PageData<UserVo> data(UserChannelQuery query) {
+		RoleContext roleContext = userService.getCurrUser();
+		User currUser = userService.getById(roleContext.getId());
+		PageData<User> pageData = userService.queryUser(currUser.getLevel(), query.getPage(), query.getLimit());
+		
+		PageData<UserVo> result = new PageData<>();
+		for(User user : pageData.getData()) {
+			UserVo vo = new UserVo();
+			vo.setId(user.getId());
+			vo.setName(user.getName());
+			vo.setPhone(user.getPhone());
+			vo.setMailAddress(user.getMailAddress());
+			result.getData().add(vo);
+		}
+		result.setCount(pageData.getCount());
+		return result;
+	}
+	
+	@ApiDocument("保存用户与渠道关系数据")
+	@RequestMapping(value = "/userChannel/save.authw")
+	@ResponseBody
+	public PageData<ChannelGranting> save(UserChannelForm form) {
+		RoleContext roleContext = userService.getCurrUser();
+		User currUser = userService.getById(roleContext.getId());
+		User targetUser = userService.getById(form.getUserId());
+		Asserts.isTrue(currUser.getLevel() < targetUser.getLevel(), WebCode.USER_LEVEL_LACK);
+		Asserts.isTrue(!targetUser.isSuperUser(), WebCode.USER_SUPER_DONT_GRANT);
+		
+		List<UserChannel> targetChannels = userChannelService.getEntityList(targetUser.getId());
+		Map<Long, UserChannel> targetChannelMap = ListMapUtil.listToMap(targetChannels, UserChannel::getChannelId);
+		
+		List<UserChannel> insertList = new ArrayList<>();
+		Set<Long> channelIds = new HashSet<>();
+		
+		if(!currUser.isSuperUser()) {
+			List<UserChannel> userChannels = userChannelService.getEntityList(currUser.getId());
+			Map<Long, UserChannel> userFunctionMap = ListMapUtil.listToMap(userChannels, UserChannel::getChannelId);
+			
+			for(long channelId : form.getChannel()) {
+				UserChannel userChannel = userFunctionMap.get(channelId);
+				if(userChannel == null) {
+					//当前用户没有的权限,不能授权给下级用户
+					continue;
+				}
+				if(channelIds.contains(channelId)) {
+					continue;
+				}
+				GameChannel channel = gameChannelService.getEntity(channelId);
+				if(channel == null) {
+					continue;
+				}
+				channelIds.add(channelId);
+				
+				UserChannel targetChannel = targetChannelMap.get(channelId);
+				if(targetChannel == null) {
+					targetChannel = new UserChannel();
+					targetChannel.setUserId(targetUser.getId());
+					targetChannel.setUserName(targetUser.getName());
+					targetChannel.setChannelId(channel.getId());
+					targetChannel.setChannelName(channel.getName());
+					targetChannel.setGrantUserId(currUser.getId());
+					targetChannel.setGrantUserName(currUser.getName());
+					insertList.add(targetChannel);
+				}
+			}
+		} else {
+			for(long channelId : form.getChannel()) {
+				if(channelIds.contains(channelId)) {
+					continue;
+				}
+				GameChannel channel = gameChannelService.getEntity(channelId);
+				if(channel == null) {
+					continue;
+				}
+				channelIds.add(channelId);
+				
+				UserChannel targetChannel = targetChannelMap.get(channelId);
+				if(targetChannel == null) {
+					targetChannel = new UserChannel();
+					targetChannel.setUserId(targetUser.getId());
+					targetChannel.setUserName(targetUser.getName());
+					targetChannel.setChannelId(channel.getId());
+					targetChannel.setChannelName(channel.getName());
+					targetChannel.setGrantUserId(currUser.getId());
+					targetChannel.setGrantUserName(currUser.getName());
+					insertList.add(targetChannel);
+				}
+			}
+		}
+		//被移除的权限
+		List<UserChannel> deleteList = new ArrayList<>();
+		for(UserChannel targetChannel : targetChannels) {
+			if(channelIds.contains(targetChannel.getChannelId())) {
+				continue;
+			}
+			deleteList.add(targetChannel);
+		}
+		if(!deleteList.isEmpty()) {
+			userChannelService.deleteAll(deleteList);
+		}
+		if(!insertList.isEmpty()) {
+			userChannelService.insertAll(insertList);
+		}
+		return targetUserChannelOption(roleContext.getId(), form.getUserId());
+	} 
+	
+	@ApiDocument("获取可授权的渠道数据")
+	@RequestMapping(value = "/userChannel/options.auth")
+	@ResponseBody
+	public PageData<ChannelGranting> options(@RequestParam("userId") long userId) {
+		RoleContext userContext = userService.getCurrUser();
+		return targetUserChannelOption(userContext.getId(), userId);
+	}
+	
+	private PageData<ChannelGranting> targetUserChannelOption(long userId, long targetUserId) {
+		//当前用户
+		User user = userService.getById(userId);
+		User targetUser = userService.getById(targetUserId);
+		//目标用户当前用的权限
+		List<UserChannel> targetHavingChannels = userChannelService.getEntityList(targetUser.getId());
+		Map<Long, UserChannel> targetHavingChannelMap = ListMapUtil.listToMap(targetHavingChannels, UserChannel::getChannelId);
+		
+		PageData<ChannelGranting> pageData = new PageData<>();
+		if(user.isSuperUser()) {
+			List<GameChannel> channels = gameChannelService.getEntities();
+			
+			for(GameChannel channel : channels) {
+				ChannelGranting granting = new ChannelGranting();
+				granting.setId(channel.getId());
+				granting.setName(channel.getName());
+				
+				UserChannel havingChannel = targetHavingChannelMap.get(channel.getId());
+				if(havingChannel != null) {
+					granting.setHas(true);
+				}
+				pageData.getData().add(granting);
+			}
+		} else {
+			//当前用户可以授权的菜单数据
+			List<UserChannel> userChannels = userChannelService.getEntityList(user.getId());
+			for(UserChannel userChannel : userChannels) {
+				ChannelGranting granting = new ChannelGranting();
+				granting.setId(userChannel.getId());
+				granting.setName(userChannel.getChannelName());
+				
+				UserChannel havingChannel = targetHavingChannelMap.get(userChannel.getChannelId());
+				if(havingChannel != null) {
+					granting.setHas(true);
+				}
+				pageData.getData().add(granting);
+			}
+		}
+		pageData.setCount(pageData.getData().size());
+		SortUtil.sort(pageData.getData(), ChannelGranting::getId);
+		return pageData;
+	}
+}

+ 32 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/BulletinForm.java

@@ -0,0 +1,32 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+/**
+ * @author YY
+ *
+ */
+public class BulletinForm {
+	private long id;
+	private String title;
+	private String content;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getTitle() {
+		return title;
+	}
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	public String getContent() {
+		return content;
+	}
+	public void setContent(String content) {
+		this.content = content;
+	}
+}

+ 28 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/ChannelServerRelationForm.java

@@ -0,0 +1,28 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author YY
+ *
+ */
+public class ChannelServerRelationForm {
+	private long channelId;
+	private List<Integer> serverUids = new ArrayList<>();
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public List<Integer> getServerUids() {
+		return serverUids;
+	}
+	public void setServerUids(List<Integer> serverUids) {
+		this.serverUids = serverUids;
+	}
+}

+ 54 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameChannelForm.java

@@ -0,0 +1,54 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+/**
+ * @author YY
+ *
+ */
+public class GameChannelForm {
+	private long id;
+	private String name;
+	private long bulletinId;
+	private long platformId;
+	private String programVersion;
+	private String resourceVersion;
+	
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public long getBulletinId() {
+		return bulletinId;
+	}
+	public void setBulletinId(long bulletinId) {
+		this.bulletinId = bulletinId;
+	}
+	public long getPlatformId() {
+		return platformId;
+	}
+	public void setPlatformId(long platformId) {
+		this.platformId = platformId;
+	}
+	public String getProgramVersion() {
+		return programVersion;
+	}
+	public void setProgramVersion(String programVersion) {
+		this.programVersion = programVersion;
+	}
+	public String getResourceVersion() {
+		return resourceVersion;
+	}
+	public void setResourceVersion(String resourceVersion) {
+		this.resourceVersion = resourceVersion;
+	}
+}

+ 25 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GamePlatformForm.java

@@ -0,0 +1,25 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+/**
+ * @author YY
+ *
+ */
+public class GamePlatformForm {
+	private long id;
+	private String name;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}

+ 46 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameRegionForm.java

@@ -0,0 +1,46 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+/**
+ * @author YY
+ *
+ */
+public class GameRegionForm {
+	private long id;
+	private int regionId;
+	private String name;
+	private long channelId;
+	private int serverType;
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public int getRegionId() {
+		return regionId;
+	}
+	public void setRegionId(int regionId) {
+		this.regionId = regionId;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public int getServerType() {
+		return serverType;
+	}
+	public void setServerType(int serverType) {
+		this.serverType = serverType;
+	}
+}

+ 152 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameServerForm.java

@@ -0,0 +1,152 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+/**
+ * @author YY
+ *
+ */
+public class GameServerForm {
+	//数据唯一ID
+	private long id;
+	private long platformId;
+	private String platformName;
+	private int serverId;
+	private String name;
+	private String externalIp;
+	private String internalIp;
+	private int tcpPort;
+	private int httpPort;
+	private String dbIp;
+	private String dbPort;
+	private String dbUser;
+	private String dbPwd;
+	private String dbGameName;
+	private String dbLogName;
+	private int status;
+	private boolean recommend;
+	private int serverType;
+	private String socketType;
+	private boolean hide;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public int getServerId() {
+		return serverId;
+	}
+	public void setServerId(int serverId) {
+		this.serverId = serverId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getExternalIp() {
+		return externalIp;
+	}
+	public void setExternalIp(String externalIp) {
+		this.externalIp = externalIp;
+	}
+	public String getInternalIp() {
+		return internalIp;
+	}
+	public void setInternalIp(String internalIp) {
+		this.internalIp = internalIp;
+	}
+	public int getTcpPort() {
+		return tcpPort;
+	}
+	public void setTcpPort(int tcpPort) {
+		this.tcpPort = tcpPort;
+	}
+	public int getHttpPort() {
+		return httpPort;
+	}
+	public void setHttpPort(int httpPort) {
+		this.httpPort = httpPort;
+	}
+	public String getDbIp() {
+		return dbIp;
+	}
+	public void setDbIp(String dbIp) {
+		this.dbIp = dbIp;
+	}
+	public String getDbPort() {
+		return dbPort;
+	}
+	public void setDbPort(String dbPort) {
+		this.dbPort = dbPort;
+	}
+	public String getDbUser() {
+		return dbUser;
+	}
+	public void setDbUser(String dbUser) {
+		this.dbUser = dbUser;
+	}
+	public String getDbGameName() {
+		return dbGameName;
+	}
+	public void setDbGameName(String dbGameName) {
+		this.dbGameName = dbGameName;
+	}
+	public String getDbLogName() {
+		return dbLogName;
+	}
+	public void setDbLogName(String dbLogName) {
+		this.dbLogName = dbLogName;
+	}
+	public int getStatus() {
+		return status;
+	}
+	public void setStatus(int status) {
+		this.status = status;
+	}
+	public boolean isRecommend() {
+		return recommend;
+	}
+	public void setRecommend(boolean recommend) {
+		this.recommend = recommend;
+	}
+	public String getDbPwd() {
+		return dbPwd;
+	}
+	public void setDbPwd(String dbPwd) {
+		this.dbPwd = dbPwd;
+	}
+	public long getPlatformId() {
+		return platformId;
+	}
+	public void setPlatformId(long platformId) {
+		this.platformId = platformId;
+	}
+	public String getPlatformName() {
+		return platformName;
+	}
+	public void setPlatformName(String platformName) {
+		this.platformName = platformName;
+	}
+	public int getServerType() {
+		return serverType;
+	}
+	public void setServerType(int serverType) {
+		this.serverType = serverType;
+	}
+	public String getSocketType() {
+		return socketType;
+	}
+	public void setSocketType(String socketType) {
+		this.socketType = socketType;
+	}
+	public boolean isHide() {
+		return hide;
+	}
+	public void setHide(boolean hide) {
+		this.hide = hide;
+	}
+}

+ 27 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/GameServerMaintainForm.java

@@ -0,0 +1,27 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+import java.util.List;
+
+/**
+ * @author YY
+ *
+ */
+public class GameServerMaintainForm {
+	private long platformId;
+	private List<Integer> serverIds;
+	public long getPlatformId() {
+		return platformId;
+	}
+	public void setPlatformId(long platformId) {
+		this.platformId = platformId;
+	}
+	public List<Integer> getServerIds() {
+		return serverIds;
+	}
+	public void setServerIds(List<Integer> serverIds) {
+		this.serverIds = serverIds;
+	}
+}

+ 32 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/ServerToRegionForm.java

@@ -0,0 +1,32 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+/**
+ * @author YY
+ *
+ */
+public class ServerToRegionForm {
+	private long channelId;
+	private long serverUid;
+	private long regionId;
+	public long getRegionId() {
+		return regionId;
+	}
+	public void setRegionId(long regionId) {
+		this.regionId = regionId;
+	}
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public long getServerUid() {
+		return serverUid;
+	}
+	public void setServerUid(long serverUid) {
+		this.serverUid = serverUid;
+	}
+}

+ 27 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/form/UserChannelForm.java

@@ -0,0 +1,27 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.form;
+
+import java.util.List;
+
+/**
+ * @author YY
+ *
+ */
+public class UserChannelForm {
+	private long userId;
+	private List<Long> channel;
+	public long getUserId() {
+		return userId;
+	}
+	public void setUserId(long userId) {
+		this.userId = userId;
+	}
+	public List<Long> getChannel() {
+		return channel;
+	}
+	public void setChannel(List<Long> channel) {
+		this.channel = channel;
+	}
+}

+ 53 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/Bulletin.java

@@ -0,0 +1,53 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Table;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ * 公告
+ */
+@Repository
+@Table(name = "bulletin", comment = "游戏公告表", dbAlias = "backstage")
+public class Bulletin extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO, autoBase = 1)
+	@Column(comment = "公告ID")
+	private long id;
+	@Column(comment = "公告标题")
+	private String title;
+	@Column(comment = "公告内容", extra = "text")
+	private String content;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getTitle() {
+		return title;
+	}
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	public String getContent() {
+		return content;
+	}
+	public void setContent(String content) {
+		this.content = content;
+	}
+	@Override
+	public Long redisOwnerKey() {
+		return 0L;
+	}
+	@Override
+	public Long redisHashKey() {
+		return id;
+	}
+}

+ 102 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameChannel.java

@@ -0,0 +1,102 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Table;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_channel", comment = "游戏渠道表", dbAlias = "backstage")
+public class GameChannel extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO, autoBase = 1)
+	@Column(comment = "渠道ID")
+	private long id;
+	@Column(comment = "渠道名字")
+	private String name;
+	@Column(name = "platform_id", comment = "归属平台ID", readonly = true)
+	private long platformId;
+	@Column(name = "platform_name", comment = "归属平台名称")
+	private String platformName;
+	@Column(name = "user_id", comment = "操作员ID", readonly = true)
+	private long userId;
+	@Column(name = "user_name", comment = "操作员名称", readonly = true)
+	private String userName;
+	@Column(name = "bulletin_id", comment = "公告ID")
+	private long bulletinId;
+	@Column(name = "program_version", comment = "客户端程序版本号")
+	private String programVersion;
+	@Column(name = "resource_version", comment = "客户端资源版本号")
+	private String resourceVersion;
+	
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	@Override
+	public Long redisOwnerKey() {
+		return 0L;
+	}
+	@Override
+	public Long redisHashKey() {
+		return id;
+	}
+	public long getUserId() {
+		return userId;
+	}
+	public void setUserId(long userId) {
+		this.userId = userId;
+	}
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+	public long getBulletinId() {
+		return bulletinId;
+	}
+	public void setBulletinId(long bulletinId) {
+		this.bulletinId = bulletinId;
+	}
+	public String getProgramVersion() {
+		return programVersion;
+	}
+	public void setProgramVersion(String programVersion) {
+		this.programVersion = programVersion;
+	}
+	public String getResourceVersion() {
+		return resourceVersion;
+	}
+	public void setResourceVersion(String resourceVersion) {
+		this.resourceVersion = resourceVersion;
+	}
+	public long getPlatformId() {
+		return platformId;
+	}
+	public void setPlatformId(long platformId) {
+		this.platformId = platformId;
+	}
+	public String getPlatformName() {
+		return platformName;
+	}
+	public void setPlatformName(String platformName) {
+		this.platformName = platformName;
+	}
+}

+ 123 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameChannelServer.java

@@ -0,0 +1,123 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.enuma.IndexType;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.Table;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_channel_server", comment = "游戏渠道与服务器关系表", dbAlias = "backstage", indexs = {
+		@Index(name = "channelid", columns = { "channel_id" }),
+		@Index(name = "channelid_serverid", columns = { "channel_id", "server_id" }, type = IndexType.UNIQUE)})
+public class GameChannelServer extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO, autoBase = 1)
+	@Column(comment = "关系ID")
+	private long id;
+	@Column(name = "channel_id", comment = "渠道ID", readonly = true)
+	private long channelId;
+	@Column(name = "channel_name", comment = "渠道名字")
+	private String channelName;
+	@Column(name = "server_uid", comment = "服务器唯一ID", readonly = true)
+	private int serverUid;
+	@Column(name = "server_id", comment = "服务器ID", readonly = true)
+	private int serverId;
+	@Column(name = "server_name", comment = "服务器名字")
+	private String serverName;
+	@Column(name = "region_id", comment = "所属大区ID")
+	private int regionId;
+	@Column(name = "region_name", comment = "所属大区名称")
+	private String regionName;
+	@Column(name = "user_id", comment = "操作员ID", readonly = true)
+	private long userId;
+	@Column(name = "user_name", comment = "操作员名称", readonly = true)
+	private String userName;
+	@Column(comment = "是否为推荐服务器")
+	private boolean recommend;
+	
+	
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public int getServerId() {
+		return serverId;
+	}
+	public void setServerId(int serverId) {
+		this.serverId = serverId;
+	}
+	public String getServerName() {
+		return serverName;
+	}
+	public void setServerName(String serverName) {
+		this.serverName = serverName;
+	}
+	@Override
+	public Long redisOwnerKey() {
+		return channelId;
+	}
+	@Override
+	public Long redisHashKey() {
+		return (long)serverId;
+	}
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public String getChannelName() {
+		return channelName;
+	}
+	public void setChannelName(String channelName) {
+		this.channelName = channelName;
+	}
+	public String getRegionName() {
+		return regionName;
+	}
+	public void setRegionName(String regionName) {
+		this.regionName = regionName;
+	}
+	public long getUserId() {
+		return userId;
+	}
+	public void setUserId(long userId) {
+		this.userId = userId;
+	}
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+	public int getServerUid() {
+		return serverUid;
+	}
+	public void setServerUid(int serverUid) {
+		this.serverUid = serverUid;
+	}
+	public int getRegionId() {
+		return regionId;
+	}
+	public void setRegionId(int regionId) {
+		this.regionId = regionId;
+	}
+	public boolean isRecommend() {
+		return recommend;
+	}
+	public void setRecommend(boolean recommend) {
+		this.recommend = recommend;
+	}
+}

+ 121 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameDb.java

@@ -0,0 +1,121 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.enuma.IndexType;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.orm.AbstractEntity;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_db", comment = "游戏数据库管理表", dbAlias = "backstage", indexs = {
+		@Index(name = "db_name", columns = "db_name", type = IndexType.UNIQUE)})
+public class GameDb extends AbstractEntity {
+	@Id(strategy = Strategy.IDENTITY)
+	@Column(name = "db_name", comment = "数据库名字,唯一ID")
+	private String dbName;
+	@Column(name = "platform_id", comment = "平台ID")
+	private int platformId;
+	@Column(name = "server_id", comment = "服务器ID")
+	private int serverId;
+	@Column(comment = "服务器类型")
+	private String type;
+	@Column(name = "zone_id", comment = "在服务器里面用的一个ID,基本是1")
+	private int zoneId;
+	@Column(comment = "别名")
+	private String alias;
+	@Column(name = "ip_port", comment = "IP与端口,填内网IP与端口")
+	private String ipPort;
+	@Column(comment = "数据库用户")
+	private String user;
+	@Column(comment = "数据库密码")
+	private String password;
+	@Column(name = "min_idle", comment = "最少空闲连接数")
+	private int minIdle;
+	@Column(name = "max_active", comment = "最大活跃连接数")
+	private int maxActive;
+	@Column(name = "max_wait_millis", comment = "最大等级时间")
+	private int maxWaitMillis;
+	
+	public int getZoneId() {
+		return zoneId;
+	}
+	public void setZoneId(int zoneId) {
+		this.zoneId = zoneId;
+	}
+	public String getAlias() {
+		return alias;
+	}
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+	public String getIpPort() {
+		return ipPort;
+	}
+	public void setIpPort(String ipPort) {
+		this.ipPort = ipPort;
+	}
+	public String getDbName() {
+		return dbName;
+	}
+	public void setDbName(String dbName) {
+		this.dbName = dbName;
+	}
+	public String getUser() {
+		return user;
+	}
+	public void setUser(String user) {
+		this.user = user;
+	}
+	public String getPassword() {
+		return password;
+	}
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	public int getMinIdle() {
+		return minIdle;
+	}
+	public void setMinIdle(int minIdle) {
+		this.minIdle = minIdle;
+	}
+	public int getMaxActive() {
+		return maxActive;
+	}
+	public void setMaxActive(int maxActive) {
+		this.maxActive = maxActive;
+	}
+	public int getMaxWaitMillis() {
+		return maxWaitMillis;
+	}
+	public void setMaxWaitMillis(int maxWaitMillis) {
+		this.maxWaitMillis = maxWaitMillis;
+	}
+	public int getPlatformId() {
+		return platformId;
+	}
+	public void setPlatformId(int platformId) {
+		this.platformId = platformId;
+	}
+	public int getServerId() {
+		return serverId;
+	}
+	public void setServerId(int serverId) {
+		this.serverId = serverId;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+}

+ 62 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GamePlatform.java

@@ -0,0 +1,62 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Table;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_platform", comment = "游戏平台表", dbAlias = "backstage")
+public class GamePlatform extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO, autoBase = 1000)
+	@Column(comment = "平台ID")
+	private long id;
+	@Column(comment = "平台名称")
+	private String name;
+	@Column(name = "user_id", comment = "操作员ID", readonly = true)
+	private long userId;
+	@Column(name = "user_name", comment = "操作员名称", readonly = true)
+	private String userName;
+	
+	@Override
+	public Long redisOwnerKey() {
+		return 0L;
+	}
+	@Override
+	public Long redisHashKey() {
+		return id;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public long getUserId() {
+		return userId;
+	}
+	public void setUserId(long userId) {
+		this.userId = userId;
+	}
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+}

+ 81 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameRegion.java

@@ -0,0 +1,81 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.enuma.IndexType;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_region", comment = "游戏大区表", dbAlias = "backstage", indexs = {
+		@Index(name = "channelid_regionid", columns = { "channel_id", "region_id" }, type = IndexType.UNIQUE) })
+public class GameRegion extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO, autoBase = 1)
+	@Column(comment = "数据唯一ID")
+	private long id;
+	@Column(name = "region_id", comment = "大区ID")
+	private int regionId;
+	@Column(comment = "大区名称")
+	private String name;
+	@Column(name = "channel_id", comment = "渠道ID", readonly = true)
+	private long channelId;
+	@Column(name = "channel_name", comment = "渠道名字")
+	private String channelName;
+	@Column(name = "server_type", comment = "服务器类型,1测试服,2审核服,3正式服")
+	private int serverType;
+	
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	@Override
+	public Long redisOwnerKey() {
+		return channelId;
+	}
+	@Override
+	public Long redisHashKey() {
+		return (long)regionId;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public long getChannelId() {
+		return channelId;
+	}
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+	public int getRegionId() {
+		return regionId;
+	}
+	public void setRegionId(int regionId) {
+		this.regionId = regionId;
+	}
+	public String getChannelName() {
+		return channelName;
+	}
+	public void setChannelName(String channelName) {
+		this.channelName = channelName;
+	}
+	public int getServerType() {
+		return serverType;
+	}
+	public void setServerType(int serverType) {
+		this.serverType = serverType;
+	}
+}

+ 256 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameServer.java

@@ -0,0 +1,256 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import java.time.LocalDateTime;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.enuma.IndexType;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_server", comment = "游戏服务器表", dbAlias = "backstage", indexs = {
+		@Index(name = "platformid_serverid", columns = { "platform_id", "server_id" }, type = IndexType.UNIQUE) })
+public class GameServer extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO, autoBase = 10000)
+	@Column(comment = "数据唯一ID")
+	private int id;
+	@Column(name = "platform_id", comment = "归属平台ID", readonly = true)
+	private long platformId;
+	@Column(name = "platform_name", comment = "归属平台名称")
+	private String platformName;
+	@Column(name = "server_id", comment = "服务器ID", readonly = true)
+	private int serverId;
+	@Column(comment = "服务器名字")
+	private String name;
+	@Column(name = "server_type", comment = "服务器类型,1测试服,2审核服,3正式服")
+	private int serverType;
+	@Column(name = "socket_type", comment = "socket连接方式")
+	private String socketType;
+	@Column(name = "external_ip", comment = "外网IP")
+	private String externalIp;
+	@Column(name = "internal_ip", comment = "内网IP")
+	private String internalIp;
+	@Column(name = "tcp_port", comment = "tcp/ws端口")
+	private int tcpPort;
+	@Column(name = "http_port", comment = "http端口")
+	private int httpPort;
+	@Column(name = "db_game_name", comment = "游戏数据库名")
+	private String dbGameName;
+	@Column(name = "db_log_name", comment = "日志数据库名")
+	private String dbLogName;
+	@Column(comment = "状态,0维护,1流畅,2爆满,3新服")
+	private int status;
+	@Column(comment = "是否为推荐服务器")
+	private boolean recommend;
+	@Column(name = "open_time", comment = "预期开服时间")
+	private LocalDateTime openTime = LocalDateTime.now();
+	@Column(name = "real_open_time", comment = "实际开服时间")
+	private LocalDateTime realOpenTime = LocalDateTime.now();
+	@Column(name = "send_open_status", comment = "开服时间是否发送成功,0未发送,1成功,2失败")
+	private int sendOpenStatus;
+	@Column(comment = "服务器是否维护中")
+	private boolean maintain;
+	@Column(name = "maintain_response", comment = "服务器维护消息是否发送成功")
+	private boolean maintainResponse;
+	@Column(comment = "服务器是否已被合服")
+	private boolean merge;
+	@Column(comment = "是否隐藏入口")
+	private boolean hide;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getExternalIp() {
+		return externalIp;
+	}
+
+	public void setExternalIp(String externalIp) {
+		this.externalIp = externalIp;
+	}
+
+	public String getInternalIp() {
+		return internalIp;
+	}
+
+	public void setInternalIp(String internalIp) {
+		this.internalIp = internalIp;
+	}
+
+	public int getTcpPort() {
+		return tcpPort;
+	}
+
+	public void setTcpPort(int tcpPort) {
+		this.tcpPort = tcpPort;
+	}
+
+	public int getHttpPort() {
+		return httpPort;
+	}
+
+	public void setHttpPort(int httpPort) {
+		this.httpPort = httpPort;
+	}
+
+	public String getDbGameName() {
+		return dbGameName;
+	}
+
+	public void setDbGameName(String dbGameName) {
+		this.dbGameName = dbGameName;
+	}
+
+	public String getDbLogName() {
+		return dbLogName;
+	}
+
+	public void setDbLogName(String dbLogName) {
+		this.dbLogName = dbLogName;
+	}
+
+	public int getStatus() {
+		return status;
+	}
+
+	public void setStatus(int status) {
+		this.status = status;
+	}
+
+	public LocalDateTime getOpenTime() {
+		return openTime;
+	}
+
+	public void setOpenTime(LocalDateTime openTime) {
+		this.openTime = openTime;
+	}
+
+	public boolean isRecommend() {
+		return recommend;
+	}
+
+	public void setRecommend(boolean recommend) {
+		this.recommend = recommend;
+	}
+
+	@Override
+	public Long redisOwnerKey() {
+		return 0L;
+	}
+
+	@Override
+	public Long redisHashKey() {
+		return (long) id;
+	}
+
+	public int getServerId() {
+		return serverId;
+	}
+
+	public void setServerId(int serverId) {
+		this.serverId = serverId;
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
+	}
+
+	public LocalDateTime getRealOpenTime() {
+		return realOpenTime;
+	}
+
+	public void setRealOpenTime(LocalDateTime realOpenTime) {
+		this.realOpenTime = realOpenTime;
+	}
+
+	public int getSendOpenStatus() {
+		return sendOpenStatus;
+	}
+
+	public void setSendOpenStatus(int sendOpenStatus) {
+		this.sendOpenStatus = sendOpenStatus;
+	}
+
+	public long getPlatformId() {
+		return platformId;
+	}
+
+	public void setPlatformId(long platformId) {
+		this.platformId = platformId;
+	}
+
+	public String getPlatformName() {
+		return platformName;
+	}
+
+	public void setPlatformName(String platformName) {
+		this.platformName = platformName;
+	}
+
+	public boolean isMaintain() {
+		return maintain;
+	}
+
+	public void setMaintain(boolean maintain) {
+		this.maintain = maintain;
+	}
+
+	public boolean isMaintainResponse() {
+		return maintainResponse;
+	}
+
+	public void setMaintainResponse(boolean maintainResponse) {
+		this.maintainResponse = maintainResponse;
+	}
+
+	public boolean isMerge() {
+		return merge;
+	}
+
+	public void setMerge(boolean merge) {
+		this.merge = merge;
+	}
+
+	public int getServerType() {
+		return serverType;
+	}
+
+	public void setServerType(int serverType) {
+		this.serverType = serverType;
+	}
+
+	public String getSocketType() {
+		return socketType;
+	}
+
+	public void setSocketType(String socketType) {
+		this.socketType = socketType;
+	}
+
+	public boolean isHide() {
+		return hide;
+	}
+
+	public void setHide(boolean hide) {
+		this.hide = hide;
+	}
+}

+ 136 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/GameServerRuntime.java

@@ -0,0 +1,136 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import java.time.LocalDateTime;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Table;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "game_server_runtime", comment = "游戏服务器运行数据表", dbAlias = "backstage")
+public class GameServerRuntime extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.IDENTITY)
+	@Column(name = "server_uid", comment = "服务器唯一ID")
+	private int serverUid;
+	@Column(name = "register_num", comment = "注册数")
+	private int registerNum;
+	@Column(name = "create_num", comment = "创角数")
+	private int createNum;
+	@Column(name = "online_num", comment = "在线数")
+	private int onlineNum;
+	@Column(name = "battle_num", comment = "战斗数")
+	private int battleNum;
+	@Column(name = "curr_battle_num", comment = "当前战斗数")
+	private int currBattleNum;
+	@Column(comment = "服务器是否正常运行")
+	private boolean running;
+	@Column(name = "heart_time", comment = "最后心跳时间")
+	private LocalDateTime heartTime = LocalDateTime.now();
+	@Column(name = "max_memory", comment = "最大可用内存")
+	private String maxMemory;
+	@Column(name = "free_memory", comment = "空闲内存")
+	private String freeMemory;
+	@Column(name = "total_memory", comment = "占用内存(占用内存=空闲内存+实际使用内存)")
+	private String totalMemory;
+	@Column(name = "used_memory", comment = "实际使用内存")
+	private String usedMemory;
+	@Column(name = "left_memory", comment = "剩余可用内存(剩余可用内存=最大可用内存-实际使用内存)")
+	private String leftMemory;
+	
+	public int getServerUid() {
+		return serverUid;
+	}
+	public void setServerUid(int serverUid) {
+		this.serverUid = serverUid;
+	}
+	public int getRegisterNum() {
+		return registerNum;
+	}
+	public void setRegisterNum(int registerNum) {
+		this.registerNum = registerNum;
+	}
+	public int getCreateNum() {
+		return createNum;
+	}
+	public void setCreateNum(int createNum) {
+		this.createNum = createNum;
+	}
+	public int getOnlineNum() {
+		return onlineNum;
+	}
+	public void setOnlineNum(int onlineNum) {
+		this.onlineNum = onlineNum;
+	}
+	public int getBattleNum() {
+		return battleNum;
+	}
+	public void setBattleNum(int battleNum) {
+		this.battleNum = battleNum;
+	}
+	public int getCurrBattleNum() {
+		return currBattleNum;
+	}
+	public void setCurrBattleNum(int currBattleNum) {
+		this.currBattleNum = currBattleNum;
+	}
+	public boolean isRunning() {
+		return running;
+	}
+	public void setRunning(boolean running) {
+		this.running = running;
+	}
+	public LocalDateTime getHeartTime() {
+		return heartTime;
+	}
+	public void setHeartTime(LocalDateTime heartTime) {
+		this.heartTime = heartTime;
+	}
+	@Override
+	public Long redisOwnerKey() {
+		return 0L;
+	}
+	@Override
+	public Long redisHashKey() {
+		return (long)serverUid;
+	}
+	public String getMaxMemory() {
+		return maxMemory;
+	}
+	public void setMaxMemory(String maxMemory) {
+		this.maxMemory = maxMemory;
+	}
+	public String getFreeMemory() {
+		return freeMemory;
+	}
+	public void setFreeMemory(String freeMemory) {
+		this.freeMemory = freeMemory;
+	}
+	public String getTotalMemory() {
+		return totalMemory;
+	}
+	public void setTotalMemory(String totalMemory) {
+		this.totalMemory = totalMemory;
+	}
+	public String getUsedMemory() {
+		return usedMemory;
+	}
+	public void setUsedMemory(String usedMemory) {
+		this.usedMemory = usedMemory;
+	}
+	public String getLeftMemory() {
+		return leftMemory;
+	}
+	public void setLeftMemory(String leftMemory) {
+		this.leftMemory = leftMemory;
+	}
+}

+ 104 - 0
x1-backstage/src/main/java/com/xiugou/x1/backstage/module/gameserver/model/UserChannel.java

@@ -0,0 +1,104 @@
+/**
+ * 
+ */
+package com.xiugou.x1.backstage.module.gameserver.model;
+
+import org.gaming.backstage.service.OneToManyRedisHashEntity;
+import org.gaming.db.annotation.Column;
+import org.gaming.db.annotation.Id;
+import org.gaming.db.annotation.Id.Strategy;
+import org.gaming.db.annotation.Index;
+import org.gaming.db.annotation.Table;
+import org.gaming.db.annotation.enuma.IndexType;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author YY
+ *
+ */
+@Repository
+@Table(name = "user_channel", comment = "用户渠道表", dbAlias = "backstage", indexs = {
+		@Index(name = "userId_channelId", columns = { "user_id", "channel_id" }, type = IndexType.UNIQUE) })
+public class UserChannel extends OneToManyRedisHashEntity {
+	@Id(strategy = Strategy.AUTO)
+	@Column(comment = "唯一ID")
+	private long id;
+	@Column(name = "user_id", comment = "用户ID")
+	private long userId;
+	@Column(name = "user_name", comment = "用户名称")
+	private String userName;
+	@Column(name = "channel_id", comment = "渠道ID")
+	private long channelId;
+	@Column(name = "channel_name", comment = "渠道名称")
+	private String channelName;
+	@Column(name = "grant_user_id", comment = "授权的用户ID")
+	private long grantUserId;
+	@Column(name = "grant_user_name", comment = "授权的用户名称")
+	private String grantUserName;
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	public long getUserId() {
+		return userId;
+	}
+
+	public void setUserId(long userId) {
+		this.userId = userId;
+	}
+
+	public String getUserName() {
+		return userName;
+	}
+
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+
+	public long getChannelId() {
+		return channelId;
+	}
+
+	public void setChannelId(long channelId) {
+		this.channelId = channelId;
+	}
+
+	public String getChannelName() {
+		return channelName;
+	}
+
+	public void setChannelName(String channelName) {
+		this.channelName = channelName;
+	}
+
+	public long getGrantUserId() {
+		return grantUserId;
+	}
+
+	public void setGrantUserId(long grantUserId) {
+		this.grantUserId = grantUserId;
+	}
+
+	public String getGrantUserName() {
+		return grantUserName;
+	}
+
+	public void setGrantUserName(String grantUserName) {
+		this.grantUserName = grantUserName;
+	}
+
+	@Override
+	public Long redisOwnerKey() {
+		return userId;
+	}
+
+	@Override
+	public Long redisHashKey() {
+		return channelId;
+	}
+}

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff