<template>
  <div style="display: flex;
  height: 100vh;">
    <Menu
        :initial-active="1"
    />
    <div class="qwen-chat">

      <!-- 聊天消息区域 -->
      <div ref="messagesContainer" class="chat-messages">
        <div
            v-for="(msg, index) in messages"
            :key="index"
            :class="['message', msg.role]"
        >
          <div class="time">{{ msg.time }}</div>
          <div class="word" v-if="msg.role === 'user'&& msg.hasFile" style="margin-bottom: 6px">
            <img src="../assets/word.svg" style="width: 28px;margin-right: 5px; flex-shrink: 0; flex-grow: 0;">
            <div style="flex: 1; overflow: auto;">
              <div class="wordName" style="text-align: left;margin-bottom: 1px;font-size: 11px;line-height: 14px;">{{msg.file.name}}</div>
              <div style="    align-items: center;height: 18px;font-size: 10px; line-height: 12px;display: flex;">{{msg.file.size}}</div>
            </div>
<!--            <img-->
<!--                src="../assets/close.svg"-->
<!--                alt="close"-->
<!--                class="close-btn"-->
<!--                @click="removeFile"-->
<!--            />-->

          </div>
          <div v-if="msg.role === 'user'" style="display: flex;align-items: flex-start;    justify-content: flex-end;">
            <div class="bubble" v-if="msg.content">
              {{ msg.content }}
            </div>

          </div>
          <div v-else-if="msg.role === 'assistant'" style="    display: flex;align-items: flex-start;    justify-content: flex-start;">
            <img src="../assets/gpt.png" style="width: 45px;height: 45px;margin-right: 15px">
            <div v-if="msg.isKG" class="kg-card">
              <div v-if="msg.entities?.length" class="kg-section">
                <h5 style="text-align: left">识别出的实体</h5>
                <div class="entity-list">
                  <div
                      v-for="(ent, i) in msg.entities"
                      :key="i"
                      class="entity-item"
                      style="display: flex;margin-bottom: 10px"
                  >
                    <!-- 复选框放在外面 -->
                    <input
                        type="checkbox"
                        :id="'entity-' + i"
                        :value="ent"
                        v-model="ent.selected"
                        @change="handleEntitySelectionChange(msg,ent)"
                    />
                    <!-- 使用 for 关联到 input 的 id -->
                    <label
                        :for="'entity-' + i"
                        class="entity-tag"
                        :class="'tag-' + ent.t"
                    >
                      {{ ent.n }}<small>({{ ent.t }})</small>
                    </label>
                  </div>
                </div>
              </div>

              <div v-if="msg.relations?.length" class="kg-section">
                <h5 style="text-align: left">识别出的关系</h5>
                <ul class="relation-list">
                  <li v-for="(rel, i) in msg.relations" :key="i" class="relation-item">
                    <!-- 复选框 -->
                    <input
                        type="checkbox"
                        :id="'rel-' + i"
                        :value="rel"
                        v-model="rel.selected"
                        :disabled="!isRelationEnabled(msg,rel)"
                    />
                    <!-- 标签区域（可点击） -->
                    <label :for="'rel-' + i" class="relation-label">
                      <span class="rel-subject">{{ rel.e1 }}</span>
                      <span class="rel-predicate">— {{ rel.r }} →</span>
                      <span class="rel-object">{{ rel.e2 }}</span>
                    </label>
                  </li>
                </ul>
              </div>
              <div v-if="msg.entities?.length || msg.relations?.length" style="text-align: right;  display: flex;
  justify-content: flex-end;
  margin-top: 12px;">
                <button class="send-btn" @click="build(msg)" style="border-radius: 10px">
                  构建
                </button>
                </div>
              <div v-if="!msg.entities?.length && !msg.relations?.length" style="font-size: 12px;
    text-align: left;" >
                未提取到有效医学实体或关系。</div>
            </div>
            <div v-else class="bubble assistant-text">
              {{ msg.content }}
            </div>
          </div>

        </div>
        <div v-if="isSending" style="display: flex;margin-left: 5px;margin-bottom: 10px">
          <div class="loading-indicator">
            <div class="dot dot-1"></div>
            <div class="dot dot-2"></div>
            <div class="dot dot-3"></div>
            <div class="dot dot-4"></div>
          </div>
        </div>
      </div>
      <!-- 输入区域（Qwen 风格） -->
      <div class="input-area">
        <!-- 下拉图标：绝对定位在 input-area 上方居中 -->
        <div class="dropdown-icon" v-if="showScrollToBottom" @click="scrollToLatest">
          <img  src="../assets/下拉.png" style="width: 45px" />
        </div>
        <div class="word" v-if="showFile">
          <img src="../assets/word.png" style="width: 28px;margin-right: 5px; flex-shrink: 0; flex-grow: 0;">
          <div style="flex: 1; overflow: auto;">
            <div class="wordName" style="text-align: left;margin-bottom: 1px;font-size: 11px;line-height: 14px;">{{file.fileName}}</div>
            <div style=" color:#a2a5a7;   align-items: center;height: 18px;font-size: 10px; line-height: 12px;display: flex;">{{file.size}}</div>
          </div>
          <img
              src="../assets/close.svg"
              alt="close"
              class="close-btn"
              @click="removeFile"
          />

        </div>

      <textarea
          v-model="inputText"
          placeholder="有什么可以帮助您？"
          class="input-box"
          @keyup.enter.exact.prevent="sendMessage"
          :rows="rows"
      ></textarea>



        <div class="icon-group">
          <img

              src="../assets/upload.png"
              alt="用户头像"
              class="avatar"
              @click="upload"
              style="margin-left: 10px;cursor:pointer;border-radius: 50%;width: 30px;box-shadow: rgb(0 0 0 / 18%) 0px 2px 8px; "
          >
          <div style="display: flex;align-items: center;">
            <img v-if="inputStatus"

                src="../assets/放大.png"
                alt="用户头像"
                class="avatar"
                style="margin-left: 10px;cursor:pointer;width: 15px;margin-right: 26px "
                @click="adjustHeight(false)"
            >
            <img v-if="!inputStatus"

                src="../assets/缩小.png"
                alt="用户头像"
                class="avatar"
                style="margin-left: 10px;cursor:pointer;width: 15px;margin-right: 26px "
                @click="adjustHeight(true)"
            >
            <button class="send-btn" @click="sendMessage" title="发送" :disabled="isSending">
              发送
            </button>
            <input
                ref="fileInput"
                type="file"
                style="display: none;"
                accept=".docx"
                @change="handleFileChange"
            />
          </div>

        </div>
      </div>
    </div>
  </div>

