Browse Source

init from phab

xielq 4 years ago
parent
commit
e43dea672d
100 changed files with 4472 additions and 1275 deletions
  1. 4 2
      build.gradle
  2. 5 0
      develop.md
  3. 1 1
      src/main/docker/Dockerfile
  4. 34 7
      src/main/java/com/uas/demo/api/ChatApiController.java
  5. 5 15
      src/main/java/com/uas/demo/api/ChatSessionController.java
  6. 5 0
      src/main/java/com/uas/demo/api/FileController.java
  7. 184 0
      src/main/java/com/uas/demo/api/GroupController.java
  8. 14 15
      src/main/java/com/uas/demo/api/MessageController.java
  9. 16 0
      src/main/java/com/uas/demo/configuration/CorsConfig.java
  10. 21 0
      src/main/java/com/uas/demo/configuration/MongoConfig.java
  11. 25 0
      src/main/java/com/uas/demo/dao/ChatInfoDao.java
  12. 3 3
      src/main/java/com/uas/demo/dao/ChatSessionDao.java
  13. 16 0
      src/main/java/com/uas/demo/dao/EnterpriseDao.java
  14. 15 0
      src/main/java/com/uas/demo/dao/GroupInfoDao.java
  15. 0 15
      src/main/java/com/uas/demo/dao/MessageCountDao.java
  16. 22 4
      src/main/java/com/uas/demo/dao/MessageDao.java
  17. 3 1
      src/main/java/com/uas/demo/dao/UserDao.java
  18. 23 0
      src/main/java/com/uas/demo/dao/UserInfoDao.java
  19. 23 0
      src/main/java/com/uas/demo/facade/ChatInfoFacade.java
  20. 145 0
      src/main/java/com/uas/demo/facade/impl/ChatInfoFacadeImpl.java
  21. 9 3
      src/main/java/com/uas/demo/facade/impl/MessageFacadeImpl.java
  22. 143 0
      src/main/java/com/uas/demo/model/ChatInfo.java
  23. 165 0
      src/main/java/com/uas/demo/model/ChatInfoDto.java
  24. 181 32
      src/main/java/com/uas/demo/model/ChatSession.java
  25. 109 0
      src/main/java/com/uas/demo/model/Enterprise.java
  26. 135 0
      src/main/java/com/uas/demo/model/GroupInfo.java
  27. 212 175
      src/main/java/com/uas/demo/model/Message.java
  28. 0 81
      src/main/java/com/uas/demo/model/MessageCount.java
  29. 8 0
      src/main/java/com/uas/demo/model/StoreType.java
  30. 97 0
      src/main/java/com/uas/demo/model/UserInfo.java
  31. 6 0
      src/main/java/com/uas/demo/model/UserType.java
  32. 19 0
      src/main/java/com/uas/demo/monitor/MongoMonitor.java
  33. 22 0
      src/main/java/com/uas/demo/service/ChatInfoService.java
  34. 8 9
      src/main/java/com/uas/demo/service/ChatSessionService.java
  35. 14 0
      src/main/java/com/uas/demo/service/EnterpriseService.java
  36. 85 0
      src/main/java/com/uas/demo/service/GroupInfoService.java
  37. 0 13
      src/main/java/com/uas/demo/service/MessageCountService.java
  38. 23 3
      src/main/java/com/uas/demo/service/MessageService.java
  39. 22 0
      src/main/java/com/uas/demo/service/UserInfoService.java
  40. 83 0
      src/main/java/com/uas/demo/service/impl/ChatInfoServiceImpl.java
  41. 8 4
      src/main/java/com/uas/demo/service/impl/ChatServiceImpl.java
  42. 53 44
      src/main/java/com/uas/demo/service/impl/ChatSessionServiceImpl.java
  43. 31 0
      src/main/java/com/uas/demo/service/impl/EnterpriseServiceImpl.java
  44. 211 0
      src/main/java/com/uas/demo/service/impl/GroupInfoServiceImpl.java
  45. 0 66
      src/main/java/com/uas/demo/service/impl/MessageCountServiceImpl.java
  46. 226 131
      src/main/java/com/uas/demo/service/impl/MessageServiceImpl.java
  47. 60 0
      src/main/java/com/uas/demo/service/impl/UserInfoServiceImpl.java
  48. 20 7
      src/main/java/com/uas/demo/web/ChatController.java
  49. 1 1
      src/main/java/com/uas/demo/web/HomeController.java
  50. 6 6
      src/main/java/com/uas/demo/web/UserController.java
  51. 14 0
      src/main/resources/application-dev.yml
  52. 14 0
      src/main/resources/application-prod.yml
  53. 2 13
      src/main/resources/application.yml
  54. 0 91
      src/main/resources/static/app/app.js
  55. 885 193
      src/main/resources/static/app/client.js
  56. 22 0
      src/main/resources/static/app/common/data-service.js
  57. 48 24
      src/main/resources/static/app/common/xmpp-client.js
  58. 84 11
      src/main/resources/static/app/index.js
  59. 6 3
      src/main/resources/static/app/model/message.js
  60. 0 187
      src/main/resources/static/app/private.js
  61. 14 0
      src/main/resources/static/app/service/chat-service.js
  62. 81 0
      src/main/resources/static/app/service/group-service.js
  63. 15 3
      src/main/resources/static/app/service/message-service.js
  64. 4 8
      src/main/resources/static/app/service/session-service.js
  65. 3 2
      src/main/resources/static/lib/css/jquery.emoji.css
  66. 0 43
      src/main/resources/static/login.html
  67. 759 59
      src/main/resources/static/style/css/chat.css
  68. BIN
      src/main/resources/static/style/img/arrow-right.png
  69. BIN
      src/main/resources/static/style/img/close.png
  70. BIN
      src/main/resources/static/style/img/double-active.png
  71. BIN
      src/main/resources/static/style/img/double.png
  72. BIN
      src/main/resources/static/style/img/left.png
  73. BIN
      src/main/resources/static/style/img/loading.gif
  74. BIN
      src/main/resources/static/style/img/magnifier.png
  75. BIN
      src/main/resources/static/style/img/photo01.png
  76. BIN
      src/main/resources/static/style/img/qq/1.gif
  77. BIN
      src/main/resources/static/style/img/qq/10.gif
  78. BIN
      src/main/resources/static/style/img/qq/100.gif
  79. BIN
      src/main/resources/static/style/img/qq/101.gif
  80. BIN
      src/main/resources/static/style/img/qq/102.gif
  81. BIN
      src/main/resources/static/style/img/qq/103.gif
  82. BIN
      src/main/resources/static/style/img/qq/104.gif
  83. BIN
      src/main/resources/static/style/img/qq/105.gif
  84. BIN
      src/main/resources/static/style/img/qq/106.gif
  85. BIN
      src/main/resources/static/style/img/qq/107.gif
  86. BIN
      src/main/resources/static/style/img/qq/108.gif
  87. BIN
      src/main/resources/static/style/img/qq/109.gif
  88. BIN
      src/main/resources/static/style/img/qq/11.gif
  89. BIN
      src/main/resources/static/style/img/qq/110.gif
  90. BIN
      src/main/resources/static/style/img/qq/111.gif
  91. BIN
      src/main/resources/static/style/img/qq/112.gif
  92. BIN
      src/main/resources/static/style/img/qq/113.gif
  93. BIN
      src/main/resources/static/style/img/qq/114.gif
  94. BIN
      src/main/resources/static/style/img/qq/115.gif
  95. BIN
      src/main/resources/static/style/img/qq/116.gif
  96. BIN
      src/main/resources/static/style/img/qq/117.gif
  97. BIN
      src/main/resources/static/style/img/qq/118.gif
  98. BIN
      src/main/resources/static/style/img/qq/119.gif
  99. BIN
      src/main/resources/static/style/img/qq/12.gif
  100. BIN
      src/main/resources/static/style/img/qq/120.gif

+ 4 - 2
build.gradle

