瀏覽代碼

Merge remote-tracking branch 'origin/developerM' into developer

zhengjinyi 10 月之前
父節點
當前提交
cc5f1600fa
共有 40 個文件被更改,包括 2101 次插入738 次删除
  1. 93 93
      src/main/java/com/caimei/www/controller/BaseController.java
  2. 69 63
      src/main/java/com/caimei/www/controller/authorized/document/DocumentController.java
  3. 1 0
      src/main/resources/static/css/account/login.css
  4. 6 3
      src/main/resources/static/css/base/base.h5.css
  5. 234 28
      src/main/resources/static/css/base/base.pc.css
  6. 621 0
      src/main/resources/static/css/caimei-chat/chats.css
  7. 47 44
      src/main/resources/static/css/user-center/operation/form.css
  8. 二進制
      src/main/resources/static/img/base/icon-ai@1x.png
  9. 二進制
      src/main/resources/static/img/base/icon-ai@2x.png
  10. 二進制
      src/main/resources/static/img/base/icon-aiAdd@2x.png
  11. 二進制
      src/main/resources/static/img/base/icon-aiBtn@2x.png
  12. 二進制
      src/main/resources/static/img/base/icon-aiUser@2x.jpg
  13. 二進制
      src/main/resources/static/img/base/icon-ailoading@2x.gif
  14. 21 10
      src/main/resources/static/js/account/login.js
  15. 25 0
      src/main/resources/static/js/anonymous/anonymous.js
  16. 130 131
      src/main/resources/static/js/base.js
  17. 31 0
      src/main/resources/static/js/caimei-chat/chats.js
  18. 40 0
      src/main/resources/static/js/caimei-chat/worker.js
  19. 16 21
      src/main/resources/static/js/common/ajax.service.js
  20. 25 0
      src/main/resources/static/js/common/serviceapi/user.service.js
  21. 66 0
      src/main/resources/static/js/common/serviceapi/utils.service.js
  22. 300 97
      src/main/resources/static/js/mixins/cmAiMixins.js
  23. 3 3
      src/main/resources/static/js/mixins/cmSysMixins.js
  24. 91 0
      src/main/resources/static/js/we_chat/we_chat.js
  25. 125 125
      src/main/resources/templates/account/bind.html
  26. 1 1
      src/main/resources/templates/account/forget.html
  27. 1 1
      src/main/resources/templates/account/login-fast.html
  28. 1 1
      src/main/resources/templates/account/login.html
  29. 1 1
      src/main/resources/templates/account/register-club.html
  30. 1 1
      src/main/resources/templates/account/register-supplier.html
  31. 32 32
      src/main/resources/templates/account/register.html
  32. 1 1
      src/main/resources/templates/account/upgrade.html
  33. 1 1
      src/main/resources/templates/article/list.html
  34. 1 1
      src/main/resources/templates/article/recommendation.html
  35. 68 0
      src/main/resources/templates/caimei-chat/chats.html
  36. 34 26
      src/main/resources/templates/components/drawer-ai.html
  37. 1 0
      src/main/resources/templates/components/foot-link.html
  38. 3 3
      src/main/resources/templates/components/footer.html
  39. 6 0
      src/main/resources/templates/components/header.html
  40. 5 51
      src/main/resources/templates/we_chat/redirect_uri.html

+ 93 - 93
src/main/java/com/caimei/www/controller/BaseController.java

@@ -1,93 +1,93 @@
-package com.caimei.www.controller;
-
-import com.alibaba.fastjson.JSONObject;
-import com.caimei.www.pojo.page.BaseLink;
-import com.caimei.www.pojo.page.TopMenu;
-import com.caimei.www.service.page.BaseService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.ModelAttribute;
-
-import java.util.List;
-
-/**
- * 页面全局变量
- *
- * @author : Charles
- * @date : 2020/6/18
- */
-@Controller
-public class BaseController {
-	@Value("${caimei.coreServer}")
-	private String coreServer;
-	@Value("${caimei.zplmDomain}")
-	private String zplmDomain;
-	@Value("${caimei.zplmServer}")
-	private String zplmServer;
-	@Value("${aliyunOss.ossBucket}")
-	private String ossBucket;
-    /** 打包时间 */
-    @Value("${caimei.siteEnv}")
-    private String siteEnv;
-    /** 打包时间 */
-    @Value("${spring.application.build-time}")
-    private String buildTime;
-    /** 错误页面 */
-	private static final String ERROR_PATH = "error/404";
-
-    public BaseService baseService;
-    @Autowired
-    public void setBaseService(BaseService baseService) {
-        this.baseService = baseService;
-    }
-
-	/**
-	 * 页面公共请求
-	 * @param model
-	 * @param request
-	 * @return
-	 */
-	@ModelAttribute
-	public Model init(final Model model, ServerHttpRequest request) {
-		// 环境变量,(2:正式环境,1:测试环境,0:开发环境)
-	    model.addAttribute("siteEnv", siteEnv);
-		// 判断请求设备
-		List<String> strings = request.getHeaders().get("User-Agent");
-		String agent = strings!=null ? strings.get(0) : "";
-		model.addAttribute("agent", agent);
-	    // 静态文件版本号
-	    model.addAttribute("version", buildTime);
-		// spi服务器地址
-		model.addAttribute("coreServer", coreServer);
-		// zplm服务器地址
-		model.addAttribute("zplmDomain", zplmDomain);
-		// zplm接口地址
-		model.addAttribute("zplmServer", zplmServer);
-		// 阿里云oss对象存储文件上传目录
-		model.addAttribute("ossBucket", ossBucket);
-		// 搜索热门关键字
-		List<String> searchHotWord = baseService.getSearchHotWord();
-		model.addAttribute("searchHotWord", searchHotWord);
-		// 头部菜单
-		List<TopMenu> menuList = baseService.getNavMenu();
-		model.addAttribute("topMenuList", menuList);
-		// 分类菜单
-		List<JSONObject> classifyList = baseService.getClassifyJson();
-		model.addAttribute("classifyJson", classifyList);
-		// 底部帮助页
-		List<BaseLink> helpPages = baseService.getHelpPages();
-		model.addAttribute("helpPages", helpPages);
-		// 友情链接
-		List<BaseLink> friendLinks = baseService.getFriendLinks();
-		model.addAttribute("friendLinks", friendLinks);
-
-		return model;
-	}
-
-	protected String errorPath(){
-		return ERROR_PATH;
-	}
-}
+package com.caimei.www.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.caimei.www.pojo.page.BaseLink;
+import com.caimei.www.pojo.page.TopMenu;
+import com.caimei.www.service.page.BaseService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.ModelAttribute;
+
+import java.util.List;
+
+/**
+ * 页面全局变量
+ *
+ * @author : Charles
+ * @date : 2020/6/18
+ */
+@Controller
+public class BaseController {
+	@Value("${caimei.coreServer}")
+	private String coreServer;
+	@Value("${caimei.zplmDomain}")
+	private String zplmDomain;
+	@Value("${caimei.zplmServer}")
+	private String zplmServer;
+	@Value("${aliyunOss.ossBucket}")
+	private String ossBucket;
+    /** 打包时间 */
+    @Value("${caimei.siteEnv}")
+    private String siteEnv;
+    /** 打包时间 */
+    @Value("${spring.application.build-time}")
+    private String buildTime;
+    /** 错误页面 */
+	private static final String ERROR_PATH = "error/404";
+
+    public BaseService baseService;
+    @Autowired
+    public void setBaseService(BaseService baseService) {
+        this.baseService = baseService;
+    }
+
+	/**
+	 * 页面公共请求
+	 * @param model
+	 * @param request
+	 * @return
+	 */
+	@ModelAttribute
+	public Model init(final Model model, ServerHttpRequest request) {
+		// 环境变量,(2:正式环境,1:测试环境,0:开发环境)
+	    model.addAttribute("siteEnv", siteEnv);
+		// 判断请求设备
+		List<String> strings = request.getHeaders().get("User-Agent");
+		String agent = strings!=null ? strings.get(0) : "";
+		model.addAttribute("agent", agent);
+	    // 静态文件版本号
+	    model.addAttribute("version", buildTime);
+		// spi服务器地址
+		model.addAttribute("coreServer", coreServer);
+		// zplm服务器地址
+		model.addAttribute("zplmDomain", zplmDomain);
+		// zplm接口地址
+		model.addAttribute("zplmServer", zplmServer);
+		// 阿里云oss对象存储文件上传目录
+		model.addAttribute("ossBucket", ossBucket);
+		// 搜索热门关键字
+		List<String> searchHotWord = baseService.getSearchHotWord();
+		model.addAttribute("searchHotWord", searchHotWord);
+		// 头部菜单
+		List<TopMenu> menuList = baseService.getNavMenu();
+		model.addAttribute("topMenuList", menuList);
+		// 分类菜单
+		List<JSONObject> classifyList = baseService.getClassifyJson();
+		model.addAttribute("classifyJson", classifyList);
+		// 底部帮助页
+		List<BaseLink> helpPages = baseService.getHelpPages();
+		model.addAttribute("helpPages", helpPages);
+		// 友情链接
+		List<BaseLink> friendLinks = baseService.getFriendLinks();
+		model.addAttribute("friendLinks", friendLinks);
+
+		return model;
+	}
+
+	protected String errorPath(){
+		return ERROR_PATH;
+	}
+}

+ 69 - 63
src/main/java/com/caimei/www/controller/authorized/document/DocumentController.java

@@ -1,63 +1,69 @@
-package com.caimei.www.controller.authorized.document;
-
-import com.caimei.www.controller.BaseController;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-
-@Controller
-public class DocumentController extends BaseController {
-    /** 资料库登录 */
-    private static final String DOCUMENT_LOGIN = "document/login";
-    /** 资料列表 */
-    private static final String DOCUMENT_LIST = "document/list";
-    /** 资料详情 */
-    private static final String DOCUMENT_DETAILS = "document/details";
-    /** PDF资料详情 */
-    private static final String DOCUMENT_PDFDETAILS = "document/pdfdetails";
-    /** 更多资料 */
-    private static final String DOCUMENT_MORECONTENT= "document/more-content";
-    /** 美业资料 */
-    private static final String BEAUTY_ARCHIVE = "document/beauty-archive";
-    /** 美业资料自定义页面 */
-    private static final String BEAUTY_ARCHIVE_DETAIL = "document/beauty-archive-detail";
-
-    /** 资料库登录 */
-    @GetMapping("/document/login.html")
-    public String dashboard() {
-        return DOCUMENT_LOGIN;
-    }
-
-    /** 资料列表 */
-    @GetMapping("/document/list.html")
-    public String documentList() {
-        return DOCUMENT_LIST;
-    }
-
-    /** 资料详情 */
-    @GetMapping("/document/details.html")
-    public String documentDetails() {
-        return DOCUMENT_DETAILS;
-    }
-
-    /** pdf资料详情 */
-    @GetMapping("/document/pdfdetails.html")
-    public String documentPdfDetail() {
-        return DOCUMENT_PDFDETAILS;
-    }
-
-    /** 更多资料 */
-    @GetMapping("/document/more-content.html")
-    public String orderSettlement() {
-        return DOCUMENT_MORECONTENT;
-    }
-
-    /** 美业资料 */
-    @GetMapping("/document/beauty-archive.html")
-    public String productArchiveList() {
-        return BEAUTY_ARCHIVE;
-    }
-
-    /** 美业资料 */
-    @GetMapping("/document/archive-detail.html")
-    public String productArchiveDetail() { return BEAUTY_ARCHIVE_DETAIL; }
-}
+package com.caimei.www.controller.authorized.document;
+
+import com.caimei.www.controller.BaseController;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class DocumentController extends BaseController {
+    /** 资料库登录 */
+    private static final String DOCUMENT_LOGIN = "document/login";
+    /** 资料列表 */
+    private static final String DOCUMENT_LIST = "document/list";
+    /** 资料详情 */
+    private static final String DOCUMENT_DETAILS = "document/details";
+    /** PDF资料详情 */
+    private static final String DOCUMENT_PDFDETAILS = "document/pdfdetails";
+    /** 更多资料 */
+    private static final String DOCUMENT_MORECONTENT= "document/more-content";
+    /** 美业资料 */
+    private static final String BEAUTY_ARCHIVE = "document/beauty-archive";
+    /** 美业资料自定义页面 */
+    private static final String BEAUTY_ARCHIVE_DETAIL = "document/beauty-archive-detail";
+    /** 采美AI助手h5页面 */
+    private static final String CAIMEI_CHATS = "caimei-chat/chats";
+
+    /** 资料库登录 */
+    @GetMapping("/document/login.html")
+    public String dashboard() {
+        return DOCUMENT_LOGIN;
+    }
+
+    /** 资料列表 */
+    @GetMapping("/document/list.html")
+    public String documentList() {
+        return DOCUMENT_LIST;
+    }
+
+    /** 资料详情 */
+    @GetMapping("/document/details.html")
+    public String documentDetails() {
+        return DOCUMENT_DETAILS;
+    }
+
+    /** pdf资料详情 */
+    @GetMapping("/document/pdfdetails.html")
+    public String documentPdfDetail() {
+        return DOCUMENT_PDFDETAILS;
+    }
+
+    /** 更多资料 */
+    @GetMapping("/document/more-content.html")
+    public String orderSettlement() {
+        return DOCUMENT_MORECONTENT;
+    }
+
+    /** 美业资料 */
+    @GetMapping("/document/beauty-archive.html")
+    public String productArchiveList() {
+        return BEAUTY_ARCHIVE;
+    }
+
+    /** 美业资料 */
+    @GetMapping("/document/archive-detail.html")
+    public String productArchiveDetail() { return BEAUTY_ARCHIVE_DETAIL; }
+
+    /** 采美AI助手 */
+    @GetMapping("/chats.html")
+    public String caimeiChats() { return CAIMEI_CHATS; }
+}

+ 1 - 0
src/main/resources/static/css/account/login.css

