You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
2.9 KiB

  1. <template>
  2. <div
  3. class="message-item"
  4. :class="{
  5. 'user-message': msg.sender === 'user',
  6. 'ai-message': msg.sender === 'ai',
  7. [msg.class]: msg.class
  8. }"
  9. >
  10. <div v-if="msg.type === 'kline'" class="kline-container">
  11. <div :id="'kline-container-' + index" class="chart-mount-point">
  12. <div v-if="!msg.hasValidData" class="no-data-message">
  13. <p>暂无K线数据</p>
  14. </div>
  15. </div>
  16. </div>
  17. <div v-else-if="msg.type == 'ing'" class="ai-message-container">
  18. <thinking-gif
  19. v-if="msg.gif"
  20. :type="getGifType(msg.gif)"
  21. />
  22. <div class="ai-message-content" :class="{ fourStep: msg.nowrap }">
  23. <div v-if="msg.flag">
  24. <span>{{ msg.content }}</span>
  25. <span class="loading-dots">
  26. <span class="dot">.</span>
  27. <span class="dot">.</span>
  28. <span class="dot">.</span>
  29. <span class="dot">.</span>
  30. <span class="dot">.</span>
  31. <span class="dot">.</span>
  32. </span>
  33. </div>
  34. <div v-else v-html="msg.content"></div>
  35. </div>
  36. </div>
  37. <div v-else class="message-content" v-html="msg.content"></div>
  38. </div>
  39. </template>
  40. <script setup>
  41. import { ref } from 'vue';
  42. import ThinkingGif from './ThinkingGif.vue';
  43. import thinkingGif from "@/assets/img/gif/思考.gif";
  44. import analyzeGif from "@/assets/img/gif/解析.gif";
  45. import generateGif from "@/assets/img/gif/生成.gif";
  46. const props = defineProps({
  47. msg: {
  48. type: Object,
  49. required: true
  50. },
  51. index: {
  52. type: Number,
  53. required: true
  54. }
  55. });
  56. // 根据GIF路径确定类型
  57. const getGifType = (gifPath) => {
  58. if (gifPath === thinkingGif) return 'thinking';
  59. if (gifPath === analyzeGif) return 'analyze';
  60. if (gifPath === generateGif) return 'generate';
  61. return 'thinking';
  62. };
  63. </script>
  64. <style scoped>
  65. .message-item {
  66. margin-bottom: 15px;
  67. padding: 10px;
  68. border-radius: 8px;
  69. }
  70. .user-message {
  71. background-color: #e6f7ff;
  72. margin-left: 20%;
  73. }
  74. .ai-message {
  75. background-color: #f5f5f5;
  76. margin-right: 20%;
  77. }
  78. .kline-container {
  79. width: 100%;
  80. height: 400px;
  81. }
  82. .chart-mount-point {
  83. width: 100%;
  84. height: 100%;
  85. }
  86. .no-data-message {
  87. display: flex;
  88. justify-content: center;
  89. align-items: center;
  90. height: 100%;
  91. color: #999;
  92. }
  93. .ai-message-container {
  94. display: flex;
  95. flex-direction: column;
  96. }
  97. .ai-message-content {
  98. padding: 10px;
  99. }
  100. .loading-dots .dot {
  101. animation: loading 1.4s infinite;
  102. display: inline-block;
  103. opacity: 0;
  104. }
  105. .loading-dots .dot:nth-child(1) {
  106. animation-delay: 0s;
  107. }
  108. .loading-dots .dot:nth-child(2) {
  109. animation-delay: 0.2s;
  110. }
  111. .loading-dots .dot:nth-child(3) {
  112. animation-delay: 0.4s;
  113. }
  114. .loading-dots .dot:nth-child(4) {
  115. animation-delay: 0.6s;
  116. }
  117. .loading-dots .dot:nth-child(5) {
  118. animation-delay: 0.8s;
  119. }
  120. .loading-dots .dot:nth-child(6) {
  121. animation-delay: 1s;
  122. }
  123. @keyframes loading {
  124. 0% {
  125. opacity: 0;
  126. }
  127. 50% {
  128. opacity: 1;
  129. }
  130. 100% {
  131. opacity: 0;
  132. }
  133. }
  134. </style>