@@ -2,7 +2,7 @@ buildscript {
 	ext {
 		springBootVersion = '1.5.3.RELEASE'
 		// 0.12.0 升级到了 Gradle 3.4,Gradle 2.14.1 只能使用 0.11.0及以下
-		dockerVersion = '0.11.0'
+		dockerVersion = '0.12.0'
 		dcokerRegistry = "10.10.100.200:5000"
 	}
 	repositories {
@@ -18,7 +18,7 @@ buildscript {
 }
 
 group 'com.uas.demo.im'
-version '0.1.9'
+version '0.2.0'
 
 apply plugin: 'java'
 apply plugin: "com.palantir.docker"
@@ -49,5 +49,7 @@ dependencies {
 	compile("org.webjars:bootstrap:3.3.7")
 	compile("org.webjars:jquery:3.1.0")
 
+	compile("org.springframework.boot:spring-boot-starter-actuator")
+
 	testCompile("org.springframework.boot:spring-boot-starter-test")
 }

+ 5 - 0
develop.md

@@ -1,4 +1,9 @@
 # Develop Log
 
+version 0.1.9
 * feature 002: add emoji support
 
+version 0.2.0
+* feature 003: change message to 2 types, text, image and file.Dispatch message to one enterprise's someone.Count unread message for notifying the contact.
+
+

+ 1 - 1
src/main/docker/Dockerfile

@@ -3,4 +3,4 @@ VOLUME /tmp
 ADD web-chat.jar app.jar
 RUN sh -c "touch /app.jar"
 ENV JAVA_OPTS=""
-ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar --spring.profiles.active=test"]
+ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar --spring.profiles.active=prod"]

+ 34 - 7
src/main/java/com/uas/demo/api/ChatApiController.java

@@ -1,11 +1,11 @@
 package com.uas.demo.api;
 
+import com.uas.demo.facade.ChatInfoFacade;
+import com.uas.demo.model.ChatInfoDto;
 import com.uas.demo.service.ChatService;
+import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.Map;
 
@@ -13,11 +13,16 @@ import java.util.Map;
 @RequestMapping(value = "/api/chat/infos")
 public class ChatApiController {
 
+	private Logger logger = Logger.getLogger(getClass());
+
 	private final ChatService chatService;
 
+	private final ChatInfoFacade chatInfoFacade;
+
 	@Autowired
-	public ChatApiController(ChatService chatService) {
+	public ChatApiController(ChatService chatService, ChatInfoFacade chatInfoFacade) {
 		this.chatService = chatService;
+		this.chatInfoFacade = chatInfoFacade;
 	}
 
 	/**
@@ -26,9 +31,9 @@ public class ChatApiController {
 	 * @param from		信息发送者的手机号
 	 * @param to		信息接收者的手机号
 	 */
-	@ResponseBody
 	@RequestMapping(method = RequestMethod.GET, params = "condition=phone")
 	public Map<String, String> findChatUserInfo(String from, String to) {
+		logger.info(String.format("User find information by phone[from: %s, to: %s]", from, to));
 		return chatService.findChatUserInfo(from, to);
 	}
 
@@ -38,10 +43,32 @@ public class ChatApiController {
 	 * @param from		信息发送者的UserId
 	 * @param to		信息接收者的UserId
 	 */
-	@ResponseBody
 	@RequestMapping(method = RequestMethod.GET, params = "condition=userid")
 	public Map<String, String> findChatUserInfoByUserId(String from, String to) {
+		logger.info(String.format("User find information by user id[from: %s, to: %s]", from, to));
 		return chatService.findChatUserInfoByUserId(from, to);
 	}
 
+	/**
+	 * 当用户访问会话列表或发起客服,生成会话信息
+	 *
+	 * @param chatInfoDto		聊天信息
+	 */
+	@RequestMapping(method = RequestMethod.POST, params = "condition=chat_info")
+	public Map<String, Object> generateChatInfoWhenUserVisitListOrChat(@RequestBody ChatInfoDto chatInfoDto) {
+		logger.info(String.format("Generate chat info when user visit list or chat, chat info %s", chatInfoDto.toString()));
+		return chatInfoFacade.generateChatInfoWhenUserVisitListOrChat(chatInfoDto);
+	}
+
+	/**
+	 * 用户访问网站时,根据聊天信息id获取聊天信息
+	 *
+	 * @param id    聊天信息ID
+	 */
+	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
+	public Map<String, Object> queryChatInfoWhenUserVisitWebSite(@PathVariable("id") String id) {
+		logger.info(String.format("Query chat info[%s] when user visit web site", id));
+		return chatInfoFacade.queryChatInfoWhenUserVisitWebSite(id);
+	}
+
 }

+ 5 - 15
src/main/java/com/uas/demo/api/ChatSessionController.java

@@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
-import java.util.Map;
 
 @RestController
 @RequestMapping(value = "/api/chat/session")
@@ -22,21 +21,12 @@ public class ChatSessionController {
 		this.chatSessionService = chatSessionService;
 	}
 
-	@RequestMapping(method = RequestMethod.GET, params = "operate=refresh")
-	public List<ChatSession> loadSessionsWhenUserRefresh(String ownId) {
-		logger.info(String.format("Load sessions when user %s refresh website", ownId));
-		return chatSessionService.loadSessionsWhenUserRefresh(ownId);
+	@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
+	public List<ChatSession> updateSessionStateWhenUserSwitchNewSession(@PathVariable("id") String id) {
+		logger.info("Update session when user switch new session [" + id + "]");
+		return chatSessionService.updateSessionStateWhenUserSwitchNewSession(id);
 	}
 
-	@RequestMapping(method = RequestMethod.POST)
-	public ChatSession persistSessionWhenUserSendMessage(@RequestBody ChatSession session) {
-		logger.info("Persist session when user send message " + session.toString());
-		return chatSessionService.persistSessionWhenUserSendMessage(session);
-	}
 
-	@RequestMapping(method = RequestMethod.GET, params = "operate=count_unread")
-	public Map<String, String> countUnReadSessionsWhenUserQuery(String phone) {
-		logger.info(String.format("Count unread sessions when user %s query", phone));
-		return chatSessionService.countUnReadSessionsWhenUserQuery(phone);
-	}
+
 }

+ 5 - 0
src/main/java/com/uas/demo/api/FileController.java

@@ -1,6 +1,7 @@
 package com.uas.demo.api;
 
 import org.apache.commons.io.FilenameUtils;
+import org.apache.log4j.Logger;
 import org.springframework.core.io.FileSystemResource;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
@@ -20,6 +21,8 @@ import java.net.URI;
 @RequestMapping(value = "/api/utils/file")
 public class FileController {
 
+	private final Logger logger = Logger.getLogger(getClass());
+
 	private RestTemplate restTemplate;
 
 	public FileController() {
@@ -51,6 +54,8 @@ public class FileController {
 				.toUri();
 		headers.setLocation(uri);
 
+		logger.info(String.format("Upload file[%s]", fileUrl));
+
 		return new ResponseEntity<>(fileUrl, headers, HttpStatus.CREATED);
 	}
 }

+ 184 - 0
src/main/java/com/uas/demo/api/GroupController.java

@@ -0,0 +1,184 @@
+package com.uas.demo.api;
+
+import com.uas.demo.facade.ChatInfoFacade;
+import com.uas.demo.model.ChatSession;
+import com.uas.demo.model.GroupInfo;
+import com.uas.demo.service.GroupInfoService;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by wangdy on 2017-09-11.
+ */
+@RestController
+@RequestMapping(value = "/api/chat/group")
+public class GroupController {
+    private Logger logger = Logger.getLogger(getClass());
+
+    private final GroupInfoService groupInfoService;
+
+    private final ChatInfoFacade chatInfoFacade;
+
+    @Autowired
+    public GroupController(GroupInfoService groupInfoService , ChatInfoFacade chatInfoFacade) {
+        this.groupInfoService = groupInfoService;
+        this.chatInfoFacade = chatInfoFacade;
+    }
+
+    /**
+     * 新增分组
+     */
+    @RequestMapping(method = RequestMethod.PUT)
+    public Map<String, Object> newGroup(@RequestParam(value = "ownid",required = true) String ownid,
+                                        @RequestParam(value = "groupName",required = true)String groupName) {
+        logger.info(String.format("User add group[id: %s, groupName: %s]", ownid, groupName));
+        Map<String, Object> result = new HashMap<>();
+        GroupInfo groupInfo = groupInfoService.createGroup(ownid, groupName);
+        if (groupInfo != null) {
+            result.put("success", true);
+            return result;
+        } else {
+            result.put("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 修改分组名
+     */
+    @RequestMapping(method = RequestMethod.POST)
+    public Map<String, Object> modifyGroup(@RequestParam(value = "ownid",required = true)String ownid,
+                                           @RequestParam(value = "groupName",required = true)String groupName,
+                                           @RequestParam(value = "newGroupName",required = true)String newgroupName) {
+        logger.info(String.format("User modify group[id: %s, groupName: %s]", ownid, groupName));
+        Map<String, Object> result = new HashMap<>();
+        GroupInfo groupInfo = groupInfoService.modifyGroup(ownid, groupName,newgroupName);
+        if (groupInfo != null) {
+            result.put("success", true);
+            return result;
+        } else {
+            result.put("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 删除当前分组
+     */
+    @RequestMapping(value = "/delete", method = RequestMethod.POST)
+    public Map<String, Object> deleteGroup(@RequestParam(value = "ownid",required = true)String ownid,
+                                           @RequestParam(value = "groupName",required = true)String groupName) {
+        logger.info(String.format("User delete group[id: %s, groupName: %s]", ownid, groupName));
+        Map<String, Object> result = new HashMap<>();
+        if (groupInfoService.deleteGroup(ownid, groupName)) {
+            result.put("success", true);
+            return result;
+        } else {
+            result.put("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 将好友移动到另一分组
+     */
+    @RequestMapping(value = "/fromto", method = RequestMethod.POST)
+    public Map<String, Object> fromToGroup(@RequestParam(value = "chatSessionId",required = true)String chatSessionId,
+                                           @RequestParam(value = "ownid",required = true)String ownid,
+                                           @RequestParam(value = "fromGroupName",required = true)String fromGroupName,
+                                           @RequestParam(value = "toGroupName",required = true)String toGroupName) {
+        logger.info(String.format("User from to other group[id: %s, newGroupName: %s]", ownid,toGroupName));
+        Map<String, Object> result = new HashMap<>();
+        if (groupInfoService.fromToGroup(chatSessionId, ownid, fromGroupName, toGroupName) != null) {
+            result.put("success", true);
+            return result;
+        } else {
+            result.put("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 从分组中删除该联系人
+     */
+    @RequestMapping(value = "/deleteLinkman", method = RequestMethod.POST)
+    public Map<String, Object> deletelinkman(@RequestParam(value = "chatSessionId",required = true)String chatSessionId,
+                                             @RequestParam(value = "ownerId",required = true)String ownerId,
+                                             @RequestParam(value = "groupName",required = true)String groupName) {
+        logger.info(String.format("User delete linkman from group[id: %s, groupName: %s]",ownerId,groupName));
+        Map<String, Object> result = new HashMap<>();
+        if (groupInfoService.deletelinkman( chatSessionId, ownerId, groupName) != null) {
+            result.put("success", true);
+            return result;
+        } else {
+            result.put("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 将联系人移到黑名单
+     */
+    @RequestMapping(value = "/setToBlack", method = RequestMethod.POST)
+    public Map<String, Object> setlinkmanToBlacklist(@RequestParam(value = "chatSessionId",required = true)String chatSessionId,
+                                                     @RequestParam(value = "ownerId",required = true)String ownerId,
+                                                     @RequestParam(value = "groupName",required = true)String groupName) {
+        logger.info(String.format("User move to black[id: %s, groupName: %s]",ownerId,groupName));
+        Map<String, Object> result = new HashMap<>();
+        if (groupInfoService.setlinkmanToBlacklist( chatSessionId, ownerId, groupName)!= null) {
+            result.put("success", true);
+            return result;
+        } else {
+            result.put("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 将联系人移出黑名单
+     */
+    @RequestMapping(value = "/setOutBlack", method = RequestMethod.POST)
+    public Map<String, Object> setlinkmanOutBlacklist( @RequestParam(value = "chatSessionId",required = true)String chatSessionId,
+                                                       @RequestParam(value = "ownerId",required = true)String ownerId,
+                                                       @RequestParam(value = "groupName",required = true,defaultValue = "黑名单")String groupName) {
+        logger.info(String.format("User move out group[id: %s, groupName: %s]",ownerId,groupName));
+        Map<String, Object> result = new HashMap<>();
+        if (groupInfoService.setlinkmanOutBlacklist( chatSessionId, ownerId, groupName) != null) {
+            result.put("success", true);
+            return result;
+        } else {
+            result.put("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 搜索联系人
+     */
+    @RequestMapping(value = "/searchLinkman", method = RequestMethod.GET)
+    public Map<String, Object> searchLinkman( @RequestParam(value = "keyword",required = true)String keyword,
+                                              @RequestParam(value = "ownerId",required = true)String ownerId) {
+        logger.info(String.format("User search linkman[id: %s, keyword: %s]",ownerId,keyword));
+        Map<String, Object> result = new HashMap<>();
+        if (keyword == null || "".equals(keyword)){
+            Map<String,Object> reMap = chatInfoFacade.queryChatInfoWhenUserVisitWebSite(ownerId);
+            if (null == reMap.get("sessions")){
+                return null;
+            }else {
+                List<ChatSession> res = (List<ChatSession>)reMap.get("sessions");
+                result.put("success", res);
+                return result;
+            }
+        }
+        result.put("success",groupInfoService.searchLinkman(keyword, ownerId));
+        return result;
+    }
+}

+ 14 - 15
src/main/java/com/uas/demo/api/MessageController.java

@@ -3,14 +3,10 @@ package com.uas.demo.api;
 import com.uas.demo.facade.MessageFacade;
 import com.uas.demo.model.ChatSession;
 import com.uas.demo.model.Message;
-import com.uas.demo.service.MessageCountService;
 import com.uas.demo.service.MessageService;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 import java.util.Map;
@@ -25,13 +21,10 @@ public class MessageController {
 
 	private final MessageFacade messageFacade;
 
-	private final MessageCountService messageCountService;
-
 	@Autowired
-	public MessageController(MessageService messageService, MessageFacade messageFacade, MessageCountService messageCountService) {
+	public MessageController(MessageService messageService, MessageFacade messageFacade) {
 		this.messageService = messageService;
 		this.messageFacade = messageFacade;
-		this.messageCountService = messageCountService;
 	}
 
 	@RequestMapping(method = RequestMethod.POST)
@@ -41,14 +34,20 @@ public class MessageController {
 	}
 
 	@RequestMapping(method = RequestMethod.GET, params = "operate=user_read")
-	public List<Message> loadReadableMessageWhenUserRead(String sender, String receiver) {
-		logger.info(String.format("Load readable message when user %s read message from sender %s", receiver, sender));
-		return messageService.loadReadableMessageWhenUserRead(sender, receiver);
+	public List<Message> loadReadableMessageWhenUserRead(String owner, String contact) {
+		logger.info(String.format("Load readable message when user %s read message from contact %s", owner, contact));
+		return messageService.loadReadableMessageWhenUserRead(owner, contact);
 	}
 
 	@RequestMapping(method = RequestMethod.GET, params = "operate=count_unread")
-	public Map<String, String> countUnReadMessageWhenUserQuery(String phone) {
-		logger.info(String.format("Count unread message when user %s query", phone));
-		return messageCountService.countUnReadMessageWhenUserQuery(phone);
+	public Map<String, String> countUnReadMessageWhenUserQuery(String phone, Long enUU) {
+		logger.info(String.format("Count unread message when user %s %s query", phone, enUU));
+		return messageService.countUnReadMessageWhenUserQuery(phone, enUU);
+	}
+
+	@RequestMapping(method = RequestMethod.GET, params = "operate=history_message")
+	public List<Message> loadHistoryMessage(String owner, String contact, @RequestParam(required = false) Long max, @RequestParam(required = false) Long min) {
+		logger.info(String.format("Load history message(%s, %s) from %d to %d", owner, contact, min, max));
+		return messageService.loadHistoryMessage(owner, contact, max, min);
 	}
 }

+ 16 - 0
src/main/java/com/uas/demo/configuration/CorsConfig.java

@@ -0,0 +1,16 @@
+package com.uas.demo.configuration;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@Configuration
+public class CorsConfig extends WebMvcConfigurerAdapter {
+
+	@Override
+	public void addCorsMappings(CorsRegistry registry) {
+		registry.addMapping("/api/**")
+				.allowedOrigins("*")
+				.allowedMethods("*");
+	}
+}

+ 21 - 0
src/main/java/com/uas/demo/configuration/MongoConfig.java

@@ -0,0 +1,21 @@
+package com.uas.demo.configuration;
+
+import com.mongodb.Mongo;
+import com.mongodb.MongoClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.mongodb.core.MongoTemplate;
+
+@Configuration
+public class MongoConfig {
+
+/*	public @Bean
+	Mongo mongo() throws Exception {
+		return new MongoClient("10.10.100.22:27017");
+	}
+
+	public @Bean
+	MongoTemplate mongoTemplate() throws Exception {
+		return new MongoTemplate(mongo(), "im_infos");
+	}*/
+}

+ 25 - 0
src/main/java/com/uas/demo/dao/ChatInfoDao.java

@@ -0,0 +1,25 @@
+package com.uas.demo.dao;
+
+import com.uas.demo.model.ChatInfo;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ChatInfoDao extends MongoRepository<ChatInfo, String> {
+
+	/**
+	 * 获取当前用户当前企业的聊天信息
+	 *
+	 * @param userId	当前用户User Id
+	 * @param enUU		当前企业UU
+	 */
+	ChatInfo findByUserIdAndEnUU(String userId, Long enUU);
+
+	/**
+	 * 获取当前用户当前企业的聊天信息
+	 *
+	 * @param phone		当前用户手机号
+	 * @param enUU		当前企业UU
+	 */
+	ChatInfo findByPhoneAndEnUU(String phone, Long enUU);
+}

+ 3 - 3
src/main/java/com/uas/demo/dao/ChatSessionDao.java

@@ -9,9 +9,9 @@ import java.util.List;
 @Repository
 public interface ChatSessionDao extends MongoRepository<ChatSession, String> {
 
-	List<ChatSession> findByOwn(String own);
+	List<ChatSession> findByOwner(String owner);
 
-	ChatSession findByOwnAndRelateUser(String own, String relateUser);
+	List<ChatSession> findByOwnerAndCurrent(String owner, Boolean current);
 
-	Long countByOwnAndRead(String own, Boolean read);
+	ChatSession findByOwnerAndLinkman(String owner, String linkman);
 }

+ 16 - 0
src/main/java/com/uas/demo/dao/EnterpriseDao.java

@@ -0,0 +1,16 @@
+package com.uas.demo.dao;
+
+import com.uas.demo.model.Enterprise;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface EnterpriseDao extends MongoRepository<Enterprise, String> {
+
+	/**
+	 * 根据企业UU获取缓存的企业信息(包含店铺信息,如果有)
+	 *
+	 * @param enUU		企业UU
+	 */
+	Enterprise findByEnUU(Long enUU);
+}

+ 15 - 0
src/main/java/com/uas/demo/dao/GroupInfoDao.java

@@ -0,0 +1,15 @@
+package com.uas.demo.dao;
+
+import com.uas.demo.model.GroupInfo;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface GroupInfoDao extends MongoRepository<GroupInfo, String> {
+
+    List<GroupInfo> findByUserIdOrderByCreateTimeAsc(String owner);
+
+    List<GroupInfo> findByUserIdAndGroupName(String owner, String groupName);
+}

+ 0 - 15
src/main/java/com/uas/demo/dao/MessageCountDao.java

@@ -1,15 +0,0 @@
-package com.uas.demo.dao;
-
-import com.uas.demo.model.MessageCount;
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.stereotype.Repository;
-
-import java.util.List;
-
-@Repository
-public interface MessageCountDao extends MongoRepository<MessageCount, String> {
-
-	MessageCount findByOwnerIdAndSenderId(String ownerId, String senderId);
-
-	List<MessageCount> findByOwnerId(String ownerId);
-}

+ 22 - 4
src/main/java/com/uas/demo/dao/MessageDao.java

@@ -12,11 +12,10 @@ public interface MessageDao extends MongoRepository<Message, String> {
 	/**
 	 * 根据发起者和接收者获取相应状态的消息缓存
 	 *
-	 * @param sender		消息的发送者
-	 * @param receiver		消息的接受者
-	 * @param read			消息是否已读
+	 * @param senderInfo		消息的发送者信息
+	 * @param read				消息是否已读
 	 */
-	List<Message> findBySenderAndReceiverAndReadOrderByTimeSendAsc(String sender, String receiver, Boolean read);
+	List<Message> findBySenderInfoAndOwnAndReadOrderByTimeSendAsc(String senderInfo, String own, Boolean read);
 
 	/**
 	 * 获取当前用户的前3条消息
@@ -26,4 +25,23 @@ public interface MessageDao extends MongoRepository<Message, String> {
 	 * @param read			消息是否已读
 	 */
 	List<Message> findTop3ByOwnAndCommunicatorAndReadOrderByTimeSendDescStyleAsc(String own, String communicator, Boolean read);
+
+	/**
+	 * 统计用户的未读或已读消息的数量
+	 *
+	 * @param own		用户User Id
+	 * @param read		消息阅读状态
+	 */
+	Long countByOwnAndRead(String own, Boolean read);
+
+	/**
+	 * 查找该uuid是否已被保存
+	 * @param uuid
+	 * @param receiver
+	 * @param senderType
+	 * @return
+	 */
+	List<Message> findByUuidAndReceiverAndSenderType(String uuid, String receiver, String senderType);
+
+	List<Message> findByOwnAndCommunicatorAndTimeSendBetweenOrderByTimeSendAsc(String own, String communicator, Long max, Long min);
 }

+ 3 - 1
src/main/java/com/uas/demo/dao/UserDao.java

@@ -6,11 +6,13 @@ import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
+
 @Repository
 public interface UserDao extends JpaRepository<User, Long> {
 
 	@Query(value = "SELECT u FROM User u where u.phone = :phone and u.app = 'im'")
-	User findByPhone(@Param("phone") String phone);
+	List<User> findByPhone(@Param("phone") String phone);
 
 	@Query(value = "SELECT u FROM User u where u.userId = :userId and u.app = 'im'")
 	User findByUserId(@Param("userId") String userId);

+ 23 - 0
src/main/java/com/uas/demo/dao/UserInfoDao.java

@@ -0,0 +1,23 @@
+package com.uas.demo.dao;
+
+import com.uas.demo.model.UserInfo;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserInfoDao extends MongoRepository<UserInfo, String> {
+
+	/**
+	 * 根据手机号获取用户信息
+	 *
+	 * @param phone		手机号
+	 */
+	UserInfo findByPhone(String phone);
+
+	/**
+	 * 根据用户ID获取用户信息
+	 *
+	 * @param userId	用户User Id
+	 */
+	UserInfo findByUserId(String userId);
+}

+ 23 - 0
src/main/java/com/uas/demo/facade/ChatInfoFacade.java

@@ -0,0 +1,23 @@
+package com.uas.demo.facade;
+
+import com.uas.demo.model.ChatInfoDto;
+
+import java.util.Map;
+
+public interface ChatInfoFacade {
+
+	/**
+	 * 当用户访问会话列表或发起客服,生成会话信息
+	 *
+	 * @param chatInfoDto		聊天信息
+	 */
+	Map<String, Object> generateChatInfoWhenUserVisitListOrChat(ChatInfoDto chatInfoDto);
+
+	/**
+	 * 当用户访问客服系统时,根据联系信息id获取聊天信息,并带出当前用户当前账套的
+	 * 会话列表信息
+	 *
+	 * @param id	聊天信息Id
+	 */
+	Map<String, Object> queryChatInfoWhenUserVisitWebSite(String id);
+}

+ 145 - 0
src/main/java/com/uas/demo/facade/impl/ChatInfoFacadeImpl.java

@@ -0,0 +1,145 @@
+package com.uas.demo.facade.impl;
+
+import com.uas.demo.dao.GroupInfoDao;
+import com.uas.demo.facade.ChatInfoFacade;
+import com.uas.demo.model.ChatInfo;
+import com.uas.demo.model.ChatInfoDto;
+import com.uas.demo.model.ChatSession;
+import com.uas.demo.model.GroupInfo;
+import com.uas.demo.service.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+
+@Service
+public class ChatInfoFacadeImpl implements ChatInfoFacade {
+
+	private final EnterpriseService enterpriseService;
+
+	private final UserInfoService userInfoService;
+
+	private final ChatSessionService chatSessionService;
+
+	private final ChatInfoService chatInfoService;
+
+	private final GroupInfoService groupInfoService;
+
+	private final GroupInfoDao groupInfoDao;
+
+	@Autowired
+	public ChatInfoFacadeImpl(EnterpriseService enterpriseService, UserInfoService userInfoService, ChatSessionService chatSessionService, ChatInfoService chatInfoService, GroupInfoService groupInfoService, GroupInfoDao groupInfoDao) {
+		this.enterpriseService = enterpriseService;
+		this.userInfoService = userInfoService;
+		this.chatSessionService = chatSessionService;
+		this.chatInfoService = chatInfoService;
+		this.groupInfoService = groupInfoService;
+		this.groupInfoDao = groupInfoDao;
+	}
+
+	@Override
+	@Transactional
+	public Map<String, Object> generateChatInfoWhenUserVisitListOrChat(ChatInfoDto chatInfoDto) {
+		if (chatInfoDto == null) {
+			return createErrorMessage("聊天信息不能为空");
+		}
+
+		// 创建或获取当前用户的聊天信息
+		ChatInfo chatInfo = chatInfoService.generateChatInfoWhenUserVisitListOrChat(chatInfoDto.getUserPhone(), chatInfoDto.getEnterprise());
+		if (chatInfo == null) {
+			return createErrorMessage("创建或获取聊天信息失败");
+		}
+
+		if ("CHAT".equals(chatInfoDto.getType())) {
+			// 创建或获取当前用户联系人的聊天信息
+			ChatInfo otherChatInfo = chatInfoService.generateChatInfoWhenUserVisitListOrChat(chatInfoDto.getToPhone(), chatInfoDto.getOtherEnterprise());
+			if (otherChatInfo == null) {
+				return createErrorMessage("创建或获取聊天信息失败");
+			}
+
+			ChatSession session = createSessionIfUserFindNone(chatInfo.getId(), otherChatInfo.getId(), chatInfoDto);
+			if (session == null) {
+				return createErrorMessage("生成或更新会话信息失败");
+			}
+		}
+		return createSuccessContent(chatInfo.getId());
+	}
+
+	@Override
+	public Map<String, Object> queryChatInfoWhenUserVisitWebSite(String id) {
+		if (StringUtils.isEmpty(id)) {
+			return createErrorMessage("聊天信息ID不能为空");
+		}
+
+		ChatInfo chatInfo = chatInfoService.queryChatInfoWhenUserVisitWebSite(id);
+		if (chatInfo == null) {
+			return createErrorMessage("聊天用户信息不存在");
+		}
+
+		List<ChatSession> sessions = chatSessionService.loadSessionsWhenUserVisitWebSite(id);
+		if (CollectionUtils.isEmpty(sessions)) {
+			sessions = Collections.emptyList();
+		}
+
+		List<GroupInfo> groups = groupInfoService.loadGroupsWhenUserVisitWebSite(id);
+		if (CollectionUtils.isEmpty(groups)) {
+			groups = new ArrayList<>();
+            GroupInfo groupInfo = new GroupInfo();
+            groupInfo.setGroupName("我的好友");
+            groupInfo.setChatSessionList(sessions);
+            groupInfo.setUserId(id);
+			groupInfo.setCreateTime(System.currentTimeMillis());
+			groupInfoDao.save(groupInfo);
+            groups.add(groupInfo);
+		}else {
+			for (GroupInfo groupInfo : groups){
+				if ("我的好友".equals(groupInfo.getGroupName())){
+					groupInfo.setChatSessionList(sessions);
+					groupInfoDao.save(groupInfo);
+				}
+			}
+		}
+
+		// 保存获取信息
+		Map<String, Object> result = new HashMap<>();
+		result.put("chatInfo", chatInfo);
+		result.put("sessions", sessions);
+		result.put("groups", groups);
+		result.put("success", true);
+		return result;
+	}
+
+	private ChatSession createSessionIfUserFindNone(String owner, String linkman, ChatInfoDto chatInfoDto) {
+		if (StringUtils.isEmpty(owner) || StringUtils.isEmpty(linkman)) {
+			return null;
+		}
+
+		ChatSession session = new ChatSession();
+		session.setOwner(owner);
+		session.setLinkman(linkman);
+		session.setCommunicatorType(chatInfoDto.getOtherUserType());
+		session.setTimeSend(new Date().getTime() / 1000);
+		session.setContent("");
+		session.setTopic(chatInfoDto.getTopic());
+		session.setRead(true);
+		session = chatSessionService.createSessionIfUserFindNone(session);
+		return session;
+	}
+
+	private Map<String, Object> createErrorMessage(String message) {
+		Map<String, Object> result = new HashMap<>();
+		result.put("message", message);
+		result.put("success", false);
+		return result;
+	}
+
+	private Map<String, Object> createSuccessContent(String content) {
+		Map<String, Object> result = new HashMap<>();
+		result.put("content", content);
+		result.put("success", true);
+		return result;
+	}
+}

+ 9 - 3
src/main/java/com/uas/demo/facade/impl/MessageFacadeImpl.java

@@ -3,6 +3,7 @@ package com.uas.demo.facade.impl;
 import com.uas.demo.facade.MessageFacade;
 import com.uas.demo.model.ChatSession;
 import com.uas.demo.model.Message;
+import com.uas.demo.model.MessageType;
 import com.uas.demo.service.ChatSessionService;
 import com.uas.demo.service.MessageService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,9 +31,14 @@ public class MessageFacadeImpl implements MessageFacade {
 		if (message == null) {
 			return Collections.emptyList();
 		}
-		messageService.cacheMessageWhenClientReceive(message);
-
-		List<ChatSession> sessions = chatSessionService.loadSessionsWhenUserRefresh(message.getOwn());
+		// 保持接收者与拥有着数据一致
+		if (message.getStyle().equals(MessageType.RECEIVE)){
+			message.setReceiverInfo(message.getOwn());
+		}
+		//if (message.getStyle().equals(MessageType.SEND)){
+			messageService.cacheMessageWhenClientReceive(message);
+		//}
+		List<ChatSession> sessions = chatSessionService.loadSessionsWhenUserVisitWebSite(message.getOwn());
 		if (CollectionUtils.isEmpty(sessions)) {
 			return Collections.emptyList();
 		}

+ 143 - 0
src/main/java/com/uas/demo/model/ChatInfo.java

@@ -0,0 +1,143 @@
+package com.uas.demo.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.CompoundIndex;
+import org.springframework.data.mongodb.core.index.CompoundIndexes;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * 聊天信息
+ */
+@Document(collection = "chat_info")
+@CompoundIndexes(value = {
+		@CompoundIndex(name = "user_enterprise_unique", def = "{'userId': 1, 'enUU': 1}", unique = true),
+		@CompoundIndex(name = "user_enterprise_unique_1", def = "{'phone': 1, 'enUU': 1}", unique = true)
+})
+
+public class ChatInfo {
+
+	/**
+	 * 主键
+	 */
+	@Id
+	private String id;
+
+	/**
+	 * 当前用户User Id
+	 */
+	private String userId;
+
+	/**
+	 * 当前用户手机号
+	 */
+	private String phone;
+
+	/**
+	 * 当前用户当前企业UU
+	 */
+	private Long enUU;
+
+	/**
+	 * 缓存用户信息
+	 */
+	@DBRef
+	private UserInfo userInfo;
+
+	/**
+	 * 缓存企业信息
+	 */
+	@DBRef
+	private Enterprise enterprise;
+
+	/**
+	 * 时间戳
+	 */
+	private long version;
+
+	/**
+	 * 统计未读消息数量
+	 */
+	private long count = 0L;
+
+	public ChatInfo() {
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+
+	public Long getEnUU() {
+		return enUU;
+	}
+
+	public void setEnUU(Long enUU) {
+		this.enUU = enUU;
+	}
+
+	public UserInfo getUserInfo() {
+		return userInfo;
+	}
+
+	public void setUserInfo(UserInfo userInfo) {
+		this.userInfo = userInfo;
+	}
+
+	public Enterprise getEnterprise() {
+		return enterprise;
+	}
+
+	public void setEnterprise(Enterprise enterprise) {
+		this.enterprise = enterprise;
+	}
+
+	public long getVersion() {
+		return version;
+	}
+
+	public void setVersion(long version) {
+		this.version = version;
+	}
+
+	public long getCount() {
+		return count;
+	}
+
+	public void setCount(long count) {
+		this.count = count;
+	}
+
+	@Override
+	public String toString() {
+		return "ChatInfo{" +
+				"id='" + id + '\'' +
+				", userId='" + userId + '\'' +
+				", phone='" + phone + '\'' +
+				", enUU=" + enUU +
+				", userInfo=" + userInfo +
+				", enterprise=" + enterprise +
+				", version=" + version +
+				", count=" + count +
+				'}';
+	}
+}

+ 165 - 0
src/main/java/com/uas/demo/model/ChatInfoDto.java

@@ -0,0 +1,165 @@
+package com.uas.demo.model;
+
+/**
+ * 聊天信息
+ */
+public class ChatInfoDto {
+
+	/**
+	 * 当前用户手机号
+	 */
+	private String userPhone;
+
+	/**
+	 * 缓存用户信息Id
+	 */
+	private UserInfo userInfo;
+
+	/**
+	 * 用户企业信息
+	 */
+	private Enterprise enterprise;
+
+	/**
+	 * 当年用户类型,企业(买家) or 店铺(卖家)
+	 */
+	private UserType userType;
+
+	/**
+	 * 联系人手机号
+	 */
+	private String toPhone;
+
+	/**
+	 * 联系人缓存用户信息Id
+	 */
+	private String otherUserInfo;
+
+	/**
+	 * 联系人企业信息
+	 */
+	private Enterprise otherEnterprise;
+
+	/**
+	 * 交谈者用户类型,企业(买家) or 店铺(卖家)
+	 */
+	private UserType otherUserType;
+
+	/**
+	 * 交涉内容
+	 */
+	private String topic;
+
+	/**
+	 * 通信类型
+	 */
+	private String type;
+
+	public ChatInfoDto() {
+	}
+
+	public String getUserPhone() {
+		return userPhone;
+	}
+
+	public void setUserPhone(String userPhone) {
+		this.userPhone = userPhone;
+	}
+
+	public UserInfo getUserInfo() {
+		return userInfo;
+	}
+
+	public void setUserInfo(UserInfo userInfo) {
+		this.userInfo = userInfo;
+	}
+
+	public Enterprise getEnterprise() {
+		return enterprise;
+	}
+
+	public void setEnterprise(Enterprise enterprise) {
+		this.enterprise = enterprise;
+	}
+
+	public UserType getUserType() {
+		return userType;
+	}
+
+	public void setUserType(UserType userType) {
+		this.userType = userType;
+
+		// 设置联系人用户类型
+		if (UserType.STORE.equals(this.userType)) {
+			this.otherUserType = UserType.ENTERPRISE;
+		} else if (UserType.ENTERPRISE.equals(this.userType)) {
+			this.otherUserType = UserType.STORE;
+		} else {
+			this.otherUserType = null;
+		}
+	}
+
+	public String getToPhone() {
+		return toPhone;
+	}
+
+	public void setToPhone(String toPhone) {
+		this.toPhone = toPhone;
+	}
+
+	public String getOtherUserInfo() {
+		return otherUserInfo;
+	}
+
+	public void setOtherUserInfo(String otherUserInfo) {
+		this.otherUserInfo = otherUserInfo;
+	}
+
+	public Enterprise getOtherEnterprise() {
+		return otherEnterprise;
+	}
+
+	public void setOtherEnterprise(Enterprise otherEnterprise) {
+		this.otherEnterprise = otherEnterprise;
+	}
+
+	public UserType getOtherUserType() {
+		return otherUserType;
+	}
+
+	public void setOtherUserType(UserType otherUserType) {
+		this.otherUserType = otherUserType;
+	}
+
+	public String getTopic() {
+		return topic;
+	}
+
+	public void setTopic(String topic) {
+		this.topic = topic;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+	@Override
+	public String toString() {
+		return "ChatInfoDto{" +
+				"userPhone='" + userPhone + '\'' +
+				", userInfo=" + userInfo +
+				", enterprise=" + enterprise +
+				", userType=" + userType +
+				", toPhone='" + toPhone + '\'' +
+				", otherUserInfo='" + otherUserInfo + '\'' +
+				", otherEnterprise=" + otherEnterprise +
+				", otherUserType=" + otherUserType +
+				", topic='" + topic + '\'' +
+				", type='" + type + '\'' +
+				'}';
+	}
+}

+ 181 - 32
src/main/java/com/uas/demo/model/ChatSession.java

@@ -2,15 +2,20 @@ package com.uas.demo.model;
 
 import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.index.CompoundIndex;
+import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 /**
  * 聊天会话记录
  */
-@Document
-@CompoundIndex(name = "session_unique", def = "{'own': 1, 'relateUser': 1}", unique = true)
+@Document(collection = "chat_session")
+@CompoundIndex(name = "owner_linkman_unique", def = "{'owner': 1, 'linkman': 1}", unique = true)
 public class ChatSession {
 
+	//===============================================================
+	// 主键信息
+	//===============================================================
+
 	/**
 	 * 主键
 	 */
@@ -18,24 +23,80 @@ public class ChatSession {
 	private String id;
 
 	/**
-	 * 会话所属人
+	 * 会话持有者聊天信息ID
+	 */
+	private String owner;
+
+	/**
+	 * 会话持有者联系人聊天信息ID
+	 */
+	private String linkman;
+
+
+	//===============================================================
+	// 基础信息
+	//===============================================================
+
+	/**
+	 * 会话持有者联系人聊天信息
+	 */
+	@DBRef
+	private ChatInfo linkmanInfo;
+
+	/**
+	 * 会话所属人 User Id
 	 */
 	private String own;
 
 	/**
-	 * 会话关联人
+	 * 沟通者 User Id
 	 */
-	private String relateUser;
+	private String communicator;
 
 	/**
-	 * 会话关联人名称
+	 * 沟通者姓名
 	 */
-	private String contactUserName;
+	private String communicatorName;
 
 	/**
-	 * 消息发起者UserId
+	 * 缓存企业Id
 	 */
-	private String fromUserId;
+	private String enterpriseId;
+
+	/**
+	 * 缓存企业信息
+	 */
+	@DBRef
+	private Enterprise enterprise;
+
+	/**
+	 * 沟通者所属,企业 or 店铺
+	 */
+	private UserType communicatorType;
+
+	/**
+	 * 话题
+	 */
+	private String topic;
+
+	/**
+	 * 消息发送者
+	 */
+	private String sender;
+
+	/**
+	 * 是否当前会话
+	 */
+	private Boolean current = false;
+
+	/**
+	 * 是否被加入黑名单
+	 */
+	private Boolean isBlack = false;
+
+	//===============================================================
+	// 消息基础信息
+	//===============================================================
 
 	/**
 	 * 消息发送时间戳
@@ -55,7 +116,12 @@ public class ChatSession {
 	/**
 	 * 是否已读
 	 */
-	private Boolean read = false;
+	private Boolean read = true;
+
+	/**
+	 * 是否自己发送
+	 */
+	private MessageType style = MessageType.SEND;
 
 	public ChatSession() {
 	}
@@ -76,22 +142,6 @@ public class ChatSession {
 		this.own = own;
 	}
 
-	public String getFromUserId() {
-		return fromUserId;
-	}
-
-	public void setFromUserId(String fromUserId) {
-		this.fromUserId = fromUserId;
-	}
-
-	public String getRelateUser() {
-		return relateUser;
-	}
-
-	public void setRelateUser(String relateUser) {
-		this.relateUser = relateUser;
-	}
-
 	public Long getTimeSend() {
 		return timeSend;
 	}
@@ -124,12 +174,108 @@ public class ChatSession {
 		this.read = read;
 	}
 
-	public String getContactUserName() {
-		return contactUserName;
+	public String getCommunicator() {
+		return communicator;
+	}
+
+	public void setCommunicator(String communicator) {
+		this.communicator = communicator;
+	}
+
+	public String getCommunicatorName() {
+		return communicatorName;
+	}
+
+	public void setCommunicatorName(String communicatorName) {
+		this.communicatorName = communicatorName;
+	}
+
+	public UserType getCommunicatorType() {
+		return communicatorType;
+	}
+
+	public void setCommunicatorType(UserType communicatorType) {
+		this.communicatorType = communicatorType;
+	}
+
+	public MessageType getStyle() {
+		return style;
+	}
+
+	public void setStyle(MessageType style) {
+		this.style = style;
+	}
+
+	public String getSender() {
+		return sender;
+	}
+
+	public void setSender(String sender) {
+		this.sender = sender;
+	}
+
+	public Boolean getCurrent() {
+		return current;
+	}
+
+	public void setCurrent(Boolean current) {
+		this.current = current;
+	}
+
+	public String getTopic() {
+		return topic;
+	}
+
+	public void setTopic(String topic) {
+		this.topic = topic;
+	}
+
+	public String getEnterpriseId() {
+		return enterpriseId;
+	}
+
+	public void setEnterpriseId(String enterpriseId) {
+		this.enterpriseId = enterpriseId;
+	}
+
+	public Enterprise getEnterprise() {
+		return enterprise;
+	}
+
+	public void setEnterprise(Enterprise enterprise) {
+		this.enterprise = enterprise;
+	}
+
+	public String getOwner() {
+		return owner;
+	}
+
+	public void setOwner(String owner) {
+		this.owner = owner;
+	}
+
+	public String getLinkman() {
+		return linkman;
+	}
+
+	public void setLinkman(String linkman) {
+		this.linkman = linkman;
+	}
+
+	public ChatInfo getLinkmanInfo() {
+		return linkmanInfo;
+	}
+
+	public void setLinkmanInfo(ChatInfo linkmanInfo) {
+		this.linkmanInfo = linkmanInfo;
+	}
+
+	public Boolean getBlack() {
+		return isBlack;
 	}
 
-	public void setContactUserName(String contactUserName) {
-		this.contactUserName = contactUserName;
+	public void setBlack(Boolean black) {
+		isBlack = black;
 	}
 
 	@Override
@@ -137,12 +283,15 @@ public class ChatSession {
 		return "ChatSession{" +
 				"id='" + id + '\'' +
 				", own='" + own + '\'' +
-				", relateUser='" + relateUser + '\'' +
-				", fromUserId='" + fromUserId + '\'' +
+				", communicator='" + communicator + '\'' +
+				", communicatorName='" + communicatorName + '\'' +
+				", communicatorType=" + communicatorType +
+				", sender='" + sender + '\'' +
 				", timeSend=" + timeSend +
 				", type=" + type +
 				", content='" + content + '\'' +
 				", read=" + read +
+				", style=" + style +
 				'}';
 	}
 }

+ 109 - 0
src/main/java/com/uas/demo/model/Enterprise.java

@@ -0,0 +1,109 @@
+package com.uas.demo.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * 缓存企业及其店铺信息
+ */
+@Document(collection = "enterprise")
+public class Enterprise {
+
+	/**
+	 * 主键
+	 */
+	@Id
+	private String id;
+
+	/**
+	 * 企业UU
+	 */
+	@Indexed(unique = true)
+	private Long enUU;
+
+	/**
+	 * 企业名称
+	 */
+	@Indexed
+	private String name;
+
+	/**
+	 * 店铺名称
+	 */
+	private String storeName;
+
+	/**
+	 * 店铺类型
+	 */
+	private String storeType;
+
+	/**
+	 * 店铺信息JSON
+	 */
+	private String storeInfo;
+
+	// 后续新增
+
+	public Enterprise() {
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public Long getEnUU() {
+		return enUU;
+	}
+
+	public void setEnUU(Long enUU) {
+		this.enUU = enUU;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getStoreName() {
+		return storeName;
+	}
+
+	public void setStoreName(String storeName) {
+		this.storeName = storeName;
+	}
+
+	public String getStoreType() {
+		return storeType;
+	}
+
+	public void setStoreType(String storeType) {
+		this.storeType = storeType;
+	}
+
+	public String getStoreInfo() {
+		return storeInfo;
+	}
+
+	public void setStoreInfo(String storeInfo) {
+		this.storeInfo = storeInfo;
+	}
+
+	@Override
+	public String toString() {
+		return "Enterprise{" +
+				"id='" + id + '\'' +
+				", enUU=" + enUU +
+				", name='" + name + '\'' +
+				", storeName='" + storeName + '\'' +
+				", storeType='" + storeType + '\'' +
+				'}';
+	}
+}

+ 135 - 0
src/main/java/com/uas/demo/model/GroupInfo.java

@@ -0,0 +1,135 @@
+package com.uas.demo.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.List;
+
+/**
+ * 分组信息
+ */
+@Document(collection = "group_info")
+public class GroupInfo {
+
+    /**
+     * 主键
+     */
+    @Id
+    private String id;
+
+    /**
+     * 分组名
+     */
+    private String groupName;
+
+    /**
+     * 当前用户User Id
+     */
+    private String userId;
+
+    /**
+     * 当前用户手机号
+     */
+    private String phone;
+
+    /**
+     * 当前用户当前企业UU
+     */
+    private Long enUU;
+
+    /**
+     * 创建时间
+     */
+    private Long createTime;
+
+    /**
+     * 缓存用户信息
+     */
+    @DBRef
+    private UserInfo userInfo;
+
+    /**
+     * 缓存企业信息
+     */
+    @DBRef
+    private Enterprise enterprise;
+
+    /**
+     * 缓存分组信息
+     */
+    @DBRef
+    private List<ChatSession> chatSessionList;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public void setGroupName(String groupName) {
+        this.groupName = groupName;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public Long getEnUU() {
+        return enUU;
+    }
+
+    public void setEnUU(Long enUU) {
+        this.enUU = enUU;
+    }
+
+    public UserInfo getUserInfo() {
+        return userInfo;
+    }
+
+    public void setUserInfo(UserInfo userInfo) {
+        this.userInfo = userInfo;
+    }
+
+    public Enterprise getEnterprise() {
+        return enterprise;
+    }
+
+    public void setEnterprise(Enterprise enterprise) {
+        this.enterprise = enterprise;
+    }
+
+    public List<ChatSession> getChatSessionList() {
+        return chatSessionList;
+    }
+
+    public void setChatSessionList(List<ChatSession> chatSessionList) {
+        this.chatSessionList = chatSessionList;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+}

+ 212 - 175
src/main/java/com/uas/demo/model/Message.java

@@ -1,185 +1,222 @@
 package com.uas.demo.model;
 
 import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
 
 /**
  * 聊天记录-缓存
  */
+@Document(collection = "message")
 public class Message {
 
-	/**
-	 * 主键
-	 */
-	@Id
-	private String id;
-
-	//-----------------------------------------------------
-	// 消息基础信息
-	//-----------------------------------------------------
-
-	/**
-	 * 发送时间
-	 */
-	private Long timeSend;
-
-	/**
-	 * 消息缓存拥有者[alias owner]
-	 */
-	private String own;
-
-	/**
-	 * 沟通者
-	 */
-	private String communicator;
-
-	//-----------------------------------------------------
-	// 消息内容信息
-	//-----------------------------------------------------
-
-	/**
-	 * 消息类型
-	 */
-	private String type;
-
-	/**
-	 * 发送者
-	 */
-	private String sender;
-
-	/**
-	 * 接收者
-	 */
-	private String receiver;
-
-	/**
-	 * 消息内容
-	 */
-	private String content;
-
-	/**
-	 * 是否已读
-	 */
-	private Boolean read = false;
-
-	/**
-	 * 是否自己发送
-	 */
-	@Deprecated
-	private Boolean mySend = false;
-
-	private MessageType style = MessageType.SEND;
-
-	public Message() {
-	}
-
-	public String getId() {
-		return id;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public Long getTimeSend() {
-		return timeSend;
-	}
-
-	public void setTimeSend(Long timeSend) {
-		this.timeSend = timeSend;
-	}
-
-	public String getOwn() {
-		return own;
-	}
-
-	public void setOwn(String own) {
-		this.own = own;
-	}
-
-	public String getCommunicator() {
-		return communicator;
-	}
-
-	public void setCommunicator() {
-		if (MessageType.RECEIVE.equals(this.style)) {
-			this.communicator = this.sender;
-		}
-		if (MessageType.SEND.equals(this.style)) {
-			this.communicator = this.receiver;
-		}
-	}
-
-	public String getType() {
-		return type;
-	}
-
-	public void setType(String type) {
-		this.type = type;
-	}
-
-	public String getSender() {
-		return sender;
-	}
-
-	public void setSender(String sender) {
-		this.sender = sender;
-	}
-
-	public String getReceiver() {
-		return receiver;
-	}
-
-	public void setReceiver(String receiver) {
-		this.receiver = receiver;
-	}
-
-	public String getContent() {
-		return content;
-	}
-
-	public void setContent(String content) {
-		this.content = content;
-	}
-
-	public Boolean getRead() {
-		return read;
-	}
-
-	public void setRead(Boolean read) {
-		this.read = read;
-	}
-
-	@Deprecated
-	public Boolean getMySend() {
-		return mySend;
-	}
-
-	@Deprecated
-	public void setMySend(Boolean mySend) {
-		this.mySend = mySend;
-	}
-
-	public MessageType getStyle() {
-		return style;
-	}
-
-	public void setStyle(MessageType style) {
-		this.style = style;
-	}
-
-	@Override
-	public String toString() {
-		return "Message{" +
-				"id='" + id + '\'' +
-				", timeSend=" + timeSend +
-				", own='" + own + '\'' +
-				", communicator='" + communicator + '\'' +
-				", type='" + type + '\'' +
-				", sender='" + sender + '\'' +
-				", receiver='" + receiver + '\'' +
-				", content='" + content + '\'' +
-				", read=" + read +
-				", style=" + style +
-				'}';
-	}
+    /**
+     * 主键
+     */
+    @Id
+    private String id;
+
+    //-----------------------------------------------------
+    // 消息基础信息
+    //-----------------------------------------------------
+
+    /**
+     * 发送时间
+     */
+    private Long timeSend;
+
+    /**
+     * 消息缓存拥有者[alias owner]
+     */
+    private String own;
+
+    /**
+     * 联系人
+     */
+    private String communicator;
+
+    //-----------------------------------------------------
+    // 消息内容信息
+    //-----------------------------------------------------
+
+    /**
+     * 消息类型
+     */
+    private String type;
+
+    /**
+     * 消息发送者
+     */
+    private String senderInfo;
+
+    /**
+     * 消息接收者
+     */
+    private String receiverInfo;
+
+    /**
+     * 发送者
+     */
+    private String sender;
+
+    /**
+     * 发送者类型
+     */
+    private UserType senderType;
+
+    /**
+     * 接收者
+     */
+    private String receiver;
+
+    /**
+     * 消息内容
+     */
+    private String content;
+
+    /**
+     * 标识一次发送接受的唯一id
+     */
+    private String uuid;
+
+    /**
+     * 是否已读
+     */
+    private Boolean read = false;
+
+    private MessageType style = MessageType.SEND;
+
+    public Message() {
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public Long getTimeSend() {
+        return timeSend;
+    }
+
+    public void setTimeSend(Long timeSend) {
+        this.timeSend = timeSend;
+    }
+
+    public String getOwn() {
+        return own;
+    }
+
+    public void setOwn(String own) {
+        this.own = own;
+    }
+
+    public String getCommunicator() {
+        return communicator;
+    }
+
+    public void setCommunicator(String communicator) {
+        this.communicator = communicator;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getSenderInfo() {
+        return senderInfo;
+    }
+
+    public void setSenderInfo(String senderInfo) {
+        this.senderInfo = senderInfo;
+    }
+
+    public String getReceiverInfo() {
+        return receiverInfo;
+    }
+
+    public void setReceiverInfo(String receiverInfo) {
+        this.receiverInfo = receiverInfo;
+    }
+
+    public String getSender() {
+        return sender;
+    }
+
+    public void setSender(String sender) {
+        this.sender = sender;
+    }
+
+    public UserType getSenderType() {
+        return senderType;
+    }
+
+    public void setSenderType(UserType senderType) {
+        this.senderType = senderType;
+    }
+
+    public String getReceiver() {
+        return receiver;
+    }
+
+    public void setReceiver(String receiver) {
+        this.receiver = receiver;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Boolean getRead() {
+        return read;
+    }
+
+    public void setRead(Boolean read) {
+        this.read = read;
+    }
+
+    public MessageType getStyle() {
+        return style;
+    }
+
+    public void setStyle(MessageType style) {
+        this.style = style;
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+    @Override
+    public String toString() {
+        return "Message{" +
+                "id='" + id + '\'' +
+                ", timeSend=" + timeSend +
+                ", own='" + own + '\'' +
+                ", communicator='" + communicator + '\'' +
+                ", type='" + type + '\'' +
+                ", senderInfo='" + senderInfo + '\'' +
+                ", receiverInfo='" + receiverInfo + '\'' +
+                ", sender='" + sender + '\'' +
+                ", senderType=" + senderType +
+                ", receiver='" + receiver + '\'' +
+                ", content='" + content + '\'' +
+                ", read=" + read +
+                ", style=" + style +
+                ", uuid=" + uuid +
+                '}';
+    }
 }

+ 0 - 81
src/main/java/com/uas/demo/model/MessageCount.java

@@ -1,81 +0,0 @@
-package com.uas.demo.model;
-
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.index.CompoundIndex;
-import org.springframework.data.mongodb.core.index.Indexed;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-/**
- * 统计未读消息数量
- */
-@Document(collection = "message_count")
-@CompoundIndex(name = "own_sender_unique", def = "{'ownerId': 1, 'senderId': 1}", unique = true)
-public class MessageCount {
-
-	/**
-	 * 主键
-	 */
-	@Id
-	private String id;
-
-	/**
-	 * 用户 User Id
-	 */
-	@Indexed
-	private String ownerId;
-
-	/**
-	 * 发送者 User Id
-	 */
-	private String senderId;
-
-	/**
-	 * 统计数量
-	 */
-	private Long count = 0L;
-
-	public MessageCount() {
-	}
-
-	public String getId() {
-		return id;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public String getOwnerId() {
-		return ownerId;
-	}
-
-	public void setOwnerId(String ownerId) {
-		this.ownerId = ownerId;
-	}
-
-	public String getSenderId() {
-		return senderId;
-	}
-
-	public void setSenderId(String senderId) {
-		this.senderId = senderId;
-	}
-
-	public Long getCount() {
-		return count;
-	}
-
-	public void setCount(Long count) {
-		this.count = count;
-	}
-
-	@Override
-	public String toString() {
-		return "MessageCount{" +
-				"id='" + id + '\'' +
-				", ownerId='" + ownerId + '\'' +
-				", senderId='" + senderId + '\'' +
-				", count=" + count +
-				'}';
-	}
-}

+ 8 - 0
src/main/java/com/uas/demo/model/StoreType.java

@@ -0,0 +1,8 @@
+package com.uas.demo.model;
+
+public enum StoreType {
+	AGENCY, 			// 代理
+	DISTRIBUTION,		// 经销
+	ORIGINAL_FACTORY,	// 原厂
+	CONSIGNMENT,		// 库存寄售
+}

+ 97 - 0
src/main/java/com/uas/demo/model/UserInfo.java

@@ -0,0 +1,97 @@
+package com.uas.demo.model;
+
+import org.springframework.data.mongodb.core.index.CompoundIndex;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import javax.persistence.Id;
+
+/**
+ * 缓存用户或联系人信息
+ */
+@Document(collection = "user_info")
+@CompoundIndex(name = "phone_user_id_unique", def = "{'phone': 1, 'userId': 1}", unique = true)
+public class UserInfo {
+
+	/**
+	 * 主键
+	 */
+	@Id
+	private String id;
+
+	/**
+	 * 手机号
+	 */
+	@Indexed(unique = true)
+	private String phone;
+
+	/**
+	 * 用户User Id[IM]
+	 */
+	@Indexed(unique = true)
+	private String userId;
+
+	/**
+	 * 资质
+	 */
+	private String certification;
+
+	/**
+	 * 用户名称
+	 */
+	private String name;
+
+	public UserInfo() {
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
+	public String getCertification() {
+		return certification;
+	}
+
+	public void setCertification(String certification) {
+		this.certification = certification;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	@Override
+	public String toString() {
+		return "UserInfo{" +
+				"id='" + id + '\'' +
+				", phone='" + phone + '\'' +
+				", userId='" + userId + '\'' +
+				", certification='" + certification + '\'' +
+				", name='" + name + '\'' +
+				'}';
+	}
+}

+ 6 - 0
src/main/java/com/uas/demo/model/UserType.java

@@ -0,0 +1,6 @@
+package com.uas.demo.model;
+
+public enum UserType {
+	ENTERPRISE,		// 企业
+	STORE			// 店铺
+}

+ 19 - 0
src/main/java/com/uas/demo/monitor/MongoMonitor.java

@@ -0,0 +1,19 @@
+package com.uas.demo.monitor;
+
+import com.mongodb.MongoClient;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+
+public class MongoMonitor extends AbstractHealthIndicator {
+
+	private final MongoClient client;
+
+	public MongoMonitor(MongoClient client) {
+		this.client = client;
+	}
+
+	@Override
+	protected void doHealthCheck(Health.Builder builder) throws Exception {
+		builder.up().withDetail("mongoClient", client.getAddress());
+	}
+}

+ 22 - 0
src/main/java/com/uas/demo/service/ChatInfoService.java

@@ -0,0 +1,22 @@
+package com.uas.demo.service;
+
+import com.uas.demo.model.ChatInfo;
+import com.uas.demo.model.Enterprise;
+
+public interface ChatInfoService {
+
+	/**
+	 * 当用户访问会话列表或发起客服,创建或获取聊天信息
+	 *
+	 * @param userPhone		用户手机号
+	 * @param enterprise	用户对应的企业信息
+	 */
+	ChatInfo generateChatInfoWhenUserVisitListOrChat(String userPhone, Enterprise enterprise);
+
+	/**
+	 * 用户访问网站时,根据聊天信息id获取聊天信息
+	 *
+	 * @param id	聊天信息ID
+	 */
+	ChatInfo queryChatInfoWhenUserVisitWebSite(String id);
+}

+ 8 - 9
src/main/java/com/uas/demo/service/ChatSessionService.java

@@ -3,28 +3,27 @@ package com.uas.demo.service;
 import com.uas.demo.model.ChatSession;
 
 import java.util.List;
-import java.util.Map;
 
 public interface ChatSessionService {
 
 	/**
 	 * 用户刷新页面时加载会话记录数据
 	 *
-	 * @param ownId		用户UserId
+	 * @param ownerId		聊天信息ID
 	 */
-	List<ChatSession> loadSessionsWhenUserRefresh(String ownId);
+	List<ChatSession> loadSessionsWhenUserVisitWebSite(String ownerId);
 
 	/**
-	 * 用户发送聊天消息时持久化会话记录
+	 * 如果用户没有找到会话记录,则创建一个新的会话
 	 *
-	 * @param session	消息发送者的会话记录
+	 * @param session	会话信息
 	 */
-	ChatSession persistSessionWhenUserSendMessage(ChatSession session);
+	ChatSession createSessionIfUserFindNone(ChatSession session);
 
 	/**
-	 * 用户查询未读会话数据
+	 * 当用户切换新的会话时,更新选中会话的状态
 	 *
-	 * @param userPhone		用户手机号
+	 * @param sessionId    会话ID
 	 */
-	Map<String, String> countUnReadSessionsWhenUserQuery(String userPhone);
+	List<ChatSession> updateSessionStateWhenUserSwitchNewSession(String sessionId);
 }

+ 14 - 0
src/main/java/com/uas/demo/service/EnterpriseService.java

@@ -0,0 +1,14 @@
+package com.uas.demo.service;
+
+import com.uas.demo.model.Enterprise;
+
+public interface EnterpriseService {
+
+	/**
+	 * 当用户访问系统时,如果不存在缓存的企业信息,则保存外部系统传入的企业
+	 * 信息;否则,根据企业UU获取企业信息
+	 *
+	 * @param enterprise		企业信息
+	 */
+	Enterprise cacheEnterpriseInfoWhenUserVisitSystem(Enterprise enterprise);
+}

+ 85 - 0
src/main/java/com/uas/demo/service/GroupInfoService.java

@@ -0,0 +1,85 @@
+package com.uas.demo.service;
+
+import com.uas.demo.model.ChatSession;
+import com.uas.demo.model.GroupInfo;
+
+import java.util.List;
+
+/**
+ * Created by yc on 2017/9/9.
+ */
+public interface GroupInfoService {
+    /**
+     * 用户刷新页面时加载分组记录数据
+     *
+     * @param ownerId		聊天信息ID
+     */
+    List<GroupInfo> loadGroupsWhenUserVisitWebSite(String ownerId);
+
+    /**
+     * 新建分组
+     * @param ownerId
+     * @param groupName
+     * @return
+     */
+    GroupInfo createGroup(String ownerId, String groupName);
+
+    /**
+     * 修改分组名
+     * @param ownerId
+     * @param groupName
+     * @return
+     */
+    GroupInfo modifyGroup(String ownerId, String groupName, String newGroupName);
+
+    /**
+     * 删除该分组
+     * @param ownerId
+     * @param groupName
+     * @return
+     */
+    boolean deleteGroup(String ownerId, String groupName);
+
+    /**
+     * 移动联系人到另一分组
+     * @param ownerId
+     * @param
+     * @return
+     */
+    GroupInfo fromToGroup(String chatSessionId, String ownerId, String fromGroupName, String toGroupName);
+
+    /**
+     * 删除联系人
+     * @param ownerId
+     * @param groupName
+     * @return
+     */
+    GroupInfo deletelinkman( String chatSessionId, String ownerId, String groupName);
+
+    /**
+     * 移动联系人到黑名单
+     * @param ownerId
+     * @param groupName
+     * @return
+     */
+    GroupInfo setlinkmanToBlacklist( String chatSessionId, String ownerId, String groupName);
+
+    /**
+     * 移出联系人到黑名单
+     * @param ownerId
+     * @param groupName
+     * @return
+     */
+    GroupInfo setlinkmanOutBlacklist( String chatSessionId, String ownerId, String groupName);
+
+    /**
+     * 搜索联系人
+     * @param keyword
+     * @param ownerId
+     * @return
+     */
+    List<ChatSession> searchLinkman(String keyword, String ownerId);
+
+
+
+}

+ 0 - 13
src/main/java/com/uas/demo/service/MessageCountService.java

@@ -1,13 +0,0 @@
-package com.uas.demo.service;
-
-import java.util.Map;
-
-public interface MessageCountService {
-
-	/**
-	 * 用户查询未读会话数据
-	 *
-	 * @param userPhone		用户手机号
-	 */
-	Map<String, String> countUnReadMessageWhenUserQuery(String userPhone);
-}

+ 23 - 3
src/main/java/com/uas/demo/service/MessageService.java

@@ -3,6 +3,7 @@ package com.uas.demo.service;
 import com.uas.demo.model.Message;
 
 import java.util.List;
+import java.util.Map;
 
 public interface MessageService {
 
@@ -16,9 +17,28 @@ public interface MessageService {
 	/**
 	 * 用户读取消息时获取未读消息,并更新为已读
 	 *
-	 * @param sender		消息发送者UserId
-	 * @param receiver		消息接受者UserId
+	 * @param owner        消息缓存拥有者聊天信息ID
+	 * @param contact      消息缓存聊天联系人聊天信息ID
 	 */
-	List<Message> loadReadableMessageWhenUserRead(String sender, String receiver);
+	List<Message> loadReadableMessageWhenUserRead(String owner, String contact);
+
+	/**
+	 * 用户查询未读会话数据
+	 *
+	 * @param userPhone		用户手机号
+	 * @param enUU			用户企业UU
+	 */
+	Map<String, String> countUnReadMessageWhenUserQuery(String userPhone, Long enUU);
+
+	/**
+	 * 获取用户的聊天历史记录,如果小于30天,则返回某个区间的消息历史,否则,返回余下所有
+	 * 的消息历史记录
+	 *
+	 * @param owner		消息缓存拥有者聊天信息ID
+	 * @param contact	消息缓存聊天联系人聊天信息ID
+	 * @param max		最近时间点
+	 * @param min		最早时间点
+	 */
+	List<Message> loadHistoryMessage(String owner, String contact, Long max, Long min);
 
 }

+ 22 - 0
src/main/java/com/uas/demo/service/UserInfoService.java

@@ -0,0 +1,22 @@
+package com.uas.demo.service;
+
+import com.uas.demo.model.User;
+import com.uas.demo.model.UserInfo;
+
+public interface UserInfoService {
+
+	/**
+	 * 当用户访问系统时,如果用户信息不存在,则缓存用户信息或联系人信息;
+	 * 否则返回已缓存的用户或联系人信息
+	 *
+	 * @param phone		用户或联系人手机号
+	 */
+	UserInfo cacheUserInfoWhenUserVisitSystem(String phone);
+
+	/**
+	 * 根据用户收好
+	 * @param phone
+	 * @return
+	 */
+	User findUserByPhone(String phone);
+}

+ 83 - 0
src/main/java/com/uas/demo/service/impl/ChatInfoServiceImpl.java

@@ -0,0 +1,83 @@
+package com.uas.demo.service.impl;
+
+import com.uas.demo.dao.ChatInfoDao;
+import com.uas.demo.dao.UserDao;
+import com.uas.demo.model.ChatInfo;
+import com.uas.demo.model.Enterprise;
+import com.uas.demo.model.UserInfo;
+import com.uas.demo.service.ChatInfoService;
+import com.uas.demo.service.EnterpriseService;
+import com.uas.demo.service.UserInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+
+@Service
+public class ChatInfoServiceImpl implements ChatInfoService {
+
+	private final UserDao userDao;
+
+	private final UserInfoService userInfoService;
+
+	private final EnterpriseService enterpriseService;
+
+	private final ChatInfoDao chatInfoDao;
+
+	@Autowired
+	public ChatInfoServiceImpl(UserDao userDao, UserInfoService userInfoService, EnterpriseService enterpriseService
+			, ChatInfoDao chatInfoDao) {
+		this.userDao = userDao;
+		this.userInfoService = userInfoService;
+		this.enterpriseService = enterpriseService;
+		this.chatInfoDao = chatInfoDao;
+	}
+
+	@Override
+	public ChatInfo generateChatInfoWhenUserVisitListOrChat(String userPhone, Enterprise enterprise) {
+		// 验证参数信息
+		if (StringUtils.isEmpty(userPhone) ){  //可以允许个人用户 || enterprise == null || enterprise.getEnUU() == null) {
+			return null;
+		}
+
+		// 获取用户缓存信息
+		UserInfo userInfo = userInfoService.cacheUserInfoWhenUserVisitSystem(userPhone);
+		assert userInfo != null;
+		ChatInfo chatInfo;
+		if (enterprise != null && enterprise.getEnUU() != null) {
+			chatInfo = chatInfoDao.findByUserIdAndEnUU(userInfo.getUserId(), enterprise.getEnUU());
+		}else {
+			chatInfo = chatInfoDao.findByUserIdAndEnUU(userInfo.getUserId(), null);
+		}
+		if (chatInfo == null) {
+			chatInfo = new ChatInfo();
+			chatInfo.setUserInfo(userInfo);
+			chatInfo.setUserId(userInfo.getUserId());
+			chatInfo.setPhone(userInfo.getPhone());
+
+			// 获取用户缓存企业信息
+			if (enterprise != null && enterprise.getEnUU() != null){
+				enterprise = enterpriseService.cacheEnterpriseInfoWhenUserVisitSystem(enterprise);
+				assert enterprise != null;
+				chatInfo.setEnterprise(enterprise);
+				chatInfo.setEnUU(enterprise.getEnUU());
+			}
+		}
+
+		// 更新聊天信息版本信息,并持久化
+		chatInfo.setVersion(new Date().getTime());
+		chatInfo = chatInfoDao.save(chatInfo);
+		return chatInfo;
+	}
+
+	@Override
+	public ChatInfo queryChatInfoWhenUserVisitWebSite(String id) {
+		if (StringUtils.isEmpty(id)) {
+			return null;
+		}
+		ChatInfo chatInfo = chatInfoDao.findOne(id);
+		userInfoService.cacheUserInfoWhenUserVisitSystem(chatInfo.getUserInfo().getPhone());
+		return chatInfo;
+	}
+}

+ 8 - 4
src/main/java/com/uas/demo/service/impl/ChatServiceImpl.java

@@ -5,10 +5,12 @@ import com.uas.demo.model.User;
 import com.uas.demo.service.ChatService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 @Service
@@ -28,10 +30,11 @@ public class ChatServiceImpl implements ChatService {
 		}
 
 		// 设置聊天发起人信息
-		User fromUser = userDao.findByPhone(fromPhone);
-		if (fromUser == null) {
+		List<User> fromUsers = userDao.findByPhone(fromPhone);
+		if (CollectionUtils.isEmpty(fromUsers)) {
 			return Collections.emptyMap();
 		}
+		User fromUser = fromUsers.get(0);
 		Map<String, String> userInfos = new HashMap<>();
 		userInfos.put("userId", fromUser.getUserId());
 		userInfos.put("userName", fromUser.getName());
@@ -43,8 +46,9 @@ public class ChatServiceImpl implements ChatService {
 		}
 
 		// 设置聊天接受人信息
-		User toUser = userDao.findByPhone(toPhone);
-		if (toUser != null) {
+		List<User> toUsers = userDao.findByPhone(toPhone);
+		if (!CollectionUtils.isEmpty(toUsers)) {
+			User toUser = toUsers.get(0);
 			userInfos.put("contactId", toUser.getUserId());
 			userInfos.put("contactName", toUser.getName());
 			userInfos.put("type", "CHAT");

+ 53 - 44
src/main/java/com/uas/demo/service/impl/ChatSessionServiceImpl.java

@@ -1,9 +1,9 @@
 package com.uas.demo.service.impl;
 
+import com.uas.demo.dao.ChatInfoDao;
 import com.uas.demo.dao.ChatSessionDao;
-import com.uas.demo.dao.UserDao;
+import com.uas.demo.model.ChatInfo;
 import com.uas.demo.model.ChatSession;
-import com.uas.demo.model.User;
 import com.uas.demo.service.ChatSessionService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -11,83 +11,92 @@ import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 @Service
 public class ChatSessionServiceImpl implements ChatSessionService {
 
-	private final UserDao userDao;
+	private final ChatInfoDao chatInfoDao;
 
 	private final ChatSessionDao chatSessionDao;
 
 	@Autowired
-	public ChatSessionServiceImpl(UserDao userDao, ChatSessionDao chatSessionDao) {
-		this.userDao = userDao;
+	public ChatSessionServiceImpl(ChatInfoDao chatInfoDao, ChatSessionDao chatSessionDao) {
+		this.chatInfoDao = chatInfoDao;
 		this.chatSessionDao = chatSessionDao;
 	}
 
 	@Override
-	public List<ChatSession> loadSessionsWhenUserRefresh(String ownId) {
-		if (StringUtils.isEmpty(ownId)) {
+	public List<ChatSession> loadSessionsWhenUserVisitWebSite(String ownerId) {
+		if (StringUtils.isEmpty(ownerId)) {
 			return Collections.emptyList();
 		}
 
-		List<ChatSession> sessions = chatSessionDao.findByOwn(ownId);
-		if (CollectionUtils.isEmpty(sessions)) {
-			return Collections.emptyList();
-		}
-		return sessions;
+		return chatSessionDao.findByOwner(ownerId);
 	}
 
 	@Override
-	public ChatSession persistSessionWhenUserSendMessage(ChatSession session) {
-		if (session == null) {
+	public ChatSession createSessionIfUserFindNone(ChatSession session) {
+		if (session == null || StringUtils.isEmpty(session.getOwner()) || StringUtils.isEmpty(session.getLinkman())) {
+			return null;
+		}
+
+		// 删除遗留的会话激活状态
+		List<ChatSession> sessions = chatSessionDao.findByOwnerAndCurrent(session.getOwner(), true);
+		if (CollectionUtils.isEmpty(sessions)) {
+			sessions = Collections.emptyList();
+		}
+		for (ChatSession chatSession : sessions) {
+			chatSession.setCurrent(false);
+			chatSessionDao.save(chatSession);
+		}
+
+		ChatInfo chatInfo = chatInfoDao.findOne(session.getLinkman());
+		if (chatInfo == null) {
 			return null;
 		}
+		session.setLinkmanInfo(chatInfo);
 
 		// 如果已存在会话记录,则更新相应的会话
-		ChatSession existSession = chatSessionDao.findByOwnAndRelateUser(session.getOwn(), session.getRelateUser());
+		ChatSession existSession = chatSessionDao.findByOwnerAndLinkman(session.getOwner(), session.getLinkman());
 		if (existSession != null) {
-			session.setId(existSession.getId());
+			existSession.setTopic(session.getTopic());
+			session = existSession;
 		}
 
-		User user = userDao.findByUserId(session.getRelateUser());
-		if (user != null && StringUtils.hasText(user.getName())) {
-			session.setContactUserName(user.getName());
-		}
+		// 创建会话信息
+		session.setCurrent(true);
 		session = chatSessionDao.save(session);
-
 		return session;
 	}
 
 	@Override
-	public Map<String, String> countUnReadSessionsWhenUserQuery(String userPhone) {
-		Map<String, String> map = new HashMap<>();
-		if (StringUtils.isEmpty(userPhone)) {
-			map.put("success", Boolean.toString(false));
-			map.put("message", "用户手机号不能为空");
-			return map;
+	public List<ChatSession> updateSessionStateWhenUserSwitchNewSession(String sessionId) {
+		if (StringUtils.isEmpty(sessionId)) {
+			return null;
 		}
 
-		User user = userDao.findByPhone(userPhone);
-		if (user == null) {
-			map.put("success", Boolean.toString(false));
-			map.put("message", String.format("用户 %s 不存在", userPhone));
-			return map;
-		} else if (StringUtils.isEmpty(user.getUserId())) {
-			map.put("success", Boolean.toString(false));
-			map.put("message", String.format("用户 %s 不存在IM ID", userPhone));
-			return map;
+		ChatSession session = chatSessionDao.findOne(sessionId);
+		if (session == null || StringUtils.isEmpty(session.getOwner())) {
+			return null;
 		}
 
-		Long count = chatSessionDao.countByOwnAndRead(user.getUserId(), false);
-		if (count == null) {
-			count = 0L;
+		// 删除遗留的会话激活状态
+		List<ChatSession> sessions = chatSessionDao.findByOwnerAndCurrent(session.getOwner(), true);
+		if (CollectionUtils.isEmpty(sessions)) {
+			sessions = Collections.emptyList();
 		}
-		map.put("success", Boolean.toString(true));
-		map.put("count", Long.toString(count));
-		return map;
+		for (ChatSession chatSession : sessions) {
+			chatSession.setCurrent(false);
+			chatSessionDao.save(chatSession);
+		}
+
+		session.setRead(true);
+		session.setCurrent(true);
+		chatSessionDao.save(session);
+
+		sessions = chatSessionDao.findByOwner(session.getOwner());
+		return sessions;
 	}
+
 }

+ 31 - 0
src/main/java/com/uas/demo/service/impl/EnterpriseServiceImpl.java

@@ -0,0 +1,31 @@
+package com.uas.demo.service.impl;
+
+import com.uas.demo.dao.EnterpriseDao;
+import com.uas.demo.model.Enterprise;
+import com.uas.demo.service.EnterpriseService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EnterpriseServiceImpl implements EnterpriseService {
+
+	private final EnterpriseDao enterpriseDao;
+
+	@Autowired
+	public EnterpriseServiceImpl(EnterpriseDao enterpriseDao) {
+		this.enterpriseDao = enterpriseDao;
+	}
+
+	@Override
+	public Enterprise cacheEnterpriseInfoWhenUserVisitSystem(Enterprise enterprise) {
+		if (enterprise == null || enterprise.getEnUU() == null) {
+			return null;
+		}
+
+		Enterprise findEnterprise = enterpriseDao.findByEnUU(enterprise.getEnUU());
+		if (findEnterprise == null) {
+			findEnterprise = enterpriseDao.save(enterprise);
+		}
+		return findEnterprise;
+	}
+}

+ 211 - 0
src/main/java/com/uas/demo/service/impl/GroupInfoServiceImpl.java

@@ -0,0 +1,211 @@
+package com.uas.demo.service.impl;
+
+import com.uas.demo.dao.ChatSessionDao;
+import com.uas.demo.dao.GroupInfoDao;
+import com.uas.demo.facade.ChatInfoFacade;
+import com.uas.demo.model.*;
+import com.uas.demo.service.ChatService;
+import com.uas.demo.service.GroupInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * Created by wangdy on 2017/9/9.
+ */
+@Service
+public class GroupInfoServiceImpl implements GroupInfoService {
+
+    @Autowired
+    private GroupInfoDao groupInfoDao;
+
+    @Autowired
+    private ChatSessionDao chatSessionDao;
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    @Override
+    public List<GroupInfo> loadGroupsWhenUserVisitWebSite(String ownerId) {
+        if (StringUtils.isEmpty(ownerId)) {
+            return Collections.emptyList();
+        }
+        return groupInfoDao.findByUserIdOrderByCreateTimeAsc(ownerId);
+    }
+
+    @Override
+    public GroupInfo createGroup(String ownerId, String groupName) {
+        if (CollectionUtils.isEmpty(groupInfoDao.findByUserIdAndGroupName(ownerId, groupName))) {
+            GroupInfo groupInfo = new GroupInfo();
+            groupInfo.setUserId(ownerId);
+            groupInfo.setGroupName(groupName);
+            groupInfo.setCreateTime(System.currentTimeMillis());
+            return groupInfoDao.save(groupInfo);
+        } else {
+            //已经存在的分组不允许创建
+            return null;
+        }
+    }
+
+    @Override
+    public GroupInfo modifyGroup(String ownerId, String groupName, String newGroupName) {
+        List<GroupInfo> groupInfoList = groupInfoDao.findByUserIdAndGroupName(ownerId, groupName);
+        if (CollectionUtils.isEmpty(groupInfoList) || groupName.equals(newGroupName)) {
+            return null;
+        }
+        GroupInfo groupInfo = groupInfoList.get(0);
+        groupInfo.setGroupName(newGroupName);
+        return groupInfoDao.save(groupInfo);
+    }
+
+    @Override
+    public boolean deleteGroup(String ownerId, String groupName) {
+        List<GroupInfo> groupInfoList = groupInfoDao.findByUserIdAndGroupName(ownerId, groupName);
+        if (CollectionUtils.isEmpty(groupInfoList)) {
+            return false;
+        }
+        try {
+            groupInfoDao.delete(groupInfoList.get(0));
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    @Override
+    @Transactional
+    public GroupInfo fromToGroup(String chatSessionId, String ownerId, String fromGroupName, String toGroupName) {
+        List<GroupInfo> groupInfoList = groupInfoDao.findByUserIdAndGroupName(ownerId, fromGroupName);
+        if (CollectionUtils.isEmpty(groupInfoList)) {
+            return null;
+        }
+        for (ChatSession chatSession : groupInfoList.get(0).getChatSessionList()) {
+            if (chatSessionId.equals(chatSession.getId())) {
+                if (!"我的好友".equals(fromGroupName)) {
+                    groupInfoList.get(0).getChatSessionList().remove(chatSession);
+                }
+                //插入另一个分组
+                List<GroupInfo> groupInfoList2 = groupInfoDao.findByUserIdAndGroupName(ownerId, toGroupName);
+                if ( groupInfoList2.get(0).getChatSessionList() == null){
+                    List<ChatSession> chatSessionList = new ArrayList<>();
+                    chatSessionList.add(chatSession);
+                    groupInfoList2.get(0).setChatSessionList(chatSessionList);
+                }else{
+                    groupInfoList2.get(0).getChatSessionList().add(chatSession);
+                }
+                groupInfoDao.save(groupInfoList2);
+                break;
+            }
+        }
+        return groupInfoDao.save(groupInfoList.get(0));
+    }
+
+    @Override
+    public GroupInfo deletelinkman(String chatSessionId, String ownerId, String groupName) {
+        List<GroupInfo> groupInfoList = groupInfoDao.findByUserIdAndGroupName(ownerId, groupName);
+        if (CollectionUtils.isEmpty(groupInfoList)) {
+            return null;
+        }
+        for (ChatSession chatSession : groupInfoList.get(0).getChatSessionList()) {
+            if (chatSessionId.equals(chatSession.getId())) {
+                groupInfoList.get(0).getChatSessionList().remove(chatSession);
+                break;
+            }
+        }
+        return groupInfoDao.save(groupInfoList.get(0));
+    }
+
+    @Override
+    @Transactional
+    public GroupInfo setlinkmanToBlacklist(String chatSessionId, String ownerId, String groupName) {
+        List<GroupInfo> groupInfoList = groupInfoDao.findByUserIdAndGroupName(ownerId, groupName);
+        if (CollectionUtils.isEmpty(groupInfoList)) {
+            return null;
+        }
+        for (ChatSession chatSession : groupInfoList.get(0).getChatSessionList()) {
+            if (chatSessionId.equals(chatSession.getId())) {
+                if (!"我的好友".equals(groupName)) {
+                    groupInfoList.get(0).getChatSessionList().remove(chatSession);
+                }
+                //插入黑名单中
+                List<GroupInfo> groupInfoList2 = groupInfoDao.findByUserIdAndGroupName(ownerId, "黑名单");
+                if (CollectionUtils.isEmpty(groupInfoList2)) {
+                    GroupInfo groupInfo = new GroupInfo();
+                    groupInfo.setGroupName("黑名单");
+                    groupInfo.setUserId(ownerId);
+                    List<ChatSession> chatSessionList = new ArrayList<>();
+                    chatSessionList.add(chatSession);
+                    groupInfo.setChatSessionList(chatSessionList);
+                    groupInfoList2.add(groupInfo);
+                } else {
+                    if ( groupInfoList2.get(0).getChatSessionList() == null){
+                        List<ChatSession> chatSessionList2 = new ArrayList<>();
+                        chatSessionList2.add(chatSession);
+                        groupInfoList2.get(0).setChatSessionList(chatSessionList2);
+                    }else{
+                        groupInfoList2.get(0).getChatSessionList().add(chatSession);
+                    }
+                }
+                chatSession.setBlack(true);
+                chatSessionDao.save(chatSession);
+                groupInfoDao.save(groupInfoList2);
+                break;
+            }
+        }
+        return groupInfoDao.save(groupInfoList.get(0));
+    }
+
+    @Override
+    @Transactional
+    public GroupInfo setlinkmanOutBlacklist(String chatSessionId, String ownerId, String groupName) {
+        List<GroupInfo> groupInfoList = groupInfoDao.findByUserIdAndGroupName(ownerId, groupName);
+        if (CollectionUtils.isEmpty(groupInfoList)) {
+            return null;
+        }
+        for (ChatSession chatSession : groupInfoList.get(0).getChatSessionList()) {
+            if (chatSessionId.equals(chatSession.getId())) {
+                groupInfoList.get(0).getChatSessionList().remove(chatSession);
+                chatSession.setBlack(false);
+                chatSessionDao.save(chatSession);
+                break;
+            }
+        }
+        return groupInfoDao.save(groupInfoList.get(0));
+    }
+
+    @Override
+    public List<ChatSession> searchLinkman(String keyword, String ownerId) {
+        Query query = new Query();
+        Query query1 = new Query();
+        Query query2 = new Query();
+        query2.addCriteria(Criteria.where("owner").is(ownerId));
+        //左匹配
+        Pattern pattern = Pattern.compile(keyword+".*$", Pattern.CASE_INSENSITIVE);
+        query.addCriteria(Criteria.where("name").regex(pattern));
+        List<Enterprise> userInfoList = mongoTemplate.find(query, Enterprise.class);
+        List<Long>  chatinfoId = new ArrayList<>();
+        for (Enterprise userInfo : userInfoList){
+            chatinfoId.add(userInfo.getEnUU());
+        }
+        query1.addCriteria(Criteria.where("enUU").in(chatinfoId));
+        List<ChatInfo> chatInfoList = mongoTemplate.find(query1,ChatInfo.class);
+        List<String>  sessioninfoId = new ArrayList<>();
+        for (ChatInfo chatInfo : chatInfoList){
+            sessioninfoId.add(chatInfo.getId());
+        }
+        query2.addCriteria(Criteria.where("linkman").in(sessioninfoId));
+        List<ChatSession> chatSessionList = mongoTemplate.find(query2,ChatSession.class);
+        return chatSessionList;
+    }
+}

+ 0 - 66
src/main/java/com/uas/demo/service/impl/MessageCountServiceImpl.java

@@ -1,66 +0,0 @@
-package com.uas.demo.service.impl;
-
-import com.uas.demo.dao.MessageCountDao;
-import com.uas.demo.dao.UserDao;
-import com.uas.demo.model.MessageCount;
-import com.uas.demo.model.User;
-import com.uas.demo.service.MessageCountService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-@Service
-public class MessageCountServiceImpl implements MessageCountService {
-
-	private final UserDao userDao;
-
-	private final MessageCountDao messageCountDao;
-
-	@Autowired
-	public MessageCountServiceImpl(UserDao userDao, MessageCountDao messageCountDao) {
-		this.userDao = userDao;
-		this.messageCountDao = messageCountDao;
-	}
-
-	@Override
-	public Map<String, String> countUnReadMessageWhenUserQuery(String userPhone) {
-		Map<String, String> map = new HashMap<>();
-		if (StringUtils.isEmpty(userPhone)) {
-			map.put("success", Boolean.toString(false));
-			map.put("message", "用户手机号不能为空");
-			return map;
-		}
-
-		User user = userDao.findByPhone(userPhone);
-		if (user == null) {
-			map.put("success", Boolean.toString(false));
-			map.put("message", String.format("用户 %s 不存在", userPhone));
-			return map;
-		} else if (StringUtils.isEmpty(user.getUserId())) {
-			map.put("success", Boolean.toString(false));
-			map.put("message", String.format("用户 %s 不存在IM ID", userPhone));
-			return map;
-		}
-
-		Long count = 0L;
-		List<MessageCount> counts = messageCountDao.findByOwnerId(user.getUserId());
-		if (!CollectionUtils.isEmpty(counts)) {
-			for (MessageCount messageCount : counts) {
-				if (messageCount == null || messageCount.getCount() == null || messageCount.getCount() < 0) {
-					count += 0L;
-				} else {
-					count += messageCount.getCount();
-				}
-			}
-		}
-
-		map.put("success", Boolean.toString(true));
-		map.put("count", Long.toString(count));
-		return map;
-	}
-}

+ 226 - 131
src/main/java/com/uas/demo/service/impl/MessageServiceImpl.java

@@ -1,153 +1,248 @@
 package com.uas.demo.service.impl;
 
-import com.uas.demo.dao.ChatSessionDao;
-import com.uas.demo.dao.MessageCountDao;
-import com.uas.demo.dao.MessageDao;
-import com.uas.demo.dao.UserDao;
-import com.uas.demo.model.ChatSession;
-import com.uas.demo.model.Message;
-import com.uas.demo.model.MessageCount;
-import com.uas.demo.model.User;
+import com.uas.demo.dao.*;
+import com.uas.demo.model.*;
+import com.uas.demo.service.GroupInfoService;
 import com.uas.demo.service.MessageService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
 
 @Service
 public class MessageServiceImpl implements MessageService {
 
-	private final UserDao userDao;
+    private final UserDao userDao;
 
-	private final MessageDao messageDao;
+    private final ChatInfoDao chatInfoDao;
 
-	private final MessageCountDao messageCountDao;
+    private final MessageDao messageDao;
 
-	private final ChatSessionDao chatSessionDao;
+    private final ChatSessionDao chatSessionDao;
 
-	@Autowired
-	public MessageServiceImpl(UserDao userDao, MessageDao messageDao, MessageCountDao messageCountDao, ChatSessionDao chatSessionDao) {
-		this.userDao = userDao;
-		this.messageDao = messageDao;
-		this.messageCountDao = messageCountDao;
-		this.chatSessionDao = chatSessionDao;
-	}
+    private final GroupInfoDao groupInfoDao;
 
-	@Override
-	@Transactional
-	public Message cacheMessageWhenClientReceive(Message message) {
-		if (message == null) {
+    private final MongoTemplate mongoTemplate;
+
+    @Autowired
+    public MessageServiceImpl(UserDao userDao, ChatInfoDao chatInfoDao, MessageDao messageDao, ChatSessionDao chatSessionDao, GroupInfoDao groupInfoDao, MongoTemplate mongoTemplate) {
+        this.userDao = userDao;
+        this.chatInfoDao = chatInfoDao;
+        this.messageDao = messageDao;
+        this.chatSessionDao = chatSessionDao;
+        this.groupInfoDao = groupInfoDao;
+        this.mongoTemplate = mongoTemplate;
+    }
+
+    @Override
+    @Transactional
+    public Message cacheMessageWhenClientReceive(Message message) {
+        if (message == null) {
+            return null;
+        }
+        /*List<Message> messages = messageDao.findByUuidAndReceiverAndSenderType(message.getUuid(),message.getReceiver(),MessageType.RECEIVE.toString());
+		if (messages != null && messages.size() > 0){
 			return null;
-		}
-
-		message.setCommunicator();
-		message = messageDao.save(message);
-
-		Boolean read = message.getRead();
-		String relateUser = message.getReceiver();
-		if (!Objects.equals(message.getOwn(), message.getSender())) {
-			relateUser = message.getSender();
-		}
-
-		ChatSession session = chatSessionDao.findByOwnAndRelateUser(message.getOwn(), relateUser);
-
-		if (session == null) {
-			session = new ChatSession();
-			session.setOwn(message.getOwn());
-			session.setRelateUser(relateUser);
-			User user = userDao.findByUserId(relateUser);
-			if (user != null && StringUtils.hasText(user.getName())) {
-				session.setContactUserName(user.getName());
-			}
-		}
-		session.setTimeSend(message.getTimeSend());
-		session.setRead(read);
-
-		session.setContent(message.getContent());
-		session.setFromUserId(message.getSender());
-		session.setType(Integer.parseInt(message.getType()));
-
-		chatSessionDao.save(session);
-
-		if (Objects.equals(message.getSender(), message.getReceiver())) {
-			return message;
-		}
-
-		MessageCount messageCount = messageCountDao.findByOwnerIdAndSenderId(message.getReceiver(), "ALL");
-		if (messageCount == null) {
-			messageCount = new MessageCount();
-			messageCount.setOwnerId(message.getReceiver());
-			messageCount.setSenderId("ALL");
-			messageCount.setCount(messageCount.getCount() + 1);
-		} else if (message.getMySend()) {
-			if (messageCount.getCount() == null || messageCount.getCount() < 0) {
-				messageCount.setCount(0L);
-			} else {
-				messageCount.setCount(messageCount.getCount() + 1);
-			}
-		} else {
-			if (message.getRead()) {
-				if (messageCount.getCount() == null || messageCount.getCount() <= 0) {
-					messageCount.setCount(0L);
-				} else {
-					messageCount.setCount(messageCount.getCount() - 1);
-				}
-			}
-		}
-
-		messageCountDao.save(messageCount);
-
-		return message;
-	}
-
-	@Override
-	public List<Message> loadReadableMessageWhenUserRead(String sender, String receiver) {
-		if (StringUtils.isEmpty(sender) || StringUtils.isEmpty(receiver)) {
-			return Collections.emptyList();
-		}
-
-		List<Message> readMessages = messageDao.findTop3ByOwnAndCommunicatorAndReadOrderByTimeSendDescStyleAsc(receiver, sender, true);
-		if (CollectionUtils.isEmpty(readMessages)) {
-			readMessages = new ArrayList<>();
-		}
-		Collections.reverse(readMessages);
-
-		// 获取未读消息列表
-		List<Message> messages = messageDao.findBySenderAndReceiverAndReadOrderByTimeSendAsc(sender, receiver, false);
-		if (CollectionUtils.isEmpty(messages)) {
-			return readMessages;
-		}
-
-		// 更新未读消息为已读消息
-		for (Message message : messages) {
-			message.setRead(true);
-			messageDao.save(message);
-		}
-
-		MessageCount messageCount = messageCountDao.findByOwnerIdAndSenderId(receiver, "ALL");
-		if (messageCount == null) {
-			messageCount = new MessageCount();
-			messageCount.setOwnerId(receiver);
-			messageCount.setSenderId("ALL");
-			messageCount.setCount(0L);
+		}*/
+
+        Boolean read = message.getRead();
+        UserType communicatorType = message.getSenderType();
+        String linkman = message.getSenderInfo();
+        // 当前用户发送消息
+        if (Objects.equals(message.getOwn(), message.getSenderInfo())) {
+            linkman = message.getReceiverInfo();
+            if (UserType.STORE == message.getSenderType()) {
+                communicatorType = UserType.ENTERPRISE;
+            }
+            if (UserType.ENTERPRISE == message.getSenderType()) {
+                communicatorType = UserType.STORE;
+            }
+        }
+        setCommunicator(message);
+        message = messageDao.save(message);
+
+        ChatSession session = chatSessionDao.findByOwnerAndLinkman(message.getOwn(), linkman);
+        if (session == null) {
+            session = new ChatSession();
+            session.setOwner(message.getOwn());
+            session.setLinkman(linkman);
+            session.setCommunicatorType(communicatorType);
+
+            ChatInfo chatInfo = chatInfoDao.findOne(linkman);
+            if (chatInfo == null) {
+                return null;
+            }
+            session.setLinkmanInfo(chatInfo);
+        }
+
+        session.setSender(message.getSender());
+        session.setTimeSend(message.getTimeSend());
+        session.setType(Integer.parseInt(message.getType()));
+        session.setContent(message.getContent());
+        session.setStyle(message.getStyle());
+
+        if (!read) {
+            session.setRead(read);
+        }
+        chatSessionDao.save(session);
+        //更新分组信息
+        List<GroupInfo> groupInfos = groupInfoDao.findByUserIdOrderByCreateTimeAsc(message.getOwn());
+        if (CollectionUtils.isEmpty(groupInfos)) {
+            GroupInfo groupInfo = new GroupInfo();
+            groupInfo.setGroupName("我的好友");
+            groupInfo.setChatSessionList(chatSessionDao.findByOwner(message.getOwn()));
+            groupInfo.setUserId(message.getOwn());
+            groupInfo.setCreateTime(System.currentTimeMillis());
+            groupInfoDao.save(groupInfo);
+        } else {
+            for (GroupInfo groupInfo : groupInfos) {
+                if ("我的好友".equals(groupInfo.getGroupName())) {
+                    List<ChatSession> chatSessionList = groupInfo.getChatSessionList();
+                    chatSessionList.add(session);
+                    groupInfo.setChatSessionList(chatSessionList);
+                    groupInfoDao.save(groupInfo);
+                }
+            }
+        }
+
+
+        // 发送消息时,联系人未读消息 + 1
+        if (MessageType.SEND == message.getStyle()) {
+            System.out.println(message.getCommunicator() + " MESSAGE_UN_READ: +1");
+
+            ChatInfo chatInfo = chatInfoDao.findOne(message.getCommunicator());
+            assert chatInfo != null;
+            chatInfo.setCount(chatInfo.getCount() + 1);
+            chatInfoDao.save(chatInfo);
+        }
+        // 当前用户接收消息时,统计未读数量并更新记录
+        if (MessageType.RECEIVE == message.getStyle()) {
+            Long count = messageDao.countByOwnAndRead(message.getOwn(), false);
+            System.out.println(message.getOwn() + " MESSAGE_UN_READ: " + count);
+
+            ChatInfo chatInfo = chatInfoDao.findOne(message.getOwn());
+            assert chatInfo != null;
+            chatInfo.setCount(count);
+            chatInfoDao.save(chatInfo);
+        }
+
+        return message;
+    }
+
+    private void setCommunicator(Message message) {
+        if (message == null) return;
+
+        if (MessageType.RECEIVE == message.getStyle()) {
+            message.setCommunicator(message.getSenderInfo());
+        }
+        if (MessageType.SEND == message.getStyle()) {
+            message.setCommunicator(message.getReceiverInfo());
+        }
+    }
+
+    @Override
+    public List<Message> loadReadableMessageWhenUserRead(String owner, String contact) {
+        if (StringUtils.isEmpty(owner) || StringUtils.isEmpty(contact)) {
+            return Collections.emptyList();
+        }
+
+        List<Message> readMessages = messageDao.findTop3ByOwnAndCommunicatorAndReadOrderByTimeSendDescStyleAsc(owner, contact, true);
+        if (CollectionUtils.isEmpty(readMessages)) {
+            readMessages = new ArrayList<>();
+        }
+        Collections.reverse(readMessages);
+
+        // 获取未读消息列表
+        List<Message> messages = messageDao.findBySenderInfoAndOwnAndReadOrderByTimeSendAsc(contact, owner, false);
+        if (CollectionUtils.isEmpty(messages)) {
+            messages = new ArrayList<>();
+        }
+
+        // 更新未读消息为已读消息
+        for (Message message : messages) {
+            message.setRead(true);
+            messageDao.save(message);
+        }
+
+        // 更新当前用户未读消息数量
+        Long count = messageDao.countByOwnAndRead(owner, false);
+        System.out.println(owner + " MESSAGE_UN_READ: " + count);
+
+        ChatInfo chatInfo = chatInfoDao.findOne(owner);
+        assert chatInfo != null;
+        chatInfo.setCount(count);
+        chatInfoDao.save(chatInfo);
+
+        readMessages.addAll(messages);
+        return readMessages;
+    }
+
+    @Override
+    public Map<String, String> countUnReadMessageWhenUserQuery(String userPhone, Long enUU) {
+        // 验证方法参数
+        if (StringUtils.isEmpty(userPhone)) {
+            return createErrorMessage("用户手机号不能为空");
+        }
+
+        ChatInfo chatInfo = chatInfoDao.findByPhoneAndEnUU(userPhone, enUU);
+        // 更新当前用户未读消息数量
+        Long count = messageDao.countByOwnAndRead(chatInfo.getId(), false);
+        if (chatInfo == null) {
+            return createSuccessMessage(0L);
+        }
+        /*if (!count.equals(chatInfo.getCount())) {
+            chatInfo.setCount(count);
+            chatInfoDao.save(chatInfo);
+        }*/
+        return createSuccessMessage(chatInfo.getCount());
+    }
+
+    @Override
+    public List<Message> loadHistoryMessage(String owner, String contact, Long max, Long min) {
+        if (StringUtils.isEmpty(owner) || StringUtils.isEmpty(contact) || (max == null && min == null)) {
+            return Collections.emptyList();
+        }
+
+        Query query = new Query();
+        query.addCriteria(Criteria.where("own").is(owner));
+        query.addCriteria(Criteria.where("communicator").is(contact));
+
+		/*if (max != null && min != null) {
+			query.addCriteria(Criteria.where("timeSend").lte(max).gt(min));
+		} else if (max == null) {
+			query.addCriteria(Criteria.where("timeSend").gt(min));
 		} else {
-			if (messageCount.getCount() == null || messageCount.getCount() < messages.size()) {
-				messageCount.setCount(0L);
-			} else {
-				messageCount.setCount(messageCount.getCount() - messages.size());
-			}
-		}
-
-		messageCountDao.save(messageCount);
-
-		readMessages.addAll(messages);
-		return readMessages;
-	}
+			query.addCriteria(Criteria.where("timeSend").lte(max));
+		}*/
+        query.with(new Sort(Sort.Direction.ASC, "timeSend"));
+
+        List<Message> messages = mongoTemplate.find(query, Message.class);
+        if (CollectionUtils.isEmpty(messages)) {
+            return Collections.emptyList();
+        }
+        Collections.reverse(messages);
+        return messages;
+    }
+
+    private Map<String, String> createErrorMessage(String message) {
+        Map<String, String> map = new HashMap<>();
+        map.put("success", Boolean.toString(false));
+        map.put("message", message);
+        return map;
+    }
+
+    private Map<String, String> createSuccessMessage(Long count) {
+        Map<String, String> map = new HashMap<>();
+        map.put("success", Boolean.toString(true));
+        map.put("count", Long.toString(count != null ? count : 0L));
+        return map;
+    }
 
 }

+ 60 - 0
src/main/java/com/uas/demo/service/impl/UserInfoServiceImpl.java

@@ -0,0 +1,60 @@
+package com.uas.demo.service.impl;
+
+import com.uas.demo.dao.UserDao;
+import com.uas.demo.dao.UserInfoDao;
+import com.uas.demo.model.User;
+import com.uas.demo.model.UserInfo;
+import com.uas.demo.service.UserInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+@Service
+public class UserInfoServiceImpl implements UserInfoService {
+
+	private final UserDao userDao;
+
+	private final UserInfoDao userInfoDao;
+
+	@Autowired
+	public UserInfoServiceImpl(UserDao userDao, UserInfoDao userInfoDao) {
+		this.userDao = userDao;
+		this.userInfoDao = userInfoDao;
+	}
+
+	@Override
+	public UserInfo cacheUserInfoWhenUserVisitSystem(String phone) {
+		if (StringUtils.isEmpty(phone)) {
+			return null;
+		}
+
+		UserInfo userInfo = userInfoDao.findByPhone(phone);
+		// 获取账号中心的用户信息
+		List<User> users = userDao.findByPhone(phone);
+		if (CollectionUtils.isEmpty(users)) {
+			return null;
+		}
+		User user = users.get(0);
+		if (userInfo == null) {
+			userInfo = new UserInfo();
+		}
+		userInfo.setPhone(user.getPhone());
+		userInfo.setUserId(user.getUserId());
+		userInfo.setCertification(user.getPassword());
+		userInfo.setName(user.getName());
+		userInfo = userInfoDao.save(userInfo);
+		return userInfo;
+	}
+
+	@Override
+	public User findUserByPhone(String phone) {
+		List<User> users = userDao.findByPhone(phone);
+		if (CollectionUtils.isEmpty(users)) {
+			return null;
+		}
+		return users.get(0);
+	}
+}

+ 20 - 7
src/main/java/com/uas/demo/web/ChatController.java

@@ -1,13 +1,15 @@
 package com.uas.demo.web;
 
+import com.uas.demo.model.ChatInfo;
+import com.uas.demo.service.ChatInfoService;
 import com.uas.demo.service.ChatService;
-import com.uas.demo.service.ChatSessionService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -19,12 +21,12 @@ public class ChatController {
 
 	private final ChatService chatService;
 
-	private final ChatSessionService sessionService;
+	private final ChatInfoService chatInfoService;
 
 	@Autowired
-	public ChatController(ChatService chatService, ChatSessionService sessionService) {
+	public ChatController(ChatService chatService, ChatInfoService chatInfoService) {
 		this.chatService = chatService;
-		this.sessionService = sessionService;
+		this.chatInfoService = chatInfoService;
 	}
 
 	/**
@@ -34,6 +36,7 @@ public class ChatController {
 	 * @param to		信息接收者的手机号
 	 * @param model		模型属性
 	 */
+	@Deprecated
 	@RequestMapping(method = RequestMethod.GET)
 	public String chatIndex(String from, String to, Model model, HttpServletResponse response) throws IOException {
 		Map<String, String> map = chatService.findChatUserInfo(from, to);
@@ -51,8 +54,18 @@ public class ChatController {
 		return "chat/private";
 	}
 
-	@RequestMapping(value = "/sample", method = RequestMethod.GET)
-	public String sample() {
-		return "chat/Sample";
+	@RequestMapping(value = "/visit", method = RequestMethod.GET)
+	public String visitWebIm(@RequestParam(value = "gid", required = false) String id, HttpServletResponse response) throws IOException {
+		if (StringUtils.isEmpty(id)) {
+			//response.sendRedirect("/");
+			return "id不可为空";
+		} else {
+			ChatInfo chatInfo = chatInfoService.queryChatInfoWhenUserVisitWebSite(id);
+			if (chatInfo == null || chatInfo.getUserInfo() == null || StringUtils.isEmpty(chatInfo.getUserInfo().getUserId())) {
+				//response.sendRedirect("/");
+				return "chat/chat-list";
+			}
+		}
+		return "chat/chat-list";
 	}
 }

+ 1 - 1
src/main/java/com/uas/demo/web/HomeController.java

@@ -10,6 +10,6 @@ public class HomeController {
 	@RequestMapping(value = {"/index", "/"}, method = RequestMethod.GET)
 	public String index() {
 		// TODO 之后修改为实际的首页HTML
-		return "index-a";
+		return "数据错误,请退出重试!";
 	}
 }

+ 6 - 6
src/main/java/com/uas/demo/web/UserController.java

@@ -2,24 +2,24 @@ package com.uas.demo.web;
 
 import com.uas.demo.dao.UserDao;
 import com.uas.demo.model.User;
+import com.uas.demo.service.UserInfoService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 @RestController
 @RequestMapping(value = "/user")
 public class UserController {
 
-	private final UserDao userDao;
-
 	@Autowired
-	public UserController(UserDao userDao) {
-		this.userDao = userDao;
-	}
+	private UserInfoService userInfoService;
 
 	@RequestMapping(value = "/phone", method = RequestMethod.GET)
 	public User findUser(String phone) {
-		return userDao.findByPhone(phone);
+		return userInfoService.findUserByPhone(phone);
 	}
 }

+ 14 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,14 @@
+server:
+  port: 20220
+spring:
+  datasource:
+    url: jdbc:oracle:thin:@//192.168.253.6:1521/orcl
+    username: platformmanager$test
+    password: select!#%*(
+    driver-class-name: oracle.jdbc.driver.OracleDriver
+  thymeleaf:
+    cache: false
+  data:
+    mongodb:
+      uri: mongodb://10.10.100.22:27017/im_test
+      database: im_test

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

@@ -0,0 +1,14 @@
+server:
+  port: 20220
+spring:
+  datasource:
+    url: jdbc:oracle:thin:@//10.10.100.215:1521/orcl
+    username: platformmanager
+    password: select!#%*(
+    driver-class-name: oracle.jdbc.driver.OracleDriver
+  thymeleaf:
+    cache: false
+  data:
+    mongodb:
+      uri: mongodb://10.10.100.22:27017/im_infos
+      database: im_infos

+ 2 - 13
src/main/resources/application.yml

@@ -1,15 +1,4 @@
-server:
-  port: 20220
 
 spring:
-  datasource:
-    url: jdbc:oracle:thin:@//10.10.100.215:1521/orcl
-    username: platformmanager
-    password: select!#%*(
-    driver-class-name: oracle.jdbc.driver.OracleDriver
-  thymeleaf:
-    cache: false
-  data:
-    mongodb:
-      uri: mongodb://10.10.100.22:27017/im_infos
-      database: im_infos
+  profiles:
+    active: prod

+ 0 - 91
src/main/resources/static/app/app.js

@@ -1,91 +0,0 @@
-
-// 连接状态改变的事件
-function onConnect(status) {
-	if (status == Strophe.Status.CONNFAIL) {
-		alert("连接失败!");
-	} else if (status == Strophe.Status.AUTHFAIL) {
-		alert("登录失败!");
-	} else if (status == Strophe.Status.DISCONNECTED) {
-		alert("连接断开!");
-		client.updateState(false);
-	} else if (status == Strophe.Status.CONNECTED) {
-		// alert("连接成功,可以开始聊天了!");
-		client.updateState(true);
-
-		client.getConnection().addHandler(onRosterChange, Strophe.NS.ROSTER, 'iq', 'set');
-		// getFriendsList();
-		client.getConnection().addHandler(onPresenceOn, null, 'presence');
-		// 当接收到<message>节,调用onMessage回调函数
-		client.getConnection().addHandler(onMessage, null, 'message', 'chat');
-
-		// getFriendsList();
-
-		// 首先要发送一个<presence>给服务器(initial presence)
-		client.getConnection().send($pres().tree());
-
-		console.log('Login Success');
-	}
-}
-
-function onRosterChange(stanza) {
-	console.log('监听好友列表变化', stanza);
-	var items = $(stanza).find('item');
-	items.push($('<item jid="' + jid + '" name="胡学志" presence="available"></item>'));
-	console.log(items);
-	return true;
-}
-
-function onPresenceOn(stanza) {
-	console.log('监听好友在线状态的变化', stanza);
-	return true;
-}
-
-// 接收到<message>
-function onMessage(msg) {
-	console.log('received message', msg);
-	// 解析出<message>的from、type属性,以及body子元素
-	var from = msg.getAttribute('from');
-	var type = msg.getAttribute('type');
-	var msgId = msg.getAttribute('id');
-	var elems = msg.getElementsByTagName('body');
-	if (type == "chat" && elems.length > 0) {
-		var body = elems[0], text = $.parseJSON(formatFace(body.textContent));
-		$("#chat-receiver-log").append('<div class="row"><div class="msg">' + text.content + '</div></div>');
-		$("#chat-receiver-log").animate({
-			scrollTop : $("#chat-receiver-log").height()
-		}, 300);
-	}
-	// 发送回执,告诉发送端收到了消息
-	/*received(msgId, from);*/
-	return true;
-}
-
-// 表情
-var faces = {
-	"奋斗" : "14.gif",
-	"坏笑" : "20.gif"
-};
-function formatFace(text) {
-	return text.replace(/(\[(.{2})\])/gi, function() {
-		var face = faces[arguments[2]];
-		return face ? ('<img src="../../style/img/face/' + face + '"/>') : arguments[0];
-	});
-}
-
-/**
- * 连接XMPP服务器
- *
- * @param userId	用户IM ID
- * @param password  密码
- * @param onConnect 连接生命周期函数
- */
-function connect(userId, password) {
-	if (!client.isConnected()) {
-		jid = userId + '@' + client.getBoshHostAddress();
-		var connection = client.getConnection();
-		console.log('jid', jid);
-		console.log('password', password);
-		console.log('onConnect', onConnect);
-		connection.connect(jid, password, onConnect);
-	}
-}

+ 885 - 193
src/main/resources/static/app/client.js

@@ -3,106 +3,123 @@ window.debug = true;
 // 记录聊天双方信息
 var dataInfo = {};
 
-// 储存聊天的会话记录信息
-var sessions = {};
-
 // 存储应用数据
 var app = {};
+app.gid = undefined;
+// 储存聊天的会话记录信息
+app.sessions = {};
+// 聊天记录是否已经展开
+app.isShowRecord = false;
 
 $(document).ready(ready);
 
-// 表情
-var faces = {
-	"奋斗" : "14.gif",
-	"坏笑" : "20.gif"
-};
-function formatFace(text) {
-	return text.replace(/(\[(.{2})\])/gi, function() {
-		var face = faces[arguments[2]];
-		return face ? ('<img src="../../style/img/face/' + face + '"/>') : arguments[0];
-	});
-}
-
 function connectServer() {
 	// 连接XMPP服务器
-	Client.connect(dataInfo.userId, dataInfo.certification);
+	Client.connect(app.userInfo.userId, app.userInfo.certification);
 }
 
 // 接收到<message>
-function onMessage(msg) {
-
-	console.log('subscribe received message', msg);
+/**
+ * 处理接收到Message
+ *
+ * @param message	用户接收到的消息
+ */
+function onMessage(message) {
+	console.log('subscribe received message', message);
 
-	var message = translateToObject(msg);
-	if (message.body) {
-		var fromUserId = message.body.fromUserId;
-		// 显示接受到的消息
-		if (fromUserId === dataInfo.contactId) {
-			// 显示消息
-			drawMessage(message.body, false);
-		}
+	// 如果是当前会话,则直接显示消息
+	if (app.currentSession && message.senderInfo === app.currentSession.linkman) {
+		// 显示消息
+		drawMessage(message, false);
 	}
+
 	// 缓存消息
-	saveMessageToLocal(message.body, false);
+	console.log(message);
+	if (message.senderInfo && message.receiverInfo) {
+		saveMessageToLocal(message, false);
+	}
+	return true;
+}
+
+/**
+ * 用户发送消息
+ *
+ * @param message	已填充的消息
+ */
+function sendMessage(message) {
+	if (!message) {
+		return ;
+	}
 
-	// 发送回执,告诉发送端收到了消息
-	Client.received(dataInfo.userId, Strophe.getBareJidFromJid(message.from), message.id);
+	if (Client.isConnected()) {
+		if (!message.receiver || message.receiver == '') {
+			alert("请输入联系人!");
+			return;
+		}
 
-	return true;
+		message = Client.sendMessage(message);
+
+		// 显示消息
+		drawMessage(message || {}, true);
+		saveMessageToLocal(message, true);
+		$("#input-msg").empty();
+	} else {
+		alert("请先登录!");
+	}
 }
 
+
 function activate() {
-	var params = httpUtils.queryParams();
-	params.enterprise = decodeURIComponent(params.enterprise);
-	params.condition = 'userid';
+	app = httpUtils.queryParams() || {};
+
 	if (window.debug) {
-		console.log('[DEBUG]Query Params', params);
+		console.log('[DEBUG]App Info', app);
 	}
 
 	onfire.on('chat.message', onMessage);
 
-	dataService.get('/api/chat/infos', params, {}, function (data) {
-		dataInfo = data;
-		dataInfo.enterprise = params.enterprise;
-
-		if (!dataInfo.contactId || dataInfo.contactId === '') {
-			hiddenChatArea();
-		} else {
-			// 绘制标题
-			drawTitle();
+	ChatService.queryChatInfoWhenUserVisitWebSite(app.gid, function (data) {
+		if (!data.success) {
+			console.log('Message', data.message);
+			return ;
 		}
 
-		// 获取会话信息
-		sessionService.loadSessionsWhenUserRefresh(dataInfo.userId, function (data) {
-
-			var sessions = handlerSessionData(data);
+		app.userInfo = data.chatInfo.userInfo;
+		app.enterprise = data.chatInfo.enterprise;
+        app.groups = data.groups || [];
 
-			createNewSession(sessions);
+		// 绘制用户信息
+		drawUserInfo();
 
-			// 绘制会话列表
-			drawSessionList(sessions);
-
-			connectServer();
-		}, function (error) {
-			console.log(error);
+		// 绘制会话列表
+		app.sessions = handlerSessionData(data.sessions || []);
+		drawSessionList(app.sessions);
 
-			connectServer();
-		});
+		// 绘制会话区域
+		if (app.currentSession) {
+			drawTitle();
+			showChatArea();
+			handlerUnReadMessage();
+		}
 
-		// 获取未读消息缓存
-		messageService.loadReadableMessageWhenUserRead(dataInfo.contactId, dataInfo.userId, function (messages) {
-			if (window.debug) {
-				console.log('message.unread', messages);
-			}
+		connectServer();
+	}, function (error) {
+		console.log(error);
+		window.location.href = '/';
+	});
+}
 
-			messages.forEach(function (message) {
-				// 显示消息
-				drawMessage(message, false);
-			});
-		}, function (error) {
-			console.log(error);
-		})
+function handlerUnReadMessage() {
+	// 获取未读消息缓存
+	messageService.loadReadableMessageWhenUserRead(app.currentSession.owner, app.currentSession.linkman, function (messages) {
+		if (window.debug) {
+			console.log('message.unread', messages);
+		}
 
+		// 显示消息
+		messages.forEach(function (message) {
+			drawMessage(message, message.style == 'SEND');
+		});
 	}, function (error) {
 		console.log(error);
 	});
@@ -112,61 +129,35 @@ function handlerSessionData(data) {
 	var sessions = {};
 	if (data && data.length > 0) {
 		for (var i = 0; i < data.length; i++) {
-			if (!data[i].relateUser || data[i].relateUser === '') {
+			if (!data[i].linkman || data[i].linkman === '') {
 				continue;
 			}
-			if (!sessions[data[i].relateUser]) {
-				sessions[data[i].relateUser] = data[i];
+			if (!sessions[data[i].linkman]) {
+				sessions[data[i].linkman] = data[i];
+				sessions[data[i].linkman].userInfo = sessions[data[i].linkman].linkmanInfo.userInfo;
+				sessions[data[i].linkman].enterprise = sessions[data[i].linkman].linkmanInfo.enterprise;
 			} else {
-				if (sessions[data[i].relateUser].timeSend < data[i].timeSend) {
-					sessions[data[i].relateUser] = data[i];
+				if (sessions[data[i].linkman].timeSend < data[i].timeSend) {
+					sessions[data[i].linkman] = data[i];
 				}
 			}
 		}
 	}
 
-	return sessions;
-}
-
-function createNewSession(sessions) {
-	var session = {};
-	if (!dataInfo.contactId || dataInfo.contactId === '') return ;
-	if (sessions[dataInfo.contactId]) return ;
-
-	session.own = dataInfo.userId;
-	session.relateUser = dataInfo.contactId;
-	session.contactUserName = dataInfo.contactName;
-	session.fromUserId = dataInfo.contactId;
-	session.timeSend = new Date().getTime() / 1000;
-	session.content = '';
-	session.read = true;
-	sessions[dataInfo.contactId] = session;
-
-	sessionService.persistSessionWhenUserSendMessage(session, function (session) {
-		if (window.debug) {
-			console.log('[DEBUG]Create Session', session);
+	// 获取当前会话
+	var current = false;
+	for (var property in sessions) {
+		if (sessions.hasOwnProperty(property) && sessions[property] && sessions[property].current) {
+			current = true;
+			app.currentSession = sessions[property] || {};
+			break ;
 		}
-	}, function (error) {
-		console.log('error', error);
-	});
-}
-
-function translateToObject(stanza) {
-	var message = {},
-		elements = stanza.getElementsByTagName('body');
-
-	message.from = stanza.getAttribute('from');
-	message.to = stanza.getAttribute('to');
-	message.id = stanza.getAttribute('id');
-	message.type = stanza.getAttribute('type');
-
-	if (message.type === 'chat' && elements.length > 0) {
-		message.body = $.parseJSON(elements[0].textContent);
 	}
 
-	console.log(message);
-
-	return message;
+	if (!current) {
+		delete app.currentSession;
+	}
+	return sessions;
 }
 
 function formatTime(timestamp) {
@@ -176,11 +167,22 @@ function formatTime(timestamp) {
 		month = '' + (date.getMonth() + 1),
 		day = '' + date.getDate();
 	if (month.length < 2) month = '0' + month;
-	if (date.length < 2) day = '0' + day;
+	if (day.length < 2) day = '0' + day;
 
 	return [year, month, day].join('-');
 }
 
+function formatHourTime(timestamp) {
+	if (timestamp == null) return '';
+	var date = new Date(timestamp * 1000),
+		hour = '' + date.getHours(),
+		minute = '' + date.getMinutes();
+	if (hour.length < 2) hour = '0' + hour;
+	if (minute.length < 2) minute = '0' + minute;
+
+	return [hour, minute].join(':');
+}
+
 function formatFullTime(timestamp) {
 	if (timestamp == null) return '';
 	var date = new Date(timestamp * 1000),
@@ -191,7 +193,7 @@ function formatFullTime(timestamp) {
 		minute = '' + date.getMinutes(),
 		second = '' + date.getSeconds();
 	if (month.length < 2) month = '0' + month;
-	if (date.length < 2) day = '0' + day;
+	if (day.length < 2) day = '0' + day;
 	if (hour.length < 2) hour = '0' + hour;
 	if (minute.length < 2) minute = '0' + minute;
 	if (second.length < 2) second = '0' + second;
@@ -199,12 +201,52 @@ function formatFullTime(timestamp) {
 	return [year, month, day].join('-') + ' ' + [hour, minute, second].join(':');
 }
 
-function hiddenChatArea() {
+function showChatArea() {
+	$('#chat-area').show();
+}
+
+function hideChatArea() {
 	$('#chat-area').hide();
 }
 
+function drawUserInfo() {
+	console.log('APP', app);
+	var str = '<div class="img"><img src="/style/img/photo01.png" /></div>' +
+    	'<div class="content">' +
+    	'<span><span>' + app.userInfo.name + '</span><div class="star-img-group"><img src="/style/img/star.png"><img src="/style/img/star.png"><img src="/style/img/star.png"></div></span>' +
+    	'<p>';
+	if (app.enterprise){
+		str +=(app.enterprise.name);
+	}else {str +=('个人账户');}
+	str +=('</p></div>');
+
+	$('#member-title').html(str);
+/*<div class="title-icon"><img src="/style/img/zoomIn.png" alt=""> <img src="/style/img/close.png" alt=""> </div>*/
+}
+
 function drawTitle() {
-	$('#chat-title').html('<h3>' + (dataInfo.contactName && dataInfo.contactName !== '' ? dataInfo.contactName : dataInfo.contactId) + '</h3>');
+	var name = '';
+	if (app.currentSession) {
+		if (app.currentSession.linkmanInfo.enterprise != null){
+            // if ('ENTERPRISE' === app.currentSession.communicatorType) {
+            //     name = app.currentSession.linkmanInfo.userInfo.name + '-' + app.currentSession.linkmanInfo.enterprise.name;
+            // } else {
+                name = app.currentSession.linkmanInfo.enterprise.name;
+            // }
+		}else{
+			name = '个人账户';
+		}
+	}
+
+	$('#chat-title').html('<h3 title="'+name +'(' +app.currentSession.linkmanInfo.userInfo.name.substring(0,1)+ '**)' +'">' + name + '(' + app.currentSession.linkmanInfo.userInfo.name.substring(0,1) + '**)</h3>');
+/*<div class="title-icon"><img src="/style/img/zoomIn.png" alt=""> <img src="/style/img/close.png" alt=""> </div>*/
+}
+
+/**
+ * 清空聊天记录
+ */
+function clearMessage() {
+	$("#chat-receiver-log ul").empty();
 }
 
 /**
@@ -214,17 +256,31 @@ function drawTitle() {
  * @param isSend	是否为发送消息
  */
 function drawMessage(message, isSend) {
+	var userName = '';
 
-	$('#chat-receiver-log').append('<dl>' +
-		'<dt><img src="/style/img/photo01.jpg"/></dt>' +
-		'<dd>' +
-		'<p class="name">' + (isSend ? dataInfo.userName : dataInfo.contactName) + '</p>' +
-		'<span class="time">' + formatFullTime(message.timeSend) + '</span>' +
-		'<p>' + message.content + '</p>' +
-		'</dd>' +
-		'</dl>');
-
-	var height = $('#chat-receiver-log')[0].scrollHeight - $("#chat-receiver-log")[0].clientHeight;
+	/*if (!isSend) {
+		if (message.senderType === 'STORE') {
+			userName = app.currentSession.enterprise.name;
+		}
+		if (message.senderType === 'ENTERPRISE') {
+			userName = app.currentSession.userInfo.name + '-' + app.currentSession.enterprise.name;
+		}
+	} else {
+		userName = app.userInfo.name;
+	}*/   //暂时没用到这个userName
+
+	console.log(message.content)
+	$('#chat-receiver-log ul').append('<li class="chat-log ' + (isSend ? 'chat-log-send' : 'chat-log-receive') + '">' +
+			'<div class="chat-log-avatar">' +
+				'<img src="/style/img/photo01.png" alt="头像"></img>' +
+			'</div>' +
+			'<div class="chat-log-text">' +
+				message.content +
+			'</div>' +
+			'<div class="clearfix"></div>' +
+        '</li>');
+
+	var height = $('#chat-receiver-log')[0].scrollHeight;
 
 	$("#chat-receiver-log").animate({
 		scrollTop : height
@@ -233,19 +289,54 @@ function drawMessage(message, isSend) {
 
 function drawSessionList(sessions) {
 	$('#session-list .list-group').text('');
+    // $('#session-list .list-group2').text('');
 	for (var property in sessions) {
+		if (sessions[property].isBlack){
+			continue;
+		}
 		if (sessions.hasOwnProperty(property) && sessions[property]) {
 
-			$('#session-list .list-group').append('<dl class="' + (sessions[property].relateUser === dataInfo.contactId ? ' active' : '' ) + '">' +
-				'<a href="/chat/sample?from=' + sessions[property].own + '&to=' + sessions[property].relateUser + '">' +
-				'<dt><img src="/style/img/photo01.jpg"/></dt>' +
-				'<dd>' +
-				'<span class="name">' + (sessions[property].contactUserName && sessions[property].contactUserName !== '' ? sessions[property].contactUserName : sessions[property].relateUser) + '</span>' +
-				'<span class="time">' + formatTime(sessions[property].timeSend) + '</span>' +
-				'</dd>' +
-				'<dd class="record">' + sessions[property].content + '</dd>' +
-				'</a>' +
-				'</dl>');
+			var sessionStyle = '', record = '';
+			if (!sessions[property].read) {
+				//sessionStyle = 'bg-warning';
+			}
+			if (app.currentSession && app.currentSession.linkman && app.currentSession.linkman !== '') {
+				if (sessions[property].id === app.currentSession.id) {
+					sessionStyle = 'active';
+				}
+			}
+
+			if (sessions[property].type == 1) {
+				record = sessions[property].content.replace(/<img class="emoji_icon".*?>/, '[表情]');
+			} else if (sessions[property].type == 2) {
+				record = '[图片]';
+			} else if (sessions[property].type == 3) {
+				record = '[文件]';
+			}
+
+			var flag = "'" + sessions[property].linkman + "'";
+			var enStr;
+			if(sessions[property].enterprise == null){
+				enStr = '个人账户'+'('+sessions[property].userInfo.name.substring(0,1)+"**)";
+			}else{
+				enStr = sessions[property].enterprise.name+'('+sessions[property].userInfo.name.substring(0,1)+"**)";
+			}
+			var listStr = '<dl class="' + sessionStyle + '">' +
+                '<a href="javascript:void(0);" onclick="switchNewSession(' + flag + ')">' +
+                // '<dt><em>寄售</em><img src="/style/img/photo01.png"/></dt>' +
+                '<dt><img src="/style/img/photo01.png"/></dt>' +
+                '<dd>' +
+                '<span class="name" title="'+enStr+'">' + enStr + '</span>' +
+                '<span class="time">' + formatHourTime(sessions[property].timeSend) + '</span>' +
+                '</dd>' +
+                '<dd class="record">' + (sessions[property].content.substring(0, 4) == '<img' ? '[图片]' : sessions[property].content);
+				console.log(sessions[property].read);
+				listStr += '</dd>';
+            if (!sessions[property].read) {  //未读信息加上标志
+                listStr += '<i></i>';
+            }
+            listStr += '</a></dl>';
+			$('#session-list .list-group').append(listStr);
 		}
 	}
 }
@@ -260,17 +351,20 @@ function saveMessageToLocal(stanza, isMySend) {
 	console.log('message.body', stanza);
 
 	if (isMySend === null || isMySend === undefined) {
-		isMySend = stanza.sender === dataInfo.userId;
+		isMySend = stanza.senderInfo === app.currentSession.owner;
 	}
 
-	stanza.own = dataInfo.userId;
+	stanza.own = app.gid;
 	stanza.mySend = isMySend;
 	stanza.style = isMySend ? 'SEND' : 'RECEIVE';
-	if (isMySend || (!isMySend && stanza.sender === dataInfo.contactId)) {
+	if (isMySend || (!isMySend && app.currentSession && stanza.senderInfo === app.currentSession.linkman)) {
 		stanza.read = true;
 	} else {
 		stanza.read = false;
 	}
+	if (stanza.style === 'RECEIVE'){
+		stanza.id = stanza.uuid;
+	}
 
 	// 缓存消息
 	messageService.cacheMessageWhenClientReceive(stanza, function (sessions) {
@@ -278,10 +372,9 @@ function saveMessageToLocal(stanza, isMySend) {
 			console.log('[DEBUG]Update Sessions:', sessions);
 		}
 
-		// 处理会话数据
-		var handlerSessions = handlerSessionData(sessions);
 		// 绘制会话列表
-		drawSessionList(handlerSessions);
+		app.sessions = handlerSessionData(sessions);
+		drawSessionList(app.sessions);
 	}, function (error) {
 		console.log('Cache Fail', error);
 	});
@@ -290,26 +383,106 @@ function saveMessageToLocal(stanza, isMySend) {
 function ready() {
 	activate();
 
-	$('#input-msg').emoji({
-		button: "#show-emoji",
-		showTab: false,
-		animation: 'slide',
-		icons: [{
-			name: "QQ表情",
-			path: "/style/img/qq/",
-			maxNum: 91,
-			excludeNums: [41, 45, 54],
-			file: ".gif"
-		}]
+	// // 添加Emoji
+	// $('#input-msg').emoji({
+	// 	button: "#show-emoji",
+	// 	showTab: false,
+	// 	animation: 'slide',
+	// 	icons: [{
+	// 		name: "QQ表情",
+	// 		path: "/style/img/qq/",
+	// 		maxNum: 91,
+	// 		excludeNums: [41, 45, 54],
+	// 		file: ".gif"
+	// 	}]
+	// });
+
+	// 点击回车发送消息
+	$('#input-msg').keydown(function (event) {
+		if (event.keyCode == 13) {
+			clickSendMessage();
+		}
 	});
 
+    // 点击回车发送消息后,清除换行字符
+	$('#input-msg').keyup(function (event) {
+		console.log(event.keyCode);
+        if (event.keyCode == 13) {
+			$("#input-msg").empty();
+		}
+	});
+
+	// 处理复制内容转化成文本内容
+    $('[contenteditable]').each(function() {
+        // 干掉IE http之类地址自动加链接
+        try {
+            document.execCommand("AutoUrlDetect", false, false);
+        } catch (e) {}
+
+        $(this).on('paste', function(e) {
+
+            var text = null;
+
+            if(window.clipboardData && clipboardData.setData) {
+                // IE
+                text = window.clipboardData.getData('text');
+            } else {
+                text = (e.originalEvent || e).clipboardData.getData('text/plain') ||
+					(e.originalEvent || e).clipboardData.getData('image');
+            }
+            // 如果获取不到文本内容,可能是图片等,直接返回
+            if (!text) return;
+            // 获取到文本内容,将文本内容添加进入输入框
+            e.preventDefault();
+            if (document.body.createTextRange) {
+                if (document.selection) {
+                    textRange = document.selection.createRange();
+                } else if (window.getSelection) {
+                    sel = window.getSelection();
+                    var range = sel.getRangeAt(0);
+
+                    // 创建临时元素,使得TextRange可以移动到正确的位置
+                    var tempEl = document.createElement("span");
+                    tempEl.innerHTML = "&#FEFF;";
+                    range.deleteContents();
+                    range.insertNode(tempEl);
+                    textRange = document.body.createTextRange();
+                    textRange.moveToElementText(tempEl);
+                    tempEl.parentNode.removeChild(tempEl);
+                }
+                textRange.text = text;
+                textRange.collapse(false);
+                textRange.select();
+            } else {
+                // Chrome之类浏览器
+                document.execCommand("insertText", false, text);
+            }
+        });
+
+        // 去除Crtl+b/Ctrl+i/Ctrl+u等快捷键
+        $(this).on('keydown', function(e) {
+            // e.metaKey for mac
+            if (e.ctrlKey || e.metaKey) {
+                switch(e.keyCode){
+                    case 66: //ctrl+B or ctrl+b
+                    case 98:
+                    case 73: //ctrl+I or ctrl+i
+                    case 105:
+                    case 85: //ctrl+U or ctrl+u
+                    case 117: {
+                        e.preventDefault();
+                        break;
+                    }
+                }
+            }
+        });
+    });
+
 	// 发送消息
 	$("#btn-send").click(clickSendMessage);
 
 	// 关闭聊天窗口
-	$("#btn-close").click(function () {
-		window.location.href = '/chat/sample?from=' + dataInfo.userId;
-	});
+	$("#btn-close").click(closeChatArea);
 
 	// 上传图片
 	$('#upload-image-btn').click(function () {
@@ -318,49 +491,81 @@ function ready() {
 	});
 
 	// 上传图片获取图片信息
-	$('#upload-image').change(uploadImage)
-}
+	$('#upload-image').change(uploadImage);
 
-function sendMessage(content) {
-	if (!content || content === '') {
-		return ;
-	}
+	// 显示聊天历史
+	$('#show-chat-record').click(showChatRecord);
 
-	if (Client.isConnected()) {
-		if (!dataInfo.contactId || dataInfo.contactId == '') {
-			alert("请输入联系人!");
-			return;
-		}
+	$('#close-chat-record').click(showChatRecord);
+}
 
-		var msg = Client.sendMessage(dataInfo.userId, dataInfo.contactId, content);
+/**
+ * 点击发送按钮,发送消息
+ */
+function clickSendMessage() {
+	console.log(1);
 
-		if (msg) {
-			console.log(msg.tree().outerHTML);
-			var message = translateToObject(msg.tree());
-			console.log('1-message', message.body || {});
+	var message = new Message();
+	message.type = 1;
+	message.senderInfo = app.currentSession.owner;
+	message.receiverInfo = app.currentSession.linkman;
+	message.senderType = app.currentSession.communicatorType;
 
-			// 显示消息
-			drawMessage(message.body || {}, true);
+	message.sender = app.userInfo.userId;
+	message.receiver = app.currentSession.userInfo.userId;
+	message.content = $("#input-msg").html();
+	message.uuid = guid();
 
-			saveMessageToLocal(message.body, true);
-		}
+	if (!message.content || message.content === '') {
+		$("#input-msg").empty();
+		return ;
+	}
 
-		$("#input-msg").text('');
-	} else {
-		alert("请先登录!");
+	if (window.debug) {
+		console.log('[DEBUG]Send Message', message);
 	}
+
+	sendMessage(message);
 }
 
+//用于生成uuid
+function S4() {
+    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
+}
+function guid() {
+    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
+}
 /**
- * 点击发送按钮,发送消息
+ * 发送图片
+ *
+ * @param url	图片URL
  */
-function clickSendMessage() {
-	var content = $("#input-msg").html();
+function sendImage(url) {
+
+	var message = new Message();
+	message.type = 2;
+	message.senderInfo = app.currentSession.owner;
+	message.receiverInfo = app.currentSession.linkman;
+	message.senderType = app.currentSession.communicatorType;
+
+	message.sender = app.userInfo.userId;
+	message.receiver = app.currentSession.userInfo.userId;
+	message.content = '<img ondblclick="previewImg(&apos;'+ url + '&apos;)" class="content-image" src="' + (url || '') + '"/>';
+    message.uuid = guid();
 
 	if (window.debug) {
-		console.log('[DEBUG]Send Message', content);
+		console.log('[DEBUG]Send Message', message.content);
 	}
-	sendMessage(content);
+
+	sendMessage(message);
+}
+
+function previewImg(url) {
+	$('#preview-img img').attr('src', url);
+	$('#preview-img').show();
+}
+function closePreview() {
+	$('#preview-img').hide();
 }
 
 /**
@@ -368,7 +573,6 @@ function clickSendMessage() {
  */
 function uploadImage() {
 	var file = $('#upload-image')[0].files[0];
-	console.log(file);
 
 	if (file) {
 		var fileSize = 0;
@@ -378,20 +582,508 @@ function uploadImage() {
 			fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
 		}
 
-		console.log('File Information', fileSize);
+		// console.log('File Information', fileSize);
 
 		var formData = new FormData();
 		formData.append('file', file);
 
+		var fileObj = $("#upload-image")
+		$('#loading').show();
 		FileService.uploadImage(formData, function (data) {
-			console.log(data);
-			var content = '<img src="' + data + '"/>';
-			// $("#input-msg").html(content);
-			sendMessage(content);
-			$('#upload-image')[0].files[0] = [];
+			sendImage(data);
+            $('#loading').hide();
+			fileObj.val("")
 		}, function (error) {
+            $('#loading').hide();
 			console.log(error);
-			$('#upload-image')[0].files[0] = [];
+			fileObj.val("");
 		})
 	}
 }
+
+function drawHistoryMessage(message, isSend) {
+	var name = '', enterpriseName = '', classStyle = '';
+
+	if (!isSend) {
+		name = app.currentSession.userInfo.name;
+		enterpriseName = app.currentSession.enterprise?app.currentSession.enterprise.name:'个人帐号';
+	} else {
+		name = app.userInfo.name;
+		enterpriseName = app.enterprise?app.enterprise.name:'个人帐号';
+		classStyle = 'customer';
+	}
+
+	$('#chat-record>ul').prepend('<li class="' + classStyle + '">' +
+		'<p>' + name.substring(0,1)+'**' + ' ( ' + enterpriseName + ' ) ' + '<time>' + formatFullTime(message.timeSend) + '</time></p>' +
+		'<p class="content">' + message.content + '</p>' +
+		'</li>');
+}
+
+function loadHistoryMessage(max, min) {
+	messageService.loadHistoryMessage(app.gid, app.currentSession.linkman, max, min, function (messages) {
+		app.history = messages;
+		if (messages && messages.length > 0) {
+			messages.forEach(function (message) {
+				drawHistoryMessage(message, message.style === 'SEND');
+			});
+		}
+
+
+        var record = $('#chat-record ul')[0];
+        var lastRecord = $('#chat-record ul li:last-child').height();
+        var height = record.scrollHeight + lastRecord;
+
+        console.log(height);
+        $("#chat-record ul").animate({
+            scrollTop : height
+        }, 0);
+
+		// 绘制聊天历史记录
+	}, function (error) {
+		console.log(error);
+	})
+
+
+}
+
+/**
+ * 显示聊天历史信息
+ */
+function showChatRecord() {
+	if (!app.isShowRecord) {
+		app.isShowRecord = true;
+		$('.col-md-8 >.row').css('right','232px');
+        $('#chat-send-area').css('right','217px');
+		$('#chat-record').show();
+		$('#chat-area').css({'width':'391px'});
+		$('#show-chat-record').html('<img src="/style/img/icon04.png"/>&nbsp;关闭聊天记录');
+		$('#show-chat-record').css('color', 'red');
+		$('#chat-record>ul').html('');
+
+		var max = Math.round(new Date().getTime() / 1000) - (60 * 60 * 24);
+		loadHistoryMessage(max, null);
+	} else {
+		app.isShowRecord = false;
+		$('.col-md-8 >.row').css('right','15px');
+        $('#chat-send-area').css('right','0');
+		$('#chat-record').hide();
+		$('#chat-area').css({'width':'609px'});
+		$('#show-chat-record').html('<img src="/style/img/icon04.png"/>&nbsp;聊天记录');
+		$('#show-chat-record').css('color', '#337ab7');
+	}
+}
+
+/**
+ * 开启新的会话
+ */
+function switchNewSession(communicator) {
+//	console.log(communicator);
+	if (!communicator || communicator === '') return ;
+
+	var session = app.sessions[communicator];
+
+	sessionService.updateSessionStateWhenUserSwitchNewSession(session.id, function (sessions) {
+		// 绘制会话列表
+		app.sessions = handlerSessionData(sessions || []);
+		drawSessionList(app.sessions);
+
+		// 绘制会话区域
+		if (app.currentSession) {
+			drawTitle();
+			showChatArea();
+			clearMessage();
+			handlerUnReadMessage();
+		}
+	}, function (error) {
+		console.log(error);
+	});
+}
+
+function closeChatArea() {
+	delete app.currentSession;
+
+	hideChatArea();
+	drawSessionList(app.sessions);
+}
+
+/**
+ *  加载分组数据
+ * */
+function reloadData(flag) {
+    ChatService.queryChatInfoWhenUserVisitWebSite(app.gid, function (data) {
+        if (!data.success) {
+            console.log('Message', data.message);
+            return;
+        }
+
+        app.userInfo = data.chatInfo.userInfo;
+        app.enterprise = data.chatInfo.enterprise;
+        app.groups = data.groups || [];
+        app.sessions = handlerSessionData(data.sessions || []);
+        // drawSessionList(app.sessions);
+        if (flag) {
+            toSingleList();
+        } else {
+            toDoubleList();
+        }
+    });
+}
+
+/**
+ *  分组列表展示
+* */
+function drawSessionGroup() {
+    // $('#session-list .list-group').text('');
+    $('#session-list .list-group2').text('');
+    var tempStr = '<ul class="group-list">';
+    app.groups.forEach(function (item, index) {
+    	if (item.chatSessionList == null){
+            tempStr += '<li><div onmousedown="onGroupMenu(event,' + index + ')" onclick="showDetailList(' + index +')"><img src="/style/img/arrow-right.png" alt=""/><span>'
+                + item.groupName + ' (0)</span></div></li>';
+		}else {
+            tempStr += '<li><div onmousedown="onGroupMenu(event,' + index + ')" onclick="showDetailList(' + index +')"><img src="/style/img/arrow-right.png" alt=""/><span>'
+                + item.groupName + ' ('+item.chatSessionList.length +')</span></div></li>';
+		}
+    });
+    $('#session-list .list-group2').append(tempStr);
+}
+
+/**
+ *  分组详细列表
+ * */
+function showDetailList(index) {
+	var temp_index = parseInt(index) + 1;
+    var tempEl = $('#session-list .list-group2 .group-list >li:nth-child(' + temp_index + ')');
+    if (tempEl.find('ul').length == 0) {
+        var tempStr = '<ul class="group-item-list">';
+		if (app.groups[index].chatSessionList) {
+			app.groups[index].chatSessionList.forEach(function (item, item_index) {
+				var id = "'" + item.linkman + "'";
+				if (item.linkmanInfo.enterprise && item.linkmanInfo.enterprise!=null){
+                    tempStr += '<li onmousedown="onLinkmanMenu(event,'+index+','+item_index+')" onclick="switchNewSession(' +id + ')"><span title="'+item.linkmanInfo.enterprise.name +'('+item.linkmanInfo.userInfo.name.substring(0,1)+'**)">' + item.linkmanInfo.enterprise.name +'('+item.linkmanInfo.userInfo.name.substring(0,1)+'**)</span></li>';
+				}else{
+                    tempStr += '<li onmousedown="onLinkmanMenu(event,'+index+','+item_index+')" onclick="switchNewSession(' +id + ')"><span title="个人账户('+item.linkmanInfo.userInfo.name.substring(0,1)+'**)">个人账户('+item.linkmanInfo.userInfo.name.substring(0,1)+'**)</span></li>';
+				}
+			});
+			tempStr += '</ul>';
+			tempEl.append(tempStr);
+		}
+    } else {
+        tempEl.find('ul').remove()
+    }
+}
+
+/**
+ *  转换显示列表为最近联系人
+ * */
+function toSingleList() {
+    drawSessionList(app.sessions);
+    $('#session-list .list-group').show();
+    $('#session-list .list-group2').hide();
+}
+
+/**
+ *  转换显示列表为分组
+ * */
+function toDoubleList() {
+    drawSessionGroup();
+    $('#session-list .list-group').hide();
+    $('#session-list .list-group2').show();
+}
+
+/**
+ *  转换显示列表
+* */
+function changeSelectList(type, e) {
+    var flag = type == 'single' ? true : false;
+    var left = $(e.target).parent()[0].firstElementChild;
+    var right = $(e.target).parent()[0].lastElementChild;
+    left.setAttribute('class', flag ? 'single active' : 'single');
+    left.firstElementChild.setAttribute('src', flag ? '/style/img/single-active.png' : '/style/img/single.png');
+    right.setAttribute('class', !flag ? 'double active' : 'double');
+    right.firstElementChild.setAttribute('src', !flag ? '/style/img/double-active.png' : '/style/img/double.png');
+    reloadData(flag);
+}
+
+/**
+ *  右键分组菜单
+ * */
+function onGroupMenu(event, index) {
+	hideGroupListMenu();
+	$('.linkman-menu').hide();
+    if (event.button == 2) {
+        document.oncontextmenu = function () {
+            return false;
+        }
+		var groupName = app.groups[index].groupName;
+
+        var x = event.pageX;
+        var y = event.pageY;
+        $('.group-menu').attr('style', 'top: ' + y + 'px; left: ' + x + 'px;');
+        $('.group-menu li').attr('name', index);
+        if ('我的好友' == groupName){
+            $('.group-menu .delete-group').hide();
+		}else {
+            $('.group-menu .delete-group').show();
+		}
+		$('.group-menu').show();
+        $(document).click(function () {
+            $('.group-menu').hide();
+        })
+    }
+}
+
+/**
+ *  右键联系人操作菜单
+ * */
+function onLinkmanMenu(event, index, item_index) {
+	hideGroupMenu();
+	if (event.button == 2) {
+		document.oncontextmenu = function () {
+			return false;
+		}
+		var x = event.pageX;
+		var y = event.pageY;
+		var deleteObj = $('.linkman-menu >li:nth-child(2)');
+		var toBlackObj = $('.linkman-menu >li:nth-child(3)');
+		$('.linkman-menu').attr('style', 'top: ' + y + 'px; left: ' + x + 'px;');
+        var groupName = app.groups[index].groupName;
+        if ('我的好友' == groupName){
+            $('.linkman-menu .delete-linkman').hide();
+        }else {
+            $('.linkman-menu .delete-linkman').show();
+        }
+		$('.linkman-menu').show();
+		$('.linkman-menu >li:first-child').attr('onmouseenter','showGroupList(event,' + index +',' + item_index + ')');
+		deleteObj.attr('onclick', 'selectLinkmanMenuItem(event, "2",' + index + ',' + item_index +')');
+		deleteObj.attr('onmouseenter', 'hideGroupListMenu()');
+		toBlackObj.attr('onclick', 'selectLinkmanMenuItem(event, "3",' + index + ',' + item_index +')');
+		toBlackObj.attr('onmouseenter', 'hideGroupListMenu()');
+		$(document).click(function () {
+			$('.linkman-menu').hide();
+			$('.group-list-menu').hide();
+		})
+	}
+}
+
+/**
+ *  分组列表菜单展示
+ * */
+function showGroupList(event, index, item_index) {
+	var obj = $('.group-list-menu');
+	obj.text('');
+	var str = '';
+	var type = 1;
+	if (app.groups) {
+		app.groups.forEach(function (item) {
+			str += '<li onclick="selectLinkmanMenuItem(event,'+ type + ',' + index + ','+item_index+')">' + item.groupName + '</li>'
+		})
+	}
+	var x = $(event.target).parent().css('left');
+	var y = $(event.target).parent().css('top');
+
+	obj.append(str);
+	obj.css({'top': y, 'left': parseInt(x.substring(0, x.length-2)) + 145 + 'px'});
+	obj.show();
+}
+
+/**
+ *  分组菜单选择
+ * */
+function selectGroupMenuItem(e, type) {
+    var ownid = app.gid;
+    var index = $(e.target).attr('name');
+    var groupName = app.groups[index].groupName;
+    if (type == 'add') {
+		var str = '<li><div><img src="/style/img/arrow-right.png" alt=""><input type="text" onkeyup="onAddGroup(event)" onblur="onAddGroup(event)" placeholder="请输入分组名称" /></div></li>'
+		$('#session-list .list-group2 .group-list').append(str);
+		$('#session-list .list-group2 .group-list >li:last-child >div > input').focus();
+    } else if (type == 'rename') {
+		var list_index = parseInt(index) +1;
+		var tempEl = '#session-list .list-group2 .group-list >li:nth-child(' + list_index + ')';
+		var str = '<input type="text" onkeyup="onRenameGroup(event,' + index +')" onblur="onRenameGroup(event,' + index +')" placeholder="' + groupName + '" />'
+		$(tempEl + '>div >span').hide();
+		$(tempEl + '>div').append(str);
+		$(tempEl + '>div >input').focus();
+    } else if (type === 'remove') {
+		if (app.groups[index].groupName === '我的好友') {
+			return;
+		}
+		$('.remind-box').text('');
+		var str = '<div class="box-header"><img onclick="hideRemindBox()" src="/style/img/remind-box-del.png" alt="" /></div>';
+		str += '<div class="box-title"><span>!</span><span>是否要删除该分组?</span><div>选定的分组将会被删除,组内联系人将会移至系统默认分组“我的好友。</div></div>';
+		str += '<div class="box-btn"> <span onclick="hideRemindBox()">取消</span> <span onclick="submitDeleteGroupAction('+ index + ')">确定</span></div>';
+		$('.remind-box').append(str);
+		$('.remind-box').show();
+    }
+}
+
+/**
+ *  联系人菜单选择
+ *  type:
+ *  1:移动联系人
+ *  2:删除联系人
+ *  3:加入黑名单
+ * */
+
+function selectLinkmanMenuItem(event, type, index, item_index) {
+	var chatSessionId = app.groups[index].chatSessionList[item_index].id;
+	var name = app.groups[index].chatSessionList[item_index].linkmanInfo.userInfo.name;
+	var ownid = app.gid;
+	var fromGroupName = app.groups[index].groupName;
+	if (type == 1) {
+		var toGroupName = $(event.target).text()
+		groupService.moveToGroup(chatSessionId, ownid, fromGroupName, toGroupName, function (data) {
+			reloadData();
+			drawSessionGroup();
+		},function (error) {
+
+		})
+	} else if (type == 2) {
+		$('.remind-box').text('');
+		var str = '<div class="box-header"><img onclick="hideRemindBox()" src="/style/img/remind-box-del.png" alt="" /></div>';
+		str += '<div class="box-title"><span>!</span><span>删除后对方将从联系人列表中消失。</span></div>';
+		str += '<div class="box-info"> <img src="/style/img/photo01.png" alt="" /><span>'  + name.substring(0,1)+'**' +'</span> </div>';
+		str += '<div class="box-btn"> <span onclick="hideRemindBox()">取消</span> <span onclick="submitDeleteAction('+ index + ',' + item_index + ')">确定</span></div>';
+		$('.remind-box').append(str);
+		$('.remind-box').show();
+	} else if (type == 3) {
+		$('.remind-box').text('');
+		var str = '<div class="box-header"><img onclick="hideRemindBox()" src="/style/img/remind-box-del.png" alt="" /></div>';
+		str += '<div class="box-title"><span>!</span><span>确认将该联系人加入至黑名单吗?</span><div>移至黑名单后将无法接收此人会话消息。</div></div>';
+		str += '<div class="box-info"> <img src="/style/img/photo01.png" alt="" /><span>' + name.substring(0,1)+'**' +'</span> </div>';
+		str += '<div class="box-btn"> <span onclick="hideRemindBox()">取消</span> <span onclick="submitBlackAction('+ index + ',' + item_index + ')">确定</span></div>';
+		$('.remind-box').append(str);
+		$('.remind-box').show();
+	}
+}
+
+/**
+ *  隐藏分组菜单
+ * */
+function hideRemindBox() {
+	$('.remind-box').hide();
+}
+
+/**
+ *  确认删除分组
+ * */
+function submitDeleteGroupAction(index) {
+	var ownid = app.gid;
+	var groupName = app.groups[index].groupName;
+	groupService.removeGroup(ownid, groupName, function (data) {
+		reloadData();
+		drawSessionGroup();
+		hideRemindBox();
+	},function (error) {
+		alert('删除分组失败!');
+	})
+}
+/**
+ *  确认删除联系人
+ * */
+function submitDeleteAction(index, item_index) {
+	var chatSessionId = app.groups[index].chatSessionList[item_index].id;
+	var ownid = app.gid;
+	var fromGroupName = app.groups[index].groupName;
+	groupService.removeLinkman(chatSessionId, ownid, fromGroupName, function (data) {
+		reloadData();
+		drawSessionGroup();
+		hideRemindBox();
+	},function (error) {
+		alert('删除联系人失败!');
+	})
+}
+/**
+ *  确认加入黑名单
+ * */
+function submitBlackAction(index, item_index) {
+	var chatSessionId = app.groups[index].chatSessionList[item_index].id;
+	var ownid = app.gid;
+	var fromGroupName = app.groups[index].groupName;
+	groupService.setlinkmanToBlacklist(chatSessionId, ownid, fromGroupName, function (data) {
+	 	reloadData();
+	 	drawSessionGroup();
+		hideRemindBox();
+	 },function (error) {
+		alert('加入黑名单失败!');
+	 })
+}
+
+/**
+ *  隐藏分组菜单
+ * */
+function hideGroupMenu() {
+    $('.group-menu').hide();
+}
+/**
+ *  隐藏分组列表菜单
+ * */
+function hideGroupListMenu() {
+	$('.group-list-menu').hide();
+}
+
+function onAddGroup(event) {
+	if (event.keyCode && event.keyCode !== 13) {
+		return;
+	}
+	var val = $(event.target).val();
+	if (!val || val == '') {
+		$('#session-list .list-group2 .group-list >li:last-child').remove();
+	} else {
+		groupService.addGroup(app.gid, val, function (data) {
+			reloadData();
+			drawSessionGroup();
+		}, function (error) {
+
+		})
+	}
+}
+
+function onRenameGroup(event, index) {
+	if (event.keyCode && event.keyCode !== 13) {
+		return;
+	}
+	var _this = $(event.target)
+	var val = _this.val();
+	if (!val || val == '') {
+		_this.prev().show();
+		_this.remove();
+	} else {
+		var groupName = app.groups[index].groupName;
+		groupService.renameGroup(app.gid, groupName, val, function (data) {
+			reloadData();
+			drawSessionGroup();
+		}, function (error) {
+
+		})
+	}
+}
+
+/**
+ * 搜索联系人
+ * */
+function onSearchLinkman(type) {
+	if (type && type == 'keyup' && event.keyCode!=13) {
+		return;
+	}
+	searchLinkMan();
+}
+
+function searchLinkMan() {
+	var keyword = $('#session-list .search-user >input').val();
+	var ownerId = app.gid;
+	groupService.searchLinkman(keyword, ownerId, function (data) {
+		app.sessions = handlerSessionData(data.success || []);
+		drawSessionList(app.sessions);
+	},function (error) {
+
+	})
+}
+
+$(window).resize(function () {          //当浏览器大小变化时
+    // alert($(window).height());          //浏览器时下窗口可视区域高度
+    //alert($(document).height());        //浏览器时下窗口文档的高度
+    //alert($(document.body).height());   //浏览器时下窗口文档body的高度
+    //alert($(document.body).outerHeight(true)); //浏览器时下窗口文档body的总高度 包括border padding margin*/
+});

+ 22 - 0
src/main/resources/static/app/common/data-service.js

@@ -57,6 +57,27 @@ var dataService = (function (window, $) {
 			error: error
 		});
 	}
+
+	function put(url, params, data, success, error) {
+		if (!url || url === '') return;
+
+		if (!data || typeof data !== 'object') {
+			data = {};
+		}
+		var queryString = getQueryString(params);
+		if (queryString && queryString !== '') {
+			url = url + '?' + queryString;
+		}
+		$.ajax({
+			url: url,
+			method: 'PUT',
+			contentType: 'application/json;charset=UTF-8',
+			data: JSON.stringify(data),
+			dataType: 'json',
+			success: success,
+			error: error
+		});
+	}
 	
 	function upload(url, formData, success, error) {
 		if (!url || url === '') return;
@@ -78,6 +99,7 @@ var dataService = (function (window, $) {
 	return {
 		get: get,
 		post: post,
+		put: put,
 		upload: upload
 	}
 })(window, $);

+ 48 - 24
src/main/resources/static/app/common/xmpp-client.js

@@ -4,7 +4,7 @@
 var Client = (function (window, Strophe, onfire, Message) {
 
 	// XMPP服务器BOSH地址
-	var BOSH_HOST = "113.105.74.140", BOSH_SERVICE = 'http://' + BOSH_HOST + ':5280';
+	var BOSH_HOST = "113.105.74.140", BOSH_SERVICE = 'https://xmpp.ubtob.com';
 
 	// XMPP连接和连接状态
 	var connection = null,
@@ -14,6 +14,9 @@ var Client = (function (window, Strophe, onfire, Message) {
 	 * 获取jabber Id
 	 */
 	function getJabberId(userId) {
+		if (!userId || userId === '') {
+			return null;
+		}
 		return userId + '@' + BOSH_HOST;
 	}
 
@@ -30,6 +33,7 @@ var Client = (function (window, Strophe, onfire, Message) {
 		} else if (status == Strophe.Status.DISCONNECTED) {
 			alert("连接断开,请刷新页面!");
 			connected = false;
+			window.location.reload();
 		} else if (status == Strophe.Status.CONNECTED) {
 			console.log("连接成功,可以开始聊天了!");
 			connected = true;
@@ -49,16 +53,44 @@ var Client = (function (window, Strophe, onfire, Message) {
 	/**
 	 * 接收到<message>
 	 *
-	 * @param msg		消息
+	 * @param stanza		消息
 	 */
-	function onMessage(msg) {
+	function onMessage(stanza) {
 		if (window.debug) {
-			console.log(new Date(), msg.outerHTML);
+			console.log(new Date(), stanza.outerHTML);
+		}
+		var message = translateToObject(stanza);
+
+		// 设置成接受消息
+		if (message.body) {
+			message.body.style = 'RECEIVE';
+		} else {
+			message.body = {
+				style: 'RECEIVE'
+			}
 		}
-		onfire.fire('chat.message', msg);
+		onfire.fire('chat.message', message.body);
+
+		received(message.to, message.from, message.id);
 		return true;
 	}
 
+	function translateToObject(stanza) {
+		var message = {},
+			elements = stanza.getElementsByTagName('body');
+
+		message.from = stanza.getAttribute('from');
+		message.to = stanza.getAttribute('to');
+		message.id = stanza.getAttribute('id');
+		message.type = stanza.getAttribute('type');
+
+		if (message.type === 'chat' && elements.length > 0) {
+			message.body = $.parseJSON(elements[0].textContent);
+		}
+
+		return message;
+	}
+
 	/**
 	 * 获取Connection
 	 */
@@ -76,29 +108,22 @@ var Client = (function (window, Strophe, onfire, Message) {
 	/**
 	 * 创建一个<message>元素并发送
 	 *
-	 * @param from
-	 * @param to
-	 * @param content
+	 * @param message		发送的消息
 	 */
-	function sendMessage(from, to, content) {
+	function sendMessage(message) {
 		if (window.debug) {
-			console.log('message info', from + '-> ' + to);
+			console.log('message info', message.sender + '-> ' + message.receiver);
 		}
 
-		var jid = getJabberId(from),
-			contactJid = getJabberId(to),
-			msg = null;
+		var jid = getJabberId(message.sender),
+			contactJid = getJabberId(message.receiver);
 
 		if (connected) {
 
-			var message = new Message();
-			message.fromUserId = from;
-			message.sender = from;
-			message.receiver = to;
+			// 设置发送时间
 			message.timeSend = Math.round(new Date().getTime() / 1000);
-			message.content = content;
 
-			msg = $msg({
+			var msg = $msg({
 				to: contactJid,
 				from: jid,
 				type: 'chat'
@@ -111,20 +136,19 @@ var Client = (function (window, Strophe, onfire, Message) {
 			}
 		}
 
-		return msg;
+		return message;
 	}
 
 	/**
 	 * 发送回执,告诉发送端收到了消息
 	 *
-	 * @param fromUserId	发送方UserId
+	 * @param fromJid		发送方UserId
 	 * @param toJid			接受方Jabber Id
 	 * @param msgId			消息ID
 	 */
-	function received(fromUserId, toJid, msgId) {
-		var jid = Client.getJabberId(fromUserId);
+	function received(fromJid, toJid, msgId) {
 		var msg = $msg({
-			from : jid,
+			from : fromJid,
 			to : toJid
 		}).c("received", {
 			'xmlns': 'urn:xmpp:receipts',

+ 84 - 11
src/main/resources/static/app/index.js

@@ -1,22 +1,94 @@
+// 全局对象
+var app = {};
+
+/**
+ * 验证用户信息
+ */
+function validateUserInfo() {
+	app.chatInfo.userPhone = $('#userPhone').val();
+	app.chatInfo.enterprise = $('#enterprise').val();
+	app.chatInfo.storeInfo = $('#storeInfo').val();
+
+	if (!app.chatInfo.userPhone || app.chatInfo.userPhone === '') {
+		alert('用户手机号不能为空');
+		return false;
+	}
+	if (!app.chatInfo.enterprise || app.chatInfo.enterprise === '') {
+		alert('用户单位不能为空');
+		return false;
+	}
+	return true;
+}
+
+/**
+ * 验证联系人信息
+ */
+function validateContactInfo() {
+	app.chatInfo.toPhone = $('#contactPhone').val();
+	app.chatInfo.otherEnterprise = $('#contactEnterprise').val();
+	app.chatInfo.storeInfo = $('#storeInfo').val();
+
+	if (!app.chatInfo.toPhone || app.chatInfo.toPhone === '') {
+		alert('请输入联系人手机号');
+		return false;
+	}
+	if (!app.chatInfo.otherEnterprise || app.chatInfo.otherEnterprise === '') {
+		alert('请输入联系人单位信息');
+		return false;
+	}
+	return true;
+}
 
 function goToChatPage() {
-	console.log('Chat');
+	app.chatInfo = { type: 'CHAT' };
+
+	if (!validateUserInfo()) return;
+	if (!validateContactInfo()) return;
 
-	var userPhone = $('#userId').val();
-	var contact = $('#contactId').val();
+	app.chatInfo.userType = $('#userType').val();
+	if ('ENTERPRISE' === app.chatInfo.userType) app.chatInfo.otherUserType = 'STORE';
+	if ('STORE' === app.chatInfo.userType) app.chatInfo.otherUserType = 'ENTERPRISE';
+	app.chatInfo.enterprise = JSON.parse(app.chatInfo.enterprise);
+	app.chatInfo.enterprise.storeInfo = app.chatInfo.storeInfo;
+	app.chatInfo.otherEnterprise = JSON.parse(app.chatInfo.otherEnterprise);
+	app.chatInfo.otherEnterprise.storeInfo = app.chatInfo.storeInfo;
+	app.chatInfo.topic = 'JUST FOR TEST';
 
-	dataService.get('/api/chat/infos', { from: userPhone, to: contact, condition: 'phone'}, {}, handlerData, handlerError);
+	dataService.post('/api/chat/infos', { condition: 'chat_info' }, app.chatInfo, handlerData, handlerError);
 
 	function handlerData(data) {
-		if (!data || !data.userId || data.userId === '') {
-			alert('用户信息不存在,请重新输入');
-			return ;
+		console.log('result data', data);
+		if (data.success) {
+			window.location.href = '/chat/visit?gid=' + data.content;
+		} else {
+			alert(data.message);
 		}
-		var url = '/chat/sample?from=' + data.userId;
-		if (data.contactId && data.contactId !== '') {
-			url = url + '&to=' + data.contactId;
+	}
+
+	function handlerError(error) {
+		console.log(error);
+		alert('输入信息异常,请重新输入');
+	}
+}
+
+function visitSessionList() {
+	app.chatInfo = { type: 'LIST' };
+
+	if (!validateUserInfo()) return;
+
+	console.log(app.enterprise);
+	app.chatInfo.enterprise = JSON.parse(app.chatInfo.enterprise);
+	app.chatInfo.enterprise.storeInfo = app.chatInfo.storeInfo;
+
+	dataService.post('/api/chat/infos', { condition: 'chat_info' }, app.chatInfo, handlerData, handlerError);
+
+	function handlerData(data) {
+		console.log('result data', data);
+		if (data.success) {
+			window.location.href = '/chat/visit?gid=' + data.content;
+		} else {
+			alert(data.message);
 		}
-		window.location.href = url;
 	}
 
 	function handlerError(error) {
@@ -31,6 +103,7 @@ function ready() {
 	});
 
 	$("#startChat").click(goToChatPage);
+	$("#visitSessionList").click(visitSessionList);
 }
 
 $(document).ready(ready);

+ 6 - 3
src/main/resources/static/app/model/message.js

@@ -4,8 +4,11 @@
 var Message = (function () {
 
 	function Message() {
-		this.type = 1;
-		this.fromUserId = null;
+		this.id = null;
+		this.type = 1;		// 1 文本, 2 图片, 3 文件
+		this.senderInfo = '';
+		this.receiverInfo = '';
+		this.senderType = 'ENTERPRISE'; // ENTERPRISE 企业, STORE 店铺
 		this.sender = null;
 		this.receiver = null;
 		this.messageState = 0;
@@ -13,10 +16,10 @@ var Message = (function () {
 		this.upload = false;
 		this.timeLen = 0;
 		this.timeReceive = 0;
-		this.mySend = true;
 		this.read = false;
 		this.timeSend = 0;
 		this.content = null;
+		this.uuid = '';
 		this.style = 'SEND';
 	}
 

+ 0 - 187
src/main/resources/static/app/private.js

@@ -1,187 +0,0 @@
-// XMPP服务器BOSH地址
-var BOSH_HOST = "113.105.74.140", BOSH_SERVICE = 'http://' + BOSH_HOST + ':5280';
-
-// XMPP连接
-var connection = null;
-
-// 当前状态是否连接
-var connected = false;
-
-// 当前登录的JID
-var jid = "";
-
-// 连接状态改变的事件
-function onConnect(status) {
-	if (status == Strophe.Status.CONNFAIL) {
-		alert("连接失败!");
-	} else if (status == Strophe.Status.AUTHFAIL) {
-		alert("登录失败!");
-	} else if (status == Strophe.Status.DISCONNECTED) {
-		alert("连接断开!");
-		connected = false;
-	} else if (status == Strophe.Status.CONNECTED) {
-		// alert("连接成功,可以开始聊天了!");
-		connected = true;
-
-		// connection.addHandler(onRosterChange, Strophe.NS.ROSTER, 'iq', 'set');
-		getFriendsList();
-		connection.addHandler(onPresenceOn, null, 'presence');
-		// 当接收到<message>节,调用onMessage回调函数
-		connection.addHandler(onMessage, null, 'message', 'chat');
-
-		// getFriendsList();
-
-		// 首先要发送一个<presence>给服务器(initial presence)
-		connection.send($pres().tree());
-
-		console.log('Login Success');
-	}
-}
-// 表情
-var faces = {
-	"奋斗" : "14.gif",
-	"坏笑" : "20.gif"
-};
-function formatFace(text) {
-	return text.replace(/(\[(.{2})\])/gi, function() {
-		var face = faces[arguments[2]];
-		return face ? ('<img src="../../style/img/face/' + face + '"/>') : arguments[0];
-	});
-}
-
-// 接收到<message>
-function onMessage(msg) {
-	console.log('received message', msg);
-	// 解析出<message>的from、type属性,以及body子元素
-	var from = msg.getAttribute('from');
-	var type = msg.getAttribute('type');
-	var msgId = msg.getAttribute('id');
-	var elems = msg.getElementsByTagName('body');
-	if (type == "chat" && elems.length > 0) {
-		var body = elems[0], text = $.parseJSON(formatFace(body.textContent));
-		$("#msg").append("<div class=\"msg_wrap\"><div class=\"msg\">" + text.content + "</div></div>");
-		$("#msg").animate({
-			scrollTop : $("#msg").height()
-		}, 300);
-	}
-	// 发送回执,告诉发送端收到了消息
-	/*received(msgId, from);*/
-	return true;
-}
-
-function onPresenceOn(stanza) {
-	console.log('监听好友在线状态的变化', stanza);
-	return true;
-}
-
-function onPresenceOff(stanza) {
-	console.log(stanza);
-	return true;
-}
-
-function onRosterChange(stanza) {
-	console.log('监听好友列表变化', stanza);
-	var items = $(stanza).find('item');
-	items.push($('<item jid="' + jid + '" name="胡学志" presence="available"></item>'));
-	console.log(items);
-	return true;
-}
-
-function received(msgId, to) {
-	var msg = $msg({
-		from : jid,
-		to : to
-	}).c("received", {
-		'xmlns': 'urn:xmpp:receipts',
-		'id': msgId
-	});
-	connection.send(msg.tree());
-}
-
-function activate() {
-	if (!connected) {
-		connection = new Strophe.Connection(BOSH_SERVICE);
-		jid = $("#input-jid").val() + "@" + BOSH_HOST;
-		console.log('jid', jid);
-		console.log('password', $("#input-certification").val());
-		connection.connect(jid, $("#input-certification").val(), onConnect);
-	}
-}
-
-function getFriendsList() {
-	var iq = $iq({ type: 'get', id: jid }).c('query', { xmlns: 'jabber:iq:roster'});
-	connection.sendIQ(iq, onRosterChange)
-}
-
-$(document).ready(
-		function() {
-
-			activate();
-
-			// 通过BOSH连接XMPP服务器
-			$('#btn-login').click(function() {
-				if (!connected) {
-					connection = new Strophe.Connection(BOSH_SERVICE);
-					connection.connect($("#input-jid").val() + "@" + BOSH_HOST, $("#input-certification").val(), onConnect);
-					jid = $("#input-jid").val() + "@" + BOSH_HOST;
-				}
-			});
-
-			$('#input-msg').bind('paste', function (e) {
-				console.log(e);
-				var clipboard = e.clipboardData;
-				console.log(clipboard);
-				for (var i = 0, len = clipboard.items.length; i < len; i++) {
-					if (clipboard.items[i].kind === 'file' || clipboard.items[i].type.indexOf('image') > -1) {
-						var imageFile = clipboard.items[i].getAsFile();
-						var form = new FormData;
-						form.append('t', 'ajax-uploadic');
-						form.append('avatar', imageFile);
-						var callback = G.uploadCallback || function (type, data) {};
-						e.preventDefault();
-					}
-				}
-			});
-
-			// 发送消息
-			$("#btn-send").click(
-					function() {
-						if (connected) {
-							if ($("#input-contacts").val() == '') {
-								alert("请输入联系人!");
-								return;
-							}
-
-							// 创建一个<message>元素并发送
-							var msg = $msg({
-								to : $("#input-contacts").val() + "@" + BOSH_HOST,
-								from : jid,
-								type : 'chat'
-							}).c("body", null, $.toJSON({
-								type : 1,
-								fromUserId : $("#input-jid").val(),
-								messageState : 0,
-								download: false,
-								upload: false,
-								timeLen: 0,
-								timeReceive: 0,
-								mySend: true,
-								read: false,
-								// 时间到分
-								timeSend : Math.round(new Date().getTime() / 1000),
-								content : $("#input-msg").val()
-							}));
-							connection.send(msg.tree());
-
-							$("#msg").append(
-									"<div class=\"msg_wrap\"><div class=\"msg msg-mine\">"
-											+ formatFace($("#input-msg").val()) + "</div></div>");
-							$("#msg").animate({
-								scrollTop : $("#msg").height()
-							}, 300);
-							$("#input-msg").val('');
-						} else {
-							alert("请先登录!");
-						}
-					});
-		});

+ 14 - 0
src/main/resources/static/app/service/chat-service.js

@@ -0,0 +1,14 @@
+/**
+ * 聊天信息服务
+ */
+var ChatService = (function (window, dataService) {
+
+	function queryChatInfoWhenUserVisitWebSite(id, success, error) {
+		if (!id || id === '') return ;
+		dataService.get('/api/chat/infos/' + id, {}, {}, success, error);
+	}
+
+	return {
+		queryChatInfoWhenUserVisitWebSite: queryChatInfoWhenUserVisitWebSite
+	}
+})(window, dataService);

+ 81 - 0
src/main/resources/static/app/service/group-service.js

@@ -0,0 +1,81 @@
+/**
+ * 分组服务
+ */
+var groupService = (function (window, dataService) {
+
+    //重命名分组
+    function renameGroup(ownid, groupName, newGroupName, success, error) {
+        if (!ownid || !groupName || !newGroupName || ownid === '' || groupName == '' || newGroupName == '') return ;
+        dataService.post('/api/chat/group', {ownid: ownid, groupName: groupName, newGroupName: newGroupName}, {}, success, error);
+    }
+
+    //新增分组
+    function addGroup(ownid, groupName, success, error) {
+        if (!ownid || !groupName || ownid === '' || groupName == '') return ;
+        dataService.put('/api/chat/group', {ownid: ownid, groupName: groupName}, {}, success, error);
+    }
+
+    //删除分组
+    function removeGroup(ownid, groupName, success, error) {
+        if (!ownid || !groupName || ownid === '' || groupName == '') return ;
+        dataService.post('/api/chat/group/delete', {ownid: ownid, groupName: groupName}, {}, success, error);
+    }
+
+    /**
+     * 将好友移动到另一分组
+     */
+    function moveToGroup(chatSessionId, ownid, fromGroupName, toGroupName, success, error) {
+        if (!chatSessionId || !fromGroupName || !ownid || !toGroupName || chatSessionId === '' || ownid == '' || fromGroupName == '' || toGroupName == '') return ;
+        dataService.post('/api/chat/group/fromto', {
+            chatSessionId: chatSessionId,
+            ownid: ownid,
+            fromGroupName: fromGroupName,
+            toGroupName: toGroupName
+        }, {}, success, error);
+    }
+
+    /**
+     * 删除联系人
+     */
+    function removeLinkman(chatSessionId, ownerId, groupName, success, error) {
+        if (!chatSessionId || !groupName || !ownerId || chatSessionId === '' || groupName == '' || ownerId == '') return ;
+        dataService.post('/api/chat/group/deleteLinkman', {
+            chatSessionId: chatSessionId,
+            groupName: groupName,
+            ownerId: ownerId
+        }, {}, success, error);
+    }
+
+    /**
+     * 加入黑名单
+     */
+    function setlinkmanToBlacklist(chatSessionId, ownerId, groupName, success, error) {
+        if (!chatSessionId || !groupName || !ownerId || chatSessionId === '' || groupName == '' || ownerId == '') return ;
+        dataService.post('/api/chat/group/setToBlack', {
+            chatSessionId: chatSessionId,
+            groupName: groupName,
+            ownerId: ownerId
+        }, {}, success, error);
+    }
+
+    /**
+     * 搜索联系人
+     */
+    function searchLinkman(keyword, ownerId, success, error) {
+        if (!ownerId || !keyword || keyword == '' || ownerId == '') return ;
+        dataService.get('/api/chat/group/searchLinkman', {
+            keyword: keyword,
+            ownerId: ownerId
+        }, {}, success, error);
+    }
+
+    return {
+        renameGroup: renameGroup,
+        addGroup: addGroup,
+        removeGroup: removeGroup,
+        setlinkmanToBlacklist: setlinkmanToBlacklist,
+        removeLinkman: removeLinkman,
+        moveToGroup: moveToGroup,
+        searchLinkman: searchLinkman
+    }
+})(window, dataService);

+ 15 - 3
src/main/resources/static/app/service/message-service.js

@@ -7,12 +7,24 @@ var messageService = (function (window, dataService) {
 		dataService.post('/api/chat/message', {}, message, success, error);
 	}
 
-	function loadReadableMessageWhenUserRead(sender, receiver, success, error) {
-		dataService.get('/api/chat/message', { operate: 'user_read', sender: sender, receiver: receiver }, {}, success, error);
+	function loadReadableMessageWhenUserRead(owner, contact, success, error) {
+		dataService.get('/api/chat/message', { operate: 'user_read', owner: owner, contact: contact }, {}, success, error);
+	}
+
+	function loadHistoryMessage(owner, contact, max, min, success, error) {
+		var param = { operate: 'history_message', owner: owner, contact: contact };
+		if (max) {
+			param.max = max;
+		}
+		if (min) {
+			param.min = min;
+		}
+		dataService.get('/api/chat/message', param, {}, success, error);
 	}
 
 	return {
 		cacheMessageWhenClientReceive: cacheMessageWhenClientReceive,
-		loadReadableMessageWhenUserRead: loadReadableMessageWhenUserRead
+		loadReadableMessageWhenUserRead: loadReadableMessageWhenUserRead,
+		loadHistoryMessage: loadHistoryMessage
 	}
 })(window, dataService);

+ 4 - 8
src/main/resources/static/app/service/session-service.js

@@ -3,16 +3,12 @@
  */
 var sessionService = (function (window, dataService) {
 
-	function loadSessionsWhenUserRefresh(ownId, success, error) {
-		dataService.get('/api/chat/session', { operate: 'refresh', ownId: ownId }, {}, success, error);
-	}
-
-	function persistSessionWhenUserSendMessage(session, success, error) {
-		dataService.post('/api/chat/session', {}, session, success, error);
+	function updateSessionStateWhenUserSwitchNewSession(sessionId, success, error) {
+		if (!sessionId || sessionId === '') return ;
+		dataService.put('/api/chat/session/' + sessionId, {}, {}, success, error);
 	}
 
 	return {
-		loadSessionsWhenUserRefresh: loadSessionsWhenUserRefresh,
-		persistSessionWhenUserSendMessage: persistSessionWhenUserSendMessage
+		updateSessionStateWhenUserSwitchNewSession: updateSessionStateWhenUserSwitchNewSession
 	}
 })(window, dataService);

+ 3 - 2
src/main/resources/static/lib/css/jquery.emoji.css

@@ -17,8 +17,9 @@
     width: 544px;
     position: absolute;
     background-color: #fff;
-    border: 1px solid #bfbfbf;
-    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.176);
+    border: 1px solid #e8e8e8;
+    /*box-shadow: 0 1px 3px rgba(0, 0, 0, 0.176);*/
+    box-shadow: 0 5px 10px rgba(0,0,0,.3);
 }
 
 .emoji_container ul {

+ 0 - 43
src/main/resources/static/login.html

@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-	<meta charset="UTF-8">
-	<title>Login Page</title>
-	<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css">
-	<script src="/webjars/jquery/jquery.min.js"></script>
-</head>
-<body>
-	<div class="container">
-		<div>
-			<form class="form-horizontal" style="margin: 110px auto 0;width: 600px;">
-				<div class="form-group">
-					<label for="inputEmail3" class="col-sm-2 control-label">Email</label>
-					<div class="col-sm-10">
-						<input type="email" class="form-control" id="inputEmail3" placeholder="Email">
-					</div>
-				</div>
-				<div class="form-group">
-					<label for="inputPassword3" class="col-sm-2 control-label">Password</label>
-					<div class="col-sm-10">
-						<input type="password" class="form-control" id="inputPassword3" placeholder="Password">
-					</div>
-				</div>
-				<div class="form-group">
-					<div class="col-sm-offset-2 col-sm-10">
-						<div class="checkbox">
-							<label>
-								<input type="checkbox"> Remember me
-							</label>
-						</div>
-					</div>
-				</div>
-				<div class="form-group">
-					<div class="col-sm-offset-2 col-sm-10">
-						<button type="submit" class="btn btn-default">Sign in</button>
-					</div>
-				</div>
-			</form>
-		</div>
-	</div>
-</body>
-</html>

+ 759 - 59
src/main/resources/static/style/css/chat.css

@@ -10,9 +10,12 @@ body{
 /* Session List */
 #session-list {
 	padding: 0;
-	height: 413px;
+	position: fixed;
+	width: 291px;
+	height: 100%;
 	overflow: hidden;
-	border: 1px #ccc solid;
+	border: 1px solid #bed8fd;
+	/*box-shadow: 1.5px 2.598px 7px 0px rgb( 0, 0, 0 );*/
 }
 ::-webkit-scrollbar {
 	width: 8px;
@@ -31,27 +34,66 @@ body{
 
 /* Chat Area */
 #chat-area {
-	border: 1px #ccc solid;
-	border-left: none;
+	position: fixed;
+	left: 291px;
+	right: 0;
+	height: 100%;
+	z-index: -1;
+	padding: 0 15px;
+	overflow-y: auto;
 }
 
 #chat-area #chat-title {
-	border-bottom: 1px #ccc solid;
-	padding: 0 15px;
-	height: 30px;
-	line-height:30px;
-	background: #efefef;
+	height: 60px;
+	line-height: 40px;
+	background: #bed8fd;
+	width: 100%;
+	position: fixed;
+	top: 0;
+	left: 291px;
+	right: 0;
+	padding: 0 30px;
 }
 #chat-area #chat-title h3{
 	margin: 0;
 	padding: 0;
 	font-size: 14px;
-	line-height:30px;
+	line-height:60px;
+	position: relative;
+	font-weight: bold;
+	color: #333;
+}
+#chat-area #chat-title h3 .title-icon {
+	float: right;
+}
+#chat-area #chat-title h3 .title-icon img {
+	position: relative;
+	top: -17px;
+	right: -5px;
+	cursor: pointer;
+}
+#chat-area #chat-title h3 .title-icon img:first-child {
+	margin-right: 20px;
+}
+#chat-area #chat-title h3 em{
+	display: inline-block;
+	width: 8px;
+	height: 8px;
+	background: #53d769;
+	border-radius: 100%;
+	position: relative;
+	margin-left: 5px;
 }
 #chat-area #chat-receiver-log {
-	padding: 10px 5px;
-	height: 215px;
 	overflow-y: auto;
+	position: fixed;
+	top: 60px;
+	left: 291px;
+	right: 0;
+	bottom: 184px;
+	z-index: 11111;
+	padding: 0 15px;
+	right:15px;
 }
 
 #chat-area #chat-receiver-log .msg {
@@ -71,13 +113,142 @@ body{
 	border-color: #faebcc;
 }
 
+#chat-area #chat-receiver-log .send-msg {
+	width: 100%;
+	padding: 10px 0;
+	margin-bottom: 10px;
+}
+
+#chat-area #chat-receiver-log .receive-msg {
+	width: 100%;
+	padding: 10px 0;
+	margin-bottom: 10px;
+}
+
+#chat-area #chat-receiver-log .send-msg dt {
+	width: 30px;
+	float: right;
+	height: 30px;
+	margin-top: 10px;
+}
+
+#chat-area #chat-receiver-log .receive-msg dt {
+	width: 30px;
+	float: left;
+	height: 30px;
+	margin-top: 10px;
+}
+
+#chat-area #chat-receiver-log .send-msg dd {
+	margin-left: 0;
+	margin-right: 35px;
+	position: relative;
+	/*line-height: 25px;
+	height: 25px;*/
+}
+
+#chat-area #chat-receiver-log .receive-msg dd {
+	margin-left: 35px;
+	margin-right: 0;
+	position: relative;
+}
+
+#chat-area #chat-receiver-log .send-msg dd>p {
+	font-size: 12px;
+	color: #666;
+	width: 100%;
+	display: inline-block;
+	margin-bottom: 0;
+	word-break: break-all;
+}
+
+#chat-area #chat-receiver-log .receive-msg dd>p {
+	font-size: 12px;
+	color: #666;
+	width: 50%;
+	margin-bottom: 0;
+	word-break: break-all;
+}
+
+#chat-area #chat-receiver-log .send-msg dd>p.name {
+	float: left;
+	text-align: right;
+	font-size: 14px;
+	color: #333;
+}
+
+#chat-area #chat-receiver-log .receive-msg dd>p.name {
+	float: left;
+	text-align: left;
+	font-size: 14px;
+	color: #333;
+}
+
+#chat-area #chat-receiver-log .send-msg dd>p.message-content {
+	text-align: right;
+	position: relative;
+	top: 20px;
+}
+#chat-area #chat-receiver-log .send-msg dd>p.message-content >img {
+	float: right;
+}
+#chat-area #chat-receiver-log .send-msg dd>p.message-content >span >img {
+    float: left;
+}
+#chat-area #chat-receiver-log dl dd>p.message-content >span {
+	display: inline-block;
+	padding: 8px 12px;
+	border-radius: 6px;
+	word-break: break-all;
+	max-width: 50%;
+}
+#chat-area #chat-receiver-log dl dd>p.message-content >span >img {
+	max-width: 72px;
+	max-height:72px;
+}
+#chat-area #chat-receiver-log .send-msg dd>p.message-content >span {
+	background: #5078cb;
+	color: #fff;
+	position: relative;
+	left: 15px;
+	top: -7px;
+    text-align: left;
+    word-break: break-all;
+}
+#chat-area #chat-receiver-log .receive-msg dd>p.message-content >span {
+	position: relative;
+	left: -15px;
+	top: 6px;
+	background: #e4eefd;
+	color: #5078cb;
+}
+
+#chat-area #chat-receiver-log .receive-msg dd>p.message-content {
+	text-align: left;
+	position: relative;
+	top: 7px;
+	left: 3px;
+}
+
+#chat-area #chat-receiver-log .send-msg dd>p>img.content-image,
+#chat-area #chat-receiver-log .receive-msg dd>p>img.content-image {
+	max-width: 420px;
+	max-height: 100px;
+}
+
 #chat-area #chat-operations {
-	height: 25px;
-	border: 1px #ccc solid;
-	border-bottom: none;
-	background: #efefef;
-	border-left: none;
-	border-right: none;
+	height: 32px;
+	line-height: 32px;
+	background: #bed8fd;
+	position: fixed;
+	left: 291px;
+	right: 0;
+	bottom: 152px;
+	padding: 0 15px;
+}
+#chat-area #chat-operations .text-edit {
+	color: #fff;
+	font-size: 18px;
 }
 #chat-area #chat-operations a{
 	margin: 0 5px;
@@ -86,7 +257,7 @@ body{
 	margin-left: 20px;
 }
 #chat-area #chat-operations #show-emoji {
-	background: url(/style/img/icon01.png) no-repeat;
+	background: url(/style/img/smile.png) no-repeat;
 	margin-left: 20px;
 	padding: 0;
 	height: 15px;
@@ -97,65 +268,137 @@ body{
 	float: right;
 	margin-right: 10px;
 	font-size: 12px;
-	line-height: 25px;
+	line-height: 32px;
+	color: #333!important;
 }
 #chat-area #chat-send-area {
-	height: 100px;
+	height: 112px;
+	position: fixed;
+	left: 291px;
+	right: 0;
+	bottom: 40px;
+	padding: 0 15px;
 }
 
 .container-fluid{
-	width: 730px;
-	margin-top: 100px;
-	height: 413px;
-	position: fixed;
-	top: 50%;
-	left: 50%;
-	margin: -250px 0 0 -365px;
+	/*position: fixed;
+	left: 0;
+	right: 0;
 	background: #fff;
 	box-shadow: 0 5px 20px rgba(0,0,0,.3);
+	width: 100%;
+	height: 100%;
+	top: 0;
+	margin: 0;*/
+}
+.container-fluid >.row {
+	width: 100%;
+	height: 100%;
 }
 .chat-bottom{
 	height: 40px;
 	line-height: 40px;
-	border: 1px #ccc solid;
-	border-bottom: none;
-	background: #efefef;
-	border-left: none;
-	border-right: none;
+	background: #bed8fd;
+	position: fixed;
+	left: 291px;
+	right: 0;
+	padding: 0 15px;
+	bottom: 0;
 }
 .chat-bottom button{
-	width: 80px;
-	height: 30px;
-	line-height: 30px;
-	background: #5498dd;
-	border-radius: 5px;
-	border: #2a6496 1px solid;
+	height: 25px;
+	line-height: 25px;
+	background: #5078cb;
+/*	border-radius: 5px;
+	border: #2a6496 1px solid;*/
 	float: right;
-	padding: 0;
+	padding: 0 10px;
 	color: #fff;
 	font-size: 14px;
-	margin: 5px 10px;
+	margin: 7.5px 5px;
 }
-.list-group{
+.list-group, .list-group2{
 	overflow-y: auto;
-	max-height: 400px;
+	/* height: 100%; */
+	margin: 0;
+	background: #c3d2f0;
+	position: fixed;
+	top: 203px;
+	left: 0;
+	bottom: 0;
+	overflow-y: auto;
+	width: 290px;
 }
-.list-group-title{
-	border-bottom: 1px #ccc solid;
-	padding: 0 15px;
+.list-group2 ul {
+	list-style: none;
+	padding:0;
+}
+.list-group2 ul.group-list {
+	margin: 0;
+}
+
+.list-group2 ul.group-list >li{
+	line-height: 30px;
+	cursor: default;
+}
+.list-group2 ul.group-list >li >div >input {
+	height: 20px;
+	line-height: 20px;
+	width: 135px;
+	font-size: 12px;
+}
+.list-group2 ul.group-list >li >div >img {
+	margin-right: 5px;
+	margin-left: 12px;
+}
+.list-group2 ul.group-list >li >div:hover ,.list-group2 ul.group-item-list >li:hover {
+	background: #85a1dc;
+}
+.list-group2 ul.group-item-list >li {
 	height: 30px;
 	line-height: 30px;
-	background: #efefef;
+	padding-left: 30px;
+	cursor: default;
 }
-.list-group-title h3{
-	margin: 0;
-	padding-left: 10px;
+.list-group2 ul.group-item-list >li >span {
+	margin-left: 12px;
+	display: block;
+	width: 231px;
+	text-overflow: ellipsis;
+	overflow: hidden;
+	white-space: nowrap;
+}
+.list-group-title{
+	/*border-bottom: 1px #ccc solid;*/
+	/*padding: 0 15px;*/
+	height: 50px;
+	line-height: 50px;
+	background: #fff;
+	border-bottom: 1px #c6d8fd solid;
+	margin-bottom: 6px;
+}
+.list-group-title span{
 	font-size: 14px;
-	line-height: 30px;
+	display: inline-block;
+	height: 50px;
+	line-height: 50px;
+	color: #666;
+	margin: 0 25px;
+}
+.list-group-title span:hover{
+	cursor: pointer;
+}
+.list-group-title span.active {
+	color: #5078cb;
+	border-bottom: 2px solid #5078cb;
+}
+.list-group-title span img {
+	position: relative;
+	bottom: 3px;
 }
 .list-group dl{
 	width: 100%;
-	height: 60px;
+	height: 65px;
 	margin: 0 auto;
 	padding: 10px;
 }
@@ -164,9 +407,27 @@ body{
 	width: 40px;
 	height: 40px;
 	text-align: center;
+	position: relative;
+}
+.list-group dl dt em{
+	display: inline-block;
+	width: 36px;
+	height: 16px;
+	background: #5078cb;
+	color: #fff;
+	text-align: center;
+	line-height: 16px;
+	position: absolute;
+	top: 31px;
+	left: 1px;
+	border-radius: 2px;
+	font-size: 12px;
+	font-style: normal;
+	font-weight: initial;
+	/* font-family: "宋体"; */
 }
 .list-group dl:hover,.list-group dl.active{
-	background: #ebeef3;
+	background: #88abe0;
 }
 .list-group dl dt img{
 	width: 40px;
@@ -177,12 +438,18 @@ body{
 	margin-left: 45px;
 }
 .list-group dl dd{
-	height: 25px;
+	height: 20px;
 }
 .list-group dl dd span.name{
 	float: left;
 	font-size: 14px;
 	color: #333;
+	font-weight: bold;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	display: block;
+	max-width: 155px;
 }
 .list-group dl dd span.time{
 	float: right;
@@ -196,12 +463,27 @@ body{
 	white-space: nowrap;
 	overflow: hidden;
 	text-overflow: ellipsis;
+	width: 216px;
+	padding-right: 19px;
+	padding-top: 4px;
+}
+.list-group dl i {
+	float: right;
+	background: #ca5a5a;
+	color: #fff;
+	border-radius: 100%;
+	padding: 2px;
+	font-size: 12px;
+	margin-right: 4px;
+	width: 20px;
+	height: 20px;
+	top: -18px;
+	position: relative;
 }
 #chat-receiver-log dl{
 	width: 100%;
 	margin: 0 auto;
 	padding: 10px 0;
-	border-bottom: #e8e8e8 1px solid;
 }
 #chat-receiver-log dl dt{
 	width: 30px;
@@ -216,8 +498,8 @@ body{
 	margin-left: 0;
 }
 #chat-receiver-log dl dt img{
-	width: 30px;
-	height: 30px;
+	width: 35px;
+	height: 35px;
 	border-radius: 100%;
 }
 #chat-receiver-log dl dd{
@@ -229,17 +511,435 @@ body{
 	font-size: 14px;
 	color: #333;
 }
-#chat-receiver-log dl dd span{
+/*#chat-receiver-log dl dd span{
 	position: absolute;
 	right: 10px;
 	top: 10px;
 	font-size: 12px;
 	color: #999;
-}
+}*/
 #chat-receiver-log dl dd p{
 	font-size: 12px;
 	color: #666;
 	width: 100%;
 	display: inline-block;
 	margin-bottom: 0;
+	word-break: break-all;
+}
+
+/*
+图片发送*/
+.emoji_container{
+	top: 280px !important;
+	left: 483px !important;
+}
+.chat-recored{
+	border-left: 3px solid #bed8fd;
+	border-right: 3px solid #b3d8fd;
+	display: inline-block;
+	width: 217px;
+	margin: 0;
+	float: right;
+	padding-bottom: 40px;
+	z-index: 78;
+	position: fixed;
+	right: 0;
+	bottom: 0;
+	top: 0;
+	background: #fff;
+}
+.chat-recored ul,.chat-recored ul li{
+	width: 100%;
+	margin: 0 auto;
+	display: inline-block;
+}
+.chat-recored ul{
+	-webkit-padding-start: 0;
+	overflow-y: auto;
+	overflow-x: hidden;
+	padding: 10px 10px 10px 5px;
+	position: fixed;
+	top: 37px;
+	bottom: 40px;
+	right: 0;
+	width: 217px;
+}
+.chat-recored ul li{
+	float: left;
+	list-style: none;
+}
+.chat-recored ul li p{
+	font-size: 14px;
+	color: #5078cb;
+}
+.chat-recored ul li.customer p{
+	color: #53d769;
+}
+.chat-recored ul li img {
+    max-width: 163px;
+}
+.chat-recored ul li p.content{
+	color: #333;
+	font-size: 12px;
+	padding-left: 10px;
+	padding-right: 10px;
+	word-break: break-all;
+}
+.chat-recored .recored-menu{
+	width: 100%;
+	height: 37px;
+	line-height: 37px;
+	background: #5078cb;
+}
+.chat-recored .recored-menu span{
+	font-size: 14px;
+	color: #fff;
+	margin-left: 10px;
+}
+.chat-recored .recored-menu img {
+	float: right;
+	margin-top: 11px;
+	margin-right: 5px;
+	cursor: pointer;
+}
+.chat-recored .record-time-filter {
+	position: absolute;
+	bottom: 0;
+	height: 40px;
+	background: #bed8fd;
+	width: 211px;
+}
+.member-title{
+	width: 100%;
+	height: 123px;
+	margin: 0 auto;
+	padding-top: 12px;
+	background: #5078cb;
+}
+.member-title div.img {
+	width: 50px;
+	height: 50px;
+	float: left;
+	border-radius: 100%;
+	margin-left: 10px;
+	margin-top: 17px;
+}
+.member-title div.content{
+	margin-left: 70px;
+	margin-top: 22px;
+}
+.member-title div.content p, .member-title div.content >span{
+	font-size: 14px;
+	line-height: 20px;
+	margin: 0;
+	color: #fff;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+}
+.member-title div.content span {
+	font-weight: bold;
+}
+.member-title div.content .star-img-group {
+	margin-left: 12px;
+	display: inline-block;
+}
+.member-title .title-icon {
+	padding: 0 14px;
+}
+
+.member-title .title-icon img {
+	position: relative;
+	left: 216px;
+	top: -8px;
+}
+
+.member-title .title-icon img:last-child {
+	margin-left: 20px;
+}
+
+#session-list .search-user input:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
+	color: #d9e5fd;
+}
+
+#session-list .search-user input::-moz-placeholder { /* Mozilla Firefox 19+ */
+	color: #d9e5fd;
+}
+
+#session-list .search-user input:-ms-input-placeholder{
+	color: #d9e5fd;
+}
+
+#session-list .search-user input::-webkit-input-placeholder{
+	color: #d9e5fd;
+}
+
+#session-list .search-user {
+	position: relative;
+}
+#session-list .search-user input {
+	height: 30px;
+	line-height: 30px;
+	background: #8fa9de;
+	width: 291px;
+	margin: 0;
+	border: none;
+	padding: 0;
+	padding-left: 15px;
+	padding-right: 60px;
+}
+#session-list .search-user >span {
+	position: absolute;
+	right: 10px;
+	top: 0;
+	line-height: 30px;
+	height: 30px;
+	font-size: 14px;
+	color: #fff;
+	cursor: default;
+}
+
+#session-list .search-user >span img {
+	margin-right: 2px;
+}
+
+ul.group-menu, ul.linkman-menu, ul.group-list-menu {
+	list-style: none;
+	padding: 0;
+	margin: 0;
+	background: #eff4fb;
+	width: fit-content;
+	box-shadow: 0 5px 20px rgba(0,0,0,.3);
+	position: absolute;
+	display: none;
+}
+
+ul.group-menu li, ul.linkman-menu li, ul.group-list-menu li {
+	line-height: 22px;
+	height: 22px;
+	font-size: 14px;
+	color: #666;
+	margin-left: 22px;
+	padding: 0 10px;
+	background: #fff;
+	cursor: default;
+}
+
+ul.group-menu li:hover, ul.linkman-menu li:hover, ul.group-list-menu li:hover{
+	background: #5078cb;
+	color: #fff;
+}
+
+.remind-box {
+	width: 268px;
+	background: #fff;
+	position: absolute;
+	left: 10px;
+	top: 300px;
+	z-index: 300;
+	box-shadow: 0 5px 20px rgba(0,0,0,.3);
+	display: none;
+}
+
+.remind-box .box-header {
+	height: 24px;
+	line-height: 24px;
+	background: #5078cb;
+}
+.remind-box .box-header img {
+	float: right;
+	padding-top: 7px;
+	padding-right: 10px;
+	cursor: pointer;
+}
+.remind-box .box-title {
+	margin-top: 10px;
+	text-align: center;
+}
+.remind-box .box-title span:first-child {
+	width: 20px;
+	height: 20px;
+	line-height: 20px;
+	display: inline-block;
+	background: #5078cb;
+	color: #fff;
+	border-radius: 100%;
+	margin-right: 8px;
+}
+.remind-box .box-title >div {
+	font-size: 12px;
+	color: #999;
+	padding: 5px 0;
+}
+.remind-box .box-info {
+	text-align: center;
+}
+.remind-box .box-info img {
+	width: 35px;
+	height: 35px;
+	border-radius: 100%;
+	display: inline-block;
+	margin-right: 10px;
+}
+.remind-box .box-btn {
+	height: 45px;
+	line-height: 45px;
+	text-align: center;
+}
+.remind-box .box-btn span {
+	height: 27px;
+	line-height: 27px;
+	display: inline-block;
+	padding: 0 20px;
+	cursor: pointer;
+}
+.remind-box .box-btn span:first-child {
+	background: #acabab;
+	color: #333;
+}
+.remind-box .box-btn span:last-child
+{
+	background: #5078cb;
+	color: #fff;
+}
+#preview-img {
+	position: fixed;
+	background: rgba(0,0,0,.3);
+	width: 100%;
+	height: 100%;
+	display: none;
+	text-align: center;
+	z-index: 100;
+}
+#preview-img img{
+	max-height: 400px;
+	max-width: 800px;
+	margin-top: 10%;
+}
+#preview-img div{
+	position: absolute;
+	right: 15px;
+	line-height: 35px;
+	top: 15px;
+	color: #fff;
+	width: 35px;
+	height: 35px;
+	background: rgba(0, 0, 0, 0.5);
+	border-radius: 100%;
+	opacity: 1;
+	margin: 0;
+	z-index: 100000;
+	min-height: initial;
+	text-align: center;
+	cursor: pointer;
+}
+#preview-img div a{
+	position: relative;
+	left: 0;
+	bottom: 0;
+	font-size: 34px;
+	color: #fff;
+}
+
+#chat-receiver-log ul {
+	list-style: none;
+	-webkit-padding-start: 0;
+	padding: 15px 10px 5px;
+	margin: 0;
+}
+
+#chat-receiver-log ul .chat-log {
+	position: relative;
+    margin-bottom: 10px;
+}
+
+#chat-receiver-log ul .chat-log .chat-log-avatar {
+	display: inline-block;
+	width: 35px;
+	height: 35px;
+}
+
+#chat-receiver-log ul .chat-log .chat-log-avatar img {
+	width: 35px;
+	height: 35px;
+}
+
+#chat-receiver-log ul .chat-log.chat-log-receive .chat-log-avatar {
+	float: left;
+}
+
+#chat-receiver-log ul .chat-log.chat-log-send .chat-log-avatar {
+	float: right;
+}
+
+#chat-receiver-log ul .chat-log .chat-log-text {
+	display: inline-block;
+	position: relative;
+	padding: 5px 15px;
+	background: #5078cb;
+	color: #ffffff;
+	border-radius: 10px;
+	position: relative;
+	top: 5px;
+	word-break: break-all;
+}
+
+#chat-receiver-log ul .chat-log.chat-log-receive .chat-log-text {
+	float: left;
+	margin-left: 10px;
+	background: #e4eefd;
+	color: #000000;
+	max-width: 300px;
+	max-width: 300px;
+	word-break: break-all;
+}
+
+#chat-receiver-log ul .chat-log.chat-log-send .chat-log-text {
+	float: right;
+	margin-right: 10px;
+	background: #5078cb;
+	max-width: 300px;
+}
+#chat-receiver-log ul .chat-log.chat-log-send .chat-log-text img {
+	max-width: 267px;
+	max-height: 300px;
+}
+#chat-receiver-log ul .chat-log .chat-log-text:after {
+	position: absolute;
+	top: 3px;
+	width: 23px;
+	height: 16px;
+	content: "";
+}
+
+#chat-receiver-log ul .chat-log.chat-log-receive .chat-log-text:after {
+	left: -8px;
+	background: url("/style/img/left.png") no-repeat;
+}
+
+#chat-receiver-log ul .chat-log.chat-log-send .chat-log-text:after {
+	right: -8px;
+	background: url("/style/img/right.png") no-repeat;
+}
+#chat-receiver-log ul .chat-log.chat-log-receive .chat-log-text img {
+	max-width: 270px;
+	max-height: 300px;
+}
+#loading {
+	z-index: 100;
+	position: fixed;
+	left: 0;
+	right: 0;
+	top: 0;
+	bottom: 0;
+	text-align: center;
+	background: rgba(0,0,0,.3);
+	display: none;
+}
+#loading img{
+	position: relative;
+	top: 50%;
+}
+input-msg  {
+	right: 0 !important;
 }

BIN
src/main/resources/static/style/img/arrow-right.png


BIN
src/main/resources/static/style/img/close.png


BIN
src/main/resources/static/style/img/double-active.png


BIN
src/main/resources/static/style/img/double.png


BIN
src/main/resources/static/style/img/left.png


BIN
src/main/resources/static/style/img/loading.gif


BIN
src/main/resources/static/style/img/magnifier.png


BIN
src/main/resources/static/style/img/photo01.png


BIN
src/main/resources/static/style/img/qq/1.gif


BIN
src/main/resources/static/style/img/qq/10.gif


BIN
src/main/resources/static/style/img/qq/100.gif


BIN
src/main/resources/static/style/img/qq/101.gif


BIN
src/main/resources/static/style/img/qq/102.gif


BIN
src/main/resources/static/style/img/qq/103.gif


BIN
src/main/resources/static/style/img/qq/104.gif


BIN
src/main/resources/static/style/img/qq/105.gif


BIN
src/main/resources/static/style/img/qq/106.gif


BIN
src/main/resources/static/style/img/qq/107.gif


BIN
src/main/resources/static/style/img/qq/108.gif


BIN
src/main/resources/static/style/img/qq/109.gif


BIN
src/main/resources/static/style/img/qq/11.gif


BIN
src/main/resources/static/style/img/qq/110.gif


BIN
src/main/resources/static/style/img/qq/111.gif


BIN
src/main/resources/static/style/img/qq/112.gif


BIN
src/main/resources/static/style/img/qq/113.gif


BIN
src/main/resources/static/style/img/qq/114.gif


BIN
src/main/resources/static/style/img/qq/115.gif


BIN
src/main/resources/static/style/img/qq/116.gif


BIN
src/main/resources/static/style/img/qq/117.gif


BIN
src/main/resources/static/style/img/qq/118.gif


BIN
src/main/resources/static/style/img/qq/119.gif


BIN
src/main/resources/static/style/img/qq/12.gif


BIN
src/main/resources/static/style/img/qq/120.gif


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