</template>

<script>
import Menu from "@/components/Menu.vue";
import axios from "axios";
import {analyze, build, getAIStatus} from "@/api/builder";
import {qaAnalyze} from "@/api/qa";

export default {
  name: 'QwenChat',
  components: {Menu},
  data() {
    return {
      inputText: '',
      messages: [
        { role: 'assistant', content: '你好！我是图谱构建助手，有什么可以帮你的吗？',isKG:false,hasFile:false }
      ],
      status:"wait",
      rows:3,
      inputStatus:true,
      fileName:"",
      file:{},
      showFile:false,
      selectedEntities:[],
      selectedRelations:[],
      showScrollToBottom: false,
      isSending: false,

    };
  },
  methods: {
    handleEntitySelectionChange(msg, ent) {
      // 如果该实体被取消选中
      if (!ent.selected) {
        // 遍历所有的关系，找到与当前实体相关的关系，将它们的 selected 设置为 false
        msg.relations.forEach(rel => {
          if (rel.e1 === ent.n || rel.e2 === ent.n) {
            rel.selected = false;
          }
        });
      }
      console.log(`实体 "${ent.n}" 的选中状态：`, ent.selected);

      // 如果需要，你可以在这里做其他处理，比如更新状态等
    },
    // 为 entities 或 relations 添加 selected 标志
    addSelectedFlag(items, isRelation = false) {
      if (!items) return [];
      return items.map(item => {
        if (isRelation) {
          return {
            ...item,
            selected: true // 对于关系类型，添加 selected 属性，默认值为 false
          };
        }
        return {
          ...item,
          selected: true // 对于实体类型，添加 selected 属性，默认值为 false
        };
      });
    },
    handleScroll() {
      const container = this.$refs.messagesContainer;
      const isAtBottom = container.scrollHeight - container.scrollTop <= container.clientHeight + 20;
      this.showScrollToBottom = !isAtBottom;
    },
    scrollToBottom(behavior = 'smooth') {
      this.$nextTick(() => {
        const container = this.$refs.messagesContainer;
        container.scrollTo({
          top: container.scrollHeight,
          behavior
        });
        this.showScrollToBottom = false; // 滚到底后隐藏按钮
      });
    },
    // 当用户点击“下拉”图标时
    scrollToLatest() {
      this.scrollToBottom('smooth');
    },
    build(msg) {
      // 获取选中的实体和关系
      let selectedEntities = msg.entities.filter(ent => ent.selected);  // 从 msg 中获取被选中的 entities
      let selectedRelations = msg.relations.filter(rel => rel.selected);  // 从 msg 中获取被选中的 relations

      // 构建数据对象
      let data = {
        entities: selectedEntities,  // 选中的实体
        relations: selectedRelations  // 选中的关系
      };
      // 调用后端的 build 方法
      build(data);
    },
    handleRelationSelectionChange(msg, rel) {
      // 处理关系的选中状态
      console.log(`关系 "${rel.e1} — ${rel.r} → ${rel.e2}" 被选择了: `, rel.selected);
    },

    // 更新实体和关系的选中状态
    isRelationEnabled(msg, rel) {
      const selectedEntities = msg.entities.filter(ent => ent.selected);

      // 确保 e1 和 e2 都在选中的实体中
      const hasE1 = selectedEntities.some(ent => ent.n === rel.e1);
      const hasE2 = selectedEntities.some(ent => ent.n === rel.e2);

      return hasE1 && hasE2;
    },
    removeFile(){
      this.file={}
      this.showFile=false
    },
    upload(){
      this.$refs.fileInput.value = '';
      this.$refs.fileInput.click(); // 点击按钮时打开文件选择框
    },
    handleFileChange(event) {
      console.log(event)
      const file = event.target.files[0]; // 获取第一个选择的文件
      console.log(file)
      if (file) {
        this.fileName = file.name; // 存储文件名

        const sizeInBytes = file.size; // 获取文件的字节数
        let fileSize;

        if (sizeInBytes < 1024 * 1024) {
          // 文件小于 1MB，显示为 KB
          const sizeInKB = sizeInBytes / 1024; // 将字节转换为 KB
          fileSize = `${sizeInKB.toFixed(2)} KB`;
        } else {
          // 文件大于等于 1MB，显示为 MB
          const sizeInMB = sizeInBytes / (1024 * 1024); // 将字节转换为 MB
          fileSize = `${sizeInMB.toFixed(2)} MB`;
        }

        this.file = {
          fileName: file.name,
          size: fileSize, // 自动加上单位 KB 或 MB
          file:file
        };
        this.showFile = true;
        console.log("文件信息：", this.file); // 打印文件信息
      }
    },
    allSelect(msg){
      if (msg.entities && msg.entities.length > 0) {
        msg.entities.forEach(ent => {
          ent.selected=true
          this.selectedEntities.push(ent);
        });
      }
      if (msg.relations && msg.relations.length > 0) {
        msg.relations.forEach(rel => {
          rel.selected=true
          this.selectedRelations.push(rel);
        });
      }
    },
    adjustHeight(status){
      if(status){
        this.rows=3
        this.inputStatus=true
      }else{
        this.rows=10
        this.inputStatus=false
      }
    },
    pollAIStatus() {
      if (this.status !== "wait") return; // 如果已结束，不再继续
      try {
        const data = getAIStatus();
        if (data.status === "ok") {
          this.status = "ok";
        } else if (data.status === "error") {
          this.status = "error";
        } else {
          setTimeout(() => this.pollAIStatus(), 3000);
        }
      } catch (error) {
        console.error("轮询出错:", error);
        this.status = "error";
        alert("查询状态失败，请重试");
      }
    },
    getNowDate(){
      const currentDate = new Date();

// 获取年份、月份、日期、小时、分钟和秒
      const year = currentDate.getFullYear();
      const month = String(currentDate.getMonth() + 1).padStart(2, '0'); // 月份从0开始，所以加1
      const day = String(currentDate.getDate()).padStart(2, '0');
      const hours = String(currentDate.getHours()).padStart(2, '0');
      const minutes = String(currentDate.getMinutes()).padStart(2, '0');
      const seconds = String(currentDate.getSeconds()).padStart(2, '0');

// 格式化时间为 YYYY-MM-DD HH:mm:ss
      const formattedTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
      return formattedTime;
    },
    fileToBase64(file) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => {
          // 移除 "data:...;base64," 前缀，只保留纯 base64 字符串
          const base64 = reader.result.split(',')[1];
          resolve(base64);
        };
        reader.onerror = reject;
        reader.readAsDataURL(file);
      });
    },
    async   sendMessage() {
      this.isSending=true
      const text = this.inputText.trim();
      const hasFile = this.showFile && this.file.file;

      // 如果既没文本也没文件，不发送
      if (!text && !hasFile) {
        this.isSending = false;
        return;
      }
      let data={
        "text":text
      }
      // this.pollAIStatus()
      // 添加用户消息

      const userMessage = {
        role: 'user',
        content: text,
        time: this.getNowDate(),
        file: hasFile ? { name: this.file.fileName, size: this.file.size,file:this.file.file } : null,
        hasFile:hasFile
      };
      this.messages.push(userMessage);
      this.inputText = '';
      this.showFile=false

      if (hasFile) {
        // 📎 有文件：使用 FormData 上传
        // 将 File 转为 Base64
        const fileBase64 = await this.fileToBase64(this.file.file);

        // 构造 JSON payload（不再是 FormData！）
        const payload = {
          file_base64: fileBase64,
          filename: this.file.file.name,
          text: text || ''
        };

        // 调用新的 analyzeJson 接口（注意：不是传 formData）
        analyze(payload).then(res => {
          let message = {
            role: 'assistant',
            content: res,
            entities: this.addSelectedFlag(res.entities),
            relations: this.addSelectedFlag(res.relations, true),
            isKG: true,
            time: this.getNowDate()
          };
          this.messages.push(message);
          this.scrollToBottom('smooth');
          this.isSending = false;
          this.file={}
          this.allSelect(message)
        })
      } else {
        const payload = {
          text: text || ''
        };
        analyze(payload).then(res => {
          let message = {
            role: 'assistant',
            content: res,
            entities: res.entities,
            relations: res.relations,
            isKG: true,
            time: this.getNowDate()
          };
          this.messages.push(message);
          this.scrollToBottom('smooth');
          this.isSending = false;
          this.file={}
          this.allSelect(message)
        })
      }
      this.scrollToBottom('smooth');
    },
    insertPrefix(prefix) {
      this.inputText += prefix;
      this.$nextTick(() => {
        // 自动聚焦到 textarea 末尾（简单处理）
        const el = this.$el.querySelector('.input-box');
        el.focus();
      });
    },
    // scrollToBottom() {
    //   this.$nextTick(() => {
    //     const container = this.$refs.messagesContainer;
    //     console.log(container)
    //     if (container) {
    //       // 使用 setTimeout 确保所有 DOM 更新完成后再执行滚动
    //       setTimeout(() => {
    //         container.scrollTop = container.scrollHeight;
    //         console.log(container.scrollTop)
    //         console.log(container.scrollHeight)
    //       }, 100); // 延迟 100ms
    //     }
    //   });
    // },

    saveMessage(message) {
      const messages = JSON.parse(localStorage.getItem('messages')) || [];
      messages.push(message); // 将新消息添加到消息数组中
      localStorage.setItem('messages', JSON.stringify(messages));
    },
    loadMessages() {
      const savedMessages = JSON.parse(localStorage.getItem('messages')) || [];
      console.log(savedMessages)
      this.messages = savedMessages; // 加载之前存储的消息
    },
    handleBeforeUnload() {
      localStorage.removeItem('messages');
      // 页面刷新或关闭前，保存所有消息
      console.log("页面刷新或关闭前，保存消息...");
      this.messages.forEach((message) => {
        this.saveMessage(message);
      });
    },

  },
  watch: {
    messages() {
      this.scrollToBottom('smooth');
    }
  },
  beforeUnmount() {
    const container = this.$refs.messagesContainer;
    container.removeEventListener('scroll', this.handleScroll);
  },
  beforeRouteLeave(to, from, next) {
    console.log('【守卫触发】离开 /graph 路由');
    // alert('即将离开，保存数据！'); // 临时测试
    this.handleBeforeUnload();
    next();
  },
  mounted() {
    const container = this.$refs.messagesContainer;
    container.addEventListener('scroll', this.handleScroll);
    this.loadMessages();

    this.scrollToBottom('smooth');
      window.addEventListener('beforeunload', this.handleBeforeUnload);
  },

};
</script>