@@ -95,6 +95,7 @@ li{list-style:none}
 @media screen and (max-width:768px){
  body{background:#FFF}
  footer{display:none}
+ .baseHeadCenter.account{ display: none;}
  .baseHeadCenter.account.dep{background: #1c1c1c;height: 21.4vw;}
  .baseHeadCenter.account .wrap.dep .logo{height: 19.2vw;}
  .baseHeadCenter .logo img{ width: 100%;height: 100%;display: block; }

+ 6 - 3
src/main/resources/static/css/base/base.h5.css

@@ -71,7 +71,7 @@
 .baseHeadCenter .mAddCart:before{background-position:-17vw 0}
 .baseHeadCenter .superVip:before{background-position:-32vw -93vw}
 .baseHeadCenter .mNotice:before{content:'';display:block;width:6.4vw;height:6.4vw;background-position:0 0}
-.baseHeadCenter .searchBox{position:absolute;top:13.4vw;left:0;width:100%;padding-top:1.8vw}
+.baseHeadCenter .searchBox{position:absolute;top:13.4vw;left:0;width:100%;padding:1.8vw 3vw 0 3vw;box-sizing: border-box;display: flex;}
 .baseHeadCenter .searchBox .supplierH5 {
     float: right;
     height: 9.6vw;
@@ -83,7 +83,7 @@
 .baseHeadCenter .supplier_H5:before {
     background-position: -49vw -93vw;
 }
-.baseHeadCenter .search{width:93.4vw;height:9.6vw;margin:0 auto;border:1px solid #ff5b00;border-radius:2px;position:relative;border-radius: 5.8vw;box-sizing: border-box;}
+.baseHeadCenter .search{width:85vw;height:9.6vw;border:1px solid #ff5b00;position:relative;border-radius: 5.8vw;box-sizing: border-box;}
 /*.baseHeadCenter .search {*/
 /*    width: 86.4vw;*/
 /*    height: 9.6vw;*/
@@ -97,8 +97,11 @@
 .baseHeadCenter .search .jqSelect select{width:20vw;height:9.6vw;line-height:9.6vw;border:none;font-size:3.7vw;color:#4A4F58;padding:0 6vw 0 3vw}
 .baseHeadCenter .search .jqSelect:before{right:4vw;line-height:9.6vw}
 .baseHeadCenter .search .jqSelect:after{content:'';position:absolute;right:0;top:3.4vw;width:.5vw;height:2.8vw;background:#BEC2C9}
-.baseHeadCenter .search .keyword{position:absolute;right:2vw;top:0;border:none;outline:none;width:68.4vw;height:100%;line-height:9.6vw;font-size:3.7vw;color:#4A4F58;text-indent:2.6vw;border-radius: 5.8vw;}
+.baseHeadCenter .search .keyword{position:absolute;left:2vw;top:0;border:none;outline:none;width:68vw;height:100%;line-height:9.6vw;font-size:3.7vw;color:#4A4F58;text-indent:2.6vw;border-radius: 5.8vw;}
 .baseHeadCenter .search .searchBtn{position: absolute;right: 1vw;top: 1vw;font-size: 3vw;padding: 0 4vw;height: 7.5vw;line-height: 7.5vw;text-align: center;background: #ff5b00;border-radius: 4vw;color: #FFFFFF;font-weight: bold;}
+.baseHeadCenter .searchAi{ width: 9.6vw;height: 9.6vw;margin-left: 1vw;}
+.baseHeadCenter .searchAi a{ width: 9.6vw;height: 9.6vw;display: flex;justify-content: center;flex-direction: column;align-items: center;}
+.baseHeadCenter .searchAi a img{ width: 7vw;height: 7vw;display: inline-flex;}
 .baseHeadCenter.account{height:13.4vw;border-bottom:solid 1px #ebecef}
 .baseHeadCenter.account .closeAccount{float:right;padding:3.5vw 2.8vw;width:6.4vw;height:6.4vw;text-align:center}
 .baseHeadCenter.account .closeAccount:before{content:'\2715';font-size:4.5vw;font-weight:bold}

+ 234 - 28
src/main/resources/static/css/base/base.pc.css

@@ -136,6 +136,7 @@ iframe{width:320px !important;height: 280px !important}
 .baseHeadCenter .hotKey{color:#50607A;font-size:12px;line-height:36px;box-sizing: border-box;padding-left: 24px;}
 .baseHeadCenter .hotKey .word{padding:0 8px;font-style:normal;cursor:pointer;}
 .baseHeadCenter .hotKey .word:hover{color:#FF5B00}
+.baseHeadCenter .searchAi{ display: none; }
 /*优化供应商登录位置*/
 /*.baseHeadCenter .wechat_qrcode{width: 270px;height: 100%;float: left;margin-left: 33px; padding: 10px 0; box-sizing: border-box;}*/
 /*.baseHeadCenter .wechat_qrcode .q_item{width: 60px;height: 100%;float: left;margin: 0 15px;position: relative;cursor: pointer;*/
@@ -404,7 +405,7 @@ iframe{width:320px !important;height: 280px !important}
 .loginAlert:after{content:'';display:block;width:125px;height:125px;background:url(/img/account/to_login.png) no-repeat left top;background-size:100% 100%;margin:10px 0 0 15px;}
 #supplierLogin {display: none;}
 /* 咨询,回到顶部 */
-#scrollTop{display:none;position:fixed;right:0;margin-right:0;width:88px;z-index:999;bottom:60px;padding: 10px 0;background: #FFFFFF; border-radius: 16px;box-shadow: -2px 0 30px 2px rgba(97, 105, 119, 0.18);}
+#scrollTop{display:none;position:fixed;right:0;margin-right:0;width:88px;z-index:999;bottom:36px;padding: 10px 0;background: #FFFFFF; border-radius: 16px;box-shadow: -2px 0 30px 2px rgba(97, 105, 119, 0.18);}
 #scrollTop .item{width:100%;border-radius: 10px;display: flex;align-items: center;flex-direction: row; background-color:#fff;box-sizing:border-box;text-align:center;font-size:12px;position:relative}
 #scrollTop .item>span{display:block;width:94px;box-sizing:border-box;position:relative;cursor:pointer;white-space:pre-wrap;word-break:break-all;}
 #scrollTop .item>span:hover{color:#FF5B00;}
@@ -556,22 +557,139 @@ iframe{width:320px !important;height: 280px !important}
 }
 /*采美AI助手弹窗样式*/
 .el-drawer__header{ margin-bottom: 10px !important; }
-.cm_ai_container{ width: 100%;height: 100%;display: flex;flex-direction: column; box-sizing: border-box;padding:0 15px; background-image: radial-gradient(circle at 14% 85%,#e7ecf7 0,rgba(231,236,247,0) 37%),radial-gradient(circle at 3.4% 3.7%,rgba(245,237,241,.5) 0,rgba(245,237,241,0) 28%),radial-gradient(circle at 100% 18%,#e8ebea 0,hsla(160,7%,92%,0) 30%),linear-gradient(180deg,#f5f4f6,#e6ebf7);}
+.cm_ai_container_body{
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+    position: relative;
+    display: flex;
+}
+.cm_ai_container_records{
+    width: 240px;
+    box-shadow: 1px 0 20px rgba(0,0,0,.02);
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    box-sizing: border-box;
+    padding: 10px;
+    position: absolute;
+    flex: 0 0 auto;
+    background-image: linear-gradient(180deg,#f0edf7 .03%,#ebeaf5 32.19%,#e8e8f3 68.86%,#e4eaf7 99.12%);
+}
+.cm_ai_container_records .cm_ai_records_btn{
+    height: 48px;
+    line-height: 16px;
+    cursor: pointer;
+    flex-shrink: 0;
+    padding: 16px 0;
+    box-sizing: border-box;
+    margin-bottom: 12px;
+    background-color: rgba(255, 91, 0, 0.05);
+    text-align: center;
+    border-radius: 8px;
+    display: flex;
+    justify-content: center;
+    color: #ff5b00 !important;
+    opacity: 1 ;
+}
+.cm_ai_container_records .cm_ai_records_btn.disabled{
+    cursor: not-allowed;
+    opacity: 0.7 ;
+}
+.cm_ai_container_records .cm_ai_records_btn.show:hover{
+    background-color: rgba(255, 91, 0, 0.1);
+}
+.cm_ai_container_records .cm_ai_records_btn .cm_ai_add{
+    width: 16px;
+    height: 16px;
+    display: flex;
+    background: url("/img/base/icon-aiAdd@2x.png") no-repeat;
+    background-size: cover;
+    margin-right: 3px;
+}
+.cm_ai_container_records .cm_ai_records_list{
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+}
+.cm_ai_container_records .cm_ai_records_item{
+    display: flex;
+    align-items: flex-start;
+    height: 62px;
+    padding: 14px 10px;
+    gap: 8px;
+    box-sizing: border-box;
+    flex-direction: column;
+    justify-content: space-between;
+    cursor: pointer;
+}
+.cm_ai_container_records .cm_ai_records_item:hover{
+    border-radius: 9px;
+    background: hsla(0, 0%, 100%, .5);
+}
+.cm_ai_container_records .cm_ai_records_item .content{
+    font-size: 14px;
+    font-weight: 500;
+    line-height: 14px;
+    color: #50525c;
+    display: -webkit-box;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    word-break: break-all;
+    -webkit-line-clamp: 1;
+    -webkit-box-orient: vertical;
+}
+.cm_ai_container_records .cm_ai_records_item .time{
+    font-size: 12px;
+    font-weight: 400;
+    line-height: 12px;
+    color: #848691;
+}
+.cm_ai_container_records .cm_ai_records_user{
+    flex-shrink: 0;
+    display: flex;
+    align-items: center;
+    height: 72px;
+    padding: 0 22px;
+    font-size: 14px;
+    cursor: pointer;
+    border-top: 1px solid hsla(210, 3%, 87%, .5);
+}
+.cm_ai_container_records .cm_ai_records_user .avatar{
+    width: 24px;
+    height: 24px;
+    border-radius: 100%;
+    overflow: hidden;
+}
+.cm_ai_container_records .cm_ai_records_user .name{
+    margin-left: 8px;
+}
+.cm_ai_container_main{
+    width: calc(100% - 240px);
+    height: 100%;
+    margin-left: 240px;
+    background-image: radial-gradient(circle at 14% 85%,#e7ecf7 0,rgba(231,236,247,0) 37%),radial-gradient(circle at 3.4% 3.7%,rgba(245,237,241,.5) 0,rgba(245,237,241,0) 28%),radial-gradient(circle at 100% 18%,#e8ebea 0,hsla(160,7%,92%,0) 30%),linear-gradient(180deg,#f5f4f6,#e6ebf7);
+}
+.cm_ai_container{
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    box-sizing: border-box;
+    padding:0 24px;
+}
 .cm_ai_content{
     width: 100%;
     height: auto;
     background-color: #FFFFFF;
     box-shadow: 0 16px 20px 0 rgba(174,167,223,.2);
-    border-radius: 8px;
+    border-radius: 16px;
     box-sizing: border-box;
-    padding: 9px 10px 24px 10px;
-    margin:10px 0;
+    padding: 16px;
+    margin:10px 0 20px 0;
     position: relative;
 }
-.cm_ai_header{ width: 100%;height: 24px;box-sizing: border-box;justify-content: left;align-items: center;display: inline-flex;}
-.cm_ai_header .cm_ai_icon{ width: 24px;height: 24px;box-sizing: border-box;margin-right: 5px }
-.cm_ai_header .cm_ai_icon img{ width: 24px;height: 24px;display: block; }
-.cm_ai_header .cm_ai_text{line-height: 24px;font-size: 14px;color: #ff5b00;font-weight: 600; }
 .cm_ai_content .cm_ai_input{
     display: flex;
     align-items: center;
@@ -585,6 +703,7 @@ iframe{width:320px !important;height: 280px !important}
 .cm_ai_content .cm_ai_input textarea{
     width: 100%;
     max-height: 106px !important;
+    min-height: 60px !important;
     font-size: 14px;
     line-height: 1.5715;
     background-color: transparent;
@@ -596,29 +715,38 @@ iframe{width:320px !important;height: 280px !important}
     box-sizing: border-box;
     padding-left: 4px;
 }
+.cm_ai_content .cm_ai_input textarea:focus {
+    outline: none;
+}
+.cm_ai_content .cm_ai_button_main{
+    position: relative;
+    right: 0;
+    bottom: 0;
+    display: flex;
+    flex-direction: row-reverse;
+    justify-content: space-between;
+    width: 100%;
+    height: 32px;
+    margin-top: 4px;
+}
 .cm_ai_content .cm_ai_button{
-    width: 40px;
-    height: 24px;
-    position: absolute;
-    right: 6px;
-    bottom: 6px;
-    border-radius: 16px;
+    width: 66px;
+    height: 32px;
+    border-radius: 4px;
     background-image: linear-gradient(90deg, #FF9300 0%, #FF5B00 100%);
     display: inline-flex;
     align-items: center;
-    justify-content: space-between;
+    justify-content: center;
     transition: all .16s;
     cursor: pointer;
 }
 .cm_ai_content .cm_ai_button.none{
     opacity: 0.5;
+    cursor: not-allowed;
 }
 .cm_ai_content .cm_ai_button .cm_ai_icon{
-    width: 14px;
-    height: 14px;
-    margin: 0 auto;
-    display: block;
     transition: all .16s;
+    color: #FFFFFF;
 }
 .cm_ai_content .cm_ai_button:hover{
     transform: scale(1.05);
@@ -628,10 +756,9 @@ iframe{width:320px !important;height: 280px !important}
 }
 .cm_ai_answer_main{
     width: 100%;
-    min-height: 600px;
+    min-height: 400px;
     overflow-y: auto;
     flex: 9;
-    padding: 10px 0 0 0;
 }
 .cm_ai_answer_main::-webkit-scrollbar{
     display: none;
@@ -640,10 +767,35 @@ iframe{width:320px !important;height: 280px !important}
     width: 100%;
     height: auto;
     box-sizing: border-box;
-    padding-left:36px;
     position: relative;
+    display: flex;
+    margin: 10px 0;
+}
+.cm_ai_answer.info{
+    padding-left:0;
+    padding-right:0;
+}
+.cm_ai_answer.chat{
+    padding-left:36px;
+    justify-content: flex-start;
+}
+.cm_ai_answer.user{
+    padding-left:0px;
+    padding-right:36px;
+    justify-content: flex-end;
+}
+.cm_ai_answer.user .cm_ai_html_icon{
+    width: 32px;
+    height: 32px;
+    border-radius: 20px;
+    background-color: #FFFFFF;
+    position: absolute;
+    right: 0;
+    top: 0;
+    box-sizing: border-box;
+    padding: 5px;
 }
-.cm_ai_answer .cm_ai_html_icon{
+.cm_ai_answer.chat .cm_ai_html_icon{
     width: 32px;
     height: 32px;
     border-radius: 20px;
@@ -664,15 +816,69 @@ iframe{width:320px !important;height: 280px !important}
     display: block;
 }
 .cm_ai_answer .cm_ai_html{
-    width: 100%;
-    min-height: 300px;
-    border-radius: 8px;
+    width: auto;
+    min-height: 50px;
+    border-radius: 0 16px 16px 16px;
     line-height: 1.5715;
     background-color: #FFFFFF;
     box-sizing: border-box;
     padding: 10px;
+    font-size: 16px;
+    color: #666666;
+}
+.cm_ai_answer .cm_ai_html.info{
+    width: 100%;
+    border-radius: 16px;
+    padding: 16px;
+}
+.cm_ai_answer .cm_ai_html.info h1{
+    font-size: 30px;
+    font-weight: 600;
+    color: #333333;
+    line-height: 60px;
+    letter-spacing:2px;
+    display: flex;
+    align-items: center;
+}
+.cm_ai_answer .cm_ai_html.info h1 .cm_ai_logo{
+    width: 40px;
+    height: 40px;
+    display: block;
 }
 .cm_ai_answer .cm_ai_html.user{
     min-height: 50px;
-    margin-bottom: 10px;
+    margin-bottom: 0;
+    border-radius: 16px 16px 0 16px;
+    background-color: rgba(255, 91, 0, 0.1);
+    font-size: 16px;
+    color: #333333;
+}
+.cm_ai_answer .cm_ai_html .cm_ai_html_loading{
+    width: 60px;
+}
+.cm_ai_answer .cm_ai_link{
+    width: 100%;
+    min-height: 100px;
+    border-radius: 8px;
+    line-height: 1.5715;
+    background-color: #FFFFFF;
+    box-sizing: border-box;
+    margin: 10px 0 0 0;
+}
+.cm_ai_answer .cm_ai_link .cm_ai_link_p{
+    line-height: 22px;
+    font-size: 14px;
+    color: #666666;
+}
+.cm_ai_answer .cm_ai_link .cm_ai_link_a{
+    width: 100%;
+    line-height: 24px;
+    font-size: 14px;
+    color: #999999;
+    display: inline-block;
+    text-decoration: underline;
+}
+.cm_ai_answer .cm_ai_link .cm_ai_link_a:hover{
+    text-decoration-color: #ff5b00;
+    color: #ff5b00;
 }

+ 621 - 0
src/main/resources/static/css/caimei-chat/chats.css

@@ -0,0 +1,621 @@
+/*PC端**/
+ @media screen and (min-width:768px) {
+    html,body{
+    height: 100%;
+    background: #FFFFFF;
+    }
+    #globalHead{ width: 100%;height: auto;position: fixed;top: 0;left: 0;z-index: 1999;box-shadow: 3px 3px 5px rgba(0,0,0,.1);display: none;}
+    #globalHead .baseHeadTop{ display: none; }
+    #globalHead .baseTopNav{ display: none; }
+    #globalHead .hotKey{ display: none; }
+    #globalHead .search{ margin-top: 0; }
+    #globalHead .wechat_qrcode{ margin-top:5px; display: none;}
+    #globalHead .baseHeadCenter .wrap{ padding: 10px 0;height: auto; }
+    #globalHead .baseHeadCenter .logo{ width: 140px;height: 44px;margin-right: 162px; }
+    #caimei-chat-content{
+    height: 100%;
+    }
+    /*采美AI助手弹窗样式*/
+     .cm_ai_container_body{
+         width: 100%;
+         height: 100%;
+         box-sizing: border-box;
+         position: relative;
+         display: flex;
+     }
+     .cm_ai_container_records{
+         width: 300px;
+         box-shadow: 1px 0 20px rgba(0,0,0,.02);
+         display: flex;
+         flex-direction: column;
+         height: 100%;
+         box-sizing: border-box;
+         padding: 10px 24px;
+         position: absolute;
+         flex: 0 0 auto;
+         background-image: linear-gradient(180deg,#f0edf7 .03%,#ebeaf5 32.19%,#e8e8f3 68.86%,#e4eaf7 99.12%);
+     }
+     .cm_ai_container_records .cm_ai_records_btn{
+         height: 48px;
+         line-height: 16px;
+         cursor: pointer;
+         flex-shrink: 0;
+         padding: 16px 0;
+         box-sizing: border-box;
+         margin-bottom: 12px;
+         background-color: rgba(255, 91, 0, 0.05);
+         text-align: center;
+         border-radius: 8px;
+         display: flex;
+         justify-content: center;
+         color: #ff5b00 !important;
+         opacity: 1 ;
+     }
+     .cm_ai_container_records .cm_ai_records_btn.disabled{
+         cursor: not-allowed;
+         opacity: 0.7 ;
+     }
+     .cm_ai_container_records .cm_ai_records_btn.show:hover{
+         background-color: rgba(255, 91, 0, 0.1);
+     }
+     .cm_ai_container_records .cm_ai_records_btn .cm_ai_add{
+         width: 16px;
+         height: 16px;
+         display: flex;
+         background: url("/img/base/icon-aiAdd@2x.png") no-repeat;
+         background-size: cover;
+         margin-right: 3px;
+     }
+     .cm_ai_container_records .cm_ai_records_list{
+         flex: 1;
+         display: flex;
+         flex-direction: column;
+         overflow: hidden;
+     }
+     .cm_ai_container_records .cm_ai_records_item{
+         display: flex;
+         align-items: flex-start;
+         height: 62px;
+         padding: 14px 10px;
+         gap: 8px;
+         box-sizing: border-box;
+         flex-direction: column;
+         justify-content: space-between;
+         cursor: pointer;
+     }
+     .cm_ai_container_records .cm_ai_records_item:hover{
+         border-radius: 9px;
+         background: hsla(0, 0%, 100%, .5);
+     }
+     .cm_ai_container_records .cm_ai_records_item .content{
+         font-size: 14px;
+         font-weight: 500;
+         line-height: 14px;
+         color: #50525c;
+         display: -webkit-box;
+         text-overflow: ellipsis;
+         overflow: hidden;
+         word-break: break-all;
+         -webkit-line-clamp: 1;
+         -webkit-box-orient: vertical;
+     }
+     .cm_ai_container_records .cm_ai_records_item .time{
+         font-size: 12px;
+         font-weight: 400;
+         line-height: 12px;
+         color: #848691;
+     }
+     .cm_ai_container_records .cm_ai_records_user{
+         flex-shrink: 0;
+         display: flex;
+         align-items: center;
+         height: 72px;
+         padding: 0 22px;
+         font-size: 14px;
+         cursor: pointer;
+         border-top: 1px solid hsla(210, 3%, 87%, .5);
+     }
+     .cm_ai_container_records .cm_ai_records_user .avatar{
+         width: 24px;
+         height: 24px;
+         border-radius: 100%;
+         overflow: hidden;
+     }
+     .cm_ai_container_records .cm_ai_records_user .name{
+         margin-left: 8px;
+     }
+     .cm_ai_container_main{
+         width: calc(100% - 300px);
+         height: 100%;
+         margin-left: 300px;
+         background-image: radial-gradient(circle at 14% 85%,#e7ecf7 0,rgba(231,236,247,0) 37%),radial-gradient(circle at 3.4% 3.7%,rgba(245,237,241,.5) 0,rgba(245,237,241,0) 28%),radial-gradient(circle at 100% 18%,#e8ebea 0,hsla(160,7%,92%,0) 30%),linear-gradient(180deg,#f5f4f6,#e6ebf7);
+     }
+     .cm_ai_container{
+         width: 100%;
+         height: 100%;
+         display: flex;
+         flex-direction: column;
+         box-sizing: border-box;
+         padding:0 15px;
+         position: relative;
+     }
+     .cm_ai_mall_header{
+         box-sizing: border-box;
+         position: absolute;
+         left: 0;
+         top: 0;
+         right: 0;
+         display: flex;
+         align-items: center;
+         justify-content: space-between;
+         height: 64px;
+         width: 100%;
+         padding: 0 24px;
+         background-image: linear-gradient(360deg,#f0edf7 .03%,#ebeaf5 32.19%,#e8e8f3 68.86%,#e4eaf7 99.12%);
+         -webkit-backdrop-filter: blur(20px);
+         backdrop-filter: blur(20px);
+         z-index: 99;
+     }
+     .cm_ai_mall_header .cm_ai_logo{
+         display: flex;
+         align-items: center;
+         flex: 0 0 auto;
+     }
+     .cm_ai_mall_header .cm_ai_logo .logo{
+         width: 120px;
+         height: auto;
+     }
+     .cm_ai_content{
+         width: 850px;
+         height: auto;
+         background-color: #FFFFFF;
+         box-shadow: 0 16px 20px 0 rgba(174,167,223,.2);
+         border-radius: 16px;
+         box-sizing: border-box;
+         padding: 16px;
+         margin:0px auto 20px;
+         position: relative;
+     }
+    .cm_ai_content .cm_ai_input{
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        width: 100%;
+        min-height: 60px;
+        padding: 0 ;
+        overflow: hidden;
+        box-sizing: border-box;
+    }
+    .cm_ai_content .cm_ai_input textarea{
+        width: 100%;
+        max-height: 106px !important;
+        min-height: 60px !important;
+        font-size: 14px;
+        line-height: 1.5715;
+        background-color: transparent;
+        border: none;
+        box-shadow: none;
+        overflow: auto;
+        scrollbar-width:none;
+        resize: none;
+        box-sizing: border-box;
+        padding-left: 4px;
+    }
+    .cm_ai_content .cm_ai_input textarea:focus {
+        outline: none;
+    }
+     .cm_ai_content .cm_ai_button_main{
+         position: relative;
+         right: 0;
+         bottom: 0;
+         display: flex;
+         flex-direction: row-reverse;
+         justify-content: space-between;
+         width: 100%;
+         height: 32px;
+         margin-top: 4px;
+     }
+     .cm_ai_content .cm_ai_button{
+         width: 66px;
+         height: 32px;
+         border-radius: 4px;
+         background-image: linear-gradient(90deg, #FF9300 0%, #FF5B00 100%);
+         display: inline-flex;
+         align-items: center;
+         justify-content: center;
+         transition: all .16s;
+         cursor: pointer;
+     }
+     .cm_ai_content .cm_ai_button.none{
+         opacity: 0.5;
+         cursor: not-allowed;
+     }
+     .cm_ai_content .cm_ai_button .cm_ai_icon{
+         transition: all .16s;
+         color: #FFFFFF;
+     }
+    .cm_ai_content .cm_ai_button:hover{
+        transform: scale(1.05);
+    }
+    .cm_ai_content .cm_ai_button:hover .cm_ai_icon{
+        transform: scale(1.05);
+    }
+    .cm_ai_answer_main{
+        width: 850px;
+        min-height: 400px;
+        margin: 0 auto 15px;
+        overflow-y: auto;
+        flex: 9;
+        padding: 64px 0 0 0;
+    }
+    .cm_ai_answer_main::-webkit-scrollbar{
+        display: none;
+    }
+    .cm_ai_answer{
+        width: 100%;
+        height: auto;
+        box-sizing: border-box;
+        position: relative;
+        display: flex;
+    }
+    .cm_ai_answer.info{
+         padding-left:0;
+         padding-right:0;
+    }
+    .cm_ai_answer.chat{
+         padding-left:36px;
+         justify-content: flex-start;
+    }
+    .cm_ai_answer.user{
+         padding-left:0px;
+         padding-right:36px;
+         justify-content: flex-end;
+    }
+    .cm_ai_answer.user .cm_ai_html_icon{
+        width: 32px;
+        height: 32px;
+        border-radius: 20px;
+        background-color: #FFFFFF;
+        position: absolute;
+        right: 0;
+        top: 0;
+        box-sizing: border-box;
+        padding: 5px;
+    }
+    .cm_ai_answer.chat .cm_ai_html_icon{
+        width: 32px;
+        height: 32px;
+        border-radius: 20px;
+        background-color: #FFFFFF;
+        position: absolute;
+        left: 0;
+        top: 0;
+        box-sizing: border-box;
+        padding: 5px;
+    }
+    .cm_ai_answer .cm_ai_html_icon.user{
+        background-color: rgba(255,91,0,0.1);
+    }
+    .cm_ai_answer .cm_ai_html_icon img{
+        width: 22px;
+        height: 22px;
+        border-radius: 20px;
+        display: block;
+    }
+    .cm_ai_answer .cm_ai_html{
+         width: auto;
+         min-height: 50px;
+         border-radius: 0 16px 16px 16px;
+         line-height: 1.5715;
+         background-color: #FFFFFF;
+         box-sizing: border-box;
+         padding: 10px;
+         font-size: 16px;
+         color: #666666;
+     }
+     .cm_ai_answer .cm_ai_html.info{
+         width: 100%;
+         border-radius: 16px;
+         padding: 16px;
+     }
+     .cm_ai_answer .cm_ai_html.info h1{
+         font-size: 30px;
+         font-weight: 600;
+         color: #333333;
+         line-height: 60px;
+         letter-spacing:2px;
+         display: flex;
+         align-items: center;
+     }
+     .cm_ai_answer .cm_ai_html.info h1 .cm_ai_logo{
+         width: 40px;
+         height: 40px;
+         display: block;
+     }
+     .cm_ai_answer .cm_ai_html.user{
+         min-height: 50px;
+         margin-bottom: 0;
+         border-radius: 16px 16px 0 16px;
+         background-color: rgba(255, 91, 0, 0.1);
+         font-size: 16px;
+         color: #333333;
+     }
+    .cm_ai_answer .cm_ai_html .cm_ai_html_loading{
+        width: 60px;
+    }
+    .cm_ai_answer .cm_ai_link{
+         width: 100%;
+         min-height: 100px;
+         border-radius: 8px;
+         line-height: 1.5715;
+         background-color: #FFFFFF;
+         box-sizing: border-box;
+         margin: 10px 0 0 0;
+     }
+     .cm_ai_answer .cm_ai_link .cm_ai_link_p{
+         line-height: 22px;
+         font-size: 14px;
+         color: #666666;
+     }
+     .cm_ai_answer .cm_ai_link .cm_ai_link_a{
+         width: 100%;
+         line-height: 22px;
+         font-size: 14px;
+         color: #999999;
+         display: inline-block;
+         text-decoration: underline;
+     }
+     .cm_ai_answer .cm_ai_link .cm_ai_link_a:hover{
+         text-decoration-color: #ff5b00;
+         color: #ff5b00;
+     }
+    footer{display: none;}
+    #scrollTop .item .phone{ display: none; }
+    #scrollTop .item .Iphone{ display: none; }
+
+}
+
+/*移动端**/
+ @media screen and (max-width:768px){
+    html,body{
+        height: 100%;
+        background: #FFFFFF;
+    }
+     #globalHead{ display: none;}
+    .baseHeadCenter{ height: 14vw;}
+    .baseHeadCenter .searchBox{display: none;}
+    /*采美AI助手弹窗样式*/
+     #caimei-chat-content,.cm_ai_container_body,.cm_ai_container_main{
+         width: 100%;
+         height: 100%;
+         position: relative;
+     }
+    .cm_ai_container_records{
+         display: none;
+    }
+    .cm_ai_container{
+        width: 100%;
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+        box-sizing: border-box;
+        padding:0 3vw 0 3vw;
+        background-image: radial-gradient(circle at 14% 85%,#e7ecf7 0,rgba(231,236,247,0) 37%),radial-gradient(circle at 3.4% 3.7%,rgba(245,237,241,.5) 0,rgba(245,237,241,0) 28%),radial-gradient(circle at 100% 18%,#e8ebea 0,hsla(160,7%,92%,0) 30%),linear-gradient(180deg,#f5f4f6,#e6ebf7);
+        overflow: auto;
+        position: relative;
+    }
+     .cm_ai_mall_header{
+         box-sizing: border-box;
+         position: absolute;
+         left: 0;
+         top: 0;
+         right: 0;
+         display: flex;
+         align-items: center;
+         justify-content: space-between;
+         height: 14vw;
+         width: 100%;
+         padding: 0 3vw;
+         background-image: linear-gradient(360deg,#f0edf7 .03%,#ebeaf5 32.19%,#e8e8f3 68.86%,#e4eaf7 99.12%);
+         -webkit-backdrop-filter: blur(20px);
+         backdrop-filter: blur(20px);
+         z-index: 99;
+     }
+     .cm_ai_mall_header .cm_ai_logo{
+         display: flex;
+         align-items: center;
+         flex: 0 0 auto;
+     }
+     .cm_ai_mall_header .cm_ai_logo .logo{
+         width: 26vw;
+         height: auto;
+     }
+    .cm_ai_content{
+        width: 100%;
+        height: auto;
+        background-color: #FFFFFF;
+        box-shadow: 0 16px 20px 0 rgba(174,167,223,.2);
+        border-radius: 9vw;
+        box-sizing: border-box;
+        padding:2vw 3vw;
+        margin:3vw 0 8vw;
+        position: relative;
+    }
+    .cm_ai_content .cm_ai_input{
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        width: 100%;
+        height: 10vw;
+        padding: 0 16vw 0 2vw;
+        overflow: hidden;
+        box-sizing: border-box;
+    }
+    .cm_ai_content .cm_ai_input textarea{
+        width: 100%;
+        height: 10vw;
+        font-size: 3.4vw;
+        line-height: 10vw;
+        background-color: transparent;
+        border: none;
+        box-shadow: none;
+        overflow: auto;
+        scrollbar-width:none;
+        resize: none;
+        box-sizing: border-box;
+        padding-left: 0;
+    }
+    .cm_ai_content .cm_ai_input textarea:focus {
+        outline: none;
+    }
+    .cm_ai_content .cm_ai_button_main{
+         position: absolute;
+         right: 3vw;
+         bottom: 2vw;
+         display: flex;
+         flex-direction: row-reverse;
+         justify-content: space-between;
+         width: 16vw;
+         height: 10vw;
+     }
+     .cm_ai_content .cm_ai_button{
+         width: 16vw;
+         height: 10vw;
+         border-radius: 5vw;
+         background-image: linear-gradient(90deg, #FF9300 0%, #FF5B00 100%);
+         display: inline-flex;
+         align-items: center;
+         justify-content: center;
+         transition: all .16s;
+         cursor: pointer;
+     }
+     .cm_ai_content .cm_ai_button.none{
+         opacity: 0.5;
+         cursor: not-allowed;
+     }
+     .cm_ai_content .cm_ai_button .cm_ai_icon{
+         transition: all .16s;
+         color: #FFFFFF;
+     }
+    .cm_ai_content .cm_ai_button:hover{
+        transform: scale(1.05);
+    }
+    .cm_ai_content .cm_ai_button:hover .cm_ai_icon{
+        transform: scale(1.05);
+    }
+    .cm_ai_answer_main{
+        width: 100%;
+        min-height: 100vw;
+        overflow-y: auto;
+        flex: 9;
+        padding: 14vw 0 0 0;
+    }
+    .cm_ai_answer_main::-webkit-scrollbar{
+        display: none;
+    }
+    .cm_ai_answer{
+        width: 100%;
+        height: auto;
+        box-sizing: border-box;
+        position: relative;
+        margin: 10px 0;
+        display: flex;
+    }
+    .cm_ai_answer.info{
+         padding-left:0;
+         padding-right:0;
+    }
+    .cm_ai_answer.chat{
+        justify-content: flex-start;
+    }
+    .cm_ai_answer.user{
+        justify-content: flex-end;
+    }
+    .cm_ai_answer .cm_ai_html_icon{
+        width: 32px;
+        height: 32px;
+        border-radius: 20px;
+        background-color: #FFFFFF;
+        position: absolute;
+        left: 0;
+        top: 0;
+        box-sizing: border-box;
+        padding: 5px;
+        display: none;
+    }
+    .cm_ai_answer .cm_ai_html_icon.user{
+        background-color: rgba(255,91,0,0.1);
+    }
+    .cm_ai_answer .cm_ai_html_icon img{
+        width: 22px;
+        height: 22px;
+        border-radius: 20px;
+        display: block;
+    }
+    .cm_ai_answer .cm_ai_html{
+        min-height: 50px;
+        border-radius: 0 4vw 4vw 4vw;
+        line-height: 1.5715;
+        background-color: #FFFFFF;
+        box-sizing: border-box;
+        padding: 3vw;
+        font-size: 4vw;
+    }
+    .cm_ai_answer .cm_ai_html.info{
+         width: 100%;
+         border-radius: 4vw;
+         padding: 3vw;
+    }
+    .cm_ai_answer .cm_ai_html.info h1{
+        font-size: 6vw;
+        font-weight: 600;
+        color: #333333;
+        line-height: 14vw;
+        letter-spacing: 0.3vw;
+        display: flex;
+        align-items: center;
+     }
+    .cm_ai_answer .cm_ai_html.info h1 .cm_ai_logo{
+         width: 8vw;
+         height: 8vw;
+         display: block;
+    }
+    .cm_ai_answer .cm_ai_html.user{
+         min-height: 50px;
+         border-radius: 4vw 4vw 0 4vw;
+         background-color: rgba(255, 91, 0, 0.1);
+         font-size: 3.4vw;
+         color: #666666;
+    }
+    .cm_ai_answer .cm_ai_html .cm_ai_html_loading{
+        width: 60px;
+    }
+    .cm_ai_answer .cm_ai_link{
+        width: 100%;
+        min-height: 100px;
+        border-radius: 8px;
+        line-height: 1.5715;
+        background-color: #FFFFFF;
+        box-sizing: border-box;
+        margin: 10px 0 0 0;
+    }
+    .cm_ai_answer .cm_ai_link .cm_ai_link_p{
+        line-height: 22px;
+        font-size: 14px;
+        color: #666666;
+    }
+    .cm_ai_answer .cm_ai_link .cm_ai_link_a{
+        width: 100%;
+        line-height: 22px;
+        font-size: 14px;
+        color: #999999;
+        display: inline-block;
+        text-decoration: underline;
+    }
+    .cm_ai_answer .cm_ai_link .cm_ai_link_a:hover{
+         text-decoration-color: #666666;
+         color: #666666;
+    }
+
+    footer{display: none;}
+}

+ 47 - 44
src/main/resources/static/css/user-center/operation/form.css

@@ -1,44 +1,47 @@
-@charset "utf-8";
-li{list-style:none}
-/**
- * PC端
- */
-@media screen and (min-width:768px){
-    .pageWrap{width: 100%;}
-    /*个人中心右侧*/
-    .navLayout .right{float:right;width:968px}
-    .order-header{width: 100%;height: 78px;box-sizing: border-box;padding: 20px;background-color: #FFF;}
-    .order-header .header-bt {width: 100%;height: 38px;float: left;position: relative;}
-    .order-header .header-bt .header-title{width: 100%;height: 38px;float: left;line-height: 38px;font-size: 24px;color: #22272e;text-align: center;}
-    .order-header .header-bt .header-button{height: 38px;position: absolute;top: 0;right: 0;}
-    .order-header .header-bt .header-button .btn-add{width: 90px;height: 36px;display: block;background-color: #ffe6dc;border-radius: 2px;border: solid 1px #FF5B00;font-size: 14px;color: #FF5B00;line-height: 36px;text-align: center;float: left;margin: 0 5px;}
-    .container{width: 100%;height:526px;box-sizing: border-box;background-color: #FFF;box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.07);padding:32px 90px;}
-    .container .form{float: left;width:220px;}
-    .container .formLine{float: left;width: 100%;}
-    .container .text{width: 100%;height: auto;float: left;}
-    .container .text p{font-size: 14px;color: #22272e;text-align: left;line-height: 44px;}
-    .container .button{width: 100%;height: 50px;float: left;margin-top: 16px;}
-    .container .button a{display: block;width: 232px;height: 50px;background-color: #FF5B00;box-shadow: 0px 3px 6px 0px rgba(249, 75, 75, 0.17);border-radius: 2px;margin: 0 auto;text-align: center;line-height: 50px;font-size: 14px;color: #FFFFFF;}
-    .container .button a.disabled{background-color: #999999;}
-}
-
-/**
-* 移动端
-*/
-@media screen and (max-width:768px){
-    .order-header{width: 100%;height: 16vw;box-sizing: border-box;padding:4vw;background-color: #FFF;}
-    .order-header .header-bt {width: 100%;height: 8vw;float: left;position: relative;}
-    .order-header .header-bt .header-title{width: 100%;height: 8vw;float: left;line-height:8vw;font-size:4vw;color: #22272e;text-align: center;}
-    .order-header .header-bt .header-button{height: 8vw;position: absolute;top: 0;right: 0;}
-    .order-header .header-bt .header-button .btn-add{width:12vw;height:8vw;display: block;background-color: #ffe6dc;border-radius: 2px;border: solid 1px #FF5B00;font-size: 14px;color: #FF5B00;line-height: 36px;text-align: center;float: left;margin: 0 5px;}
-
-    .container{width: 100%;box-sizing: border-box;padding:4vw}
-    .container .text{width: 100%;height: auto;float: left;}
-    .container .text p{font-size: 3.4vw;color: #22272e;text-align: left;line-height: 6vw;}
-    .container .button{width: 100%;height: 11vw;float: left;margin-top: 16px;}
-    .container .button a{display: block;width: 100%;height: 11vw;background-color: #FF5B00;box-shadow: 0px 3px 6px 0px rgba(249, 75, 75, 0.17);border-radius: 2px;margin: 0 auto;text-align: center;line-height: 11vw;font-size:3.4vw;color: #FFFFFF;}
-    .container .button a.disabled{background-color: #999999;}
-
-
-}
-
+@charset "utf-8";
+li{list-style:none}
+/**
+ * PC端
+ */
+@media screen and (min-width:768px){
+    .pageWrap{width: 100%;}
+    /*个人中心右侧*/
+    .navLayout .right{float:right;width:968px}
+    .order-header{width: 100%;height: 78px;box-sizing: border-box;padding: 20px;background-color: #FFF;}
+    .order-header .header-bt {width: 100%;height: 38px;float: left;position: relative;}
+    .order-header .header-bt .header-title{width: 100%;height: 38px;float: left;line-height: 38px;font-size: 24px;color: #22272e;text-align: center;}
+    .order-header .header-bt .header-button{height: 38px;position: absolute;top: 0;right: 0;}
+    .order-header .header-bt .header-button .btn-add{width: 90px;height: 36px;display: block;background-color: #ffe6dc;border-radius: 2px;border: solid 1px #FF5B00;font-size: 14px;color: #FF5B00;line-height: 36px;text-align: center;float: left;margin: 0 5px;}
+    .container{width: 100%;height:526px;box-sizing: border-box;background-color: #FFF;box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.07);padding:32px 90px;}
+    .container .form{float: left;width:220px;}
+    .container .formLine{float: left;width: 100%;}
+    .container .text{width: 100%;height: auto;float: left;}
+    .container .text p{font-size: 14px;color: #22272e;text-align: left;line-height: 44px;}
+    .container .button{width: 100%;height: 50px;float: left;margin-top: 16px;}
+    .container .button a{display: block;width: 232px;height: 50px;background-image:linear-gradient(90deg, #FF9300 0%, #FF5B00 100%);box-shadow: 0px 3px 6px 0px rgba(249, 75, 75, 0.17);border-radius: 25px;margin: 0 auto;text-align: center;line-height: 50px;font-size: 14px;color: #FFFFFF;}
+    .container .button a.disabled{background-color: #999999;}
+}
+
+/**
+* 移动端
+*/
+@media screen and (max-width:768px){
+    body{width:100%;height:100%;background-color: #ffffff;}
+    footer{display:none}
+    #operationPage{padding-top: 27vw;}
+    .order-header{width: 100%;height: 16vw;box-sizing: border-box;padding:4vw;background-color: #FFF;}
+    .order-header .header-bt {width: 100%;height: 8vw;float: left;position: relative;}
+    .order-header .header-bt .header-title{width: 100%;height: 8vw;float: left;line-height:8vw;font-size:4vw;color: #22272e;text-align: center;}
+    .order-header .header-bt .header-button{height: 8vw;position: absolute;top: 0;right: 0;}
+    .order-header .header-bt .header-button .btn-add{width:12vw;height:8vw;display: block;background-color: #ffe6dc;border-radius: 2px;border: solid 1px #FF5B00;font-size: 14px;color: #FF5B00;line-height: 36px;text-align: center;float: left;margin: 0 5px;}
+
+    .container{width: 100%;box-sizing: border-box;padding:4vw}
+    .container .text{width: 100%;height: auto;float: left;}
+    .container .text p{font-size: 3.4vw;color: #22272e;text-align: left;line-height: 6vw;}
+    .container .button{width: 100%;height: 11vw;float: left;margin-top: 16px;}
+    .container .button a{display: block;width: 100%;height: 11vw;background-color: #FF5B00;box-shadow: 0px 3px 6px 0px rgba(249, 75, 75, 0.17);border-radius: 2px;margin: 0 auto;text-align: center;line-height: 11vw;font-size:3.4vw;color: #FFFFFF;}
+    .container .button a.disabled{background-color: #999999;}
+
+
+}
+

二進制
src/main/resources/static/img/base/icon-ai@1x.png


二進制
src/main/resources/static/img/base/icon-ai@2x.png


二進制
src/main/resources/static/img/base/icon-aiAdd@2x.png


二進制
src/main/resources/static/img/base/icon-aiBtn@2x.png


二進制
src/main/resources/static/img/base/icon-aiUser@2x.jpg


二進制
src/main/resources/static/img/base/icon-ailoading@2x.gif


+ 21 - 10
src/main/resources/static/js/account/login.js

@@ -238,18 +238,29 @@ var loginPage = new Vue({
                 }
             });
         },
-        handleWeChatLogin(){
-            // 微信公众号授权登录
-            if (this.isWeChat) {
-                // 微信浏览器自动授权登录
-                var urlForWeChat = 'https://www.caimei365.com/we_chat/redirect_uri.html';
-                $.get(coreServer+'/user/login/auth/link?mode=2&redirectUri='+urlForWeChat, function(r){
-                    if(r.code===0 && r.data){
-                        setBaseCookie("weChatAutoLogin", 2);
-                        window.location.href = r.data;
+        async handleWeChatLogin(){
+            // 微信公众号授权登录 微信浏览器自动授权登录
+            try {
+                const redirectUri = `https://www.caimei365.com/we_chat/redirect_uri.html`;
+                const data = await this.getWechatAuthLink({mode:2,redirectUri:redirectUri})
+                console.log('data',data)
+                setBaseCookie("weChatAutoLogin", 2);
+                window.location.href = data;
+            } catch (error) {
+                console.error('Error', error);
+            }
+        },
+        // 微信登录异步回调
+        getWechatAuthLink(params){
+            return new Promise((resolve, reject) => {
+                UserApi.wechatAuthLink(params, function(response) {
+                    if (response.code === 0) {
+                        resolve(response.data)
+                    } else {
+                        reject(response);
                     }
                 });
-            }
+            });
         },
         toNormalLogin(){
             this.qrCodeLogin = false;

+ 25 - 0
src/main/resources/static/js/anonymous/anonymous.js

@@ -0,0 +1,25 @@
+const siteEnv = $("#siteEnv").val();
+console.log('siteEnv',siteEnv)
+if(siteEnv === 2){
+    function onWindowResize() {
+        const width = window.innerWidth;
+        const height = window.innerHeight;
+        console.log('新的窗口宽度:', width, 'px')
+        console.log('新的窗口高度:', height, 'px')
+        debugger
+        window.location.href = 'about:blank';
+    }
+    window.addEventListener('resize', onWindowResize);
+    let resizeTimeout;
+    function onWindowResizeThrottled() {
+        if (resizeTimeout) {
+            clearTimeout(resizeTimeout);
+        }
+        resizeTimeout = setTimeout(function() {
+            onWindowResize();
+        }, 250);
+    }
+    window.removeEventListener('resize', onWindowResize)
+    window.addEventListener('resize', onWindowResizeThrottled)
+}
+

+ 130 - 131
src/main/resources/static/js/base.js

@@ -1,15 +1,15 @@
-var coreServer = $("#coreServer").val();
-var isPC = ($(window).width()>768);
-var globalUserData = '';
-var GLOBAL_TOKEN = 'X-Token';
-var GLOBAL_USER_ID = 0;  //  用户Id
-var GLOBAL_USER_IDENTITY = 0;//2-会员机构;3-供应商;4-普通机构
-var GLOBAL_SHOP_ID = 0;  // 供应商Id
-var GLOBAL_VIP_FLAG = 0; // 超级会员标记
-var GLOBAL_CLUB_TYPE = 0; // 会员类型 1 医美机构  2 胜美机构
-var IDENTITY = 0; // 用户标记
-var isForbidTabs = true; //控制菜单
-var isShopIsOrder = false; //控制菜单
+const coreServer = $("#coreServer").val();
+const isPC = ($(window).width() > 768);
+let globalUserData = '';
+let GLOBAL_TOKEN = 'X-Token';
+let GLOBAL_USER_ID = 0;  //  用户Id
+let GLOBAL_USER_IDENTITY = 0;//2-会员机构;3-供应商;4-普通机构
+let GLOBAL_SHOP_ID = 0;  // 供应商Id
+let GLOBAL_VIP_FLAG = 0; // 超级会员标记
+let GLOBAL_CLUB_TYPE = 0; // 会员类型 1 医美机构  2 胜美机构
+let IDENTITY = 0; // 用户标记
+let isForbidTabs = true; //控制菜单
+let isShopIsOrder = false; //控制菜单
 if(localStorage.getItem('userInfo')){
     globalUserData = JSON.parse(localStorage.getItem('userInfo'));
     GLOBAL_TOKEN = globalUserData.token;
@@ -32,28 +32,27 @@ if(localStorage.getItem('userInfo')){
     if(globalUserData){
         isShopIsOrder = globalUserData.shopIsOrder;
     }
-    console.log('isShopIsOrder',isShopIsOrder)
 } else {
-    var pathname = window.location.pathname;
-    var weChatLoginFlag = (Number(getBaseCookie("weChatAutoLogin"))===1 || Number(getBaseCookie("weChatAutoLogin"))===2);
-    if(pathname.indexOf('/product/auth/') === -1 && !weChatLoginFlag ){
-        var userAgent = navigator.userAgent.toLowerCase();
-        const isWechatLogin = window.location.href.indexOf('isDataBase') !== -1
-        if (userAgent.match(/MicroMessenger/i) && !isWechatLogin) {
-            // 微信浏览器自动授权登录
-            var urlForWeChat = 'https://www.caimei365.com/we_chat/redirect_uri.html';
-            $.get(coreServer+'/user/login/auth/link?mode=1&redirectUri='+urlForWeChat, function(r){
-                if(r.code===0 && r.data){
-                    setBaseCookie("weChatAutoLogin", 1);
-                    setBeforeUrl();
-                    window.location.href = r.data;
-                }
-            });
-        }
-    }
+    // const pathname = window.location.pathname;
+    // const weChatLoginFlag = (Number(getBaseCookie("weChatAutoLogin")) === 1 || Number(getBaseCookie("weChatAutoLogin")) === 2);
+    // if(pathname.indexOf('/product/auth/') === -1 && !weChatLoginFlag ){
+    //     const userAgent = navigator.userAgent.toLowerCase();
+    //     const isWechatLogin = window.location.href.indexOf('isDataBase') !== -1
+    //     if (userAgent.match(/MicroMessenger/i) && !isWechatLogin) {
+    //         // 微信浏览器自动授权登录
+    //         var urlForWeChat = 'https://www.caimei365.com/we_chat/redirect_uri.html';
+    //         $.get(coreServer+'/user/login/auth/link?mode=1&redirectUri='+urlForWeChat, function(r){
+    //             if(r.code===0 && r.data){
+    //                 setBaseCookie("weChatAutoLogin", 1);
+    //                 setBeforeUrl();
+    //                 window.location.href = r.data;
+    //             }
+    //         });
+    //     }
+    // }
 }
 // 头部
-var globalHead = new Vue({
+const globalHead = new Vue({
     el: '#globalHead',
     data: {
         loginStatus: false,
@@ -65,12 +64,12 @@ var globalHead = new Vue({
             productCount: 0,
             priceTotal: 0
         },
-        noticeNum:0,
-        shopId:'',
-        userIdentity:'',
+        noticeNum: 0,
+        shopId: '',
+        userIdentity: '',
         articleType: '',
-        isFiexd:false,
-        classifyIndex:1,
+        isFiexd: false,
+        classifyIndex: 1,
         supplierLinks: [
             {
                 title: '美业参谋',
@@ -95,8 +94,8 @@ var globalHead = new Vue({
         ], // 供应商链接
         activeLinks: [],
     },
-    watch:{
-        isFiexd: function(nVal,oVal){
+    watch: {
+        isFiexd: function (nVal, oVal) {
             // 防止跳动
             // if(nVal && isPC){
             //     $("body").css('paddingTop', $("#globalHead").height() + "px");
@@ -117,111 +116,111 @@ var globalHead = new Vue({
         }
     },
     methods: {
-        changeClassify: function(value){
-            this.classifyIndex=value;
+        changeClassify: function (value) {
+            this.classifyIndex = value;
         },
         // 初始化分类菜单效果
-        initClassufyTab: function(){
-            if(isPC){
-                setTimeout(function(){
+        initClassufyTab: function () {
+            if (isPC) {
+                setTimeout(function () {
                     $('#mainClassify').slide({
-                        mainCell:".clsCon",
-                        titCell:".clsTab a",
+                        mainCell: ".clsCon",
+                        titCell: ".clsTab a",
                         trigger: "mouseover"
                     });
                     $('#mainClassify_1').slide({
-                        mainCell:".tabItem_right",
-                        titCell:".tabItem_lift a",
+                        mainCell: ".tabItem_right",
+                        titCell: ".tabItem_lift a",
                         trigger: "mouseover"
                     });
                     $('#mainClassify_2').slide({
-                        mainCell:".tabItem_right",
-                        titCell:".tabItem_lift a",
+                        mainCell: ".tabItem_right",
+                        titCell: ".tabItem_lift a",
                         trigger: "mouseover"
                     });
                     $("#mainClassify_2 .tabItem_lift a").eq(0).trigger("mouseover");
                     $("#mainClassify_1 .tabItem_lift a").eq(0).trigger("mouseover");
-                },500);
-            }else{
-                setTimeout(function(){
+                }, 500);
+            } else {
+                setTimeout(function () {
                     $('#mainClassify').slide({
-                        mainCell:".clsCon",
-                        titCell:".clsTab a",
+                        mainCell: ".clsCon",
+                        titCell: ".clsTab a",
                         trigger: "click"
                     });
                     $('#mainClassify_1').slide({
-                        mainCell:".tabItem_right",
-                        titCell:".tabItem_lift a",
+                        mainCell: ".tabItem_right",
+                        titCell: ".tabItem_lift a",
                         trigger: "click"
                     });
                     $('#mainClassify_2').slide({
-                        mainCell:".tabItem_right",
-                        titCell:".tabItem_lift a",
+                        mainCell: ".tabItem_right",
+                        titCell: ".tabItem_lift a",
                         trigger: "click"
                     });
                     $("#mainClassify_2 .tabItem_lift a").eq(0).trigger("click");
                     $("#mainClassify_1 .tabItem_lift a").eq(0).trigger("click");
-                },500);
+                }, 500);
             }
         },
         // 头部购物车数据
-        getHeadCart: function(userId) {
+        getHeadCart: function (userId) {
             var _self = this;
-            ShoppingApi.getHeaderCartList({userId: userId},function(response){
+            ShoppingApi.getHeaderCartList({userId: userId}, function (response) {
                 if (response.code === 0 && response.data) {
                     var data = response.data;
                     _self.headCart.cartList = data.list;
                     _self.headCart.cartCount = data.list.length;
                     _self.headCart.productCount = 0;
                     _self.headCart.priceTotal = 0;
-                    data.list.map(function(item){
+                    data.list.map(function (item) {
                         _self.headCart.productCount += item.number;
-                        _self.headCart.priceTotal += item.number*item.price;
+                        _self.headCart.priceTotal += item.number * item.price;
                     });
-                }else if(r.code== -99){
+                } else if (r.code == -99) {
                     CAIMEI.Storage.clear();
                     location.href = "/login.html";
                 }
             });
         },
-        getAuthClubCount:function (clubId) {
+        getAuthClubCount: function (clubId) {
             var _self = this;
-            PublicApi.getAuthClubCount({commonId: clubId},function(response){
+            PublicApi.getAuthClubCount({commonId: clubId}, function (response) {
                 if (response.code === 0 && response.data) {
                     var data = response.data;
-                    if(data.count>99){
+                    if (data.count > 99) {
                         _self.noticeNum = '99+'
-                    }else{
+                    } else {
                         _self.noticeNum = data.count
                     }
-                    console.log('noticeNum',_self.noticeNum)
-                }else{
+                    console.log('noticeNum', _self.noticeNum)
+                } else {
                     console.log('获取机构通知消息数量异常')
                 }
             });
         },
-        getAuthShopCount:function (shopId) {
+        getAuthShopCount: function (shopId) {
             var _self = this;
-            PublicApi.getAuthShopCount({commonId: shopId},function(response){
+            PublicApi.getAuthShopCount({commonId: shopId}, function (response) {
                 if (response.code === 0 && response.data) {
                     var data = response.data;
-                    if(data.count>99){
+                    if (data.count > 99) {
                         _self.noticeNum = '99+'
-                    }else{
+                    } else {
                         _self.noticeNum = data.count
                     }
                     localStorage.setItem('noticeNum', _self.noticeNum)
-                }else{
-                   console.log('获取供应商通知消息数量异常')
+                } else {
+                    console.log('获取供应商通知消息数量异常')
                 }
             });
         },
-        goMsgLinkFn:function (url) {
+        goMsgLinkFn: function (url) {
             var _self = this;
-            if(_self.loginStatus){
-                window.location.href= url;
-            }else{
-                window.location.href='/login.html';
+            if (_self.loginStatus) {
+                window.location.href = url;
+            } else {
+                window.location.href = '/login.html';
             }
         },
         goSupplierLink() {
@@ -233,63 +232,63 @@ var globalHead = new Vue({
                 window.location.href = link
             }
         },
-        goCartsLinkFn:function(){
+        goCartsLinkFn: function () {
             var _self = this;
-            if(_self.loginStatus){
-                window.location.href='/shopping/cart.html';
-            }else{
-                window.location.href='/login.html';
+            if (_self.loginStatus) {
+                window.location.href = '/shopping/cart.html';
+            } else {
+                window.location.href = '/login.html';
             }
         },
-        productDetailsFn:function(id){  // 跳转详情
-            window.location.href='/product-'+id+'.html';
+        productDetailsFn: function (id) {  // 跳转详情
+            window.location.href = '/product-' + id + '.html';
         },
-        DeleteCartProducts:function(skuId){  // 删除购物车
+        DeleteCartProducts: function (skuId) {  // 删除购物车
             const _self = this;
-            ShoppingApi.DeleteCartProducts({userId: this.userData.userId, skuIds: skuId},function(response){
-                if(response.code === 0){
+            ShoppingApi.DeleteCartProducts({userId: this.userData.userId, skuIds: skuId}, function (response) {
+                if (response.code === 0) {
                     _self.getHeadCart(_self.userData.userId);
-                }else{
-                    CAIMEI.Alert(response.msg,'确定',false);
+                } else {
+                    CAIMEI.Alert(response.msg, '确定', false);
                 }
             });
         },
-        pageLinkSupplier: function(){//预览商品
-            window.open('/supplier-'+this.shopId+'.html');
+        pageLinkSupplier: function () {//预览商品
+            window.open('/supplier-' + this.shopId + '.html');
         },
         // 退出登录
-        userLogOut: function(){
+        userLogOut: function () {
             localStorage.removeItem('userInfo');
             delBaseCookie("loginBeforePath");
             this.loginStatus = false;
             window.location.href = "/index.html";
         },
-        showGlobalMenu: function(){
-            if(!isPC){
+        showGlobalMenu: function () {
+            if (!isPC) {
                 $("#mGlobalMenu").show().find(".cShow").slideDown(500);
             }
         },
-        hideGlobalMenu: function(){
-            if(!isPC){
+        hideGlobalMenu: function () {
+            if (!isPC) {
                 $("#mGlobalMenu").hide().find(".cShow").hide();
             }
         },
 
         // init auto-input complete
-        initAuthInputComplete(){
+        initAuthInputComplete() {
             new AutoComplete({
                 el: '.auto-input',
-                callback: async function(keyword){
+                callback: async function (keyword) {
                     try {
                         const res = await PublicApi.fetchQueryKeywordList({keyword: keyword});
-                        if(!res.data) return [];
+                        if (!res.data) return [];
                         return res.data.map(item => item.keyword);
                     } catch (e) {
                         console.log(e);
                     }
                 },
                 itemClick: function (keyword) {
-                    window.location.href = '/product/list.html?keyword='+keyword + '&productFlag=1' + '&linkageFlag=1';
+                    window.location.href = '/product/list.html?keyword=' + keyword + '&productFlag=1' + '&linkageFlag=1';
                 }
             });
         },
@@ -300,93 +299,93 @@ var globalHead = new Vue({
         if (globalUserData.token) {
             this.loginStatus = true;
             this.userData = globalUserData;
-            if(this.userData.userIdentity === 3){
+            if (this.userData.userIdentity === 3) {
                 // 获取头部通知消息数量
-                setTimeout(function(){
+                setTimeout(function () {
                     _self.getAuthShopCount(_self.userData.shopId);
                 }, 1000);
                 // 获取头部通知消息数量
-                var timerShopCount = setInterval(function(){
+                var timerShopCount = setInterval(function () {
                     _self.getAuthShopCount(_self.userData.shopId);
-                }, 1000*120);
-            }else{
-                setTimeout(function(){
+                }, 1000 * 120);
+            } else {
+                setTimeout(function () {
                     // 获取头部购物车数据
                     _self.getHeadCart(_self.userData.userId);
                     _self.getAuthClubCount(_self.userData.clubId);
                 }, 1000);
                 // 获取头部通知消息数量
-                var timerClubCount = setInterval(function(){
+                var timerClubCount = setInterval(function () {
                     _self.getAuthClubCount(_self.userData.clubId);
-                }, 1000*120);
+                }, 1000 * 600);
             }
         }
         // 信息中心
         this.articleType = getUrlParam("type");
     },
-    mounted:function(){
+    mounted: function () {
         var _self = this;
         // 初始化分类菜单效果
         this.initClassufyTab();
         var userData = JSON.parse(window.localStorage.getItem('userInfo'));
-        if(userData!=null) {
+        if (userData != null) {
             this.userIdentity = userData.userIdentity;
             this.shopId = userData.shopId;
         }
-        if($(window).height() > 750){
-            $(window).on('scroll', function() {
+        if ($(window).height() > 750) {
+            $(window).on('scroll', function () {
                 var scrollTop = $(this).scrollTop();
-                if(scrollTop>50){
+                if (scrollTop > 50) {
                     _self.isFiexd = true;
-                }else{
+                } else {
                     _self.isFiexd = false;
                 }
             })
         }
         // 判断导航菜单高亮-对比url
-        setTimeout(function(){
+        setTimeout(function () {
             var path = window.location.pathname;
             var paramsArr = path.split(".")[0].split("-");
             var key = paramsArr[0].split("/")[1];
-            var pageId =  paramsArr.length>=1 ? paramsArr[1] : '';
-            if(key && key.length>0) {
+            var pageId = paramsArr.length >= 1 ? paramsArr[1] : '';
+            if (key && key.length > 0) {
                 $('.navBox li').each(function () {
                     var href = $(this).find('a').attr("href");
-                    if (href.indexOf(path)>=0){
+                    if (href.indexOf(path) >= 0) {
                         $(this).find('a').addClass('on');
                         return false;
-                    } else if (key != 'product' && key != 'info' && href.indexOf('/'+key)>=0) {
+                    } else if (key != 'product' && key != 'info' && href.indexOf('/' + key) >= 0) {
                         $(this).find('a').addClass('on');
                         return false;
                     }
                 });
             }
-        },500);
+        }, 500);
         this.initAuthInputComplete();
     }
 });
 // 底部
-var globalFot = new Vue({
+const globalFot = new Vue({
     el: '#globalFot',
     mixins: [cmAiMixins],
     data: {
         isShowIcon: true,
     },
-    computed:{
-        copyrightYear(){
+    computed: {
+        copyrightYear() {
             let date = new Date()
             return date.getFullYear()
         }
     },
-    methods:{
+    methods: {
         goSupplierLink() {
             window.location.href = '/supplier/attraction.html'
         },
     },
-    mounted(){
+    mounted() {
 
     }
-})
+});
 // 初始化效果
 $(function(){
     // PC,H5切换时刷新
@@ -802,7 +801,7 @@ function setProductPrice(productList, productIds, userId, callback){
 // 登录后返回登录前页面
 function toBeforePath(){
     var loginBeforePath = getBaseCookie("loginBeforePath");
-    if (loginBeforePath && loginBeforePath!='undefined' && loginBeforePath.indexOf('.html')>0) {
+    if (loginBeforePath && loginBeforePath!=='undefined' && loginBeforePath.indexOf('.html')>0) {
         delBaseCookie("loginBeforePath");
         window.location.href = loginBeforePath;
     }

+ 31 - 0
src/main/resources/static/js/caimei-chat/chats.js

@@ -0,0 +1,31 @@
+/**
+ * Created by xw on 2024/07/23.
+ */
+const cmChats = new Vue({
+    el:"#caimei-chat-content",
+    mixins: [cmAiMixins],
+    data() {
+
+    },
+    computed: {
+
+    },
+    methods: {
+
+    },
+    created () {
+
+    },
+    mounted () {
+        if(globalUserData){
+            this.clubName = globalUserData.name
+            this.chatParams.userId = this.chatHistoryParams.userId = globalUserData.userId;
+            this.chatParams.question = ''
+            this.getChatHistory()
+        }
+        setTimeout(()=>{
+            this.handleCreatedInfoHtml()
+        },250)
+    }
+});
+

+ 40 - 0
src/main/resources/static/js/caimei-chat/worker.js

@@ -0,0 +1,40 @@
+// worker.js
+self.onmessage = async (event)=> {
+    const customData = event.data;
+    // 执行计算密集型任务或耗时操作
+    console.log('customData', customData);
+    try {
+        let getUrl
+        if(customData.params.chatId){
+            getUrl = `${customData.url}?userId=${customData.params.userId}&question=${customData.params.question}&chatId=${customData.params.chatId}`
+        }else{
+            getUrl = `${customData.url}?userId=${customData.params.userId}&question=${customData.params.question}`
+        }
+        // console.log('getUrl', getUrl);
+        const data = await getUserNewChats(getUrl)
+        // 将结果发送回主线程
+        if(data){
+            self.postMessage(data);
+        }
+    } catch (error) {
+        self.postMessage(error);
+    }
+};
+// 查询
+const getUserNewChats = (url) =>{
+    return new Promise((resolve, reject) => {
+        // console.log('url', url);
+        fetch(url).then(response => {
+            // 确保响应是成功的
+            if (!response.ok) {
+                throw new Error('Network response was not ok');
+            }
+            // 解析 JSON 数据
+            return response.json();
+        }).then(data => {
+            resolve(data)
+        }).catch(error => {
+            reject(error)
+        });
+    });
+}

+ 16 - 21
src/main/resources/static/js/common/ajax.service.js

@@ -10,20 +10,18 @@
 * @param  option.mask     是否使用模态层加载动画
 */
 var Http = {
-        AjaxService : function(option){
-            var NODE_ENV_BASE_URL = $("#coreServer").val();
-            var REV_TOKEN_ENV = '',REV_TOKEN_USERID='';
-            var GET_LOGIN_STAUS = JSON.parse(window.localStorage.getItem("userInfo"));
+        AjaxService : (option) =>{
+            const NODE_ENV_BASE_URL = $("#coreServer").val();
+            const GET_LOGIN_STAUS = JSON.parse(window.localStorage.getItem("userInfo"));
+            let REV_TOKEN_ENV = '';
             if (GET_LOGIN_STAUS != null) {
                 REV_TOKEN_ENV = GET_LOGIN_STAUS.token;
-                REV_TOKEN_USERID = GET_LOGIN_STAUS.userID;
             }else{
                 REV_TOKEN_ENV = 'X-token'
             }
-            var loading = '';
-            var def = $.Deferred();
+            const def = $.Deferred();
             $.ajax({
-                url: NODE_ENV_BASE_URL + option.url,
+                url: `${NODE_ENV_BASE_URL}${option.url}`,
                 data: option.data,
                 xhrFields: {//此处为跨域后台保持session一致,切勿删除!!!
                     withCredentials: true
@@ -32,14 +30,9 @@ var Http = {
                 dataType: "json",
                 headers: { 'X-Token': REV_TOKEN_ENV },
                 async:false,
-                // contentType: contentType,
                 contentType: option.json ? 'application/json;charset=UTF-8' : 'application/x-www-form-urlencoded',
-                beforeSend:function () {
-                    // if (option.mask) {
-                    //     loading = layer.load(0,{shade: [0.1,'#000']}); //0.1透明度的白色背景
-                    // }
-                }
-            }).then(function(res) {
+                beforeSend: () => {}
+            }).then((res)=> {
                 if(res.code=== -99){
                     CAIMEI.Storage.clear();
                     setBeforeUrl();
@@ -47,14 +40,14 @@ var Http = {
                 }else{
                     def.resolve(res);
                 }
-            }, function(error) {
+            }, (error)=> {
                 console.log('网络请求超时,请重试~');
                 def.reject(error);
             });
             return def;
         },
-        uploadImage : function(option,callback) {//上传图片
-            var NODE_ENV_BASE_URL = $("#coreServer").val();
+        uploadImage : (option,callback) => {//上传图片
+            const NODE_ENV_BASE_URL = $("#coreServer").val();
             $.ajax({
                 url: NODE_ENV_BASE_URL + option.url,
                 type: 'POST',
@@ -63,11 +56,13 @@ var Http = {
                 processData: false,
                 contentType: false,
                 dataType: "json",
-                success: function (res) {
+                success:  (res)=> {
                     callback(res)
                 },
-                error: function (xhr, type, errorThrown) {
-                    console.log("照片上传失败")
+                error: (xhr, type, errorThrown)=> {
+                    console.log("照片上传失败",xhr)
+                    console.log("照片上传失败",type)
+                    console.log("照片上传失败",errorThrown)
                 }
             });
         }

+ 25 - 0
src/main/resources/static/js/common/serviceapi/user.service.js

@@ -533,6 +533,31 @@ var UserApi = {
             .then(function(res){
                 callback(res)
             });
+        },
+        wechatAuthLink : function (params,callback) {//获取微信参数
+            Http.AjaxService({
+                url:'/user/login/auth/link',
+                type:'GET',
+                data:params,
+                json:false,
+                isHost:true
+            })
+            .then(function(res){
+                callback(res)
+            });
+        },
+        wechatAuthWebsite : function (params,callback) {//微信授权登录
+            Http.AjaxService({
+                url:'/user/login/auth/website',
+                type:'GET',
+                data:params,
+                json:false,
+                isHost:true
+            })
+            .then(function(res){
+                callback(res)
+            });
         }
 
+
 };

+ 66 - 0
src/main/resources/static/js/common/serviceapi/utils.service.js

@@ -680,6 +680,72 @@ var PublicApi = {
             }).then((res) => {
                 callback(res);
             });
+        },
+        /**
+         * @采美AI助手-提问
+         * @param:userId 用户userId
+         * @param:question 问题码
+         */
+        userNewChat: function (params, callback) {
+            Http.AjaxService({
+                url: '/user/chat/new/chat',
+                type:'get',
+                data:params,
+                json:false,
+                isHost:true
+            }).then(function (res) {
+                callback(res);
+            });
+        },
+        /**
+         * @采美AI助手-提问
+         * @param:chatId 记录ID
+         * @param:userId 用户userId
+         * @param:question 问题码
+         */
+        userSecondChat: function (params, callback) {
+            Http.AjaxService({
+                url: '/user/chat/second/chat',
+                type:'get',
+                data:params,
+                json:false,
+                isHost:true
+            }).then(function (res) {
+                callback(res);
+            });
+        },
+        /**
+         * @采美AI助手-提问记录
+         * @param:userId 用户userId
+         * @param:pageNum 每页页码
+         * @param:pageSize 条数
+         */
+        userNewChatHistory: function (params, callback) {
+            Http.AjaxService({
+                url: '/user/chat/chat/history',
+                type:'get',
+                data:params,
+                json:false,
+                isHost:true
+            }).then(function (res) {
+                callback(res);
+            });
+        },
+        /**
+         * @采美AI助手-提问记录详情
+         * @param:userId 用户userId
+         * @param:chatId 记录Id
+         */
+        userNewChatDetail: function (params, callback) {
+            Http.AjaxService({
+                url: '/user/chat/history/detail',
+                type:'get',
+                data:params,
+                json:false,
+                isHost:true
+            }).then(function (res) {
+                callback(res);
+            });
         }
 };
 

+ 300 - 97
src/main/resources/static/js/mixins/cmAiMixins.js

@@ -1,150 +1,353 @@
 // AI助手
-var cmAiMixins = function () {
+var cmAiMixins = function() {
     return {
         data() {
             return {
                 isAiDrawer: false,
-                textarea: '',
-                isLoading: false
+                isLoading: false,
+                chatParams: {
+                    userId: '',
+                    question: ''
+                },
+                chatHistoryParams: {
+                    userId: '',
+                    pageNum: 1,
+                    pageSize: 10
+                },
+                chatHistory: [],
+                questionTextarea: '',
+                probeChatId: 0,
+                probeIndex: 0,
+                clubName: ''
+            }
+        },
+        computed: {
+            disabled() {
+                return !this.probeIndex
             }
         },
         methods: {
+            // 关闭弹窗
             handleClose(done) {
                 this.$confirm('确认退出AI助手?')
                     .then(_ => {
-                        const answerContainer = document.getElementById('cm_ai_answer')
-                        answerContainer.innerHTML = ''
+                        const answerContent = document.getElementById('cm_ai_answer')
+                        answerContent.innerHTML = ''
                         this.isAiDrawer = false
                         done();
                     })
-                    .catch(_ => {});
+                    .catch(_ => {
+                    });
             },
-            handleShowAiDrawer(){
+            // 显示弹窗
+            handleShowAiDrawer() {
                 this.isAiDrawer = true
-                this.textarea = ''
-            },
-            handleAskQuestion(){
-                if(this.isLoading){ return; }
-                if (!this.textarea){
-                    this.$message({
-                        message: '请输入内容',
-                        type: 'warning'
-                    });
+                setTimeout(() => {
+                    this.handleCreatedInfoHtml()
+                }, 250)
+                if (globalUserData) {
+                    this.clubName = globalUserData.name
+                    this.chatParams.userId = this.chatHistoryParams.userId = globalUserData.userId;
+                    this.chatParams.question = ''
+                    this.getChatHistory()
+                }
+            },
+            //新建对话
+            handleCreatedChat() {
+                if (this.isLoading) {
+                    return;
+                }
+                const answerContent = document.getElementById('cm_ai_answer')
+                answerContent.innerHTML = ''
+                this.probeIndex = 0
+                this.probeChatId = ''
+                this.questionTextarea = ''
+                this.chatParams.question = ''
+            },
+            // 检查是否按下了回车键执行AI搜索
+            handleKeyDown(event) {
+                if (event.key === 'Enter') {
+                    // 阻止默认的换行行为(可选,根据你的需求来决定是否需要)
+                    event.preventDefault();
+                    console.log('回车键被按下,当前文本:', this.questionTextarea);
+                    // 或者发送数据到服务器等
+                    this.handleAskQuestion()
+                }
+            },
+            // 发送按钮点击事件
+            handleAskQuestion() {
+                const _this = this;
+                if (!globalUserData) {
+                    window.location.href = '/login.html'
+                    return
+                }
+                this.chatParams.question = this.questionTextarea
+                if (this.isLoading) {
+                    return;
+                }
+                if (!this.chatParams.question) {
+                    CAIMEI.dialog('请输入内容', false)
                     return
                 }
-                this.isLoading = true
-                const aiResponseLines = '在黄金微针品牌的选择上,市面上有多个知名品牌,它们各自具有独特的特点和优势。以下是一些值得推荐的品牌:\\n\\n* **以色列美迪迈(EndyMed)**:这是一个获得中国NMPA认证、美国FDA认证和欧盟CE认证的品牌,其资质认可度极高。美迪迈采用脉冲式发射非绝缘射频针技术,非绝缘针型增加了治疗范围,把射频能量作用于更多的组织。其独特的点阵脉冲模式使得能量传递更加精准,集中真皮深层,表皮无烫伤风险,操作便捷。同时,美迪迈射频能量三层叠加,针体全身都在发热,皮肤全层加热,到达深层才会释放能量,减少表皮热损伤,具有很好的治疗效果。\\n* **国产半岛**:半岛是国产的性价比之选,其在抗衰老治疗方面表现出色。由于抗衰老治疗需要能量深入皮肤深层,因此能量集中且具有绝缘性的黄金微针更为推荐。\\n* **韩国路创丽**:路创丽拥有微针点阵射频技术,同时还具备无创浅表点阵射频模式,层次精准。这一特点使得它对于一些希望以温和方式改善皮肤问题的敏感皮肤人群来说较为合适,并具有提亮肤色的效果。\\n* **韩国帝医思(原名:再希思)**:这个品牌同样在黄金微针领域有着不俗的表现,得到了许多用户的认可。\\n\\n这些品牌在市场上都有较高的知名度和用户口碑,但在选择时,建议消费者根据自身需求和皮肤状况,结合医生的建议进行选择。同时,无论选择哪个品牌的黄金微针,都应在正规医疗机构进行,并由专业医生操作,以确保治疗的安全和效果。'
-                const aiResponsText = aiResponseLines
-                    .replace(/\\n\\n/g, '') // 替换换行符
-                    .replace(/\* \*\*([^<]+?)\*\*/g, ''); // 替换加粗部分
                 // 用于显示AI回答的DOM元素
                 const answerContent = document.getElementById('cm_ai_answer')
-                this.handleCreateUserHtml(this.textarea,answerContent)
-                this.handleCreateChartHtml(aiResponsText,answerContent)
+                this.handleCreateUserHtml(this.chatParams.question, answerContent)
+                this.isLoading = true
+                console.log('isLoading', this.isLoading)
+                this.handleCreateChartHtml(answerContent)
+            },
+            // 初始化
+            handleCreatedInfoHtml() {
+                const answerContent = document.getElementById('cm_ai_answer')
+                // 创建一个新的div元素,并设置其类名为'cm_ai_answer info'
+                const answerElement = document.createElement('div');
+                answerElement.className = 'cm_ai_answer info';
+                // 创建子元素,显示欢迎语
+                const contentInfoStr = `<div class="cm_ai_html info"><h1>Hi,我是采美AI助手<img class="cm_ai_logo" src="/img/base/icon-ai@1x.png" alt="采美AI助手"></h1>我是您的AI助手,欢迎向我提出您的疑问,我会根据你给出的问题提供相对应的回答~</div>`
+                answerElement.innerHTML += contentInfoStr
+                // 最后,将answerElement添加到页面的某个现有元素中,例如body
+                answerContent.appendChild(answerElement);
             },
-            handleCreateUserHtml(userText,answerContent){
+            // 创建用户html
+            handleCreateUserHtml(question, answerContent) {
                 // 创建一个新的div元素,并设置其类名为'cm_ai_answer'
                 const answerElement = document.createElement('div');
-                answerElement.className = 'cm_ai_answer';
+                answerElement.className = 'cm_ai_answer user';
                 // 创建第一个子元素,包含图标
-                const iconDiv = document.createElement('div');
-                iconDiv.className = 'cm_ai_html_icon user';
-                // 在iconDiv中创建一个img元素
-                const img = document.createElement('img');
-                img.src = '/img/base/icon-aiUser@2x.png';
-                // 将img元素添加到iconDiv中
-                iconDiv.appendChild(img);
+                const iconDivStr = '<div class="cm_ai_html_icon user"><img src="/img/base/icon-aiUser@2x.png"></div>'
                 // 创建第二个子元素,用于显示内容
-                const contentDiv = document.createElement('div');
-                contentDiv.className = 'cm_ai_html user';
-                contentDiv.innerHTML = userText;
-                // 你可以在这里设置contentDiv的内容,例如:
-                // contentDiv.textContent = '这里是AI用户的内容';
-                // 或者,如果你想要保留空的div用于后续填充,可以跳过这一步
-                // 将iconDiv和contentDiv添加到answerElement中
-                answerElement.appendChild(iconDiv);
-                answerElement.appendChild(contentDiv);
+                const contentUserStr = `<div class="cm_ai_html user">${question}</div>`
+                answerElement.innerHTML += iconDivStr
+                answerElement.innerHTML += contentUserStr
                 // 最后,将answerElement添加到页面的某个现有元素中,例如body
                 answerContent.appendChild(answerElement);
             },
-            handleCreateChartHtml(aiResponsText,answerContent){
-                const _this = this
-                // 创建一个新的diUserv元素,并设置其类名为'cm_ai_answer'
+            // 生成
+            handleCreateChartHtml(answerContent) {
+                // 创建一个新的div元素,并设置其类名为'cm_ai_answer'
                 const answerElement = document.createElement('div');
-                answerElement.className = 'cm_ai_answer';
+                answerElement.className = 'cm_ai_answer chat';
                 // 创建第一个子元素,包含图标
-                const iconDiv = document.createElement('div');
-                iconDiv.className = 'cm_ai_html_icon';
-                // 在iconDiv中创建一个img元素
-                const img = document.createElement('img');
-                img.src = '/img/base/icon-ai@1x.png';
-                // 将img元素添加到iconDiv中
-                iconDiv.appendChild(img);
+                const iconDivStr = '<div class="cm_ai_html_icon"><img src="/img/base/icon-ai@1x.png"></div>'
+                const loadingImgStr = '<div class="cm_ai_loading">正在分析,请您稍作等待<img class="cm_ai_html_loading" src="/img/base/loading.gif"></div>'
                 // 创建第二个子元素,用于显示内容
-                const contentDiv = document.createElement('div');
-                contentDiv.className = 'cm_ai_html user';
-                // 你可以在这里设置contentDiv的内容,例如:
-                // contentDiv.textContent = '这里是AI用户的内容';
-                // 或者,如果你想要保留空的div用于后续填充,可以跳过这一步
-                // 将iconDiv和contentDiv添加到answerElement中
-                answerElement.appendChild(iconDiv);
-                answerElement.appendChild(contentDiv);
+                const contentHtml = document.createElement('div');
+                contentHtml.className = 'cm_ai_html';
+                contentHtml.innerHTML += loadingImgStr
+                // 将iconDivStr和contentHtml添加到answerElement中
+                answerElement.innerHTML += iconDivStr
+                // answerElement.appendChild(iconDiv);
+                answerElement.appendChild(contentHtml);
+                // 最后,将answerElement添加到页面的某个现有元素中,例如body
+                answerContent.appendChild(answerElement);
+                // 滚动到容器底部(如果内容超出了可视区域)
+                answerContent.scrollTop = answerContent.scrollHeight;
+                this.handleWorkerPrev(contentHtml, answerContent)
+            },
+            // worker处理页面卡顿
+            handleWorkerPrev(contentHtml, answerContent) {
+                const myWorker = new Worker('/js/caimei-chat/worker.js');
+                console.log('probeChatId',this.probeChatId)
+                const NODE_ENV_BASE_URL = $("#coreServer").val()
+                const customData = {
+                    url: this.probeIndex === 0 ? `${NODE_ENV_BASE_URL}/user/chat/new/chat` : `${NODE_ENV_BASE_URL}/user/chat/second/chat`,
+                    params: this.probeIndex === 0 ? this.chatParams : { chatId: this.probeChatId, ...this.chatParams},
+                };
+                // 向 Worker 发送数据
+                myWorker.postMessage(customData);
+                // 监听来自 worker 的消息
+                myWorker.onmessage = async (event) => {
+                    console.log('event', event)
+                    const data = event.data
+                    if (data.code === 0) {
+                        if (this.probeIndex === 0) {
+                            this.questionTextarea = ''
+                            this.probeChatId = data.data.chatId
+                            console.log('probeChatId',this.probeChatId)
+                            this.handleResponseHtml(data.data, contentHtml, answerContent)
+                            await this.getChatHistory()
+                        } else {
+                            this.questionTextarea = ''
+                            this.handleResponseHtml(data.data, contentHtml, answerContent)
+                        }
+                    } else {
+                        this.questionTextarea = ''
+                        this.handleErrorHtml(data.code,this.chatParams.question, contentHtml, answerContent)
+                    }
+                }
+            },
+            // 处理没有查询到内容
+            handleErrorHtml(code, question, contentHtml, answerContent) {
+                const _this = this;
+                const msgMap = {
+                    '-1':`您好,目前没有找到与${question}相关的信息,可以换个说法试试。`,
+                    '-2':`您的此次对话已超出对话轮次上限,可以刷新页面或新建对话重试。`,
+                    '-3':`您的单日对话次数已超出上限,请明日再来尝试提问。`
+                }
+                document.querySelector('div.cm_ai_loading').remove()
                 // 打字函数
                 let currentIndex = 0
                 const speed = 30
-                function typeEffect() {
+                const typeEffect = () => {
+                    // 如果已经显示完所有字符,则停止
+                    if (currentIndex < msgMap[code].length) {
+                        // 逐个字符添加到打字效果的元素中
+                        contentHtml.innerHTML += msgMap[code].charAt(currentIndex)
+                        // 更新索引
+                        currentIndex++
+                        // 递归调用,直到显示完所有字符
+                        setTimeout(typeEffect, speed)
+                        // 滚动到容器底部(如果内容超出了可视区域)
+                        answerContent.scrollTop = answerContent.scrollHeight;
+                    } else {
+                        _this.isLoading = false
+                        // 滚动到容器底部(如果内容超出了可视区域)
+                        answerContent.scrollTop = answerContent.scrollHeight;
+                    }
+                }
+                // 开始打字效果
+                typeEffect()
+            },
+            // 数据显示
+            handleResponseHtml(data, contentHtml, answerContent) {
+                const _this = this;
+                // 替换换行符 ,替换加粗部分
+                const aiResponsText = data.result.replace(/\\n\\n/g, '').replace(/\* \*\*([^<]+?)\*\*/g, '');
+                // console.log('aiResponsText',aiResponsText)
+                // console.log('search_info',search_results)
+                document.querySelector('div.cm_ai_loading').remove()
+                // 打字函数
+                let currentIndex = 0
+                const speed = 30
+                const typeEffect = () => {
                     // 如果已经显示完所有字符,则停止
                     if (currentIndex < aiResponsText.length) {
                         // 逐个字符添加到打字效果的元素中
-                        contentDiv.innerHTML += aiResponsText.charAt(currentIndex)
+                        contentHtml.innerHTML += aiResponsText.charAt(currentIndex)
                         // 更新索引
                         currentIndex++
                         // 递归调用,直到显示完所有字符
                         setTimeout(typeEffect, speed)
                         // 滚动到容器底部(如果内容超出了可视区域)
                         answerContent.scrollTop = answerContent.scrollHeight;
-                    }else{
+                    } else {
+                        // 如果有推荐信息源的话执行
+                        if (data.search_info.search_results) {
+                            _this.handleCreateChartLink(contentHtml, data.search_info.search_results)
+                        }
+                        _this.probeIndex++
                         _this.isLoading = false
+                        // 滚动到容器底部(如果内容超出了可视区域)
+                        answerContent.scrollTop = answerContent.scrollHeight;
                     }
-                    // 这里可以添加在文本显示完成后执行的代码(如果有的话)
                 }
                 // 开始打字效果
                 typeEffect()
-                // let index = 0
-                // function showNextLine() {
-                //     if (index < aiResponseLines.length) {
-                //         // 创建一个新的元素来显示当前行
-                //         const lineElement = document.createElement('p')
-                //         lineElement.textContent = aiResponseLines[index]
-                //         answerContainer.appendChild(lineElement)
-                //         // 递增索引并设置下一个显示的时间
-                //         index++
-                //         setTimeout(showNextLine, 500) // 500毫秒后显示下一行
-                //     }
-                // }
-                // // 开始显示
-                // showNextLine()
-                // 最后,将answerElement添加到页面的某个现有元素中,例如body
-                answerContent.appendChild(answerElement);
             },
-            // 图像加载后的处理函数
-            adjustScrollIfNeeded(element,container) {
-                // 等待DOM更新(可选,但在某些情况下可能需要)
-                requestAnimationFrame(() => {
-                    // 计算元素相对于容器的顶部位置
-                    const offsetTop = element.offsetTop;
-                    const containerRect = container.getBoundingClientRect();
-                    const visibleHeight = containerRect.bottom - containerRect.top; // 容器的可视高度
-                    // 检查元素是否在可视区域内
-                    // 如果不在,则调整容器的scrollTop
-                    console.log('element-offsetTop',offsetTop)
-                    console.log('container-containerRect',containerRect)
-                    console.log('visibleHeight',visibleHeight)
-                    if (offsetTop < container.scrollTop || offsetTop + element.offsetHeight > container.scrollTop + visibleHeight) {
-                        // 这里我们简单地将scrollTop设置为新内容的顶部
-                        // 但你可以根据需要调整这个逻辑,比如保持元素居中或靠近容器顶部/底部
-                        container.scrollTop = offsetTop;
+            // 参考信息源渲染
+            handleCreateChartLink(contentHtml, search_results) {
+                const contentLink = document.createElement('div')
+                contentLink.className = 'cm_ai_link'
+                // 创建第二个子元素,用于显示内容
+                const linkPstr = `<p class="cm_ai_link_p">参考${search_results.length}条信息源</p>`
+                contentLink.innerHTML += linkPstr
+                contentHtml.appendChild(contentLink)
+                // 循环插入信息源内容,可跳转链接
+                search_results.forEach(result => {
+                    // 创建a标签并插入
+                    const linkStr = `<a href="${result.url}" class="cm_ai_link_a" target="_blank">${result.title}</a>`
+                    contentLink.innerHTML += linkStr
+                });
+            },
+            // 查询记录
+            async getChatHistory() {
+                const data = await this.userNewChatHistory(this.chatHistoryParams)
+                console.log('chatHistory', data)
+                this.chatHistory = data
+            },
+            // 查询详情
+            async handleChatDetail(chatId) {
+                try {
+                    this.probeIndex = 1
+                    this.probeChatId = chatId
+                    const list = await this.userNewChatDetail({userId: this.chatParams.userId, chatId: chatId})
+                    this.handleCreateDetailHtml(list)
+                } catch (error) {
+                    console.log('Error fetching new chats:', error);
+                }
+            },
+            // 渲染记录详情html
+            handleCreateDetailHtml(list) {
+                // console.log('Detail',list)
+                const answerContent = document.getElementById('cm_ai_answer')
+                answerContent.innerHTML = ''
+                // 初始化一个空的字符串来存储构建的 HTML
+                let htmlContent = '';
+                // 循环处理 list 数组
+                list.forEach(item => {
+                    // 根据 identity 的值构建不同的 HTML 结构
+                    let iconSrc, className;
+                    if (item.identity === 0) {
+                        iconSrc = '/img/base/icon-aiUser@2x.png';
+                        className = 'user';
+                    } else {
+                        iconSrc = '/img/base/icon-ai@1x.png';
+                        className = 'chat'; // 如果不需要特别的类名,这里可以留空
                     }
+                    // 拼接 HTML 字符串
+                    htmlContent += `<div class="cm_ai_answer ${className}"><div class="cm_ai_html_icon ${className}"><img src="${iconSrc}"></div>  
+                                    <div class="cm_ai_html ${className}">${item.message}</div></div>`;
+                });
+                // 将构建好的 HTML 字符串设置到 answerContent 中
+                answerContent.innerHTML = htmlContent;
+                answerContent.scrollTop = answerContent.scrollHeight;
+            },
+            // 查询详情
+            userNewChatDetail(params) {// 查询详情
+                return new Promise((resolve, reject) => {
+                    PublicApi.userNewChatDetail(params, (response) => {
+                        if (response.code === 0) {
+                            resolve(response.data)
+                        } else {
+                            reject(response)
+                        }
+                    });
+                });
+            },
+            // 查询记录
+            userNewChatHistory(params) {
+                return new Promise((resolve, reject) => {
+                    PublicApi.userNewChatHistory(params, (response) => {
+                        if (response.code === 0) {
+                            resolve(response.data)
+                        } else {
+                            reject(response)
+                        }
+                    });
+                });
+            },
+            // 查询获取问题结果
+            getUserNewChats(params) {
+                return new Promise((resolve, reject) => {
+                    PublicApi.userNewChat(params, (response) => {
+                        if (response.code === 0) {
+                            resolve(response.data)
+                        } else {
+                            reject(response)
+                        }
+                    });
+                });
+            },
+            // 追问
+            getUserSecondChat(params) {
+                return new Promise((resolve, reject) => {
+                    PublicApi.userSecondChat(params, (response) => {
+                        if (response.code === 0) {
+                            resolve(response.data)
+                        } else {
+                            reject(response)
+                        }
+                    });
                 });
             }
         }

+ 3 - 3
src/main/resources/static/js/mixins/cmSysMixins.js

@@ -87,12 +87,12 @@ var cmSysVitaMixins = function () {
                 },2000)
             },
             handleSetNetworks(params){// 进入页面执行统计
-                console.log(`页面路径:${params.pagePath}`,`标签:${params.pageLabel}`)
+                // console.log(`页面路径:${params.pagePath}`,`标签:${params.pageLabel}`)
                 PublicApi.userRecordStatisticsApp(params,function(response){
                      if(response.code === 0){
-                         console.log('上送浏览记录统计成功~')
+                         // console.log('上送浏览记录统计成功~')
                      }else{
-                         console.log('上送浏览记录统计失败~')
+                         // console.log('上送浏览记录统计失败~')
                      }
                 });
             },

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

@@ -0,0 +1,91 @@
+const redirectUri = new Vue({
+    el: "#weChatContention",
+    data() {
+        return {
+            loginParams:{
+                code:'',
+                state:'',
+                mode:'',
+            }
+        }
+    },
+    computed: {},
+    methods: {
+        openFullScreen() {
+            const loading = this.$loading({
+                lock: true,
+                text: '微信授权登录中~',
+                spinner: 'el-icon-loading',
+                background: 'rgba(0, 0, 0, 0.4)'
+            });
+            setTimeout(() => {
+                this.weChatLoginInit()
+                loading.close();
+            }, 2000);
+        },
+        // 初始化
+        async weChatLoginInit(){
+            try {
+                const data = await this.getWechatAuthWebsite(this.loginParams)
+                console.log('data', data);
+                const userData = {
+                    account: data.account,
+                    email: data.email,
+                    phone: data.bindMobile,
+                    name: data.name,
+                    userName: data.userName,
+                    userId: data.userId,
+                    spId: data.serviceProviderId,
+                    clubId: data.clubId,
+                    shopId: data.shopId,
+                    unionId: data.unionId,
+                    userIdentity: data.userIdentity,
+                    permission: data.userPermission,
+                    token: data.token
+                };
+                localStorage.setItem('userInfo',JSON.stringify(userData))
+                this.tobeforePage()
+            } catch (error) {
+                CAIMEI.Alert(error.msg,'确定',true, function(){
+                    this.tobeforePage()
+                });
+            }
+        },
+        // 微信登录异步回调
+        getWechatAuthWebsite(params){
+            return new Promise((resolve, reject) => {
+                UserApi.wechatAuthWebsite(params, function(response) {
+                    if (response.code === 0) {
+                        resolve(response.data)
+                    } else {
+                        reject(response)
+                    }
+                })
+            })
+        },
+        tobeforePage(){
+            const loginBeforePath = getBaseCookie("loginBeforePath");
+            if (loginBeforePath && loginBeforePath!=='undefined' && loginBeforePath.indexOf('.html')>0) {
+                delBaseCookie("loginBeforePath")
+                window.location.href = loginBeforePath
+            } else if (userData && userData.userIdentity*1 === 3) {
+                location.href = '/supplier/dashboard.html'
+            } else if (userData && (userData.userIdentity*1 === 2 || userData.userIdentity*1 === 4)) {
+                location.href = '/user/dashboard.html'
+            }
+        }
+    },
+    created() {
+
+    },
+    mounted() {
+        // 如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE
+        this.loginParams.mode = Number(getBaseCookie("weChatAutoLogin")) === 1 ? 1 : 2
+        this.loginParams.code = getUrlParam('code')
+        this.loginParams.state = getUrlParam('state')
+        // console.log('wx_mode',this.loginParams.mode)
+        // console.log('wx_code',this.loginParams.code)
+        // console.log('wx_state',this.loginParams.state)
+        this.openFullScreen()
+    }
+});

+ 125 - 125
src/main/resources/templates/account/bind.html

@@ -1,125 +1,125 @@
-<!DOCTYPE html>
-<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-      xsi:schemaLocation="https://www.thymeleaf.org ">
-<head>
-    <title>采美365网</title>
-    <template th:replace="components/head-link"></template>
-    <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
-    <link th:href="@{/css/account/bind.css(v=${version})}" rel="stylesheet" type="text/css">
-    <template th:replace="components/analysis"></template>
-</head>
-<body>
-<!-- 引用头部 -->
-<template th:replace="account/components/header"></template>
-
-<!-- 绑定运营人员 -->
-<div id="bindPage">
-    <div class="signAccount bind">
-        <div class="title center">绑定运营人员</div>
-        <div class="title-tips">
-            <p>您的微信尚未绑定任何账号,请输入您的账号密码,并填写自己的基本信息提交后即可微信扫码直接登录</p>
-        </div>
-        <div class="registerClub clear">
-            <form>
-                <div class="form-step">
-                    <span class="step one active">1</span>
-                    <span class="step two" :class="activeNum == 1 ? 'active':''">2</span>
-                </div>
-                <template v-if="activeNum === 0">
-                    <div class="title">确认公司账号</div>
-                    <div class="formLine-tabs">
-                        <a class="tabs-item" :class="{ current: loginTabs === 1 }" href="javascript:void(0);" @click="handleTabsClick(1)">验证码确认</a>
-                        <a class="tabs-item" :class="{ current: loginTabs === 0 }" href="javascript:void(0);" @click="handleTabsClick(0)">账号密码确认</a>
-                    </div>
-                    <template v-if="loginTabs === 1">
-                        <div class="formLine" >
-                            <p><em>*</em>手机号:</p>
-                            <input  class="codeParamsMobile"  type="text" autocomplete="off" v-model.trim="codeParams.mobile" placeholder="请输入已注册的手机号" @input="handleInputPhone" :rule="rule.mobile" maxlength="11" @blur="blurHandle($event)" needverify>
-                            <i class="checked icon mIcon"></i>
-                            <span class="errTips icon mIcon" tips="请输入正确格式的手机号"></span>
-                        </div>
-                        <div class="formLine smscode">
-                            <p><em>*</em>验证码:</p>
-                            <input type="text" class="smscode" v-model.trim="codeParams.code" autocomplete="off" placeholder="请输入短信验证码" @input="handleInputSmsCode" :rule="rule.code"  maxlength="6" @blur="blurHandle($event)" needverify>
-                            <i class="checked icon mIcon"></i>
-                            <span class="errTips icon mIcon" tips="请输入短信验证码"></span>
-                            <a class="code-btn" href="javascript:void(0);" @click="handleShowImage" :class="[isMobileDisabled1  ? 'disabled' : '']">{{ mobileCodeText1 }}</a>
-                        </div>
-                        <div class="subLine">
-                            <button class="btn" type="button" :class="isDisabled ? 'disabled' : ''"  @click="handleStepNext">下一步</button>
-                        </div>
-                    </template>
-                    <template v-if="loginTabs === 0">
-                        <div class="formLine">
-                            <p><em>*</em>账号:</p>
-                            <input class="mobileOrEmail" type="text" autocomplete="off" v-model.trim="userParams.mobileOrEmail" placeholder="请输入邮箱/手机号" @input="handleInputMobileOrEmail" :rule="rule.mobileOrEmail" maxlength="50" @blur="blurHandle($event)" needverify>
-                            <i class="checked icon mIcon"></i>
-                            <span class="errTips icon mIcon" tips="请输入邮箱/手机号"></span>
-                        </div>
-                        <div class="formLine">
-                            <p><em>*</em>登录密码:</p>
-                            <input type="password" v-model.trim="userParams.password" autocomplete="new-password" placeholder="请输入8-16位数字和字母组合" @input="handleInputPassword" :rule="rule.password" maxlength="32" @blur="blurHandle($event)" needverify>
-                            <i class="checked icon mIcon"></i>
-                            <span class="errTips icon mIcon" tips="8-16位数字或字母或字符"></span>
-                        </div>
-                        <div class="subLine">
-                            <button class="btn" type="button" :class="isDisabled ? 'disabled' : ''"  @click="handleStepNext">下一步</button>
-                        </div>
-                    </template>
-                </template>
-                <template v-if="activeNum === 1">
-                    <div class="title">填写运营人员信息</div>
-                    <div class="formLine">
-                        <p><em>*</em>姓名:</p>
-                        <input type="text" v-model.trim="userParams.linkName" @input="handleInputLinkName" placeholder="请输入真实姓名" :rule="rule.name" maxlength="50" @blur="blurHandle($event)" needverify>
-                        <i class="checked icon mIcon"></i>
-                        <span class="errTips icon mIcon" tips="请输入正确的联系人姓名"></span>
-                    </div>
-                    <div class="formLine" >
-                        <p><em>*</em>手机号:</p>
-                        <input  class="massageBtn"  type="text" autocomplete="off" @input="handleInputMobile" v-model.trim="userParams.mobile" placeholder="请输入您的常用手机号" :rule="rule.phone" maxlength="11" @blur="blurHandle($event)" needverify>
-                        <i class="checked icon mIcon"></i>
-                        <span class="errTips icon mIcon" tips="请输入有效电话号码"></span>
-                    </div>
-                    <div class="formLine smscode">
-                        <p><em>*</em>短信验证码:</p>
-                        <input class="smscode" type="text" v-model.trim="userParams.smsCode" @input="handleInputSmsCodee"  placeholder="请输入短信验证码" :rule="rule.code"  maxlength="6" @blur="blurHandle($event)" needverify>
-                        <i class="checked icon mIcon"></i>
-                        <span class="errTips icon mIcon" tips="请输入有效短信验证码"></span>
-                        <a class="code-btn" href="javascript:void(0);" @click="handleShowImage" :class="[isMobileDisabled  ? 'disabled' : '']">{{ mobileCodeText }}</a>
-                    </div>
-                    <div class="subLine">
-                        <button class="btn" type="button" :class="isSubDisabled ? 'disabled':''"  @click="handleBindConfirm">提交</button>
-                    </div>
-                </template>
-            </form>
-        </div>
-    </div>
-    <div class="content-model"  :class="isCodeModel ? 'active' : ''">
-        <div class="model-main">
-            <div class="model-title"><p>获取短信验证码</p><i class="icon mIcon icon-close"  @click="closeCodeModel"></i></div>
-            <div class="model-content">
-                <div class="model-form">
-                    <input class="input codeMsgButton" type="text" placeholder="请输入图形验证码" v-model="bindCodeParams.imgCode" maxlength="4" needverify>
-                    <div class="image"><img :src="codeImagePath" alt=""></div>
-                    <div class="refresh" @click="handleRefreshCodeImage">
-                        <i class="icon mIcon"></i>
-                        <span>刷新</span>
-                    </div>
-                    <i class="checked icon mIcon"></i>
-                    <span class="errTips icon mIcon" tips="请输入图形验证码"></span>
-                </div>
-                <div class="model-button">
-                    <div class="button"  @click="getMobileCodeFn">获取短信验证码</div>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-<!-- 引入底部 -->
-<template th:replace="article/components/article-footer"></template>
-<template th:replace="components/foot-link"></template>
-<script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/user.service.js(v=${version})}"></script>
-<script charset="utf-8" type="text/javascript" th:src="@{/js/account/bind.js(v=${version})}"></script>
-</body>
-</html>
+<!DOCTYPE html>
+<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="https://www.thymeleaf.org ">
+<head>
+    <title>采美365网-绑定运营人员</title>
+    <template th:replace="components/head-link"></template>
+    <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
+    <link th:href="@{/css/account/bind.css(v=${version})}" rel="stylesheet" type="text/css">
+    <template th:replace="components/analysis"></template>
+</head>
+<body>
+<!-- 引用头部 -->
+<template th:replace="account/components/header"></template>
+
+<!-- 绑定运营人员 -->
+<div id="bindPage">
+    <div class="signAccount bind">
+        <div class="title center">绑定运营人员</div>
+        <div class="title-tips">
+            <p>您的微信尚未绑定任何账号,请输入您的账号密码,并填写自己的基本信息提交后即可微信扫码直接登录</p>
+        </div>
+        <div class="registerClub clear">
+            <form>
+                <div class="form-step">
+                    <span class="step one active">1</span>
+                    <span class="step two" :class="activeNum == 1 ? 'active':''">2</span>
+                </div>
+                <template v-if="activeNum === 0">
+                    <div class="title">确认公司账号</div>
+                    <div class="formLine-tabs">
+                        <a class="tabs-item" :class="{ current: loginTabs === 1 }" href="javascript:void(0);" @click="handleTabsClick(1)">验证码确认</a>
+                        <a class="tabs-item" :class="{ current: loginTabs === 0 }" href="javascript:void(0);" @click="handleTabsClick(0)">账号密码确认</a>
+                    </div>
+                    <template v-if="loginTabs === 1">
+                        <div class="formLine" >
+                            <p><em>*</em>手机号:</p>
+                            <input  class="codeParamsMobile"  type="text" autocomplete="off" v-model.trim="codeParams.mobile" placeholder="请输入已注册的手机号" @input="handleInputPhone" :rule="rule.mobile" maxlength="11" @blur="blurHandle($event)" needverify>
+                            <i class="checked icon mIcon"></i>
+                            <span class="errTips icon mIcon" tips="请输入正确格式的手机号"></span>
+                        </div>
+                        <div class="formLine smscode">
+                            <p><em>*</em>验证码:</p>
+                            <input type="text" class="smscode" v-model.trim="codeParams.code" autocomplete="off" placeholder="请输入短信验证码" @input="handleInputSmsCode" :rule="rule.code"  maxlength="6" @blur="blurHandle($event)" needverify>
+                            <i class="checked icon mIcon"></i>
+                            <span class="errTips icon mIcon" tips="请输入短信验证码"></span>
+                            <a class="code-btn" href="javascript:void(0);" @click="handleShowImage" :class="[isMobileDisabled1  ? 'disabled' : '']">{{ mobileCodeText1 }}</a>
+                        </div>
+                        <div class="subLine">
+                            <button class="btn" type="button" :class="isDisabled ? 'disabled' : ''"  @click="handleStepNext">下一步</button>
+                        </div>
+                    </template>
+                    <template v-if="loginTabs === 0">
+                        <div class="formLine">
+                            <p><em>*</em>账号:</p>
+                            <input class="mobileOrEmail" type="text" autocomplete="off" v-model.trim="userParams.mobileOrEmail" placeholder="请输入邮箱/手机号" @input="handleInputMobileOrEmail" :rule="rule.mobileOrEmail" maxlength="50" @blur="blurHandle($event)" needverify>
+                            <i class="checked icon mIcon"></i>
+                            <span class="errTips icon mIcon" tips="请输入邮箱/手机号"></span>
+                        </div>
+                        <div class="formLine">
+                            <p><em>*</em>登录密码:</p>
+                            <input type="password" v-model.trim="userParams.password" autocomplete="new-password" placeholder="请输入8-16位数字和字母组合" @input="handleInputPassword" :rule="rule.password" maxlength="32" @blur="blurHandle($event)" needverify>
+                            <i class="checked icon mIcon"></i>
+                            <span class="errTips icon mIcon" tips="8-16位数字或字母或字符"></span>
+                        </div>
+                        <div class="subLine">
+                            <button class="btn" type="button" :class="isDisabled ? 'disabled' : ''"  @click="handleStepNext">下一步</button>
+                        </div>
+                    </template>
+                </template>
+                <template v-if="activeNum === 1">
+                    <div class="title">填写运营人员信息</div>
+                    <div class="formLine">
+                        <p><em>*</em>姓名:</p>
+                        <input type="text" v-model.trim="userParams.linkName" @input="handleInputLinkName" placeholder="请输入真实姓名" :rule="rule.name" maxlength="50" @blur="blurHandle($event)" needverify>
+                        <i class="checked icon mIcon"></i>
+                        <span class="errTips icon mIcon" tips="请输入正确的联系人姓名"></span>
+                    </div>
+                    <div class="formLine" >
+                        <p><em>*</em>手机号:</p>
+                        <input  class="massageBtn"  type="text" autocomplete="off" @input="handleInputMobile" v-model.trim="userParams.mobile" placeholder="请输入您的常用手机号" :rule="rule.phone" maxlength="11" @blur="blurHandle($event)" needverify>
+                        <i class="checked icon mIcon"></i>
+                        <span class="errTips icon mIcon" tips="请输入有效电话号码"></span>
+                    </div>
+                    <div class="formLine smscode">
+                        <p><em>*</em>短信验证码:</p>
+                        <input class="smscode" type="text" v-model.trim="userParams.smsCode" @input="handleInputSmsCodee"  placeholder="请输入短信验证码" :rule="rule.code"  maxlength="6" @blur="blurHandle($event)" needverify>
+                        <i class="checked icon mIcon"></i>
+                        <span class="errTips icon mIcon" tips="请输入有效短信验证码"></span>
+                        <a class="code-btn" href="javascript:void(0);" @click="handleShowImage" :class="[isMobileDisabled  ? 'disabled' : '']">{{ mobileCodeText }}</a>
+                    </div>
+                    <div class="subLine">
+                        <button class="btn" type="button" :class="isSubDisabled ? 'disabled':''"  @click="handleBindConfirm">提交</button>
+                    </div>
+                </template>
+            </form>
+        </div>
+    </div>
+    <div class="content-model"  :class="isCodeModel ? 'active' : ''">
+        <div class="model-main">
+            <div class="model-title"><p>获取短信验证码</p><i class="icon mIcon icon-close"  @click="closeCodeModel"></i></div>
+            <div class="model-content">
+                <div class="model-form">
+                    <input class="input codeMsgButton" type="text" placeholder="请输入图形验证码" v-model="bindCodeParams.imgCode" maxlength="4" needverify>
+                    <div class="image"><img :src="codeImagePath" alt=""></div>
+                    <div class="refresh" @click="handleRefreshCodeImage">
+                        <i class="icon mIcon"></i>
+                        <span>刷新</span>
+                    </div>
+                    <i class="checked icon mIcon"></i>
+                    <span class="errTips icon mIcon" tips="请输入图形验证码"></span>
+                </div>
+                <div class="model-button">
+                    <div class="button"  @click="getMobileCodeFn">获取短信验证码</div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<!-- 引入底部 -->
+<template th:replace="article/components/article-footer"></template>
+<template th:replace="components/foot-link"></template>
+<script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/user.service.js(v=${version})}"></script>
+<script charset="utf-8" type="text/javascript" th:src="@{/js/account/bind.js(v=${version})}"></script>
+</body>
+</html>

+ 1 - 1
src/main/resources/templates/account/forget.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.thymeleaf.org ">
 <head>
-    <title>采美365网</title>
+    <title>采美365网-找回密码</title>
     <template th:replace="components/head-link"></template>
     <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
     <link th:href="@{/css/account/forget.css(v=${version})}" rel="stylesheet" type="text/css">

+ 1 - 1
src/main/resources/templates/account/login-fast.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.thymeleaf.org ">
 <head>
-    <title>采美365网</title>
+    <title>采美365网-供应商快捷登录</title>
     <template th:replace="components/head-link"></template>
     <!--禁止抓取本页,禁止抓取和跟踪本页的其它链接-->
     <meta name='robots' content='noindex,nofollow' />

+ 1 - 1
src/main/resources/templates/account/login.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.thymeleaf.org ">
 <head>
-    <title>采美365网</title>
+    <title>采美365网-登录</title>
     <template th:replace="components/head-link"></template>
     <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
     <link th:href="@{/css/account/login.css(v=${version})}" rel="stylesheet" type="text/css">

+ 1 - 1
src/main/resources/templates/account/register-club.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.thymeleaf.org ">
 <head>
-    <title>采美365网</title>
+    <title>采美365网-机构注册</title>
     <template th:replace="components/head-link"></template>
     <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
     <link th:href="@{/css/account/register.css(v=${version})}" rel="stylesheet" type="text/css">

+ 1 - 1
src/main/resources/templates/account/register-supplier.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.thymeleaf.org ">
 <head>
-    <title>采美365网</title>
+    <title>采美365网-供应商注册</title>
     <template th:replace="components/head-link"></template>
     <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
     <link th:href="@{/css/account/register.css(v=${version})}" rel="stylesheet" type="text/css">

+ 32 - 32
src/main/resources/templates/account/register.html

@@ -1,32 +1,32 @@
-<!DOCTYPE html>
-<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-      xsi:schemaLocation="https://www.thymeleaf.org ">
-<head>
-    <title>采美365网</title>
-    <template th:replace="components/head-link"></template>
-    <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
-    <link th:href="@{/css/account/register.css(v=${version})}" rel="stylesheet" type="text/css">
-    <template th:replace="components/analysis"></template>
-</head>
-<body>
-<!-- 引用头部 -->
-<template th:replace="account/components/header"></template>
-
-<!-- 注册账号 -->
-<div id="registerPage">
-    <div class="selectAccount">
-        <div class="title">请选择注册的账号类型</div>
-        <div class="cont">
-            <span class="a"><img src="/img/account/clubPC.png" @click="clickTab(1)"> <p class="purchase">采购方(买家)</p><p class="tips-text">医院机构/美容会所/普通买家</p></span>
-            <span class="b"><img src="/img/account/supplierPC.png"  @click="clickTab(2)"><p class="purchase">供应商(卖家)</p><p class="tips-text">仪器/产品/服务供应商</p></span>
-        </div>
-    </div>
-</div>
-
-<!-- 引入底部 -->
-<template th:replace="components/footer"></template>
-<template th:replace="components/foot-link"></template>
-<script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/user.service.js(v=${version})}"></script>
-<script charset="utf-8" type="text/javascript" th:src="@{/js/account/register.js(v=${version})}"></script>
-</body>
-</html>
+<!DOCTYPE html>
+<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="https://www.thymeleaf.org ">
+<head>
+    <title>采美365网-注册</title>
+    <template th:replace="components/head-link"></template>
+    <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
+    <link th:href="@{/css/account/register.css(v=${version})}" rel="stylesheet" type="text/css">
+    <template th:replace="components/analysis"></template>
+</head>
+<body>
+<!-- 引用头部 -->
+<template th:replace="account/components/header"></template>
+
+<!-- 注册账号 -->
+<div id="registerPage">
+    <div class="selectAccount">
+        <div class="title">请选择注册的账号类型</div>
+        <div class="cont">
+            <span class="a"><img src="/img/account/clubPC.png" @click="clickTab(1)"> <p class="purchase">采购方(买家)</p><p class="tips-text">医院机构/美容会所/普通买家</p></span>
+            <span class="b"><img src="/img/account/supplierPC.png"  @click="clickTab(2)"><p class="purchase">供应商(卖家)</p><p class="tips-text">仪器/产品/服务供应商</p></span>
+        </div>
+    </div>
+</div>
+
+<!-- 引入底部 -->
+<template th:replace="components/footer"></template>
+<template th:replace="components/foot-link"></template>
+<script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/user.service.js(v=${version})}"></script>
+<script charset="utf-8" type="text/javascript" th:src="@{/js/account/register.js(v=${version})}"></script>
+</body>
+</html>

+ 1 - 1
src/main/resources/templates/account/upgrade.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.thymeleaf.org ">
 <head>
-    <title>采美365网</title>
+    <title>采美365网-升级资质</title>
     <template th:replace="components/head-link"></template>
     <link th:href="@{/css/base/form.css(v=${version})}" rel="stylesheet" type="text/css">
     <link th:href="@{/css/account/upgrade.css(v=${version})}" rel="stylesheet" type="text/css">

+ 1 - 1
src/main/resources/templates/article/list.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.thymeleaf.org ">
 <head>
-    <title>采美信息中心</title>
+    <title>采美网-采美信息中心</title>
     <template th:replace="article/components/article-link"></template>
     <template th:replace="components/analysis"></template>
     <link rel="stylesheet" href="/lib/element-ui/index.css" type="text/css"/>

+ 1 - 1
src/main/resources/templates/article/recommendation.html

@@ -1,7 +1,7 @@
 <html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.thymeleaf.org ">
 
 <head>
-    <title>采美信息中心-精选推荐</title>
+    <title>采美网-采美信息中心-精选推荐</title>
     <link th:href="@{/css/article/recommendation.css(v=${version})}" rel="stylesheet" type="text/css">
     <template th:replace="article/components/article-link"></template>
     <template th:replace="components/analysis"></template>

+ 68 - 0
src/main/resources/templates/caimei-chat/chats.html

@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="https://www.thymeleaf.org ">
+<html>
+
+<head>
+    <template th:replace="components/head-link"></template>
+    <link th:href="@{/css/caimei-chat/chats.css(v=${version})}" rel="stylesheet" type="text/css">
+    <title>采美网-采美AI助手</title>
+    <template th:replace="components/analysis"></template>
+</head>
+<body>
+  <!-- 引用头部 -->
+  <template th:replace="components/header"></template>
+  <div id="caimei-chat-content" v-cloak>
+      <div class="cm_ai_container_body">
+          <div class="cm_ai_container_records">
+              <div class="cm_ai_records_btn" :class="disabled ? 'disabled' : 'show'" @click="handleCreatedChat">
+                  <i class="cm_ai_add"></i>
+                  <span>新建对话</span>
+              </div>
+              <div class="cm_ai_records_list">
+                  <div class="cm_ai_records_item" v-for="(chat, index) in chatHistory" :key="index" @click="handleChatDetail(chat.id)">
+                      <span class="content" v-text="chat.firstQuestion"></span>
+                      <span class="time" v-text="chat.addTime"></span>
+                  </div>
+              </div>
+              <div class="cm_ai_records_user" v-if="chatParams.userId">
+                  <div class="avatar">
+                      <img src="/img/base/icon-aiUser@2x.jpg">
+                  </div>
+                  <div class="name" v-text="clubName"></div>
+              </div>
+          </div>
+          <div class="cm_ai_container_main">
+              <div class="cm_ai_container">
+                  <div class="cm_ai_mall_header">
+                      <div class="cm_ai_logo">
+                          <a class="logo" href="/index.html" target="_blank">
+                              <img src="/img/base/logo.png">
+                          </a>
+                      </div>
+                  </div>
+                  <!--提问回答element-->
+                  <div class="cm_ai_answer_main" id="cm_ai_answer"></div>
+                  <!--提问文本框-->
+                  <div class="cm_ai_content">
+                      <div class="cm_ai_input">
+                          <textarea class="cm_ai_textarea" v-model="questionTextarea" placeholder="请输入您想了解的内容" maxlength="200" @keydown="handleKeyDown"></textarea>
+                      </div>
+                      <div class="cm_ai_button_main">
+                          <div class="cm_ai_button" :class="isLoading ? 'none' : ''" @click="handleAskQuestion">
+                              <i v-if="isLoading"  class="cm_ai_icon el-icon-loading"></i>
+                              <i v-else  class="cm_ai_icon el-icon-position">发送</i>
+                          </div>
+                      </div>
+                  </div>
+              </div>
+          </div>
+      </div>
+  </div>
+  <template th:replace="components/foot-link"></template>
+  <script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/utils.service.js(v=${version})}"></script>
+  <script charset="utf-8" type="text/javascript" th:src="@{/js/mixins/cmAiMixins.js(v=${version})}"></script>
+  <script charset="utf-8" type="text/javascript" th:src="@{/js/caimei-chat/chats.js(v=${version})}"></script>
+</body>
+
+</html>

+ 34 - 26
src/main/resources/templates/components/drawer-ai.html

@@ -1,31 +1,39 @@
-<el-drawer title="" :visible.sync="isAiDrawer" direction="ltr" size="40%" :before-close="handleClose">
-  <div class="cm_ai_container">
-
-    <div class="cm_ai_answer_main" id="cm_ai_answer">
-<!--      <div class="cm_ai_answer">-->
-<!--        <div class="cm_ai_html_icon user">-->
-<!--          <img src="/img/base/icon-aiUser@2x.png">-->
-<!--        </div>-->
-<!--        <div class="cm_ai_html user" id="cm_ai_htmlcontent_user"></div>-->
-<!--      </div>-->
-<!--      <div class="cm_ai_answer">-->
-<!--        <div class="cm_ai_html_icon">-->
-<!--          <img src="/img/base/icon-ai@1x.png">-->
-<!--        </div>-->
-<!--        <div class="cm_ai_html" id="cm_ai_htmlcontent"></div>-->
-<!--      </div>-->
-    </div>
-    <div class="cm_ai_content">
-      <div class="cm_ai_header">
-        <div class="cm_ai_icon"><img src="/img/base/icon-ai@1x.png" alt="采美AI助手"></div>
-        <div class="cm_ai_text">采美AI助手</div>
+<el-drawer title="采美AI助手" :visible.sync="isAiDrawer" direction="ltr" size="60%" :before-close="handleClose">
+  <div class="cm_ai_container_body">
+    <div class="cm_ai_container_records">
+      <div class="cm_ai_records_btn" :class="disabled ? 'disabled' : 'show'" @click="handleCreatedChat">
+        <i class="cm_ai_add"></i>
+        <span>新建对话</span>
+      </div>
+      <div class="cm_ai_records_list">
+        <div class="cm_ai_records_item" v-for="(chat, index) in chatHistory" :key="index" @click="handleChatDetail(chat.id)">
+          <span class="content" v-text="chat.firstQuestion"></span>
+          <span class="time" v-text="chat.addTime"></span>
+        </div>
       </div>
-      <div class="cm_ai_input">
-        <textarea class="cm_ai_textarea" v-model="textarea" placeholder="请输入您想了解的内容"></textarea>
+      <div class="cm_ai_records_user" v-if="chatParams.userId">
+        <div class="avatar">
+          <img src="/img/base/icon-aiUser@2x.jpg">
+        </div>
+        <div class="name" v-text="clubName"></div>
       </div>
-      <div class="cm_ai_button" :class="isLoading ? 'none' : ''" @click="handleAskQuestion">
-        <img v-if="isLoading" class="cm_ai_icon" src="/img/base/icon-loading.gif">
-        <img v-else class="cm_ai_icon" src="/img/base/icon-aiBtn@2x.png">
+    </div>
+    <div class="cm_ai_container_main">
+      <div class="cm_ai_container">
+        <!--提问回答element-->
+        <div class="cm_ai_answer_main" id="cm_ai_answer"></div>
+        <!--提问文本框-->
+        <div class="cm_ai_content">
+          <div class="cm_ai_input">
+            <textarea class="cm_ai_textarea" v-model="questionTextarea" maxlength="200" placeholder="请输入您想了解的内容" @keydown="handleKeyDown"></textarea>
+          </div>
+          <div class="cm_ai_button_main">
+            <div class="cm_ai_button" :class="isLoading ? 'none' : ''" @click="handleAskQuestion">
+              <i v-if="isLoading"  class="cm_ai_icon el-icon-loading"></i>
+              <i v-else  class="cm_ai_icon el-icon-position">发送</i>
+            </div>
+          </div>
+        </div>
       </div>
     </div>
   </div>

+ 1 - 0
src/main/resources/templates/components/foot-link.html

@@ -6,6 +6,7 @@
 <script charset="utf-8" type="text/javascript" src="/lib/vue2.6.12.min.js"></script>
 <script charset="utf-8" type="text/javascript" src="/lib/lazyload.js"></script>
 <script charset="utf-8" type="text/javascript" src="/lib/element-ui/element-ui.min.js"></script>
+<script charset="utf-8" type="text/javascript" th:src="@{/js/anonymous/anonymous.js(v=${version})}"></script>
 <script charset="utf-8" type="text/javascript" th:src="@{/js/common/ajax.service.js(v=${version})}"></script>
 <script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/utils.service.js(v=${version})}"></script>
 <script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/shopping.service.js(v=${version})}"></script>

+ 3 - 3
src/main/resources/templates/components/footer.html

@@ -119,9 +119,9 @@
                 </div>
             </div>
         </div>
-<!--        <div class="item">-->
-<!--            <span class="aiItem" @click="handleShowAiDrawer">Ai助手</span>-->
-<!--        </div>-->
+        <div class="item">
+            <span class="aiItem" @click="handleShowAiDrawer">Ai助手</span>
+        </div>
         <div class="item">
             <span class="toTop icon mIcon">TOP</span>
         </div>

+ 6 - 0
src/main/resources/templates/components/header.html

@@ -117,6 +117,11 @@
                         <em class="word" th:text="${word}"></em>
                     </span>
                 </div>
+                <div class="searchAi">
+                    <a href="/chats.html">
+                        <img src="/img/base/icon-ai@1x.png" alt="采美Ai助手">
+                    </a>
+                </div>
             </div>
             <div class="wechat_qrcode">
                 <div class="q_item">
@@ -269,6 +274,7 @@
             </div>
         </div>
     </div>
+    <input type="hidden" th:value="${siteEnv}" id="siteEnv">
     <input type="hidden" th:value="${coreServer}" id="coreServer">
     <input type="hidden" th:value="${agent}" id="userAgent">
 </header>

+ 5 - 51
src/main/resources/templates/we_chat/redirect_uri.html

@@ -6,59 +6,13 @@
     <template th:replace="components/head-link"></template>
 </head>
 <body>
-
 <input type="hidden" th:value="${coreServer}" id="coreServer">
 <input type="hidden" th:value="${agent}" id="userAgent">
+<div id="weChatContention">
+<!--  微信登录  -->
+</div>
 <template th:replace="components/foot-link"></template>
-<script charset="utf-8" type="text/javascript">
-    // 如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE
-    var wx_mode = Number(getBaseCookie("weChatAutoLogin"))===1 ? 1 : 2;
-    var wx_code = getUrlParam('code');
-    var wx_state = getUrlParam('state');
-    var userData = '';
-    $.get(coreServer+'/user/login/auth/website?code='+wx_code+'&state='+wx_state+'&mode='+wx_mode, function(r){
-        if(r.code===0){
-            console.log(r.data);
-            userData = {
-                account: r.data.account,
-                email: r.data.email,
-                phone: r.data.bindMobile,
-                name: r.data.name,
-                userName: r.data.userName,
-                userId: r.data.userId,
-                spId: r.data.serviceProviderId,
-                clubId: r.data.clubId,
-                shopId: r.data.shopId,
-                userIdentity: r.data.userIdentity,
-                permission: r.data.userPermission,
-                token: r.data.token
-            };
-            localStorage.setItem('userInfo',JSON.stringify(userData));
-            tobeforePage();
-        }else{
-            if (wx_mode===2 && r.code===-4){
-                //微信绑定页面
-                window.location.href = '/bind.html';
-            }else if (wx_mode===1) {
-                tobeforePage();
-            }else{
-                CAIMEI.Alert(r.msg,'确定',true, function(){
-                    tobeforePage();
-                });
-            }
-        }
-    });
-    function tobeforePage(){
-        var loginBeforePath = getBaseCookie("loginBeforePath");
-        if (loginBeforePath && loginBeforePath!='undefined' && loginBeforePath.indexOf('.html')>0) {
-            delBaseCookie("loginBeforePath");
-            window.location.href = loginBeforePath;
-        } else if (userData && userData.userIdentity*1 === 3) {
-            location.href = '/supplier/dashboard.html';
-        } else if (userData && (userData.userIdentity*1 === 2 || userData.userIdentity*1 === 4)) {
-            location.href = '/user/dashboard.html';
-        }
-    }
-</script>
+<script charset="utf-8" type="text/javascript" th:src="@{/js/common/serviceapi/user.service.js(v=${version})}"></script>
+<script charset="utf-8" type="text/javascript" th:src="@{/js/we_chat/we_chat.js(v=${version})}"></script>
 </body>
 </html>