Files
AI/index.html
2026-10-15 10:58:43 +08:00

3712 lines
142 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no" />
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="Thu, 01 Jan 1970 00:00:00 GMT">
<meta property=" og:title" content="飒沓光伏智能体">
<meta property="og:description" content="SataBot Agent 是一款由人工智能驱动的光伏场景AI应用程序。">
<meta property="og:image" content="http://1.95.137.212:19000/mbzn/16%3A33%3A49123.png">
<title>飒沓光伏智能体</title>
<link rel="icon" href="./img/logo.png" type="image/x-icon">
<!-- <script src=" https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxopensdk.js"> -->
<!-- </script> -->
<script src="./marked.min.js"></script>
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<style>
* {
touch-action: manipulation;
/* 允许平移和捏合缩放,但禁用双击缩放和长按 */
-webkit-tap-highlight-color: transparent;
/* 移除点击时的默认高亮(可选,优化体验) */
}
body {
margin: 0;
font-family: "Segoe UI", "PingFang SC", Arial, sans-serif;
height: 100vh;
display: flex;
background: #f0f6fb;
color: #333;
width: 100%;
}
.toast {
position: fixed;
top: 20%;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 10px 18px;
border-radius: 8px;
font-size: 15px;
opacity: 0;
transition: opacity 0.3s ease;
z-index: 9999999999;
}
.toast.show {
opacity: 1;
}
.toast.success {
background-color: #09db45;
}
/* 侧边栏 */
.sidebar {
width: 240px;
background: #ffffff;
border-right: 1px solid #e3eaf2;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.04);
z-index: 10;
height: 100%;
left: 0px;
transition: all 0.3s ease;
}
.sidebar.collapsed {
left: -260px;
/* width: 0; */
overflow: hidden;
position: absolute;
}
.sidebar-header {
padding: 16px;
padding-left: 20px;
font-size: 16px;
font-weight: bold;
border-bottom: 1px solid #f0f4f8;
display: flex;
justify-content: flex-start;
}
.sidebar-header img {
width: 24px;
margin-right: 10px;
}
.sidebar-actions {
padding: 0px 12px;
}
.sidebar-actions button {
width: 100%;
padding: 10px;
border: none;
border-radius: 8px;
background: #f5f5f5;
color: #000;
font-size: 14px;
cursor: pointer;
transition: background 0.2s;
}
.chat-list {
flex: 1;
overflow-y: auto;
padding: 0px 10px;
}
.chat-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
border-bottom: 1px solid #f7f9fb;
cursor: pointer;
transition: background 0.2s;
text-align: center;
font-size: 14px;
}
.chat-item:hover {
background: #f2f8fd;
}
.chat-item.active {
background: #f5f5f5;
font-weight: bold;
color: #000;
border-radius: 8px;
}
.chat-title {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.delete-btn {
margin-left: 8px;
color: #aaa;
cursor: pointer;
font-size: 14px;
}
.delete-btn:hover {
color: #e74c3c;
}
/* 收起按钮(独立漂浮在左边) */
.toggle-btn {
position: fixed;
display: none;
justify-content: center;
align-items: center;
position: absolute;
top: 7px;
left: 10px;
color: #fff;
border: none;
border-radius: 50%;
width: 28px;
height: 28px;
font-size: 18px;
cursor: pointer;
z-index: 20;
transition: background 0.2s;
background: transparent !important;
padding: 5px;
}
.sidebar.collapsed>.toggle-btn {
position: fixed;
}
.toggle-btn:hover {
background: #999;
}
/* 右侧聊天区域 */
.chat-container {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
width: calc(100% - 240px);
height: 100%;
background-color: #fff;
}
.chat-input.mobile {
padding-bottom: 30px;
}
.chat-container .content {
height: 70%;
overflow-y: auto;
scrollbar-width: none;
/* overflow-y: auto; */
}
.chat-header {
height: 50px;
background: #fff;
font-size: 16px;
color: #000;
display: flex;
justify-content: center;
}
.chat-header .userinfo {
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
color: #666;
font-weight: 400;
font-family: fangsong;
}
.chat-header .userinfo .logout {
color: #666;
font-weight: 400;
font-family: fangsong;
/* text-decoration: underline; */
cursor: pointer
}
.price {
text-decoration: none;
}
.price:hover,
.logout:hover {
color: #999 !important;
}
.chat-header .back {
display: none;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: scroll;
position: relative;
height: 100%;
scrollbar-width: thin;
}
.message {
max-width: 70%;
margin-bottom: 16px;
padding: 12px 16px;
border-radius: 14px;
font-size: 16px;
line-height: 1.5;
/* white-space: pre-wrap;*/
white-space: normal;
word-wrap: break-word;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
animation: fadeIn 0.3s ease;
}
.message.user {
display: block;
background: #d4e5ff;
color: #000;
align-self: flex-end;
border-bottom-right-radius: 4px;
display: block;
width: fit-content;
}
.message.assistant {
max-width: 100%;
background: #fff;
color: #333;
align-self: flex-start;
box-shadow: none;
position: relative;
padding-left: 0px;
/* border: 1px solid #e6eaf0;
border-bottom-left-radius: 4px; */
}
.message.assistant .avatar {
width: 22px;
height: 22px;
position: absolute;
left: -10px;
top: 15px;
}
.message img {
max-width: 200px;
border-radius: 8px;
margin-top: 8px;
}
.message.assistant .avatar img {
width: 100%;
height: 100%;
margin-top: 0px;
}
.chat-input {
padding: 12px;
background: #fff;
border-top: 1px solid #e3eaf2;
display: flex;
flex-direction: column;
gap: 8px;
box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.04);
}
.message.thinking {
width: auto;
/* 宽度自适应内容 */
max-width: 40%;
/* 限制最大宽度 */
}
.input-row {
display: flex;
align-items: center;
flex-direction: column;
justify-content: space-between;
gap: 8px;
}
.none {
display: none;
}
.input-row .img-row {
width: 100%;
min-width: 0px;
min-height: 0px;
box-sizing: border-box;
padding: 10px;
}
.input-row .img-box .delete-btn {
position: absolute;
right: -5px;
top: -5px;
}
.input-row .img-box {
width: 40px;
position: relative
}
.input-row img {
width: 40px;
height: 40px;
border-radius: 5px;
}
.chat-input textarea {
flex: 1;
resize: none;
padding: 10px;
border-radius: 20px;
border: 1px solid #d9e4f0;
font-size: 14px;
outline: none;
background: #f9fcff;
transition: border 0.2s;
width: 100%;
}
.chat-input textarea:focus {
/* border-color: #0057ff; */
}
.chat-input button {
padding: 10px 16px;
border: none;
border-radius: 8px;
background: #0057ff;
color: #fff;
font-size: 14px;
cursor: pointer;
transition: background 0.2s;
}
.chat-input button:hover {
background: #0046cc;
}
.options-row {
display: flex;
gap: 10px;
align-items: center;
font-size: 13px;
}
select,
input[type="file"] {
font-size: 13px;
padding: 4px 6px;
border: 1px solid #d9e4f0;
border-radius: 6px;
background: #fff;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 修改后的输入框样式 - 豆包/腾讯元宝风格 */
.chat-input {
padding: 16px;
background: #fff;
border-top: 1px solid #e8e8e8;
display: flex;
flex-direction: column;
gap: 12px;
}
.input-row {
display: flex;
align-items: flex-end;
justify-content: flex-end;
/* 底部对齐 */
gap: 8px;
border: 1px solid #e5e5e5;
border-radius: 20px;
}
.input-row .button-row {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: space-between;
gap: 12px;
width: 100%;
margin-right: 10px;
margin-bottom: 10px;
}
.input-row .button-row>div {
cursor: pointer;
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
margin-left: 12px;
}
.chat-input textarea {
flex: 1;
resize: none;
padding: 12px 16px;
font-size: 14px;
outline: none;
background: #fff;
transition: all 0.2s;
min-height: 44px;
max-height: 200px;
box-shadow: none;
border: none !important;
box-sizing: border-box
}
.chat-input textarea:focus {
/* border-color: #0057ff; */
/* box-shadow: 0 0 0 2px rgba(0, 87, 255, 0.1); */
}
.chat-input button {
padding: 10px 16px;
height: 44px;
border: none;
border-radius: 8px;
background: #0057ff;
color: #fff;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
}
.chat-input button:hover {
background: #0046cc;
}
/* 文件选择和模型选择样式调整 */
.options-row {
display: flex;
gap: 8px;
align-items: center;
font-size: 13px;
}
select,
input[type="file"] {
font-size: 13px;
padding: 6px 8px;
border: 1px solid #e5e5e5;
border-radius: 6px;
background: #fff;
transition: all 0.2s;
}
select:focus,
input[type="file"]:focus {
border-color: #0057ff;
outline: none;
}
#fileInput {
display: none;
}
.mobilelogo {
display: none;
}
.userinfo-wrapper {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
height: 49px;
margin-bottom: 10px;
padding: 0px 26px;
margin-top: 10px;
}
.userinfo-wrapper img {
max-width: 30px;
max-height: 30px;
margin-right: 4px;
border-radius: 50%;
}
.userinfo-panel {
position: absolute;
bottom: 50px;
left: 0;
width: 150px;
background: #fff;
border-radius: 12px;
padding: 8px 8px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
gap: 0px;
opacity: 0;
transform: translateY(-10px);
pointer-events: none;
transition: all 0.3s ease;
z-index: 1000;
font-size: 14px;
}
/* 展开状态 */
.userinfo-panel.show {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
/* 面板内部元素 */
.userinfo-panel span,
.userinfo-panel a,
.userinfo-panel p {
padding: 8px 12px;
border-radius: 8px;
text-decoration: none;
color: #333;
text-align: left;
transition: background 0.2s;
border-bottom: 1px solid #f5f5f5;
display: flex;
justify-content: flex-start;
align-items: center;
gap: 5px;
}
.userinfo-panel p>span {
padding: 0px;
}
.userinfo-panel span:hover,
.userinfo-panel a:hover,
.userinfo-panel p:hover {
background: #f5f5f5 !important;
}
.userinfo-panel span:active,
.userinfo-panel a:active,
.userinfo-panel p:active {
background: #f5f5f5 !important;
}
/* 手机端适配 */
@media (max-width: 768px) {
.mobilelogo {
display: flex;
width: 28px;
height: 28px;
margin-right: 10px;
}
.sidebar {
/* position: absolute;
top: 10px; */
/* display: none; */
width: 240px;
background: #ffffff;
border-right: 1px solid #e3eaf2;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
box-shadow: 8px 0 60px rgba(0, 0, 0, 0.04);
z-index: 1000;
position: absolute;
top: 0px;
height: 100%;
left: 0px;
}
.sidebar.collapsed>.toggle-btn {
position: fixed;
right: 10px !important;
width: 28px;
height: 28px;
display: flex;
justify-content: center;
align-items: center;
}
.chat-container {
width: 100%;
height: 100vh;
}
.chat-input {
/* position: fixed; */
bottom: 0;
left: 0;
right: 0;
z-index: 100;
}
.chat-header .back {
display: flex;
justify-content: center;
align-items: center;
margin-right: 20px;
}
.chat-container .content {
overflow-y: auto;
/* scrollbar-width: none; */
}
/* 按钮样式 */
/* 折叠面板 */
.userinfo {
display: none !important;
}
}
.fourquestion {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 10px;
}
.fourquestion>div {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 10px;
}
.fourquestion .question {
box-sizing: border-box;
width: 172px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
color: #999;
border: 1px solid #e5e5e5;
border-radius: 14px;
padding: 10px 10px;
cursor: pointer;
flex-direction: row;
}
.fourquestion .question:hover {
background-color: #e5e5e5;
color: #0057ff;
}
.fourquestion .question img {
width: 28px;
height: 28px;
margin-right: 5px;
}
.sidequestion {
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 100%;
display: none;
}
.sidequestion>div {
width: 100%;
}
.sidequestion>div .question {
width: 80%;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
color: #999;
border: 1px solid #e5e5e5;
border-radius: 10px;
padding: 15px -16px !important;
cursor: pointer;
}
.mobile .fourquestionmain {
flex-wrap: nowrap;
overflow-x: scroll;
scrollbar-width: none;
/* 安卓端滚动条不显示 */
-ms-overflow-style: none;
justify-content: flex-start;
}
.mobile .fourquestionmain::-webkit-scrollbar {
display: none;
}
.mobile .fourquestionmain .question {
min-width: 137px;
font-size: 10px;
gap: 6px
}
/* .stopBtn {
width: 36px;
height: 36px;
} */
.none {
display: none !important;
}
.input-group {
display: flex;
align-items: center;
padding: 0px 5px;
border: 1px solid #ccc;
border-radius: 8px;
margin-bottom: 10px;
}
.area-select {
width: 130px;
font-size: 14px;
color: #333;
cursor: pointer;
}
input {
/* flex: 1; */
border: none;
outline: none;
font-size: 14px;
}
.chat-input.pc {
border: none;
display: flex;
justify-content: center;
align-items: center;
box-shadow: none;
}
.chat-input.pc .input-row {
width: 70%;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
/* 获取验证码按钮 */
.code-btn {
border: none;
/* border: 1px solid #1890ff; */
background: white;
padding: 5px 12px;
border-radius: 6px;
color: #1890ff;
cursor: pointer;
font-size: 14px;
width: 135px;
}
/* 登录按钮 */
.login-btn {
margin-top: 25px;
width: 100%;
background: #1890ff;
color: white;
padding: 12px 0;
border-radius: 10px;
border: none;
font-size: 17px;
cursor: pointer;
}
/* 协议 */
.agreement {
margin-top: 15px;
font-size: 12px;
color: #777;
display: flex;
align-items: center;
gap: 6px;
}
.pctitle {
font-size: 20px;
}
/* 微信登录 */
.wechat-login {
text-align: center;
font-size: 14px;
color: #555;
cursor: pointer;
}
.wechat-login>div {
display: flex;
justify-content: center;
align-items: center;
gap: 2px;
}
.wechat-login img {
width: 38px;
display: block;
margin: 0 auto 5px;
}
/* 区号选择框 */
.mask {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
}
.area-box {
background: #fff;
position: absolute;
bottom: 0;
width: 100%;
max-height: 300px;
overflow-y: auto;
border-radius: 10px 10px 0 0;
}
.area-item {
padding: 15px;
border-bottom: 1px solid #eee;
font-size: 16px;
cursor: pointer;
}
.area-item:hover {
background: #f5f5f5;
}
.toggle-eye {
position: absolute;
right: 10px;
top: 10px;
}
.link {
color: #1677ff;
cursor: pointer;
}
.wechat-login {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #666;
margin-bottom: 10px;
}
.wechat-login span:nth-child(1) {
margin-right: 8px;
}
.popbox {
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.4);
z-index: 999999;
}
.popbox .loading-box {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 999999999;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
opacity: 0.7;
}
.popbox .loading-box.none {
display: none;
}
.popbox .loading-box .loading {
border: solid #e2e8f0;
/* 浅灰色边框 */
border-top-color: #165DFF;
/* 蓝色顶部边框 */
border-radius: 50%;
animation: spin 1s linear infinite;
/* 旋转动画 */
display: inline-block;
margin-bottom: 20px;
width: 30px;
height: 30px;
}
#sms-form {
background-color: #fff;
border-radius: 8px;
padding: 10px;
position: relative;
}
.userinfo-toggle {
position: relative;
cursor: pointer;
}
/* 隐藏 after(退出按钮) */
</style>
<style>
body {
font-family: Arial, sans-serif;
background: #f5f5f5;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.no-after::after {
content: none !important;
display: none !important;
}
.popbgc {
background-color: rgba(0, 0, 0, 0.4);
position: fixed;
left: 0px;
right: 0px;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 999999;
transition: all 0.3s ease-in-out;
backdrop-filter: blur(2px);
/* position: relative; */
}
#sms-button {
padding: 12px;
}
.popbgc .loading-box {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 999999999;
}
.popbgc .loading-box.none {
display: none;
}
.popbgc .loading-box .loading {
border: solid #e2e8f0;
/* 浅灰色边框 */
border-top-color: #165DFF;
/* 蓝色顶部边框 */
border-radius: 50%;
animation: spin 1s linear infinite;
/* 旋转动画 */
display: inline-block;
margin-bottom: 20px;
width: 30px;
height: 30px;
}
.popup {
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
width: 400px;
}
.popup h2 {
margin-top: 0;
font-size: 18px;
margin-bottom: 15px;
}
input,
select,
button {
width: 100%;
padding: 8px;
margin: 5px 0;
border-radius: 4px;
border: 1px solid #ccc;
}
input {
border: none;
}
#popupForm input {
border: 1px solid #ccc !important;
width: 94%;
}
.options {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin: 10px 0;
}
.option {
/* flex: 1 1 calc(50% - 5px); */
width: 28%;
text-align: center;
padding: 8px;
background: #f0f0f0;
border-radius: 4px;
cursor: pointer;
user-select: none;
}
.option.selected {
background: #007bff;
color: white;
}
button {
background: #007bff;
color: white;
border: none;
cursor: pointer;
}
.popbgc.none {
display: none;
}
.userinfo-toggle {
padding: 4px 2px;
border: none;
color: #fff;
font-weight: 500;
cursor: pointer;
overflow-x: hidden;
color: #000;
text-overflow: ellipsis;
background-color: transparent !important;
}
.collapsed .toggle-btn {
display: flex;
}
.thinking-loading {
color: #888;
font-size: 13px;
position: relative;
background: #f7f7f7;
border: 1px dashed #ddd;
border-radius: 6px;
}
.ai-thinking {
display: inline-flex;
align-items: center;
/* gap: 10px; */
width: 100%;
padding: 6px 10px;
}
/* =========================
Icon (thinking)
========================= */
.ai-loading {
width: 22px;
height: 22px;
position: relative;
animation: breathe 1.8s cubic-bezier(.42, 0, .58, 1) infinite;
filter:
drop-shadow(0 1px 1px rgba(0, 0, 0, 0.10)) drop-shadow(0 0 7px rgba(0, 0, 0, 0.08));
margin-top: 0px !important;
position: relative;
top: 4px;
margin-right: 4px;
}
.ai-thinking .ai-loading {
top: 0px;
}
@keyframes breathe {
0% {
transform: scale(0.93);
}
36% {
transform: scale(1.06);
}
62% {
transform: scale(1.00);
}
100% {
transform: scale(0.93);
}
}
.ai-loading::before {
content: "";
position: absolute;
inset: -4px;
border-radius: 50%;
border: 1.2px solid rgba(0, 0, 0, 0.18);
animation: pulse 2.4s ease-out infinite;
pointer-events: none;
}
@keyframes pulse {
0% {
transform: scale(0.82);
opacity: 0.55;
}
100% {
transform: scale(1.38);
opacity: 0;
}
}
/* =========================
Text (thinking)
========================= */
.ai-text {
font-size: 13px;
letter-spacing: 0.14em;
text-transform: uppercase;
opacity: 0.7;
animation: text-step 1.8s steps(3, end) infinite;
}
@keyframes text-step {
0% {
opacity: 0.35;
}
45% {
opacity: 0.6;
}
100% {
opacity: 0.95;
}
}
/* =========================
✅ 完成态(常驻)
========================= */
.ai-thinking.is-complete .ai-loading,
.ai-thinking.is-complete .ai-loading::before {
animation: none;
transform: scale(1);
}
.is-complete .ai-text {
animation: none;
text-transform: none;
letter-spacing: 0.08em;
opacity: 0.85;
}
.is-complete .ai-loading {
animation: none;
text-transform: none;
}
@keyframes dots {
0% {
content: '';
}
25% {
content: '.';
}
50% {
content: '..';
}
75% {
content: '...';
}
}
.thinking-box {
margin-bottom: 12px;
border: 1px dashed #ddd;
border-radius: 6px;
font-size: 13px;
color: #666;
}
.thinking-box .thinking-header {
padding: 6px 10px;
cursor: pointer;
background: #f7f7f7;
user-select: none;
position: relative;
}
.thinking-title {
/* position: absolute; */
top: 3px;
left: -27px;
}
.thinking-title img {
margin-top: 0px !important;
margin-right: 6px;
}
.thinking-content {
padding: 8px 10px;
line-height: 1.6;
}
.thinking-content.collapsed {
display: none;
}
.answer-box {
font-size: 15px;
line-height: 1.7;
}
@media (max-width: 768px) {
.popbgc {
width: 100%;
height: 100%;
}
.popup {
position: absolute;
top: 50px;
width: 90%;
}
.weixin-loading {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: fixed;
z-index: 99999;
background-color: #fff;
top: 0px;
left: 0px;
opacity: 0.7;
}
.weixin-loading.none {
display: none;
}
.weixin-loading .loading {
border: solid #e2e8f0;
/* 浅灰色边框 */
border-top-color: #165DFF;
/* 蓝色顶部边框 */
border-radius: 50%;
animation: spin 1s linear infinite;
/* 旋转动画 */
display: inline-block;
margin-bottom: 20px;
width: 30px;
height: 30px;
}
.chatboxmobile {
width: 100%;
display: flex;
justify-content: flex-start;
gap: 0px;
}
.chatboxmobile .button-row {
width: 62px !important;
margin-bottom: 0px !important;
gap: 8px !important;
margin-right: 5px;
justify-content: flex-end;
}
.input-row img {
width: 20px !important;
height: 20px !important;
}
#sendFileBtn img {
width: 16px !important;
height: 16px !important;
}
.input-row .button-row>div {
margin-left: 0px !important;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
}
.loading-dots {
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 20px;
}
.dot {
width: 8px;
height: 8px;
margin: 0 5px;
border-radius: 50%;
background-color: #ccc;
animation: dot-blink 1s infinite alternate;
}
.dot:nth-child(1) {
animation-delay: 0s;
}
.dot:nth-child(2) {
animation-delay: 0.5s;
}
@keyframes dot-blink {
0% {
background-color: #ccc;
}
50% {
background-color: #333;
/* 高亮颜色 */
}
100% {
background-color: #ccc;
}
}
</style>
</head>
<body>
<div class="weixin-loading ">
<div class="loading">
</div>
</div>
<!-- 左侧侧边栏 -->
<div class="sidebar" id="sidebar">
<button class="toggle-btn" id="toggleBtn" onclick="toggleSidebar()"><svg width="50" height="24"
viewBox="0 0 30 18" xmlns="http://www.w3.org/2000/svg">
<!-- 上面较粗的横线 -->
<rect x="2" y="3" width="26" height="3.2" rx="1.6" fill="#222" />
<!-- 下面较细的横线 -->
<rect x="6" y="12" width="18" height="2.6" rx="1.3" fill="#222" />
</svg>
</button>
<div class="sidebar-header"><img src="./img/logo.png">会话列表</div>
<div class="sidebar-actions">
<button onclick="newChat()">+ 新建会话</button>
</div>
<div class="chat-list" id="chatList"></div>
<div class="fourquestion sidequestion">
<div>
<div class='question' data-value='分析这个场站' data-pre-value="详细分析这个光伏场站,根据图片给出详细的运维方案"><img
src="./img/1.png" alt="">分析这个场站</div>
<div class='question' data-value='详细的割草计划' data-pre-value="如果这个光伏场站需要割草怎么做,给出一份详细的计划"><img
src="./img/3.png" alt="">详细的割草计划</div>
<div class='question' data-value='详细的清洗计划' data-pre-value="如果这个光伏场站需要用无人机清洗怎么做,给出一份详细的计划"><img
src="./img/4.png" alt="">详细的清洗计划</div>
</div>
<div>
<div class='question' data-value='详细的巡检计划' data-pre-value="如果这个光伏场站需要巡检怎么做,给出一份详细的计划"><img
src="./img/2.png" alt="">详细的巡检计划</div>
</div>
</div>
<div class="userinfo-wrapper">
<img src="" alt="">
<!-- 初始按钮 -->
<p class="userinfo-toggle username" onclick="toggleUserInfo()">用户</p>
<!-- 折叠面板 -->
<div class="userinfo-panel">
<!-- <p style="margin:0px"><img src="" alt=""><span class="username">用户</span></p> -->
<span class="logout logout1" onclick="logout()"><svg t="1764305134824" class="icon"
viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20125" width="16"
height="16">
<path
d="M874.666667 855.744a19.093333 19.093333 0 0 1-19.136 18.922667H168.469333A19.2 19.2 0 0 1 149.333333 855.530667V168.469333A19.2 19.2 0 0 1 168.469333 149.333333h687.061334c10.581333 0 19.136 8.533333 19.136 18.922667V320h42.666666V168.256A61.717333 61.717333 0 0 0 855.530667 106.666667H168.469333A61.866667 61.866667 0 0 0 106.666667 168.469333v687.061334A61.866667 61.866667 0 0 0 168.469333 917.333333h687.061334A61.76 61.76 0 0 0 917.333333 855.744V704h-42.666666v151.744zM851.84 533.333333l-131.797333 131.754667a21.141333 21.141333 0 0 0 0.213333 29.973333 21.141333 21.141333 0 0 0 29.973333 0.192l165.589334-165.589333a20.821333 20.821333 0 0 0 6.122666-14.976 21.44 21.44 0 0 0-6.314666-14.997333l-168.533334-168.533334a21.141333 21.141333 0 0 0-29.952-0.213333 21.141333 21.141333 0 0 0 0.213334 29.973333L847.296 490.666667H469.333333v42.666666h382.506667z"
fill="#3D3D3D" p-id="20126"></path>
</svg>退出</span>
<a class="logout price" href="./modal.html"><svg t="1764305265690" class="icon" viewBox="0 0 1024 1024"
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22408" width="16" height="16">
<path
d="M799.785 63.785h-576c-88 0-160 72-160 160v112.129l64.205 57.653V217.99c0-49.5 40.5-90 90-90h588.184c49.5 0 90 40.5 90 90v343.62l63.611 57.119V223.785c0-88-72-160-160-160z m96.389 741.854c0 49.5-40.5 90-90 90H217.99c-49.5 0-90-40.5-90-90V518.558l-64.205-57.653v338.88c0 88 72 160 160 160h576c88 0 160-72 160-160V743.72l-63.611-57.119v119.038z"
p-id="22409" fill="#333333"></path>
<path
d="M63.873 460.682l106.776 89.295 0.118 71.213-106.776-89.294zM853.053 461.433l106.776 89.295 0.118 71.214-106.776-89.295zM656.41 500.181h-312c-6.6 0-12-5.4-12-12v-31c0-6.6 5.4-12 12-12h312c6.6 0 12 5.4 12 12v31c0 6.6-5.4 12-12 12zM655.247 611.809h-312c-6.6 0-12-5.4-12-12v-31c0-6.6 5.4-12 12-12h312c6.6 0 12 5.4 12 12v31c0 6.6-5.4 12-12 12z"
p-id="22410" fill="#333333"></path>
<path
d="M512.826 752.07h-31c-6.6 0-12-5.4-12-12v-330c0-6.6 5.4-12 12-12h31c6.6 0 12 5.4 12 12v330c0 6.6-5.4 12-12 12z"
p-id="22411" fill="#333333"></path>
<path
d="M633.558 327.984l-107.48 107.48c-4.667 4.667-12.304 4.667-16.971 0l-21.92-21.92c-4.667-4.667-4.667-12.304 0-16.971l107.48-107.48c4.667-4.667 12.304-4.667 16.971 0l21.92 21.92c4.667 4.668 4.667 12.304 0 16.971z"
p-id="22412" fill="#333333"></path>
<path
d="M397.984 289.07l107.48 107.48c4.667 4.667 4.667 12.304 0 16.971l-21.92 21.92c-4.667 4.667-12.304 4.667-16.971 0l-107.48-107.48c-4.667-4.667-4.667-12.304 0-16.971l21.92-21.92c4.668-4.667 12.304-4.667 16.971 0z"
p-id="22413" fill="#333333"></path>
</svg>服务价格</a>
</div>
</div>
</div>
<!-- 收起按钮 -->
<!-- 右侧聊天区 -->
<div class="chat-container">
<div class="chat-header">
<!-- <div class='back' onclick="handleBack()">
<svg t="1748925372585" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="4688" width="16" height="16">
<path
d="M395.21518 513.604544l323.135538-312.373427c19.052938-18.416442 19.052938-48.273447 0-66.660212-19.053961-18.416442-49.910737-18.416442-68.964698 0L291.75176 480.290811c-19.052938 18.416442-19.052938 48.273447 0 66.660212l357.633237 345.688183c9.525957 9.207709 22.01234 13.796214 34.497699 13.796214 12.485359 0 24.971741-4.588505 34.466999-13.82896 19.052938-18.416442 19.052938-48.242747 0-66.660212L395.21518 513.604544z"
fill="#999" p-id="4689"></path>
</svg>
</div> -->
<div style="
display: flex;
justify-content: flex-start;
align-items: center;
">
<span class="pctitle">新能源智能体</span><span style="font-size:20px" class="pctitleeng">satabot</span>
</div>
</div>
<div class="content" id='content'>
<div id="chatMessages" class="chat-messages"></div>
</div>
<div class="chat-input pc">
<div class="fourquestion fourquestionmain">
<div class='question mainauestion' data-value='分析这个场站' data-pre-value="详细分析这个光伏场站,根据图片给出详细的运维方案"><img
src="./img/1.png" alt="">分析这个场站</div>
<div class='question mainauestion' data-value='详细的割草计划' data-pre-value="如果这个光伏场站需要割草怎么做,给出一份详细的计划"><img
src="./img/3.png" alt="">详细的割草计划</div>
<div class='question mainauestion' data-value='详细的清洗计划' data-pre-value="如果这个光伏场站需要用无人机清洗怎么做,给出一份详细的计划">
<img src="./img/4.png" alt="">详细的清洗计划</div>
<div class='question mainauestion' data-value='详细的巡检计划' data-pre-value="如果这个光伏场站需要巡检怎么做,给出一份详细的计划"><img
src="./img/2.png" alt="">详细的巡检计划</div>
</div>
<div class="input-row">
<div class="img-row none">
<div class="img-box">
<img src="" alt="">
<span class="delete-btn" onclick="deleteImg()"><svg t="1757836617046" class="icon"
viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16945"
width="16" height="16">
<path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#EF4631"
p-id="16946">
</path>
<path
d="M733.6 733.6c-16.7 16.7-43.7 16.6-60.2 0.1l-151-151-151 151c-16.6 16.6-43.4 16.6-60.2-0.1-16.7-16.7-16.6-43.7-0.1-60.2l151-151-151-151c-16.6-16.6-16.6-43.4 0.1-60.2 16.7-16.7 43.7-16.6 60.2-0.1l151 151 151-151c16.6-16.6 43.4-16.6 60.2 0.1 16.7 16.7 16.6 43.7 0.1 60.2l-151 151 151 151c16.6 16.6 16.7 43.4-0.1 60.2z"
fill="#FFFFFF" p-id="16947"></path>
</svg></span>
</div>
</div>
<textarea class="chatInput" rows="1" placeholder="询问任何问题..." name="quespc"></textarea>
<div class="button-row">
<div id="sendFileBtn" style="position: relative; width: 40px; height: 40px; cursor: pointer;">
<input type="file" id="fileInput" style="position: absolute;
left: -20px; top: 0; width: 0px; height: 50%;
opacity: 0; cursor: pointer;" />
<span class="sendfileimg">
<svg t="1764306578537" class="icon" viewBox="0 0 1025 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="26780" width="24" height="24">
<path
d="M852.812 166.713c-92.715-89.28-212.9-140.789-339.954-140.789s-250.672 51.509-339.953 140.79c-188.863 188.862-188.863 491.043 0 679.906 89.28 89.28 212.9 140.789 339.953 140.789S763.531 935.9 852.812 846.62c188.863-188.863 188.863-491.044 0-679.907m-48.074 631.833c-78.98 78.979-181.996 120.185-291.88 120.185s-212.9-41.206-291.879-120.185c-161.392-161.392-161.392-422.367 0-583.759 78.98-78.979 181.996-120.185 291.88-120.185s212.9 41.206 291.879 120.185c161.392 161.392 161.392 422.367 0 583.759"
fill="#515151" p-id="26781"></path>
<path
d="M547.197 472.328V297.2c0-20.603-13.735-34.338-34.339-34.338S478.52 276.597 478.52 297.2v175.128H303.392c-20.603 0-34.339 13.735-34.339 34.339 0 10.301 3.434 17.169 10.302 24.037s13.736 10.301 24.037 10.301H478.52v175.128c0 10.302 3.434 17.17 10.301 24.037 6.868 6.868 13.736 10.302 24.037 10.302 20.604 0 34.34-13.736 34.34-34.34V541.006h175.127c20.603 0 34.338-13.735 34.338-34.338s-13.735-34.34-34.338-34.34H547.197z"
fill="#515151" p-id="26782"></path>
</svg>
</span>
</div>
<div id="sendBtn" class="sendBtn">
<span class="sendMsgImg">
<svg t="1764306257999" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="24697" width="24" height="24">
<path
d="M691.84 1014.4l-271.36-244.16v79.68l10.24-10.24 44.48 46.08-118.72 115.52V626.24l304.64 274.56 252.8-787.2-786.56 280.96 168.96 164.48 325.76-246.72 38.72 50.88L291.2 643.2 9.28 368.64 1014.72 9.6 691.84 1014.4z"
fill="#2A2A3B" p-id="24698"></path>
</svg>
</span>
<div class="stopBtn none" id="stopBtn1">
<svg t="1764310210804" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="28649" width="24" height="24">
<path
d="M365.014704 657.815846H657.084939V365.74561H365.014704V657.815846z m584.140471-146.035118c0-240.906781-197.125482-438.105353-438.105353-438.105353-240.979872 0-438.105353 197.198572-438.105354 438.105353 0 240.979872 197.125482 438.178444 438.105354 438.178444 240.979872 0 438.105353-197.198572 438.105353-438.178444zM511.634547 0.730906c281.399001 0 511.634547 230.235546 511.634547 511.634547s-230.235546 511.634547-511.634547 511.634547-511.634547-230.235546-511.634547-511.634547 230.235546-511.634547 511.634547-511.634547z"
p-id="28650" fill="#000000"></path>
</svg>
</div>
</div>
</div>
</div>
</div>
<div class="chat-input mobile">
<div class="fourquestion fourquestionmain">
<div class='question mainauestion' data-value='分析这个场站' data-pre-value="详细分析这个光伏场站,根据图片给出详细的运维方案"><img
src="./img/1.png" alt="">分析这个场站</div>
<div class='question mainauestion' data-value='详细的割草计划' data-pre-value="如果这个光伏场站需要割草怎么做,给出一份详细的计划"><img
src="./img/3.png" alt="">详细的割草计划</div>
<div class='question mainauestion' data-value='详细的清洗计划' data-pre-value="如果这个光伏场站需要用无人机清洗怎么做,给出一份详细的计划">
<img src="./img/4.png" alt="">详细的清洗计划</div>
<div class='question mainauestion' data-value='详细的巡检计划' data-pre-value="如果这个光伏场站需要巡检怎么做,给出一份详细的计划"><img
src="./img/2.png" alt="">详细的巡检计划</div>
</div>
<div class="input-row">
<div class="img-row none">
<div class="img-box">
<img src="" alt="">
<span class="delete-btn" onclick="deleteImg()"><svg t="1757836617046" class="icon"
viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16945"
width="16" height="16">
<path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#EF4631"
p-id="16946">
</path>
<path
d="M733.6 733.6c-16.7 16.7-43.7 16.6-60.2 0.1l-151-151-151 151c-16.6 16.6-43.4 16.6-60.2-0.1-16.7-16.7-16.6-43.7-0.1-60.2l151-151-151-151c-16.6-16.6-16.6-43.4 0.1-60.2 16.7-16.7 43.7-16.6 60.2-0.1l151 151 151-151c16.6-16.6 43.4-16.6 60.2 0.1 16.7 16.7 16.6 43.7 0.1 60.2l-151 151 151 151c16.6 16.6 16.7 43.4-0.1 60.2z"
fill="#FFFFFF" p-id="16947"></path>
</svg></span>
</div>
</div>
<div class="chatboxmobile">
<textarea class="chatInput1" rows="1" placeholder="询问任何问题..." name="quesmobile"></textarea>
<div class="button-row">
<div id="sendFileBtn" style="position: relative; width: 40px; height: 40px; cursor: pointer;">
<input type="file" id="fileInput1" style="position: absolute;
left: -30px; top: 0; width: 0px; height:50%;
opacity: 0; cursor: pointer;" />
<span class="sendfileimg">
<svg t="1764306578537" class="icon" viewBox="0 0 1025 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="26780" width="24" height="24">
<path
d="M852.812 166.713c-92.715-89.28-212.9-140.789-339.954-140.789s-250.672 51.509-339.953 140.79c-188.863 188.862-188.863 491.043 0 679.906 89.28 89.28 212.9 140.789 339.953 140.789S763.531 935.9 852.812 846.62c188.863-188.863 188.863-491.044 0-679.907m-48.074 631.833c-78.98 78.979-181.996 120.185-291.88 120.185s-212.9-41.206-291.879-120.185c-161.392-161.392-161.392-422.367 0-583.759 78.98-78.979 181.996-120.185 291.88-120.185s212.9 41.206 291.879 120.185c161.392 161.392 161.392 422.367 0 583.759"
fill="#515151" p-id="26781"></path>
<path
d="M547.197 472.328V297.2c0-20.603-13.735-34.338-34.339-34.338S478.52 276.597 478.52 297.2v175.128H303.392c-20.603 0-34.339 13.735-34.339 34.339 0 10.301 3.434 17.169 10.302 24.037s13.736 10.301 24.037 10.301H478.52v175.128c0 10.302 3.434 17.17 10.301 24.037 6.868 6.868 13.736 10.302 24.037 10.302 20.604 0 34.34-13.736 34.34-34.34V541.006h175.127c20.603 0 34.338-13.735 34.338-34.338s-13.735-34.34-34.338-34.34H547.197z"
fill="#515151" p-id="26782"></path>
</svg>
</span>
</div>
<div id="sendBtn" class="mobilesendbtn none sendBtn1">
<span class="sendMsgImg1">
<svg t="1764306257999" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="24697" width="24" height="24">
<path
d="M691.84 1014.4l-271.36-244.16v79.68l10.24-10.24 44.48 46.08-118.72 115.52V626.24l304.64 274.56 252.8-787.2-786.56 280.96 168.96 164.48 325.76-246.72 38.72 50.88L291.2 643.2 9.28 368.64 1014.72 9.6 691.84 1014.4z"
fill="#2A2A3B" p-id="24698"></path>
</svg>
</span>
<div class="stopBtn none" id="stopBtn">
<svg t="1764310210804" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="28649" width="24" height="24">
<path
d="M365.014704 657.815846H657.084939V365.74561H365.014704V657.815846z m584.140471-146.035118c0-240.906781-197.125482-438.105353-438.105353-438.105353-240.979872 0-438.105353 197.198572-438.105354 438.105353 0 240.979872 197.125482 438.178444 438.105354 438.178444 240.979872 0 438.105353-197.198572 438.105353-438.178444zM511.634547 0.730906c281.399001 0 511.634547 230.235546 511.634547 511.634547s-230.235546 511.634547-511.634547 511.634547-511.634547-230.235546-511.634547-511.634547 230.235546-511.634547 511.634547-511.634547z"
p-id="28650" fill="#000000"></path>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="popbgc none">
<div class="popup">
<h2>开启光伏运维智能化!</h2>
<form id="popupForm">
<input type="text" name="company" placeholder="请输入您的公司" required>
<!-- <select name="need" required>
<option value="">您的需求是什么?</option>
<option value="杂草清理">杂草清理</option>
<option value="组件积灰清扫">组件积灰清扫</option>
<option value="EL/IR缺陷识别">EL/IR缺陷识别</option>
<option value="热斑检测">热斑检测</option>
<option value="需要运维机器人">需要运维机器人</option>
<option value="定制机器人">定制机器人</option>
</select> -->
<div>
<p>您对以下哪些场景感兴趣?</p>
<div class="options" id="scenes">
<div class="option">山地光伏</div>
<div class="option">荒漠 / 戈壁</div>
<div class="option">农光互补电站</div>
<div class="option">渔光互补电站</div>
<div class="option">滩涂 / 盐碱地</div>
<div class="option">平原 / 草原</div>
</div>
</div>
<div>
<p>您的需求?</p>
<div class="options" id="needs">
<div class="option">杂草清理</div>
<div class="option">组件积灰清扫</div>
<div class="option">EL/IR缺陷识别</div>
<div class="option">热斑检测</div>
<div class="option">需要运维机器人</div>
<div class="option">定制机器人</div>
</div>
</div>
<button type="submit">立即使用</button>
</form>
</div>
</div>
</div>
<!-- <script>
// 开启 vConsole 调试面板
var vConsole = new VConsole();
console.log("✅ vConsole 已经启动");
</script> -->
<script src="./canvas.js"></script>
<script>
const sidebar = document.getElementById("sidebar");
const chatMessages = document.getElementById("chatMessages");
const chatInput = isMobile() ? document.querySelector(".chatInput1") : document.querySelector(".chatInput");
const fileInput = isMobile() ? document.getElementById("fileInput1") : document.getElementById("fileInput");
const chatList = document.getElementById("chatList");
const sendmsgbox = isMobile() ? document.querySelector('.sendBtn1') : document.querySelector('.sendBtn1');
const sendBtnImg = isMobile() ? document.querySelector('.sendBtn1 .sendMsgImg1') : document.querySelector('.sendBtn .sendMsgImg');
const stopBtn = document.querySelectorAll('.stopBtn');
const weixinloading = document.querySelector(".weixin-loading")
let controller = null;
let sessIdList = [];
let isStopped = false;//是否停止输出
let isUpload = {};
let hasImage = false;
let isPre = false;//是否点击了预设问题
// let sessIdList = JSON.parse(localStorage.getItem("sessId")) || [];
let sessId;
let activeChatId = '';
const params = new URLSearchParams(window.location.search);
console.log(params.get("userId"), 644, params.get("nickname"), params.get("headingimg"));
const encodedUserId = params.get("userId");
let openId = params.get("openid") ? params.get("openid") : '';
const from = params.get("from");
let token = params.get("token");//app的token
let localtoken = params.get("localtoken");//公众号的localtoken
function clearOldRootDomainCookies() {
const names = ['Admin-Token', 'token', 'userId', 'username', 'nickname', 'headimgurl', 'headingimg'];
const parts = location.hostname.split('.');
const rootDomain = parts.length >= 2 ? '.' + parts.slice(-2).join('.') : '';
if (!rootDomain || rootDomain === '.') return;
names.forEach(name => {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=' + rootDomain + ';';
});
console.log('[cookie] 已清除旧 root-domain cookie:', rootDomain);
}
clearOldRootDomainCookies();
// app会得到token;
// 手机端会验证token
if ((!getCookie("token") || localtoken != getCookie("token")) && isMobile() && !token) {
window.location.href = './middle.html';
}
if (!isMobile() && !getCookie("token") && !token && !params.get("nickname")) {
location.replace('./login.html');
}
// }
// else if (!isMobile() && !getCookie('sharetoken')) {//网页端token
// //
// location.replace('https://ri.satabot.com/#/login?goRemote=1&clear=1');
// }
// if (!isMobile() && !getCookie('sharetoken')) {
// location.replace('https://ri.satabot.com/#/login?goRemote=1&clear=1');
// }
// ✅ 先 URL 解码,再 Base64 解码,再 UTF-8 解码
let userId;
if (params.get("nickname") || getcookie("nickname")) {
console.log(getcookie("headingimg"), 888888, document.cookie, params.get("nickname"))
document.querySelectorAll('.logout1').forEach(el => {
el.style.display = 'none';
});
document.querySelectorAll('.username').forEach((e) => {
e.textContent = params.get("nickname") || getcookie("nickname");
})
document.querySelector(".userinfo-wrapper img").src = getcookie("headimgurl") || params.get("headingimg");
userId = decodeURIComponent(Number(escape(atob(encodedUserId))));
} else {
userId = decodeURIComponent(Number(escape(atob(encodedUserId))));
}
// 微信授权的码
if (userId && userId != "NaN") {
setCookie("userId", userId);
}
getUserName(userId);
// const userId = encodedUserId;
let sendParam = {
imageBase64: '',
userId: userId,
sessionId: '',
userPrompt: '',
requestId: ''
}
if (isMobile()) {
toggleSidebar();
document.querySelector(".pctitle").textContent = '';
document.querySelector(".chat-input.pc").classList.add('none');
} else {
document.querySelector(".pctitleeng").textContent = '';
document.querySelector(".chat-input.mobile").classList.add('none');
document.querySelector('.userinfo-panel').classList.add('pc')
document.querySelector('.price').classList.add('pc');
document.querySelector('.userinfo-toggle').classList.add('pc')
}
// if (isWeChat()) {
// if (code) {
// // gotoWeiXin();
// // 用 code 换取 openid 和 access_token
// fetch(`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=SECRET&code=CODE&grant_type=authorization_code?code=${code}`)
// .then(res => res.json())
// .then(data => {
// // data 里返回 userId / openid
// setCookie("userId", data.userId);
// window.location.href = "/"; // 回到首页
// });
// } else {
// // 没拿到 code,再次走 gotoWeiXin()
// gotoWeiXin();
// }
// } else {
getSessionList();
function isMobile() {
// 获取UA字符串
const userAgent = navigator.userAgent;
// 匹配主流手机相关关键词,忽略大小写
const mobileRegex = /iPhone|Android|BlackBerry|IEMobile|Opera Mini|RedMi|Huawei|Vivo/i;
// 返回匹配结果
return mobileRegex.test(userAgent);
}
function bindToLogin() {
document.querySelector('.popbox .loading-box').classList.remove('none');
const data = {
sourceType: 5,
openId: openId,
phonenumber: document.getElementById('sys-phone').value,
smsCode: document.getElementById('code').value,
loginPlatForm: 3,
userId: Number(userId)
}
retryFetch("https://serviceri.satabot.com/login", {
// fetch("/api/remote/login", {
method: "POST", // 必选:指定请求方法为 POST
headers: {
"Content-Type": "application/json", // 声明请求体是 JSON 格式
// 可选:如果接口需要 Token 前置验证,可添加 Authorization 头
// "Authorization": "Bearer 你的前置 Token"
},
// 必选:请求体,将参数对象转为 JSON 字符串(不能直接传对象)
body: JSON.stringify(data)
}).then(res => {
console.log(res, "绑定信息")
if (res.code == 200) {
if (document.querySelector('.popbox .loading-box')) {
document.querySelector('.popbox .loading-box').classList.add('none');
}
// userId = res.userId;
// setCookie('token', res.token);
unshowpop();
// getSessionList();
refreshAiChatNum()
} else {
showToast(res.msg)
}
// } else {
// showToast(res.msg + "denglucuowu");
// setTimeout(() => {
// // window.location.reload();
// }, 2000);
// return;
// }
}).catch(err => {
// 捕获异步异常(如网络错误、接口报错、代码报错)
console.error("请求异常:", err);
showToast("登录失败,请重试" + err); // 给用户友好提示
})
.finally(() => {
if (document.querySelector('.popbox .loading-box')) {
document.querySelector('.popbox .loading-box').classList.add('none');
}
});
// try {
// handleLogin(data).then(res => {
// if (res.code == 200) {
// if (document.querySelector('.popbox .loading-box')) {
// document.querySelector('.popbox .loading-box').classList.add('none');
// }
// userId = res.userId;
// setCookie('token', res.token);
// unshowpop();
// getSessionList();
// } else {
// showToast(res.msg + "denglucuowu");
// window.location.reload();
// return;
// }
// }).catch(err => {
// // 捕获异步异常(如网络错误、接口报错、代码报错)
// console.error("请求异常:", err);
// showToast("登录失败,请重试" + err); // 给用户友好提示
// })
// .finally(() => {
// unshowpop();
// if (document.querySelector('.popbox .loading-box')) {
// document.querySelector('.popbox .loading-box').classList.add('none');
// }
// });
// } catch (err) {
// console.error("请求异常:", err);
// }
}
async function retryFetch(url, options, maxRetry = 10) {
let lastError;
for (let i = 0; i < maxRetry; i++) {
try {
console.log(`登录请求第 ${i + 1} 次尝试...`);
const response = await fetch(url, options);
return await response.json();
} catch (err) {
lastError = err;
console.warn(`第 ${i + 1} 次尝试失败:`, err);
// 最后一次重试失败 → 抛出错误
if (i === maxRetry - 1) throw err;
// 重试前延迟 300ms
await new Promise(res => setTimeout(res, 1000));
}
}
throw lastError;
}
const questions = document.querySelectorAll(".question");
// 获取到用户名称
function getUserName(userId) {
if (params.get("nickname") || getcookie("nickname")) return;
try {
fetch("https://serviceai.satabot.com/user", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
userId,
})
}).then(res => res.json()).then(data => {
if (data.code === 0) {
document.querySelectorAll('.username').forEach((e) => {
e.textContent = data.userName;
})
console.log("成功找到该用户:", data.userName, data.userId);
} else {
window.location.href = data.error;
return;
console.error("未找到该用户:",);
}
})
} catch (err) {
console.error("请求异常:", err);
}
}
questions.forEach(q => {
q.addEventListener("click", () => {
if (q.classList.contains("mainauestion")) {
document.querySelector('.chat-messages').style.height = '100%';
// }
}
isPre = true;//s是否预设题目
if (!sendParam.imageBase64 && !fileInput.files.length) {
// if (!isUpload[activeChatId]) {
if (!hasImage) {
showToast("请先上传图片");
// alert("请先上传图片");
return;
}
}
const value = q.getAttribute("data-value");
const preValue = q.getAttribute("data-pre-value");
sendParam.userPrompt = preValue;
chatInput.value = value; // ✅ 把预设问题填入输入框
chatInput.focus(); // 可选:让光标聚焦输入框
sendMessage(true);
});
});
function isMobile() {
return /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// getHistory();
function setCookie(name, value, days = 7) {
const d = new Date();
d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000);
const expires = "expires=" + d.toUTCString();
document.cookie = `${name}=${encodeURIComponent(value)}; ${expires}; path=/`;
}
function getcookie(name, cookieStr = document.cookie) {
const match = cookieStr.match(
new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1') + '=([^;]*)')
);
return match ? decodeURIComponent(match[1]) : null;
}
function getCookie(name) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
if (match) return decodeURIComponent(match[2]);
return null;
}
function deleteCookie(name, domain) {
if (domain) {
// 删除指定域名下的 cookie
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}`;
} else {
// 删除当前域下的 cookie(兼容旧写法)
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
}
}
function handleBack() {
RPJavaFragmentInterface.navigateTo("StatusFragment");
}
function generateUniqueId16() {
// 当前时间戳(毫秒,取后几位)
const timestamp = Date.now().toString().slice(-10);
// 生成 6 位随机数
const random = Math.floor(Math.random() * 1e6).toString().padStart(6, "0");
return timestamp + random; // 一共 16 位
}
function logout() {
deleteCookie('userId');
deleteCookie('token');
deleteCookie('nickname');
deleteCookie('headimgurl');
deleteCookie("sharetoken", "ai.satabot.com")
// 清空历史记录(黑科技)
history.pushState(null, null, location.href);
window.addEventListener('popstate', function () {
history.pushState(null, null, location.href);
});
location.replace('./login.html');
}
function createSession(userId, sessionId) {
try {
fetch("https://serviceai.satabot.com/session", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
userId,
sessionId,
})
}).then(res => res.json()).then(data => {
if (data.code === 0) {
hasImage = false;
console.log("会话创建成功:", data.message);
} else {
console.error("创建失败:", data.error);
}
})
} catch (err) {
console.error("请求异常:", err);
}
}
function showToast(message, type = '') {
// 创建元素
const toast = document.createElement("div");
toast.className = `toast${type == "success" ? " success" : ""}`;
toast.innerText = message;
document.body.appendChild(toast);
// 显示
setTimeout(() => {
toast.classList.add("show");
}, 10);
// 2 秒后自动消失
setTimeout(() => {
toast.classList.remove("show");
setTimeout(() => toast.remove(), 300); // 动画结束后移除
}, 2000);
}
function scrollToBottom() {
const chatMessages = document.getElementById("chatMessages");
const chatContent = document.getElementById("content");
if (!chatMessages) return;
requestAnimationFrame(() => {
// chatContent.scrollTop = chatContent.scrollHeight + 'px';
chatMessages.scrollTop = chatMessages.scrollHeight;
});
}
// function scrollToBottom() {
// const chatMessages = document.getElementById("chatMessages");
// setTimeout(() => {
// chatMessages.scrollTop = chatMessages.scrollHeight;
// chatMessages.bottom = '0px';
// }, 0);
// }
const panel = document.querySelector('.userinfo-panel');
const toggleButton = document.querySelector('.userinfo-toggle');
function toggleUserInfo() {
panel.classList.toggle('show');
}
document.addEventListener('click', (e) => {
if (!toggleButton.contains(e.target) && !panel.contains(e.target)) {
panel.classList.remove('show');
}
const chatbox = document.querySelector(".chat-input");
if (!sidebar.contains(e.target) && !chatbox.contains(e.target) && isMobile()) {
if (!sidebar.classList.contains("collapsed")) {
sidebar.classList.add("collapsed");
toggleBtn.style.left = "10px"; // 收起后
}
}
});
// 阻止点击面板本身关闭
panel.addEventListener('click', (e) => {
e.stopPropagation();
});
function renderChatList(isNew) {
chatList.innerHTML = '';
if (!sessIdList || sessIdList.length == 0) {
activeChatId = null;
chatMessages.innerHTML = "";
weixinloading.classList.add("none");
return;
}
// if (isNew == "new") {
activeChatId = sessIdList[sessIdList.length - 1].sessId;
// } else {
// activeChatId = sessIdList[0];
// }
sendParam.sessionId = activeChatId;
getHistory();
sessIdList.forEach((item, index) => {
const item1 = document.createElement("div");
item1.setAttribute("data-sessionid", item.sessId);
item1.className = "chat-item" + (activeChatId == item.sessId ? " active" : "");
const title = document.createElement("div");
title.className = "chat-title";
if (item.title) {
title.textContent = item.title;
} else {
title.textContent = `新对话${index + 1}`;
}
item1.onclick = () => switchChat(item.sessId);
const del = document.createElement("span");
del.className = "delete-btn";
del.textContent = "✕";
del.onclick = (e) => {
e.stopPropagation();
deleteChat(item.sessId);
};
item1.appendChild(title);
item1.appendChild(del);
chatList.appendChild(item1);
})
}
// bool 是否新创建的
function renderMessages(data, bool) {
chatMessages.innerHTML = "";
if (bool || !data || !data.length) {
return;
}
data.forEach(msg => {
if (msg.image_base64) {
hasImage = true; // 只要有一个不为空,就置为 true
}
addMessage(msg.content, msg.role, msg.image_base64, '', msg.thinking);
});
scrollToBottom();
}
function setcookie(name, value) {
const d = new Date();
d.setFullYear(d.getFullYear() + 100); // +100 年
document.cookie = `${name}=${value};expires=${d.toUTCString()};path=/`;
}
function showPop(userId) {
if (!userId) {
console.error("userId 缺失,无法记录点击次数");
return;
}
const cookieName = `popupClickCount_${userId}`;
let clickCount = parseInt(getcookie(cookieName) || "0", 10);
clickCount++;
setcookie(cookieName, clickCount, 7);
console.log(`用户 ${userId} 当前点击次数:`, clickCount);
if (clickCount == 10) {
document.querySelector(".popbgc").classList.remove("none");
}
}
// 内容 角色 图片 创造时间
function addMessage(content = '', role = "assistant", imgUrl = null, time = null, thinking) {
const msg = document.createElement("div");
msg.className = `message ${role}`;
// =========================
// 时间
// =========================
if (time) {
const timeNode = document.createElement("div");
timeNode.textContent = time;
timeNode.style.fontSize = "12px";
timeNode.style.color = "#999";
timeNode.style.marginBottom = "6px";
msg.appendChild(timeNode);
}
// =========================
// 思考过程(历史:已完成)
// =========================
let thinkingContentDiv = null;
if (thinking) {
const thinkingBox = document.createElement("div");
thinkingBox.className = "thinking-box";
const header = document.createElement("div");
header.className = "thinking-header";
const title = document.createElement("span");
title.className = "thinking-title";
if (role == "assistant") {
// 1. 创建img元素
const img = document.createElement("img");
// 2. 设置图片src(你的base64地址)
img.src = "data:image/png;base64,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";
// 可选:设置图片样式(比如大小,避免图片过大)
img.style.width = "24px"; // 根据需要调整
img.style.height = "24px";
img.style.verticalAlign = "middle"; // 垂直居中
// 3. 清空title原有内容(关键)
title.innerHTML = "";
// 4. 将img元素添加到title容器中(核心修正)
title.appendChild(img);
}
const status = document.createElement("span");
status.className = "thinking-status thinking-done";
status.textContent = "思考完成";
const toggle = document.createElement("span");
toggle.className = "thinking-toggle";
toggle.textContent = "";
thinkingContentDiv = document.createElement("div");
thinkingContentDiv.className = "thinking-content collapsed";
thinkingContentDiv.innerHTML = marked.parse(thinking);
header.onclick = () => {
thinkingContentDiv.classList.toggle("collapsed");
toggle.textContent =
thinkingContentDiv.classList.contains("collapsed") ? "" : "";
};
header.appendChild(title);
header.appendChild(status);
header.appendChild(toggle);
thinkingBox.appendChild(header);
thinkingBox.appendChild(thinkingContentDiv);
msg.appendChild(thinkingBox);
}
// =========================
// 最终结论(answer)
// =========================
if (content) {
const textNode = document.createElement("div");
textNode.className = "answer-content";
textNode.innerHTML = marked.parse(content);
msg.appendChild(textNode);
}
// =========================
// 图片
// =========================
if (imgUrl) {
const img = document.createElement("img");
img.src = imgUrl;
img.style.marginTop = "8px";
msg.appendChild(img);
}
// =========================
// assistant 工具按钮
// =========================
if (role === "assistant") {
const shareSpan = document.createElement("span");
shareSpan.style.display = "inline-flex";
shareSpan.style.alignItems = "center";
shareSpan.style.cursor = "pointer";
shareSpan.style.marginTop = "8px";
shareSpan.style.opacity = "0.75";
shareSpan.title = "分享";
shareSpan.innerHTML = `
<svg t="1764059839985" class="icon" viewBox="0 0 1236 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5667" width="20" height="20"><path d="M741.743 1018.343c-28.287 0-50.917-11.315-73.547-28.288-22.63-22.63-39.602-50.917-39.602-84.862V792.044c-124.464 0-328.133 33.945-435.624 181.039-16.973 28.287-56.575 45.26-90.52 50.917H85.478C28.903 1012.685-5.042 961.768 0.616 905.193c28.287-243.27 113.15-418.652 260.243-537.458 107.492-84.862 231.956-130.122 367.735-141.437V118.807c0-50.917 22.63-96.177 67.89-113.15C736.086-5.657 781.345 0 815.29 33.945l362.077 367.735c28.288 22.63 45.26 56.574 50.918 96.176 5.657 39.603-5.658 79.205-33.945 107.492-5.658 5.658-11.315 16.972-22.63 22.63l-350.762 356.42c-22.63 22.63-50.918 33.945-79.205 33.945z m-90.52-339.448h90.52v226.298l356.42-367.734 5.658-5.658c5.657-5.657 5.657-16.972 5.657-22.63 0-11.315-5.657-16.972-11.315-22.63l-5.657-5.657-356.42-362.077V333.79l-79.205 5.658c-118.806 0-231.956 39.602-328.132 113.149-113.15 90.519-186.696 237.613-209.326 429.967 141.436-175.382 390.364-203.669 531.8-203.669z" p-id="5668" fill="#878895"></path></svg>
`;
shareSpan.onclick = () => {
generatePoster(content, imgUrl);
};
const copySpan = document.createElement("span");
copySpan.style.display = "inline-flex";
copySpan.style.alignItems = "center";
copySpan.style.cursor = "pointer";
copySpan.style.marginLeft = "10px";
copySpan.style.opacity = "0.75";
copySpan.title = "复制内容";
copySpan.innerHTML = `
<svg t="1764549398754" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5335" width="20" height="20"><path d="M639.9 256.3H192.4c-35.2 0-63.9 28.8-63.9 63.9v575.4c0 35.2 28.8 63.9 63.9 63.9h447.5c35.2 0 63.9-28.8 63.9-63.9V320.2c0-35.1-28.8-63.9-63.9-63.9z m0 639.3H192.4V320.2h447.5v575.4z" fill="#878895" p-id="5336"></path><path d="M831.6 64.5H384.1c-35.2 0-63.9 28.8-63.9 63.9v63.9h63.9v-63.9h447.5v575.4h-63.9v63.9h63.9c35.2 0 63.9-28.8 63.9-63.9V128.4c0.1-35.1-28.7-63.9-63.9-63.9z" fill="#878895" p-id="5337"></path></svg>
`;
copySpan.onclick = async () => {
await navigator.clipboard.writeText(content);
showToast("复制成功");
};
msg.appendChild(shareSpan);
msg.appendChild(copySpan);
}
chatMessages.appendChild(msg);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function generatePoster(text, imgUrl) {
// 创建一个隐藏的海报容器
const poster = document.createElement("div");
poster.style.width = "750px";
poster.style.padding = "40px";
poster.style.background = "#ffffff";
poster.style.borderRadius = "20px";
poster.style.fontFamily = "sans-serif";
poster.style.color = "#333";
poster.style.boxSizing = "border-box";
// 标题
const title = document.createElement("div");
title.textContent = "飒沓 · 智能助理";
title.style.fontSize = "32px";
title.style.fontWeight = "bold";
title.style.marginBottom = "20px";
poster.appendChild(title);
// 内容文本
const content = document.createElement("div");
content.style.fontSize = "26px";
content.style.lineHeight = "40px";
content.style.whiteSpace = "pre-wrap";
content.textContent = text.replace(/<\/?[^>]+(>|$)/g, ""); // 去除 html 标签
poster.appendChild(content);
// 如果有图片
if (imgUrl) {
const img = document.createElement("img");
img.src = imgUrl;
img.style.width = "100%";
img.style.marginTop = "30px";
img.style.borderRadius = "12px";
poster.appendChild(img);
}
// 放到 body(隐藏)
poster.style.position = "fixed";
poster.style.top = "-9999px";
document.body.appendChild(poster);
// ⭐ 开始使用 html2canvas 生成海报
html2canvas(poster, {
scale: 2, // 高清
useCORS: true
}).then(canvas => {
document.body.removeChild(poster);
// 生成图片
const dataURL = canvas.toDataURL("image/png");
// 下载到相册(浏览器下载)
const a = document.createElement("a");
a.href = dataURL;
a.download = "海报.png";
a.click();
});
}
function uuid() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
function sendMessage(isPre) {
if (controller) {
showToast("请先停止对话");
return;
}
isStopped = false;
if (!activeChatId) {
newChat();
}
// if (sessIdList.length == 0) {
// return;
// }
ifSessionId = true;
const text = chatInput.value.trim();
if (!text && !fileInput.files.length && !sendParam.imageBase64) return;
if (text) addMessage(text, "user");
let imgUrl = '';
if (sendParam.imageBase64) {
imgUrl = sendParam.imageBase64;
hasImage = true;
if (fileInput.files[0]) {
const file = fileInput.files[0];
const url = URL.createObjectURL(file);
addMessage('', "user", url);
} else {
addMessage('', "user", sendParam.imageBase64);
}
sendParam.imageBase64 = '';
fileInput.value = "";
}
if (!isPre) {
sendParam.userPrompt = text;
} else {
}
chatInput.value = "";
if (sendBtnImg && !sendBtnImg.classList.contains('none')) {
sendBtnImg.classList.add('none');
stopBtn.forEach(e => {
e.classList.remove('none')
})
}
if (sendmsgbox.classList.contains("none")) {
sendmsgbox.classList.remove("none")
}
getAiResponse(imgUrl);
}
let renderPending = false;
let lastRendered = "";
// 实时渲染 + 不闪烁 + 性能好
function smartRender(msgDiv, text) {
if (renderPending) return; // 避免频繁渲染
renderPending = true;
requestAnimationFrame(() => {
if (lastRendered !== text) {
msgDiv.innerHTML = marked.parse(text); // 实时解析 Markdown
lastRendered = text;
}
renderPending = false;
});
}
let reader;
const getAiResponse = async (img) => {
deleteImg();
// =========================
// 消息容器
// =========================
const msgDiv = document.createElement("div");
msgDiv.className = "message assistant";
chatMessages.appendChild(msgDiv);
scrollToBottom();
// =========================
// 状态变量
// =========================
let currentPhase = null;
let thinkingFinished = false;
let thinkingContentDiv = null;
let answerContentDiv = null;
let thinkingStatusSpan = null;
let thinkingToggleSpan = null;
let thinkingBuffer = "";
let answerBuffer = "";
// =========================
// loading(phase 前占位)
// =========================
const loadingDiv = document.createElement("div");
loadingDiv.className = "thinking-loading";
let thinkinghtml = `<div class="ai-thinking" id="thinking">
<img
class="ai-loading"
alt="AI thinking"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANMAAADTCAYAAAAbBybZAAAACXBIWXMAAAsSAAALEgHS3X78AAAgAElEQVR4nO2dDZBU1ZXHz0z3fA8MozFRQR1FsyoaMBoV0RWtKFImgY2KrusGCEqZVDYCm1R2tio6mN2d3VqCmE02btAA0aQUdRfULGosHeL3iiskom4iZhDRikaGYYD5nt7637635/bre99Xv9f93uv7q6Kcjzev32vfv8+9/3vOuVWZTIYM7uhpb5vND2zj/0jzfdzYTkT7pWvu4v/tbu3s7jaPhzuMmCz0tLdNIqIZRDRbEg2+b4nUhZaW3RAWF1k3F1lXlC4wClS8mHra24RwZnPRnBCBy4oLW3lUg7C6Wju79yfjtvxRcWLikWc+/ze7wiNO0OzgwtpUiZGrIsTU097WxsWziIimR+CSKoFeiIoLa1Ml3HBixSRFIAjo4ghcUiUjhLU+yRErcWLic6BlXEhmCBc9YGas4cJK1BwrMWLqaW9bZKJQrBDRqiMp9nvsxcRF1GFcuFizGdEq7kPA2IrJiCiRbOWRKpaiip2YjIgqgg1xHP7FRkw8lafDzIkqiju5qGJhVEReTNzihvuzMAKXYyg9MCqWtXZ2r4/6ex9pMfW0ty3j0chY3AbMpxZFeegXSTHxjIX1ZkhnULCytbO7I4pvTOTExA2GNSYaGWyIZJSKjJj43AjRaF4ELscQfSI3l4qEmHgK0CZjdxt8sIGLquyOX9nFxId168p6EYa4g9KP+eUe9lWX88V72tvWGyEZAgBlNdultgJloSyRic+PNhm3zhACi8s1jyp5ZOK2d5cRkiEk1vERT8kpaWTiRkOXsb0NJWBDa2f3olK+0SUTkxGSoQxs5utRJXH6SiImIyRDGYHTN7sUggp9zmSEZCgzcPq6uOkVKqGKyQjJEBFKIqjQxGSEZIgY03nOZ2iEIiYjJENEWRimbR64mKSEVSMkQxSBoEIp4QgjMnWZrqmGiHMbzwkNlEDFxEOoEZIhDqzj05HACExMvMTc9GkwxIlAHb5AxMQVfkcQ5zIYSkiLtLFb0RQtJikD3GCII9N72tsCscyDiEzrTYWsIebcEkQtVFFi4vMk07PBkAQ2FTt/8i0mXpcUyZZLBoMPWvgoyzfFRCazMGtIGvN62tvm+70nX2LiwztTKWtIIuv9DvfSXv+g0oZ3VQ0TKT35VKo5aSZVH3EcVbdOoepJx1HVxMnK48c+fJMyA72UGThAo3t30ugHb9DovvdoZO+bJb92gy/EcM9zhPJcHNjT3rYpyaYDxFN78nlUM20OpU+cqRWNH0bffYlGdr1Iw++8SMNv/08pb8vgnUu87hPlSUzcPnwmif9j6j53FdWeMYfSn768JK+XGeyjkbeeoOGdT9Dgb39Vktc0eGJ3a2d3m5c/8Cqm7iStKaWOmEL1f76YamYsoKq6CdrjMHQb/WAnjby/k0bf30mZ/j7tsK3m5HOz5z52Gjt/6phpVP2pabbnzxzYS0OvbqT+Z9dRpv9AAHdmCIjlrZ3drhd0XYspSZ1X8ZA3XL6MaqZfrfw9Hu7hNx+nkV0v0dDbLwfygOM101PPY9EvdcJMrbiGdzxEhzbfbkQVDdDPvM1t/whXYuLuRncSrPDGy2+h2gtuLHiYMewa3r6RBl95qCRmQd2Zl2XnZafOUV7L0At30+En7wz9OgyOuN7Cxq2YcLLb4vy+pyefRs1fubvAUEAU6n9qNQ2+8nBZrosZHmdcRg2fX6G8tkMPLjdmRXlxHZ0cxZSEqIR5UcPc/M+CcotIBUwQlagGn7nDRKny4io6uRFTrKNS83WrCuZGeDijOtlHpGq4aDHVXbI87+cjv3uSDt7/LTOXKg+uopObDIhlcX0HrEJCNOr74Vz2KR/VhxLXhevDdcJFFMCyn3jzA8zIMJScFjc6sI1McXbwrELCgmnf+qVFiwhzr6qGQifOzi73C6JU07xb8z8QBvvo4NoFJqOi9DhGJ6d0olimDbG1I+kBhN2MIZJXhDlQM3Vmdr3ok6c5ngEP+9gfd2bXpfa+QWM9e3wbCBA+rrtx357csA/OX/NNG42gSk8LTzHSZpZrI1Ncsx0QOSZ8Y0vue8w1+tYt9XQOLLzWnbNAuQ4lxGLFLl+PAkglgjnR+OXv511H/y87ImWgVAC2WRF2YoplDl7L8i25CII5x4G7rnU9tMN8pHHerXkpRTjH8M7HXYuALc5OPo1Sx5xOqcnT1Au0o0M0/PojNLhtoydhMXv/po155zt4zwJjnZcWbc6eUkw8M/wPcbtL66c3JvFuh0IYGtZfuiL3oGJoOPDsPYEMpSCw2s9cQXXn/TVVTcrPxvJq0VsFZeZQJUe775NOTMvi2G1oUvvzuaHW0Mv30KFN33P1d7JZgeHYoQe+xcomgkCbujQ6TJnRQaqqbWbfehGVEVTZaVUZETprvKQ7rgUBopI8Zzn8hLtFzgmLf5J70Pu3rKQDP74uECExJ27+d2nit59Tzr2GX99MfWsup8P/+bdMSLh2RFUMUyEWOyAaiAciImFKILujYWJA76bBAWWtU0Fk4j3wXovbuznxa/dT6vjz2ddu3TsRkdhk/uEVgZRCiEVXVf6fuLb+J9cUCNY6zHST9QCjpHnJxtz3mN/13jG36HswOLKjtbO7oBusSkxIOb8lTu+n1cE78K8XOkYXRI3a85awr73MrXQ4iQjDx/5frbY1C3AOCFwYIKPvbaO+n37V1kCxzhP9LgMYPHNia2d3t/xHqmGe74YS5aLuc/mLs05Cwie6EBKGWcUICQJAJnrLd55na0FWIeF64Lhh+OjkuqE8vqp+fKiWmnIOy3qwG/ZhjoX5Ye7epl/NBGYInQKd5C3achcvdsV/Naddkft6cNuDtseyucw1WW8FD2Ex6zS6xFRyGYkEdvVVsPmdFmlhtGBRWQxzG67soJFdLwdmohiUzLZunmaNTLGLSiy9R3qYh163n/dgKIbjMel3a1JYgYjgHGJ4pSqbcBuJICIM63QmxdC2e2nso9/lsh7sIhRLlZINiYVrfd2bwTXzrF2MrOlEsRNT7bTxBVZkO9jNL1h60AU3sq9RJ+Q1T88uEnmxtp0qfWWTAteMoZ6IUH0/mKuMOLiXQ/ctyRkSOB7DT1O6ESqz5T77VjHFrhdeeurM3NdDrz9heyzy7PCpzcrSPWQNYI7V+MWVytw8LyLSlVcIVE4fRIIsjpygFq7VZnXgnjB0FfNBvM7QzifN+lN4zFeKKYjG5eVAzBMA5gl2oP8CGHj+bldXChE1XLYi7zUEXnLjnJw+RNTDm2/XznFYwuuGm2jCN7OpUhMW/YQNI1Vg6Io5pIiejV+6TXusoWjyNCPPmWInJnkOgYfbacItLOdhh3kVRIR1KwyZrELC62ANqPdfZjkKya3Th0Rcp2vH78VCLa4J1r4KNtx7cDzy4Vjj7oXGCdy0Y8jDvNiJKXXs6bmvVZncMkJ4GJbpHlzMZZquXaWNRGhy4rZC17oIK+PF6ZPBcA3REMYHhnLonqRaaMZ5MWQUczK4ezBmTJVuKMzgbR3yxBS7+VKqdbzqFOUNtsfyCtWx/XuUv9MZAl5FFJRdbnduQcPVa2jo7ZnK60K7sBbe+Qj/Gufc4jpX0eCJnAnBxBT0RrmlAiUOgrEB+wcdJREARXu5n3lw1ZwIyulToTt3VW2Tdv4EgQ08vTrXSAaRbODX68zaU/DktCMiUyzFJGcLoNOqGzKHDyjLwWU8iejMy6jhCx3hiMjm3MOv3kc1Z9/AhqQYUkIoVvCz+lk35v4eHxwm1ShwciM6ISZPPZXjDKz0Fo9JqCpsnb4iRWR3bvkaGw98xIwNzM3wWqrhXv9jHdR4fXYBFx8eNR4LEg3OwIRAnp4QUyxtcS9UTzyKHa16QDGXOfzISlfrMU52eTGdWN2KSIDXqZl2RXb96bpVyvJ8GBR17740nmp02QoafttY5QGDYNRdMZFp7MBHBT/zYgi4EZHfXnxeRSRzaOMKljEP2x/nUd0L7lFkRuA1dMcZfINg1CXEVFG7pQeVhFqsiOzO7fYaEU1F1gMSePd3zio4BucYNdEpTFiOXjquTp5XhNs38s5W6lu70PGvnZw+PMDINiiXiGRY1gO2xUG1riYfz0SnUGEaSgtVJR3h9lWl62zvNEi73Mu5i1mDQs4hjY2wr+su+poyUlqjE1qZGTEFRjYyxXm+NNbzHqWOz36NPWftHg50XCXe306FnyRUt9idmzl/j3X4KplXzrXS9dT05e/RwZ8XFkvL0QmCTvm8H0MB0yn2Yto3ns2AzZvtEE5dwcJnkUmodtiduxj73M6wYL8/Yx6lJ99V4E4WzJ3MulOgeN5tPUqgMaT4tMdmzk6g4QhsZDyMI3vfKrpng45yiEhETjGM1GWLoxK5kf+9iU7BgbWmWEcmCEKAiIM5id2DgVQiiKn+wiWUarsgcBGRTYIrnD+k96gyFZxQdZqVr1deI4OgmEg0JgNELKcm1Z1zlSkgDIa26jiLCZNseduVGkzEbRjhJkT6zwq3vvTS+ESFKGVHLpx8brlkw6uQ5LJ2q5Dk65WHc/gwwesB0evCCiKjgEVP028vEGI9zAODr27MJXMiD83ugUXJAgPtzaqqsl+GlIRazBpUsa4fXpOJZOJkdn3We2PR6cqOXEY5jvETMQ35uNnsLNLID4p4eHTgExzigZAyh/exNl9Y5PQjJLumKiISed1Uza4LrJdGLXhNCBnIJRsy4vfEP4QMxRN7MeHBweRboHt4BMNvPs6+Gvn9075NAFThqkSE60ADTD8iEhW5on+DgHVR4qL3MvxkEXGwT/sBg9/nXt/hQ8jgikmxFxPxSbfA6cEQwxk2SfewpaVdKbsQEWxmL86YXVm7LCI/omcfMq9l15RUHzDWD6G6c67x/BqGPGYkQkx4gOWupmw+oJlU41jMO4ivszgRhoiAVkSDfUWJiCTjovb8bJTTRifpQwj35rRhgMGeRIiJeH6a3IQRZdo6MIEnh+iEn2OHDJWIhJPmR0RirqUSkdtGLTrsmlqqopP8wQLqL1qiO7XBzfv/nQsnLUpECcbIILJZqeaUbGlWaspnaeStJ2is708Fh47t20u1nz6fqlumUHXzRBp6/cnc71hTlXm3UuOXV1H1kVPz/o6t6Ty0gvqfvJOdwwsQ0YSFd1PtjKupqm48ajLX79l/p4O/+Bsa/r9fZ+/DI2y4eOnN1PRXayl19OmFf5wZo6r6Fsp8uJNGP3wn/73Y/y7VfjY7xMPfDr/2kGm84o+tsbfGZTAfqjt7Qa5ZpF3POCx0og5IVJ+O7Xs/lCTUMKxzgVMqlLD90XgGkbDuwiUFOYC4J7E/FJlF3KKo2vd3J3TFsTORDuueRZh/6IZNuf2ZDv2Jqpo+UfD7wJNQOcUkzZIbEVkaZOL4Sbf+hn2t2gNX3pYGf7u/40xf11XhrExUZCKPPeNy7bAsQgo7f66YXDi7fny6aCecO7bdjKL0Au9Pw5V9eYu4Zhd37yTGgJCBSPJ2hLhulfI40Q4r+80oZfr+6NtJC8v1E+jSlchiXujWuIRzpzJdmNi2j0fz+gvNIq4fEikmPBwY5ghEfwQVmGex/L6qFI1+sMOziJxcP+xKGISIlNvXuBBR7lok5w7zIityOpHIrDd4I5FiIp5mJNu+SPrUrT2hKQlx0aFXnRv8JKF6AdehExHxaIftZbxkWwy9lt2woXbWTQW/g9hQuyXAcNDgjcSKCRx6YLzwjfVH0Kw94YEXmdYNV622zaK2W8spNvOc5HSl69dqReR1yCj2ym2Y98/Z72ublYu4A8+O5+t5zRAxJFxMcjkC8RbBuuELPuEx3NPNscQDWWwSqg67ORcVISKRaWG95vqLv1b4GtwmF6iGgwY9iRYTSSIR6Gp8yDrc45/cdg+k3yRUGScR+Zl3OW1lA6qPPFmZPpRX63S2Gep5ITkZEDaM7vlfqjv3BnYAsg+qUxkaVmyMhmwJ/A4l8Ompsyg16UhqvHo1pU++OK+rEbPOf7mSDSNH3/c3JxKZFnDnkIlhJS/bQpHFoSKXCfGXPyq4ZpKyLXD9yHaorqvPy/5g70HPXqo7/wb2t3ivMgf2+L7HCiNZGRA6xJxI9Iuw255Sbjlce+4i5vIJvOwWqMOplZjfbAvbXTgs60+Ihnj9NNbYGm4vWJNCGpa4PmSTmzUnd1SEmMgiEtD8lbupd81cpRMmtrwUw6MgUn+cRIRogR3/whSRQE4hQs89q1hEHwmSssnNvrjOVMQwT1Aw3KuvpeG3fl1wHB68zKEPqea07B64h++/mQZeuj+UJFR5yOgleVaXOCtAScrBDUu1ybOZwV52f+nJZ9DAcz/N/13/gVwiMFANBw0FbE28ASEjW+Dk4O7h01oUzzVe8wPPTUesJoAVv8V/uN6W5Vts15/g+mGXQLsoylKseCWu6j0YfG68Piw7HDRNV5yoKDGRxt3TLuZuvj1nl2OHPjc4OWl+i/9k108MVWW8WudibkSaBVok9wqbXOTrGeypODGRZIETX8yFq6aC7Vy+cUVuh3OIxA4kodqJyE/xn5N1jqwFv3l/dvl6YOhVKV/PNF1xpKLmTAJmNQ/3jhcSHn26snCO+LFi/gTLXHWcmL/UnPFFrR3ttfgPk/7mG35I9Zcst7fOn77LtymSnnwqM2XYNQ/1FiwXMJt81lfZ15iXje5+wXNRZAVRGda4CiR21k6bM953+6rVNLJ3rvLTHZGkZupM9gmO40b3LWDzLz9OmhNhWecyqjKR2llLC64V74VczmJ2zrAnccWBXmAZ35IFjvlR7x1ztWfAxB/zlUzve2z9qWriMcrj/NQtlUJEbKH42lXahv+qQkprseX+2z9jytrVrKzIOZMAD3v/w+PzJwjFbl504K5rs+szLVOUQvKTP2eXOEuS61dM3p/8GiohjX2cHbaqmq5Y8/VQ4WtQU9FiIu5ayW3CYB7o7HJ8Ih/82Y2UGTqU9/NiklARGe1EFETLL51QRZZ776pLbRtWDjw/nk1u8vX0VLyYiLcJy7PLb7hHW36AuVL/Q+P99oZe+I9Ak1CDEJFdhjtpop1dO2VcR65y2XR/1VKRbl4BI4M08rutVHvONdkEz3Qd1Zwyk4Z2PKp03+DmIQEUDl/quHNcJYO6TULt27DUd2Kp/BqpyWcV/N4uQXfk/TezCa5Nnyi8n5FBSh89NZfBUd3UQoPbHrKevtLZasTEYSlEH79NNWd+if2gqukoSh8zlYa2P6o8Hg9b+qgp7AGDqHTWOnHrvHnxvbYiylnnPnAUqpss95FBqq6tZfZ/6sjjafCln1vu942cTQ6r3tjkBRgxyUAMogSDWM3PVCYYXV4afi4Elf70JTTy+668com8/LmA1p9kgo52IjpVt0wuEAs+bMS9gtQnjjPRKR8jJitYuMx7aI4+nVITJigTYokLiiWFHjmVaqfPo+HfPMoysYtJQnUDi3bX/4jSp14eXLSTo5NCLCY62VK5i7Z2wFCY0DAx1ygFCbEje9/QGgJ965fSxJsfYNa6vG5lJYi+eWEsFMuMfrSLfafaxlN0OMotdF+2gobfVnfMrUSMm6cBgpIdPmRp63aJwIPL1qAG+5RCCrJvni5bHNHOzwZrAmGjNy744fhrKhJgxaYHJAnOkMWISYMsEEHzTRu1GeZsDWrtgrzjgxBRUCUXOuzWolQJsIhUcgs10xJsHCMmG4RABE6lGGwNSmp+ObzrxaJEFGTJhRWnBV0aGWD/Ue1hJUcn0xJsHGNAOMCyxvmaEvGJt64hC3HLHIYFtrRJn3RBgcPnBMuFu/b72mxxlFwc/OlCGnzF39Yvbit/B1/awLaaqW49jgZf/nmeUSJvycPeE8u2PBWKcfPcIK8pAbhdur2fAJw/4fDVtJ2tXfyVYUm3i34SWsmF1Ua3Yl2LygnmyKlUNTZQ+OGBsne+Jmf2dWJUVtl6MbDNAKSETzRksSvlhsOH+ROGaLriQ3KRhFpsl9hiKn8Htz3I/qvKx5MrccnllqZJx4jJJSLJVWBXoUuiSve+7LaWbCsXSz6b2yTUYrLFi638ZTl5vIuRck9cqWGl6RNh5kye8FKhS3xukWtqyedPmZEhar76H9k2n3ZzlsObv+d7QTTIyt/qxgns+qsnHEmDr2zM+x2Gg/XnXsMWpllOo2o4WDmYRVuveKnQJd7AJT11Jjse+XnEOqXqt8wspuFj0Au6LNLUZMWYmnKOsn8erlnsOoidDItZMI47ZpjnA0zS5c3UUL1qh5g/ISM7jJKLMLafgTBblm2hugu/nvtZ/eybC44TLcOIvxdIpapUzDDPB9YMcye7HEMp+XgKqORC2Oh44FU5gBDRoXuXerLR7Zpbpo44iQae+beCexP5fMSatBQ2tawQjDXuF8yTvNjl8vEQUt+dc2ho51O+Xt1pLSpoEYHM0EGqqmlQ1m7laqEqu9m/scaLwWqXNy2w3yhNHI/hUP3FSzy/chjbz7hNVxp6fi37vvaMOQXHyA0tqXL3xN1uxFQEVrvcaU2J2eUPZlsl27VmtiJsdDsRed3202u60uC27HwOmfSq9CHR0JIqd0/c/WaYVyTynk7k0i4X6UY1J19Ag68+pLWnxR5OOhs9bw8nlza633QluZn/2IE9NLJ7e97fWYsHq5tbtFXKCWWDiUwBAJdMzqSGXW6X/IkGLmIxVNU6y037L68Lujin0xAR5+xbt1Q7RBQZEXWaDkWD28bXoXQRLMlATNsr6o5DwmqXNy9cq30hfIr3P5bNLkd2gqiTwnyraf53HbsKedn2M8h0JdjgxIdxqrmhtTwDGRiVBIZ5eIdnV9Rdh4CqIYtduTuGgTXHn55Nhj3xXEpNOCKbhHpC4QPvZ9vPMIaIGI7WfWYOu7exj99WX0tVZjzD/qhTaKDrx+7OHX9WQkyzjZiCAQIR8yFiWQOftZ0/jb77GmsvVj3xWDbnUqX+9D/y955ExHrmhZiuVFVby9KpqlJVyjkRSzG6aEmuZVql2OStnd3LzTAvYFDxKpe7Y/6ks8sxNxl4enXBz/1sP2O3KzwFlGnBrvm937L/ptpmaY8Z3j4+d8KeuJUCxLS/Yu62RGBP3Lz503X6dCPk+uXENzqcE5Hb1J9SdIiVX6fpK+uy39c2aXti4J4EmKdVgBGxlbiYust/LcmCbQggla/D2UL+nI7Dj96W/U2qhobfeTEYEfHoFpSIVK9Tc4o6OuH+5ehcUyH5etWtnd1GTCGABxhrNgK74R5cMLF/LtpnOZFLQnWoU0J0Kwa7eihic8Lp2rMPSrsO6qz0BIFtmXJZ4zuSfrflANkD8nCvcY5+uxqWasS3+9Q1xrdr92UVUTFlEOJ1GubephTr8M6s8VA94SjtOYa5jU42VnqCYFMlISYTnUIAD7RsMNilEOFYeScK+eELu2eem9fJM0VeutfxXNahXu3J5/m+rhjATDxRHIhv5iX5bsuFtZiw8YsrtbsTQgzotyAyIzB/wvGq3DkKqEMs8Xqohi90KIWqep1MfzbaVk86zva8I394gWr5taeOOZ3ot7+yPT7GFIjJEBKHH1lJE76xJfsAfvI0FgF0poCoXK2b/U02V3HzcPtFtbetm9cRybQ68Y0f9wbV8q9RbUxU3BwuovS2dnazYZ4RUwnAwydvtNxwZUe2QlUxJIPI6i/+OsuMsAJD4/Dm28smIq+M9ezJ/YVTFIsxOe2wORN39HqTerdRQBgM5MKMOLypPe97N0mobgiyHkrUcdmVWsi5fk5RLMZ0iUuXs8a7knSHUUNlRugWM/EQjn2c3Y2C1RUV0e6LQqqHGtu/x8VR+STU0TNiKgcwI+TK3EabQkIRnYrpR1eK3nxOyI5eevKpobxGmckf5nGMmEqAqLQlnhmhGyax6PThm2xIqKp5siOMeii/ZAYSPXvYIcwHksXU2tm93cybwsda8wPrW8fAc9l1J/SjcxOdwqiH0pHh1cGpY6eV+y0tJ3kByFppa6JTCYBVLhBWuYpce2KHfnRy/hzmYlaCSnYlaWE3fVK2+X+FN+vfJH9jFdMmMoSOsMoF1owHGdHPG8dYKaYpv1d02RGy/V1hYH3JRKYogHWcnFWu6QVBIjqhG6yleb6bjHEv9VA6nLrFVk/8ZGze84Ap0EqemPh6k0l6LQFYxxG5eOQwL5Jz9kSEcJMxXswQTKxJNV6/1naNaKS7Ytf7C0Zxqu5E60tzLQbW5J5b5axnucYqZ8fx6BR2xrjTwi7rFvuzhbnXdVrcrf7UuEEhcvoSgisxmXlTiWBdip7K3x9WVb0qZ5Rb8dOUX4WX7Ijqo07K/mz3i7bnRKSVo6fbBeEYsFm2xAUFYuJDva1JueuogzmNvLDZ+KXblFfMotPQodz3QezkTj6zI+pnZbvYDr3+RMHxMnLZhXyPCUAZcHRNKM1Qr4TkytZ5zwTVQi6LTs9nd3rPHPxjYCLymh2BORuGmWxo6WBupKeOi3P0g52+rzViwMVT6kMnpk1mAbd04GGVS9ybrrlD+dq5uVPzp3w3eCwmOwLDNmHR64adMjUzxsvVh3faR7EYoZ0GKcXEx4Nm7lRCUFohYEbD5YVZ5XKybP2lKzx1/QkiOwIiZFEJvfeeXac8RsAiGJ8vsSiWnMLANbpf2PUa1/6RIXjYThPPjEckWOUqsSBZFkMwNzsWUoDZETgHcgmJ5xc6mR1yvzx5u5mYs5Wn3SnRion/kTEiSojVKtdllYu+5phfIdqoCDI7AkNKUfWLv3HK68NCr2xmyNvNxBxbL8FpFwwTnUqI3NCfbLLK5b58iDbW3L4gsyMwtEOXIuKNW5z+hs2rvjB+D3Adi63YjQi7dcZD7t4zmYztpfa0t8EqPyEJ70ZcwHqP+GRHpOpdM1c5rIKIxE7neGiHfvNLapz3D4Hsts4a/1+7Kncd/VtW5nVq1YFIKQ8nYd8nREyLncTkZn+mDhfHGAIkb3samBGaEndECQy7iC/4Nl33o0CyIxDZJnxzCxMSGw7+4o92IR0AAAUzSURBVCZXQoK4ZSHhdRMipF43hpxjZCITncoC5ilieAXwQOscMQwFYadbhTTy5n/T4cf+ydUDjeEZxIAFWXEeGB1sBw4Xf4/MDdGBifgira6lWQxZ2drZ7RhU3IoJW3U6fzQZAiVvuIcd2n8w1/bBZgL8/LeJahpzP8NDjf51aLtlLZeobmhh/ezQhks2DJj1/dRq1xnnECE6LslWOCJhQmqdEJXaVOlDVlyJiUx0KguYt2C4JR5SCOPAXdc629IYbp0xJ2dluwXnR3Wvl7INawSFkA6uXZCkPDzHuZLAi5iwIdozAVycwQOwmVEGIXArKOJDN+THieijAmk+iFoju172NL9hm6pdtypPsAkUEhw815unuxYTZQWFgqiL/V6ZwR8wBOTurl4EFQbWYZ24pkMbVyRJSOAvWju7XWcCeRUTVPoHv1dm8A+igJwGhChw6L4loXcXkoHRoep9jrxCtuNHsvpBINvB0/a0nsREWUFhIVffjtQQGtY1HAqwZbIdiERID7KWaLA9dx9ekaS8O5kTve5d5kdMk3jjPWNGlAHVEIv4ou3As/cENsyC+QFzoea0K5SLwKziFi2fk9mdyJUVbsWzmCgrqPlE9F8+LtIQANbsBBnMXYZ3Ps62o/EyBBRmBWqQ0ideoN3GphSRsMzsJqIZbqxwK77ERFlBbTJ7OpUXFqXQJsym4QnEha6qI7sKS8yrGidS6phpbIcKu3NgOIfM7yB2xogBl1hbeLmlGDFN4jsOtiT93Y06fteVnEAUQmm6bvubBHJna2f3Mr+35VtMZNaeIgeGf+mp5zFhpY6e5nkbF0QxrDsN73qxkgQkQN/wGcWcoCgxkXH3Ig3mQdh5orr1OEq1qqtyRz94g8b6e0tqsUcQpAzNtiv8c0PRYqKsoHAR+n3sDYZo4zplyA43JRhumG8asBhiyoYghERBiYkvbs0P4lwGQwlBK3DfhoOVoCITcTtRvT24wRA9MJKa72c9SUcgcyaZnvY2hMyF5uExRJyzijUcrAQWmQStnd2LTFcjQ8RZHLSQKAwxceabrWkMESUQ505FKGLi49DZRlCGiHFnWEKiMOZMMibD3BAhNvApSGiENcxj8Ahl1qAM5SZ0IVHYYqLxNstmyGcoFyUREoU9zJPhQ74uk3ZkKCElExKVIjIJjClhKDGLSykkKqWYKF9Qm0v5uoaKIzT7246SDfOsmEwJQwgEUkrhl5JGJhkegv3tJWkwFLKD924oi5ConGKirKAQnc4y1rmhSDbwiOSpNVfQlG2YJ8Odvk2mW6zBB8tbO7sjsSlfJMQk6GlvQ6+y29wdbahwMKxbVM5hnZWyDvOs8MZ/Zxn73ODAneU0GnREKjIJ+LCvwzRqMVjYzaORr752YRNJMQl62ttm8B2uTdaEAdGoI8jK2KCJtJgEPe1ty3ikMg0vKw8Umi6L2pBORSzERONDvzVmobdi2M0jUckzGfwSGzEJ+B5R642Nnlh6+YfmmigP6VTETkwC3pq5w4gqMcRWRILYiknARbXIDP9iS+xFJIi9mAR8+NfBK3uNURF9YjcnciIxYhJwo2I+79RpLPXogTy69VFdKyqGxIlJhq9TLeLiMk1dyscOPpTbFPehnB2JFpOMEVbJ2cqTlzeVO5u7VFSMmGS4sGZzYRk3MBh28x4fXUmPQDoqUkxWuCOIfzP4PxO5nNnKeyLiX1elRB87jJgUcBNDCKuN/3dShRoaEM1+STjdcUjtKQdGTD7gkUzQxv/Fne1cNMQFU/GRxhNE9P9A7l+bY0e3kQAAAABJRU5ErkJggg==">
<div class='thinking-header'> <span class="ai-text" id="thinking-text">正在思考中...</span></div>
</div>`
loadingDiv.innerHTML = thinkinghtml;
msgDiv.appendChild(loadingDiv);
// =========================
// DOM 工具函数
// =========================
const ensureThinkingBox = () => {
if (thinkingContentDiv) return;
if (loadingDiv && loadingDiv.parentNode) {
loadingDiv.parentNode.removeChild(loadingDiv);
}
// loadingDiv?.remove();
const box = document.createElement("div");
box.className = "thinking-box";
const header = document.createElement("div");
header.className = "thinking-header";
const title = document.createElement("span");
title.className = "thinking-title";
title.innerHTML = ` <img
class="ai-loading"
alt="AI thinking"
src="data:image/png;base64,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">`
thinkingStatusSpan = document.createElement("span");
thinkingStatusSpan.className = "thinking-status thinking-running ai-text";
thinkingStatusSpan.textContent = "正在思考中...";
thinkingToggleSpan = document.createElement("span");
thinkingToggleSpan.className = "thinking-toggle";
thinkingToggleSpan.textContent = "";
thinkingContentDiv = document.createElement("div");
thinkingContentDiv.className = "thinking-content";
header.onclick = () => {
thinkingContentDiv.classList.toggle("collapsed");
thinkingToggleSpan.textContent =
thinkingContentDiv.classList.contains("collapsed") ? "" : "";
};
header.appendChild(title);
header.appendChild(thinkingStatusSpan);
header.appendChild(thinkingToggleSpan);
box.appendChild(header);
box.appendChild(thinkingContentDiv);
msgDiv.appendChild(box);
};
const ensureAnswerBox = () => {
if (answerContentDiv) return;
const box = document.createElement("answer-box");
answerContentDiv = document.createElement("div");
answerContentDiv.className = "answer-content";
box.appendChild(answerContentDiv);
msgDiv.appendChild(box);
};
// =========================
// 请求参数
// =========================
sessId = sendParam.sessionId;
sendParam.imageBase64 = img;
sendParam.userId = decodeURIComponent(Number(escape(atob(encodedUserId))));
sendParam.requestId = uuid();
controller = new AbortController();
let res;
try {
res = await fetch("https://serviceai.satabot.com/analyze", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(sendParam),
signal: controller.signal,
});
sendParam.imageBase64 = '';
} catch (err) {
loadingDiv.textContent = "请求中断";
if (controller) {
controller.abort();
controller = null;
}
sendBtnImg.classList.remove('none');
stopBtn.forEach(e => {
e.classList.add('none')
})
return;
}
if (!res?.body) {
loadingDiv.textContent = "无响应";
document.querySelectorAll('.thinking-loading').forEach(el => el.classList.add('no-after'));
return;
}
if (!res) {
if (sendBtnImg.classList.contains("none")) {
sendBtnImg.classList.remove('none');
}
stopBtn.forEach(e => {
if (!e.classList.contains('none')) {
e.classList.add('none')
}
})
document.querySelectorAll('.thinking-loading').forEach(el => el.classList.add('no-after'));
return null;
}
if (res.status === 400) {
document.querySelectorAll('.thinking-loading').forEach(el => el.classList.add('no-after'));
if (controller) {
controller.abort();
controller = null;
}
if (sendBtnImg.classList.contains("none")) {
sendBtnImg.classList.remove('none');
}
stopBtn.forEach(e => {
if (!e.classList.contains("none")) {
e.classList.add('none')
}
})
showpop();
return;
}
// =========================
// SSE 读取
// =========================
const reader = res.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
showPop(userId);
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop();
for (let line of lines) {
line = line.trim();
if (!line.startsWith("data:")) continue;
const data = line.slice(5).trim();
if (data == "[DONE]") {
console.log("完成回答");
controller = null;
// 更新聊天滚动条
sendBtnImg.classList.remove('none');
stopBtn.forEach(e => {
e.classList.add('none')
})
// renderChatList();
// msgDiv.innerHTML = marked.parse(aiMsg.content);
// const shareSpan = document.createElement("span");
// shareSpan.style.display = "inline-flex";
// shareSpan.style.alignItems = "center";
// shareSpan.style.cursor = "pointer";
// shareSpan.style.marginTop = "8px";
// shareSpan.style.opacity = "0.75";
// shareSpan.style.transition = "opacity .2s";
// shareSpan.title = "分享";
// shareSpan.onmouseenter = () => shareSpan.style.opacity = "1";
// shareSpan.onmouseleave = () => shareSpan.style.opacity = "0.75";
// shareSpan.innerHTML = `
// <svg t="1764059839985" class="icon" viewBox="0 0 1236 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5667" width="20" height="20"><path d="M741.743 1018.343c-28.287 0-50.917-11.315-73.547-28.288-22.63-22.63-39.602-50.917-39.602-84.862V792.044c-124.464 0-328.133 33.945-435.624 181.039-16.973 28.287-56.575 45.26-90.52 50.917H85.478C28.903 1012.685-5.042 961.768 0.616 905.193c28.287-243.27 113.15-418.652 260.243-537.458 107.492-84.862 231.956-130.122 367.735-141.437V118.807c0-50.917 22.63-96.177 67.89-113.15C736.086-5.657 781.345 0 815.29 33.945l362.077 367.735c28.288 22.63 45.26 56.574 50.918 96.176 5.657 39.603-5.658 79.205-33.945 107.492-5.658 5.658-11.315 16.972-22.63 22.63l-350.762 356.42c-22.63 22.63-50.918 33.945-79.205 33.945z m-90.52-339.448h90.52v226.298l356.42-367.734 5.658-5.658c5.657-5.657 5.657-16.972 5.657-22.63 0-11.315-5.657-16.972-11.315-22.63l-5.657-5.657-356.42-362.077V333.79l-79.205 5.658c-118.806 0-231.956 39.602-328.132 113.149-113.15 90.519-186.696 237.613-209.326 429.967 141.436-175.382 390.364-203.669 531.8-203.669z" p-id="5668"></path></svg>
// `;
// shareSpan.onclick = () => {
// generatePoster(aiMsg.content);
// };
// if (role === "assistant") {
// 分享按钮
const shareSpan = document.createElement("span");
shareSpan.style.display = "inline-flex";
shareSpan.style.alignItems = "center";
shareSpan.style.cursor = "pointer";
shareSpan.style.marginTop = "8px";
shareSpan.style.opacity = "0.75";
shareSpan.style.transition = "opacity .2s";
shareSpan.title = "分享";
shareSpan.onmouseenter = () => shareSpan.style.opacity = "1";
shareSpan.onmouseleave = () => shareSpan.style.opacity = "0.75";
shareSpan.innerHTML = `
<svg t="1764059839985" class="icon" viewBox="0 0 1236 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5667" width="20" height="20"><path d="M741.743 1018.343c-28.287 0-50.917-11.315-73.547-28.288-22.63-22.63-39.602-50.917-39.602-84.862V792.044c-124.464 0-328.133 33.945-435.624 181.039-16.973 28.287-56.575 45.26-90.52 50.917H85.478C28.903 1012.685-5.042 961.768 0.616 905.193c28.287-243.27 113.15-418.652 260.243-537.458 107.492-84.862 231.956-130.122 367.735-141.437V118.807c0-50.917 22.63-96.177 67.89-113.15C736.086-5.657 781.345 0 815.29 33.945l362.077 367.735c28.288 22.63 45.26 56.574 50.918 96.176 5.657 39.603-5.658 79.205-33.945 107.492-5.658 5.658-11.315 16.972-22.63 22.63l-350.762 356.42c-22.63 22.63-50.918 33.945-79.205 33.945z m-90.52-339.448h90.52v226.298l356.42-367.734 5.658-5.658c5.657-5.657 5.657-16.972 5.657-22.63 0-11.315-5.657-16.972-11.315-22.63l-5.657-5.657-356.42-362.077V333.79l-79.205 5.658c-118.806 0-231.956 39.602-328.132 113.149-113.15 90.519-186.696 237.613-209.326 429.967 141.436-175.382 390.364-203.669 531.8-203.669z" p-id="5668" fill="#878895"></path></svg>
`;
shareSpan.onclick = () => {
generatePoster(answerContentDiv.innerHTML, img);
};
// msg.appendChild(shareSpan);
// ======================
// ✅ 复制按钮(新增)
// ======================
const copySpan = document.createElement("span");
copySpan.style.display = "inline-flex";
copySpan.style.alignItems = "center";
copySpan.style.cursor = "pointer";
copySpan.style.marginTop = "8px";
copySpan.style.marginLeft = "10px";
copySpan.style.opacity = "0.75";
copySpan.style.transition = "opacity .2s";
copySpan.title = "复制内容";
copySpan.onmouseenter = () => copySpan.style.opacity = "1";
copySpan.onmouseleave = () => copySpan.style.opacity = "0.75";
copySpan.innerHTML = `
<svg t="1764549398754" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5335" width="20" height="20"><path d="M639.9 256.3H192.4c-35.2 0-63.9 28.8-63.9 63.9v575.4c0 35.2 28.8 63.9 63.9 63.9h447.5c35.2 0 63.9-28.8 63.9-63.9V320.2c0-35.1-28.8-63.9-63.9-63.9z m0 639.3H192.4V320.2h447.5v575.4z" fill="#878895" p-id="5336"></path><path d="M831.6 64.5H384.1c-35.2 0-63.9 28.8-63.9 63.9v63.9h63.9v-63.9h447.5v575.4h-63.9v63.9h63.9c35.2 0 63.9-28.8 63.9-63.9V128.4c0.1-35.1-28.7-63.9-63.9-63.9z" fill="#878895" p-id="5337"></path></svg>
`;
copySpan.onclick = async () => {
try {
await navigator.clipboard.writeText(answerBuffer);
copySpan.style.opacity = "1";
showToast("复制成功")
copySpan.title = "复制成功";
setTimeout(() => { copySpan.title = "复制内容"; }, 1200);
} catch (err) {
alert("复制失败,可能不支持 HTTPS 环境以外复制。");
}
};
// }
setTimeout(() => {
msgDiv.appendChild(shareSpan);
msgDiv.appendChild(copySpan);
}, 1000)
console.log("shareSpan appended?", msgDiv.contains(shareSpan));
scrollToBottom();
return;
}
let obj;
try {
obj = JSON.parse(data);
} catch {
continue;
}
// =========================
// phase
// =========================
if (obj.type === "phase") {
currentPhase = obj.content;
if (currentPhase === "thinking") {
ensureThinkingBox();
}
if (currentPhase === "answer") {
thinkingFinished = true;
if (thinkingStatusSpan) {
thinkingStatusSpan.textContent = "思考完成";
thinkingStatusSpan.classList.remove("thinking-running");
thinkingStatusSpan.classList.add("thinking-done");
document
.querySelectorAll('.thinking-header')?.forEach(el => el.classList.add('is-complete'));
}
ensureAnswerBox();
}
continue;
}
// =========================
// thinking 内容(不依赖 phase)
// =========================
if (obj.type === "thinking" && obj.content) {
ensureThinkingBox();
thinkingBuffer += obj.content;
thinkingContentDiv.innerHTML = marked.parse(thinkingBuffer);
scrollToBottom();
}
// =========================
// answer 内容
// =========================
if (obj.type === "answer" && obj.content) {
ensureAnswerBox();
answerBuffer += obj.content;
answerContentDiv.innerHTML = marked.parse(answerBuffer);
scrollToBottom();
}
// =========================
// 标题
// =========================
if (obj.type === "title" && obj.content) {
const chatItem = document.querySelector(
`.chat-item[data-sessionid="${sessId}"]`
);
if (chatItem) {
const chatTitle = chatItem.querySelector(".chat-title");
if (chatTitle) chatTitle.textContent = obj.content;
}
}
}
}
};
function newChat() {
const id = generateUniqueId16();
sessIdList.push({ sessId: id, title: "新对话" });
createSession(userId, id)
const chat = [{
id,
title: "新对话 " + (sessIdList.length),
messages: { role: "assistant", content: "👋 新会话已创建,请输入问题。", image_base64: '' }
}];
activeChatId = id;
ifSessionId = true;
sessId = id;
sendParam.sessionId = sessId;
renderMessages([chat[0].messages], true);
renderChatList('new');
}
let countTimer;
function getSms() {
document.getElementById('send-code').textContent = "60s";
let remainSeconds = 60;
countTimer = setInterval(() => {
if (remainSeconds > 0) {
remainSeconds--;
document.getElementById('send-code').textContent = `${remainSeconds}s`;
document.getElementById('send-code').disabled = true;
} else {
clearInterval(countTimer);
countTimer = null;
document.getElementById('send-code').textContent = "获取验证码";
document.getElementById('send-code').disabled = false;
}
}, 1000)
const phonenumber = document.getElementById('sys-phone').value;
const bindParams = {
phoneNumbers: phonenumber,
}
retryFetch("https://serviceri.satabot.com/external/sms/sendAliSmsCode", {
method: "POST", // 必选:指定请求方法为 POST
headers: {
"Content-Type": "application/json", // 声明请求体是 JSON 格式
// 可选:如果接口需要 Token 前置验证,可添加 Authorization 头
// "Authorization": "Bearer 你的前置 Token"
},
// 必选:请求体,将参数对象转为 JSON 字符串(不能直接传对象)
body: JSON.stringify(bindParams)
}).then(res => {
showToast("验证码发送成功");
if (res.code == 200) {
// showToast("验证码发送成功");
} else {
// showToast(res.msg + "yanzssahnegma");
// clearInterval(countTimer);
// countTimer = null;
// document.getElementById('send-code').textContent = "获取验证码";
// document.getElementById('send-code').disabled = false;
// return;
}
console.log(res);
}).catch(err => {
showToast(err + "验证码发送失败");
clearInterval(countTimer);
countTimer = null;
document.getElementById('send-code').textContent = "获取验证码";
document.getElementById('send-code').disabled = false;
return;
})
// handleBind(phonenumber).then(res => {
// }).catch(err => {
// showToast(err + "yanzhnegma");
// clearInterval(countTimer);
// countTimer = null;
// document.getElementById('send-code').textContent = "获取验证码";
// document.getElementById('send-code').disabled = false;
// return;
// })
}
function unshowpop() {
if (countTimer) {
clearInterval(countTimer);
}
const popbox = document.querySelector('.popbox');
if (popbox) {
popbox.remove();
}
}
async function refreshAiChatNum() {
const data = {
userId: userId
}
const res = await fetch("https://serviceai.satabot.com/refreshAiChatNum", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data) // ✅ 加上 signal
});
}
function showpop() {
let html = `<div class='popbox'>
<div class="form sms-form" id="sms-form">
<div class="loading-box none">
<div class="loading"></div>
</div>
<h2 style='margin:0px'>欢迎使用光伏运维智能体</h2>
<p style='color:#666;margin:13px 0px;'>请先绑定手机号</p>
<div class="input-group">
<div class="area-select" onclick="showAreaSelect()">
<span id="areaText">中国大陆 +86</span>
</div>
<input id="sys-phone" type="text" placeholder="请输入手机号">
</div>
<!-- 验证码登录 -->
<div id="codeLogin" class="input-group">
<input id="code" type="text" placeholder="请输入验证码">
<button class="code-btn" id="send-code" onclick="getSms()">获取验证码</button>
</div>
<div class="form-group">
<button type="button" class="button button-primary" id="sms-button" onclick="bindToLogin()">
<!-- <i class="fas fa-user-plus mr-2"></i> -->
绑定
</button>
</div>
</div></div>`;
document.body.insertAdjacentHTML('beforeend', html);
}
function switchChat(id) {
activeChatId = id;
sendParam.sessionId = id;
const items = document.querySelectorAll(".chat-item");
items.forEach(item => {
if (item.dataset.sessionid === id) {
item.classList.add("active");
} else {
item.classList.remove("active");
}
});
getHistory();
// renderChatList();
}
const deleteSession = (sessionId, userId) => {
if (activeChatId == sessionId) {
if (controller) {
controller.abort();
controller = null;
if (sendBtnImg.classList.contains('none')) {
sendBtnImg.classList.remove('none');
stopBtn.forEach(e => {
e.classList.add('none')
})
}
}
}
try {
fetch(`https://serviceai.satabot.com/session?sessionId=${sessionId}&userId=${userId}`, {
method: "DELETE"
}).then(res => res.json()).then(data => {
if (data.code === 0) {
getSessionList();
renderChatList();
console.log("删除成功:", data.message);
} else {
console.error("删除失败:", data.error);
}
})
} catch (err) {
console.error("请求异常:", err);
}
}
function deleteChat(id) {
// sessIdList = sessIdList.filter(item => item !== id);
// localStorage.setItem("sessId", JSON.stringify(sessIdList));
deleteSession(id, sendParam.userId)
}
function handleSendFile() {
console.log("选择文件");
// 触发隐藏的 input 点击
if (isMobile()) {
document.getElementById("fileInput1").click();
} else {
document.getElementById("fileInput").click();
}
}
// 监听文件选择
document.getElementById("fileInput").addEventListener("change", function (e) {
const file = e.target.files[0];
if (file) {
console.log("选择的文件:", file.name);
// 这里可以直接上传
uploadFile(file);
}
});
document.getElementById("fileInput1").addEventListener("change", function (e) {
const file = e.target.files[0];
if (file) {
console.log("选择的文件:", file.name);
// 这里可以直接上传
uploadFile(file);
}
});
// 示例上传函数(fetch 到后端接口)
function uploadFile(file) {
if (file) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = async function () {
sendParam.imageBase64 = reader.result;
document.querySelectorAll(".img-row").forEach(e => {
e.classList.remove("none");
})
const imgs = document.querySelectorAll(".img-row img");
imgs.forEach(img => {
img.src = sendParam.imageBase64;
});
isUpload[activeChatId] = true;
if (document.querySelector('.mobilesendbtn').classList.contains('none')) {
document.querySelector('.mobilesendbtn').classList.remove('none')
}
}
// document.getElementById("rawImg").src = URL.createObjectURL(file);
}
}
function deleteImg() {
document.querySelectorAll(".img-row").forEach(e => {
e.classList.add("none");
})
sendParam.imageBase64 = '';
const imgs = document.querySelectorAll(".img-row img");
imgs.forEach(img => {
img.src = '';
});
}
chatInput.addEventListener("keydown", function (e) {
if (e.key === "Enter" && !e.shiftKey) { // 按下回车且未按Shift
e.preventDefault(); // 阻止换行
sendMessage(); // 调用发送函数
}
});
chatInput.addEventListener("input", function () {
if (chatInput.value.trim() !== "") {
document.querySelector(".mobilesendbtn").classList.remove('none')
} else {
document.querySelector(".mobilesendbtn").classList.add('none')
}
});
document.querySelector(".sendMsgImg").addEventListener("click", function () {
sendMessage();
});
document.querySelector(".sendMsgImg1").addEventListener("click", function () {
sendMessage();
});
document.querySelectorAll(".sendfileimg").forEach(el => {
el.addEventListener("click", function () {
handleSendFile();
});
});
// getHistory();
// renderChatList("new");
// sendParam.sessionId = "7906661519458367";
// 调用获取历史记录的接口
function getHistory() {
// sendParam.userId = encodedUserId;
fetch(`https://serviceai.satabot.com/history?sessionId=${sendParam.sessionId}`, {
// fetch(`http://1.95.137.212:30008/history?sessionId=${sendParam.sessionId}`, {
method: "GET",
// headers: { "Content-Type": "application/json" },
// credentials: 'include', // 发送 cookie
// body: JSON.stringify(sendParam),
}).then(res => res.json()).then(data => {
if (!weixinloading.classList.contains("none")) {
weixinloading.classList.add("none");
}
// chats = data.messages;
// renderChatList();
if (controller) return;
renderMessages(data.messages)
})
}
// sessIdList
function isWeChat() {
return /MicroMessenger/i.test(navigator.userAgent);
}
// function getCookie(name) {
// const value = `; ${document.cookie}`;
// const parts = value.split(`; ${name}=`);
// if (parts.length === 2) return parts.pop().split(';').shift();
// return null;
// }
// gotoWeiXin();
function gotoWeiXin() {
console.log(isWeChat(), 8888, navigator.userAgent);
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
// 拼接完整的授权链接
// const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
// 跳转到微信授权
console.log("跳转链接:", authUrl);
window.location.href = authUrl;
}
// loginWithWeChat();
// function loginWithWeChat() {
// const appId = "wx364b8ebf17fe45fe";
// const appSecret = "9b7476020991a2c71f1416da7f011d31";
// const redirectUri = encodeURIComponent("https://www.example.com/wechat/callback");
// const state = "login_state";
// const scope = "snsapi_userinfo";
// const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&secret=${appSecret}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
// window.location.href = url; // 跳转到微信授权页面
// }
// simulateWechatLogin()
// 触发登录时执行:跳转微信授权页
function simulateWechatLogin() {
const APP_ID = 'wx0eeb7556d60121db';
const REDIRECT_URI = encodeURIComponent("https://www.satabot.com");
const STATE = Math.random().toString(36).substring(2, 12);
const SCOPE = 'snsapi_base';
// const authUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx807d86fb6b3d4fd2&redirect_uri=http%3A%2F%2Fdevelopers.weixin.qq.com&response_type=code&scope=snsapi_userinfo&state=STATE&forcePopup=true#wechat_redirect";
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APP_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=${SCOPE}&state=${STATE}&forcePopup=true#wechat_redirect`;
// window.location.href = authUrl; // 跳转后页面刷新,后续代码不执行
}
// if(from=="weixin"){
// gotoWeiXin();
// }else{
// }
// if (!isWeChat()) {
// } else {
// gotoWeiXin();
// }
// let isSuccess = false;
// function getSessionList() {
// console.log(userId, "huoqu")
// sendParam.userId = userId;
// fetch(`/api/sessions?userId=${sendParam.userId}`, {
// // fetch(`http://1.95.137.212:30008/history?sessionId=${sendParam.sessionId}`, {
// method: "GET",
// // headers: { "Content-Type": "application/json" },
// // credentials: 'include', // 发送 cookie
// // body: JSON.stringify(sendParam),
// }).then(res => res.json()).then(data => {
// debugger;
// console.log(data, 8777, data.code)
// if (data.code == 300) {
// if (!isSuccess) {
// window.location.href = data.error;
// isSuccess = true;
// } else {
// window.location.href = "https://ai.satabot.com/404.html";
// return;
// }
// // window.location.href='http://localhost/#/login?goRemote=1 '
// return;
// } else {
// sessIdList = data.sessions;
// renderChatList();
// console.log(data, 8777)
// }
// // chats = data.messages;
// // renderChatList();
// // renderMessages(data.messages)
// })
// }
function getSessionList() {
sendParam.userId = userId;
fetch(`https://serviceai.satabot.com/sessions?userId=${sendParam.userId}`, {
method: "GET",
// 确保 credentials 正确设置,以便传递 Cookie
// credentials: 'include',
})
.then(res => {
// debugger;
// 首先检查 HTTP 响应状态码
if (res.status === 401) {
// 401 表示未授权,用户需要登录
// 从后端响应头中获取登录页地址(后端需设置 Location 头)
const loginUrl = res.headers.get('Location') || '/login'; // 降级默认地址
window.location.href = loginUrl; // 跳转到后端指定的登录页
return Promise.reject('用户未授权');
}
else if (!res.ok) {
// 处理其他 HTTP 错误,如 404, 500 等
console.error('请求失败,状态码:', res.status);
// 可以在这里统一跳转到 404 页面
// window.location.href = "https://ai.satabot.com/404.html";
return Promise.reject(`HTTP error! status: ${res.status}`);
}
// 如果状态码是 200 OK,则继续解析 JSON
return res.json();
})
.then(data => {
// 请求成功,渲染页面
console.log('获取会话列表成功');
sessIdList = data.sessions;
renderChatList();
})
.catch(error => {
// 捕获网络错误或我们手动抛出的错误
console.error('获取会话列表时发生错误:', error);
// 这里可以不做任何事,因为特定的错误已经被处理了
});
}
function toggleSidebar() {
sidebar.classList.toggle("collapsed");
const toggleBtn = document.getElementById("toggleBtn");
if (sidebar.classList.contains("collapsed")) {
toggleBtn.style.left = "10px"; // 收起后
} else {
toggleBtn.style.left = "10px"; // 收起后
}
}
document.getElementById("stopBtn").addEventListener("click", () => {
document.querySelectorAll('.thinking-loading').forEach(el => el.classList.add('no-after'));
console.log(controller, '暂停消息');
isStopped = true;
if (reader) {
reader.cancel("stop");
reader = null;
}
if (controller) {
controller.abort();
controller = null;
}
if (sendBtnImg.classList.contains('none')) {
sendBtnImg.classList.remove('none');
stopBtn.forEach(e => {
e.classList.add('none')
})
}
fetch("https://serviceai.satabot.com/stop", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(sendParam),
});
});
document.getElementById("stopBtn1").addEventListener("click", () => {
document.querySelectorAll('.thinking-loading').forEach(el => el.classList.add('no-after'));
console.log(controller, '暂停消息');
isStopped = true;
if (reader) {
reader.cancel("stop");
reader = null;
}
if (controller) {
controller.abort();
controller = null;
}
if (sendBtnImg.classList.contains('none')) {
sendBtnImg.classList.remove('none');
stopBtn.forEach(e => {
e.classList.add('none')
})
}
fetch("https://serviceai.satabot.com/stop", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(sendParam),
});
});
// DOM 加载完成后执行
console.log('DOM Ready');
// });
</script>
<script>
// 1. 分别获取「场景选项」和「需求选项」(通过父容器ID精准筛选,避免混淆)
const sceneOptions = document.querySelectorAll('#scenes .option'); // 场景类选项(父容器#scenes)
const needOptions = document.querySelectorAll('#needs .option'); // 需求类选项(父容器#needs)
// 2. 创建两个隐藏输入框,分别存「场景」和「需求」数据
const scenesInput = document.createElement('input');
scenesInput.type = 'hidden';
scenesInput.name = 'scenes'; // 后端接收「场景」的字段名
const needsInput = document.createElement('input');
needsInput.type = 'hidden';
needsInput.name = 'needs'; // 后端接收「需求」的字段名
// 3. 把两个隐藏框添加到表单中
const form = document.getElementById('popupForm');
form.appendChild(scenesInput);
form.appendChild(needsInput);
// 4. 场景选项的点击事件:收集选中的场景
sceneOptions.forEach(opt => {
opt.addEventListener('click', () => {
opt.classList.toggle('selected'); // 切换选中样式
// 筛选选中的场景,提取文本并拼接成字符串(如:"山地光伏,农光互补电站")
const selectedScenes = Array.from(sceneOptions)
.filter(o => o.classList.contains('selected'))
.map(o => o.textContent);
scenesInput.value = selectedScenes.join(','); // 同步到场景隐藏框
});
});
// 5. 需求选项的点击事件:收集选中的需求
needOptions.forEach(opt => {
opt.addEventListener('click', () => {
opt.classList.toggle('selected'); // 切换选中样式
// 筛选选中的需求,提取文本并拼接成字符串(如:"杂草清理,热斑检测")
const selectedNeeds = Array.from(needOptions)
.filter(o => o.classList.contains('selected'))
.map(o => o.textContent);
needsInput.value = selectedNeeds.join(','); // 同步到需求隐藏框
});
});
// 6. 表单提交:异步发送所有数据(公司名 + 场景 + 需求)
form.addEventListener('submit', async (e) => {
e.preventDefault(); // 阻止表单默认刷新提交
const formData = new FormData(e.target); // 自动收集表单所有数据
const data = { ...Object.fromEntries(formData.entries()), userId: userId }; // 转成普通对象
if (!data.needs) {
showToast("请选择需求");
return;
}
if (!data.scenes) {
showToast("请选择场景");
return;
}
// 发送POST请求到后端
const res = await fetch('https://serviceai.satabot.com/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data) // 数据格式:{ company: "xxx", scenes: "xxx,xxx", needs: "xxx,xxx" }
});
const result = await res.json();
if (result.code == 200) {
document.querySelector('.popbgc').classList.add('none');
showToast("提交成功", 'success')
}
});
// window.addEventListener('beforeunload', function (event) {
// const data = {
// userId: userId
// }
// const res = fetch('https://serviceai.satabot.com/updateAiChatNum', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(data)
// });
// localStorage.setItem('remainChatNum', JSON.stringify(data));
// })
</script>
</body>
</html>