<style scoped>
.qwen-chat {
  flex: 1; overflow: auto;
  display: flex;
  flex-direction: column;
  height: 100vh;
  margin: 0 auto;
  border: 1px solid #e0e0e0;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background-color: #F3F3F3;
}

/* === 消息区域 === */
.chat-messages {
  flex: 1;
  padding: 16px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.message {
  display: flex;
  margin-bottom: 12px;
  align-items: flex-start;
  flex-direction: column; /* 垂直排列时间和内容 */
}

.message.user {
  align-items: flex-end;
}

.message.assistant {
  align-items: flex-start;
}

.bubble {
  padding: 16px;
  border-radius: 13px;
  max-width: 55%;
  word-break: break-word;
  font-size: 12px;
  text-align: left;
}

.message.user .bubble {
  background-color: #e9e9e9;
  color: #333;
}

.message.assistant .bubble {
  background-color: #fff;
  color: #333;
}

/* === 输入区域 === */
.input-area {
  position: relative;
  padding: 16px;
  background: white;
  border-top-left-radius: 24px;
  border-top-right-radius: 24px;
  box-shadow: 2px -1px 14px 0px rgb(159 160 161 / 22%);
}
.input-box::placeholder {
  color: #AFAFAF; /* 设置字体颜色为红色 */
  font-weight: 500;
}
.input-box {
  width: 100%;
  padding: 12px 16px;
  border: none;
  border-radius: 12px;
  font-size: 14px;
  line-height: 1.5;
  resize: none;
  outline: none;
  transition: border-color 0.2s ease;
  box-sizing: border-box;
}

.input-box:focus {
  border-color: #007bff;
}

.action-buttons {
  display: flex;
  gap: 8px;
  margin: 12px 0;
  white-space: nowrap;
  padding: 0 4px;
}

.btn {
  display: flex;              /* 使用flex布局 */
  justify-content: center;    /* 水平居中 */
  align-items: center;        /* 垂直居中 */
  width: 20px;                /* 设置按钮的宽度为20px */
  height: 20px;               /* 设置按钮的高度为20px */
  border-radius: 50%;         /* 圆形按钮 */
  background-color: white;    /* 背景色为白色 */
  font-size: 18px;            /* 设置加号的字体大小 */
  line-height: 20px;          /* 设置行高，确保加号垂直居中 */
  color: #333;                /* 加号的颜色 */
  font-weight: bold;          /* 加号字体加粗 */
  cursor: pointer;            /* 鼠标悬停时显示为点击效果 */
}

.btn:hover {
  background: #e9e9e9;
}

.btn span {
  font-size: 12px;
}

.more-btn {
  background: transparent;
  border: 1px dashed #ccc;
  color: #666;
}

.icon-group {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-top: 8px;
}

.icon,
.send-btn span {
  font-size: 16px;
  cursor: pointer;
  color: #999;
}

.icon:hover,
.send-btn:hover span {
  color: #333;
}

.send-btn {
  background: #B9CDFF;
  border: none;
  width: 60px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  cursor: pointer;
  transition: background-color 0.2s;
  font-size: 11px;
}

.send-btn:hover {
  background: #155DFF;
}
/* === 自定义助手 KG 卡片 === */
.kg-card {
  background: white;
  border: 1px solid #e0e0e0;
  border-radius: 16px;
  padding: 16px;
  width: 100%;
  box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  font-size: 14px;
  color: #333;
}

.kg-card h4 {
  margin: 0 0 16px 0;
  padding-bottom: 8px;
  border-bottom: 1px solid #f0f0f0;
  color: #1a73e8;
  font-weight: 600;
}

.kg-section {
  margin-bottom: 16px;
}

.kg-section h5 {
  margin: 0 0 8px 0;
  color: #555;
  font-size: 14px;
  font-weight: 600;
}

/* 实体标签 */
.entity-list {
  flex-wrap: wrap;
  gap: 8px;
}

.entity-tag {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 20px;
  font-size: 13px;
  background: #f0f8ff;
  color: #1e88e5;
  border: 1px solid #bbdefb;
}

.entity-tag small {
  margin-left: 6px;
  opacity: 0.8;
  font-weight: normal;
}

/* 按类型着色（可扩展） */
/*
.tag-疾病 { background: #ffebee; color: #c62828; border-color: #ffcdd2; }
.tag-症状 { background: #e8f5e9; color: #2e7d32; border-color: #c8e6c9; }
.tag-检查 { background: #fff8e1; color: #ff8f00; border-color: #ffecb3; }
.tag-药物 { background: #f3e5f5; color: #7b1fa2; border-color: #ce93d8; }
*/

/* 关系列表 */
.relation-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.relation-list li {
  padding: 6px 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.relation-list li:last-child {
  border-bottom: none;
}



/* 空状态 */
.empty-state {
  color: #999;
  font-style: italic;
  padding: 12px 0;
}

/* 普通助手文本（非 KG） */
.assistant-text {
  background-color: #e9ecef;
  color: #333;
}
.message.assistant .time{
  text-align: left;
  color: #A5A5A5;
  margin-bottom: 5px;
  font-size: 12px;
  margin-left: 60px;
}
.message.user .time{
  text-align: right;
  color: #A5A5A5;
  margin-bottom: 5px;
  font-size: 12px;

}
.word{
 /* border: 1px solid rgba(17,17,51,.1);*/
  border-radius: 8px;
  justify-content: flex-start;
  align-items: center;
  width: 16%;
  min-width: 149px;
  max-width: 206px;
  padding: 9px 6px;
  display: flex;
  margin-left: 10px;
  position: relative;
  background-color: #e9e9e9;
}
.wordName{
  overflow: hidden; /* 隐藏超出部分 */
  display: -webkit-box; /* 使用 webkit 的盒子模型 */
  -webkit-box-orient: vertical; /* 设置为垂直方向 */
  -webkit-line-clamp: 1; /* 限制为两行 */
  text-overflow: ellipsis; /* 显示省略号 */
}
.word:hover .close-btn {
  display: block; /* 悬浮时显示X按钮 */
}
.close-btn{
  position: absolute;

  width: 20px; /* 设置适合的图片大小 */
  height: 20px;
  cursor: pointer;
  padding: 5px;
  box-sizing: border-box;
  top: -8px;
  right: -7px;
  border: 1px solid rgba(17,17,51,.1);
  border-radius: 50%;
  background-color: #fff;
  display: none;
}
.dropdown-icon {
  position: absolute;
  top: -45px; /* 图标高度约45px，一半是22.5，所以 -22~ -25 可居中于顶部线上 */
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  cursor: pointer;
}
.send-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  background-color: #ccc;
}
/* 加载指示器的整体样式 */
.loading-indicator {
  display: inline-flex;
  align-items: center;
  gap: 10px; /* 圆点之间的间距 */
}

/* 单个圆点的基本样式 */
.dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  animation: bounce 1.4s infinite ease-in-out both;
}

/* 给每个圆点设定特定的灰色 */
.dot-1 { background-color: #e0e0e0; } /* 浅灰色 */
.dot-2 { background-color: #b0b0b0; } /* 中浅灰色 */
.dot-3 { background-color: #808080; } /* 中深灰色 */
.dot-4 { background-color: #505050; } /* 深灰色 */

/* 给每个圆点设置不同的动画延迟以创造连续的效果 */
.dot:nth-child(1) { animation-delay: 0.1s; }
.dot:nth-child(2) { animation-delay: 0.2s; }
.dot:nth-child(3) { animation-delay: 0.3s; }
.dot:nth-child(4) { animation-delay: 0.4s; }

.dot-1 { animation-delay: -0.4s; }
.dot-2 { animation-delay: -0.2s; }
.dot-3 { animation-delay: 0s; }
.dot-4 { animation-delay: 0.2s; }
/* 定义动画效果 */
@keyframes bounce {
  0%, 80%, 100% {
    transform: scale(0);
  } 40% {
      transform: scale(1.0);
    }
}
</style>