mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	feat: vue-mobile => 优化聊天记录拍版样式
This commit is contained in:
		@@ -1,136 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="chat-line chat-line-left">
 | 
			
		||||
    <div class="chat-icon">
 | 
			
		||||
      <img :src="icon" alt="ChatGPT">
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="chat-item">
 | 
			
		||||
      <div class="triangle"></div>
 | 
			
		||||
      <div class="content-box">
 | 
			
		||||
        <div class="content" v-html="content"></div>
 | 
			
		||||
        <div class="tool-box">
 | 
			
		||||
          <el-tooltip
 | 
			
		||||
              class="box-item"
 | 
			
		||||
              effect="light"
 | 
			
		||||
              content="复制回答"
 | 
			
		||||
              placement="bottom"
 | 
			
		||||
          >
 | 
			
		||||
            <el-button type="info" class="copy-reply" :data-clipboard-text="orgContent">
 | 
			
		||||
              <el-icon>
 | 
			
		||||
                <DocumentCopy/>
 | 
			
		||||
              </el-icon>
 | 
			
		||||
            </el-button>
 | 
			
		||||
          </el-tooltip>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {defineComponent} from "vue"
 | 
			
		||||
import {DocumentCopy} from "@element-plus/icons-vue";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'ChatReply',
 | 
			
		||||
  components: {DocumentCopy},
 | 
			
		||||
  props: {
 | 
			
		||||
    content: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: '',
 | 
			
		||||
    },
 | 
			
		||||
    orgContent: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: '',
 | 
			
		||||
    },
 | 
			
		||||
    icon: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: 'images/gpt-icon.png',
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {}
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.common-layout {
 | 
			
		||||
  .chat-line-left {
 | 
			
		||||
    justify-content: flex-start;
 | 
			
		||||
 | 
			
		||||
    .chat-icon {
 | 
			
		||||
      margin-right 5px;
 | 
			
		||||
 | 
			
		||||
      img {
 | 
			
		||||
        border-radius 50%;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .chat-item {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      position: relative;
 | 
			
		||||
      padding: 0 0 0 5px;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
 | 
			
		||||
      .triangle {
 | 
			
		||||
        width: 0;
 | 
			
		||||
        height: 0;
 | 
			
		||||
        border-top: 6px solid transparent;
 | 
			
		||||
        border-bottom: 6px solid transparent;
 | 
			
		||||
        border-right: 6px solid #404042;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        left: 0;
 | 
			
		||||
        top: 10px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .content-box {
 | 
			
		||||
 | 
			
		||||
        display flex
 | 
			
		||||
        flex-direction row
 | 
			
		||||
 | 
			
		||||
        .content {
 | 
			
		||||
          min-height 20px;
 | 
			
		||||
          word-break break-word;
 | 
			
		||||
          padding: 6px 10px;
 | 
			
		||||
          color var(--content-color)
 | 
			
		||||
          background-color: #404042;
 | 
			
		||||
          font-size: var(--content-font-size);
 | 
			
		||||
          border-radius: 5px;
 | 
			
		||||
          overflow auto;
 | 
			
		||||
 | 
			
		||||
          p {
 | 
			
		||||
            line-height 1.5
 | 
			
		||||
 | 
			
		||||
            code {
 | 
			
		||||
              color #f1f1f1
 | 
			
		||||
              background-color #202121
 | 
			
		||||
              padding 0 3px;
 | 
			
		||||
              border-radius 5px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          p:last-child {
 | 
			
		||||
            margin-bottom: 0
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          p:first-child {
 | 
			
		||||
            margin-top 0
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .tool-box {
 | 
			
		||||
          padding-left 10px;
 | 
			
		||||
          font-size 16px;
 | 
			
		||||
 | 
			
		||||
          .el-button {
 | 
			
		||||
            height 20px
 | 
			
		||||
            padding 5px 2px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="chat-line chat-line-right">
 | 
			
		||||
  <div class="message-reply">
 | 
			
		||||
    <div class="chat-item">
 | 
			
		||||
      <div class="content" v-html="content"></div>
 | 
			
		||||
      <div class="triangle"></div>
 | 
			
		||||
@@ -32,15 +32,15 @@ export default defineComponent({
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.chat-line-right {
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.message-reply {
 | 
			
		||||
  justify-content: flex-end;
 | 
			
		||||
 | 
			
		||||
  .chat-icon {
 | 
			
		||||
    margin-left 5px;
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      border-radius 50%;
 | 
			
		||||
      border-radius 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -52,9 +52,9 @@ export default defineComponent({
 | 
			
		||||
    .triangle {
 | 
			
		||||
      width: 0;
 | 
			
		||||
      height: 0;
 | 
			
		||||
      border-top: 6px solid transparent;
 | 
			
		||||
      border-bottom: 6px solid transparent;
 | 
			
		||||
      border-left: 6px solid #223A34;
 | 
			
		||||
      border-top: 5px solid transparent;
 | 
			
		||||
      border-bottom: 5px solid transparent;
 | 
			
		||||
      border-left: 5px solid #98E165;
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      right: 0;
 | 
			
		||||
      top: 10px;
 | 
			
		||||
@@ -63,23 +63,11 @@ export default defineComponent({
 | 
			
		||||
    .content {
 | 
			
		||||
      word-break break-word;
 | 
			
		||||
      padding: 6px 10px;
 | 
			
		||||
      background-color: #223A34;
 | 
			
		||||
      background-color: #98E165;
 | 
			
		||||
      color var(--content-color);
 | 
			
		||||
      font-size: var(--content-font-size);
 | 
			
		||||
      border-radius: 5px;
 | 
			
		||||
      overflow: auto;
 | 
			
		||||
 | 
			
		||||
      p {
 | 
			
		||||
        line-height 1.5
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      p:last-child {
 | 
			
		||||
        margin-bottom: 0
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      p:first-child {
 | 
			
		||||
        margin-top 0
 | 
			
		||||
      }
 | 
			
		||||
      line-height 1.5
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										134
									
								
								web/src/components/mobile/ChatReply.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								web/src/components/mobile/ChatReply.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="message-prompt">
 | 
			
		||||
    <div class="chat-icon">
 | 
			
		||||
      <img :src="icon" alt="ChatGPT">
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="chat-item">
 | 
			
		||||
      <div class="triangle"></div>
 | 
			
		||||
      <div class="content-box">
 | 
			
		||||
        <div class="content" v-html="content"></div>
 | 
			
		||||
        <div class="tool-box">
 | 
			
		||||
          <el-tooltip
 | 
			
		||||
              class="box-item"
 | 
			
		||||
              effect="dark"
 | 
			
		||||
              content="复制回答"
 | 
			
		||||
              placement="bottom"
 | 
			
		||||
          >
 | 
			
		||||
            <el-button type="info" class="copy-reply" :data-clipboard-text="orgContent" plain>
 | 
			
		||||
              <el-icon>
 | 
			
		||||
                <DocumentCopy/>
 | 
			
		||||
              </el-icon>
 | 
			
		||||
            </el-button>
 | 
			
		||||
          </el-tooltip>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {defineComponent} from "vue"
 | 
			
		||||
import {randString} from "@/utils/libs";
 | 
			
		||||
import {DocumentCopy} from "@element-plus/icons-vue";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'ChatReply',
 | 
			
		||||
  components: {DocumentCopy},
 | 
			
		||||
  props: {
 | 
			
		||||
    content: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: '',
 | 
			
		||||
    },
 | 
			
		||||
    orgContent: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: '',
 | 
			
		||||
    },
 | 
			
		||||
    icon: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: 'images/gpt-icon.png',
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      id: randString(32),
 | 
			
		||||
      clipboard: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.message-prompt {
 | 
			
		||||
  justify-content: flex-start;
 | 
			
		||||
 | 
			
		||||
  .chat-icon {
 | 
			
		||||
    margin-right 5px;
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      border-radius 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .chat-item {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    padding: 0 0 0 5px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
 | 
			
		||||
    .triangle {
 | 
			
		||||
      width: 0;
 | 
			
		||||
      height: 0;
 | 
			
		||||
      border-top: 5px solid transparent;
 | 
			
		||||
      border-bottom: 5px solid transparent;
 | 
			
		||||
      border-right: 5px solid #fff;
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      top: 13px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .content-box {
 | 
			
		||||
 | 
			
		||||
      display flex
 | 
			
		||||
      flex-direction row
 | 
			
		||||
 | 
			
		||||
      .content {
 | 
			
		||||
        min-height 20px;
 | 
			
		||||
        word-break break-word;
 | 
			
		||||
        padding: 6px 10px;
 | 
			
		||||
        color var(--content-color)
 | 
			
		||||
        background-color: #fff;
 | 
			
		||||
        font-size: var(--content-font-size);
 | 
			
		||||
        border-radius: 5px;
 | 
			
		||||
 | 
			
		||||
        p:last-child {
 | 
			
		||||
          margin-bottom: 0
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p:first-child {
 | 
			
		||||
          margin-top 0
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p > code {
 | 
			
		||||
          color #cc0000
 | 
			
		||||
          background-color #f1f1f1
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .tool-box {
 | 
			
		||||
        padding-left 10px;
 | 
			
		||||
        font-size 16px;
 | 
			
		||||
 | 
			
		||||
        .el-button {
 | 
			
		||||
          height 20px
 | 
			
		||||
          padding 5px 2px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -9,6 +9,7 @@ import {
 | 
			
		||||
    Cell,
 | 
			
		||||
    CellGroup,
 | 
			
		||||
    ConfigProvider,
 | 
			
		||||
    Dialog,
 | 
			
		||||
    DropdownItem,
 | 
			
		||||
    DropdownMenu,
 | 
			
		||||
    Field,
 | 
			
		||||
@@ -52,6 +53,7 @@ app.use(Icon);
 | 
			
		||||
app.use(DropdownItem);
 | 
			
		||||
app.use(Sticky);
 | 
			
		||||
app.use(SwipeCell);
 | 
			
		||||
app.use(Dialog);
 | 
			
		||||
app.use(router).use(ElementPlus).mount('#app')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
          @load="onLoad"
 | 
			
		||||
      >
 | 
			
		||||
        <van-swipe-cell v-for="item in chats" :key="item.id">
 | 
			
		||||
          <van-cell>
 | 
			
		||||
          <van-cell @click="changeChat(item)">
 | 
			
		||||
            <div class="chat-list-item">
 | 
			
		||||
              <van-image
 | 
			
		||||
                  round
 | 
			
		||||
@@ -70,10 +70,12 @@
 | 
			
		||||
import {ref} from "vue";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
import {getLoginUser} from "@/store/session";
 | 
			
		||||
import {showFailToast, showSuccessToast, showToast} from "vant";
 | 
			
		||||
import {showConfirmDialog, showFailToast, showSuccessToast, showToast} from "vant";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import router from "@/router";
 | 
			
		||||
import {setChatConfig} from "@/store/chat";
 | 
			
		||||
import {removeArrayItem, UUID} from "@/utils/libs";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
 | 
			
		||||
const title = ref("会话列表")
 | 
			
		||||
const chatName = ref("")
 | 
			
		||||
@@ -84,9 +86,10 @@ const finished = ref(false)
 | 
			
		||||
const error = ref(false)
 | 
			
		||||
const user = getLoginUser()
 | 
			
		||||
const isLogin = ref(false)
 | 
			
		||||
 | 
			
		||||
const roles = ref([])
 | 
			
		||||
const models = ref([])
 | 
			
		||||
const showPicker = ref(false)
 | 
			
		||||
const columns = ref([])
 | 
			
		||||
const columns = ref([roles.value, models.value])
 | 
			
		||||
 | 
			
		||||
checkSession().then(() => {
 | 
			
		||||
  isLogin.value = true
 | 
			
		||||
@@ -94,12 +97,10 @@ checkSession().then(() => {
 | 
			
		||||
  httpGet(`/api/role/list?user_id=${user.id}`).then((res) => {
 | 
			
		||||
    if (res.data) {
 | 
			
		||||
      const items = res.data
 | 
			
		||||
      const roles = []
 | 
			
		||||
      for (let i = 0; i < items.length; i++) {
 | 
			
		||||
        // console.log(items[i])
 | 
			
		||||
        roles.push({text: items[i].name, value: items[i].id, icon: items[i].icon})
 | 
			
		||||
        roles.value.push({text: items[i].name, value: items[i].id, icon: items[i].icon})
 | 
			
		||||
      }
 | 
			
		||||
      columns.value[0] = roles
 | 
			
		||||
    }
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    showFailToast("加载聊天角色失败")
 | 
			
		||||
@@ -109,11 +110,9 @@ checkSession().then(() => {
 | 
			
		||||
  httpGet('/api/admin/config/get?key=system').then(res => {
 | 
			
		||||
    if (res.data) {
 | 
			
		||||
      const items = res.data.models
 | 
			
		||||
      const models = []
 | 
			
		||||
      for (let i = 0; i < items.length; i++) {
 | 
			
		||||
        models.push({text: items[i].toUpperCase(), value: items[i]})
 | 
			
		||||
        models.value.push({text: items[i].toUpperCase(), value: items[i]})
 | 
			
		||||
      }
 | 
			
		||||
      columns.value[1] = models
 | 
			
		||||
    }
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    showFailToast("加载系统配置失败")
 | 
			
		||||
@@ -151,7 +150,19 @@ const search = () => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const clearAllChatHistory = () => {
 | 
			
		||||
  showSuccessToast('所有聊天记录已清空')
 | 
			
		||||
  showConfirmDialog({
 | 
			
		||||
    title: '操作提示',
 | 
			
		||||
    message: '确定要删除所有的会话记录吗?'
 | 
			
		||||
  }).then(() => {
 | 
			
		||||
    httpGet("/api/chat/clear").then(() => {
 | 
			
		||||
      showSuccessToast('所有聊天记录已清空')
 | 
			
		||||
      chats.value = [];
 | 
			
		||||
    }).catch(e => {
 | 
			
		||||
      showFailToast("操作失败:" + e.message)
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    // on cancel
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const newChat = (item) => {
 | 
			
		||||
@@ -164,16 +175,47 @@ const newChat = (item) => {
 | 
			
		||||
      icon: options[0].icon
 | 
			
		||||
    },
 | 
			
		||||
    model: options[1].value,
 | 
			
		||||
    title: '新建会话',
 | 
			
		||||
    chatId: UUID()
 | 
			
		||||
  })
 | 
			
		||||
  router.push('/mobile/chat/session')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const changeChat = (chat) => {
 | 
			
		||||
  let role = {}
 | 
			
		||||
  for (let i = 0; i < roles.value.length; i++) {
 | 
			
		||||
    if (roles.value[i].value === chat.role_id) {
 | 
			
		||||
      role = roles.value[i]
 | 
			
		||||
      break
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  setChatConfig({
 | 
			
		||||
    role: {
 | 
			
		||||
      id: chat.role_id,
 | 
			
		||||
      name: role.text,
 | 
			
		||||
      icon: role.icon
 | 
			
		||||
    },
 | 
			
		||||
    model: chat.model,
 | 
			
		||||
    title: chat.title,
 | 
			
		||||
    chatId: chat.chat_id
 | 
			
		||||
  })
 | 
			
		||||
  router.push('/mobile/chat/session')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const editChat = (item) => {
 | 
			
		||||
  showToast('修改会话标题')
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const removeChat = (item) => {
 | 
			
		||||
  showToast('删除当前会话')
 | 
			
		||||
  httpGet('/api/chat/remove?chat_id=' + item.chat_id).then(() => {
 | 
			
		||||
    chats.value = removeArrayItem(chats.value, item, function (e1, e2) {
 | 
			
		||||
      return e1.id === e2.id
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    showFailToast('操作失败:' + e.message);
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -18,8 +18,30 @@
 | 
			
		||||
    </van-sticky>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <div class="message-list-box" :style="{height: winHeight+'px'}">
 | 
			
		||||
 | 
			
		||||
    <div class="message-list-box" id="message-list-box" :style="{height: winHeight+'px'}">
 | 
			
		||||
      <van-list
 | 
			
		||||
          v-model:loading="loading"
 | 
			
		||||
          :finished="finished"
 | 
			
		||||
          v-model:error="error"
 | 
			
		||||
          error-text="请求失败,点击重新加载"
 | 
			
		||||
          @load="onLoad"
 | 
			
		||||
      >
 | 
			
		||||
        <van-cell v-for="item in chatData" :key="item">
 | 
			
		||||
          <chat-prompt
 | 
			
		||||
              v-if="item.type==='prompt'"
 | 
			
		||||
              :icon="item.icon"
 | 
			
		||||
              :created-at="dateFormat(item['created_at'])"
 | 
			
		||||
              :tokens="item['tokens']"
 | 
			
		||||
              :model="model"
 | 
			
		||||
              :content="item.content"/>
 | 
			
		||||
          <chat-reply v-else-if="item.type==='reply'"
 | 
			
		||||
                      :icon="item.icon"
 | 
			
		||||
                      :org-content="item.orgContent"
 | 
			
		||||
                      :created-at="dateFormat(item['created_at'])"
 | 
			
		||||
                      :tokens="item['tokens']"
 | 
			
		||||
                      :content="item.content"/>
 | 
			
		||||
        </van-cell>
 | 
			
		||||
      </van-list>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <van-sticky :offset-bottom="0" position="bottom" ref="bottomBarRef">
 | 
			
		||||
@@ -49,13 +71,17 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, ref} from "vue";
 | 
			
		||||
import {nextTick, onMounted, ref} from "vue";
 | 
			
		||||
import {showToast} from "vant";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import {UUID} from "@/utils/libs";
 | 
			
		||||
import {dateFormat, UUID} from "@/utils/libs";
 | 
			
		||||
import {getChatConfig} from "@/store/chat";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
import hl from "highlight.js";
 | 
			
		||||
import 'highlight.js/styles/a11y-dark.css'
 | 
			
		||||
import ChatPrompt from "@/components/mobile/ChatPrompt.vue";
 | 
			
		||||
import ChatReply from "@/components/mobile/ChatReply.vue";
 | 
			
		||||
 | 
			
		||||
const title = ref('简单介绍一下高更的艺术思想')
 | 
			
		||||
const winHeight = ref(0)
 | 
			
		||||
const navBarRef = ref(null)
 | 
			
		||||
const bottomBarRef = ref(null)
 | 
			
		||||
@@ -64,11 +90,52 @@ const router = useRouter()
 | 
			
		||||
const chatConfig = getChatConfig()
 | 
			
		||||
const role = chatConfig.role
 | 
			
		||||
const model = chatConfig.model
 | 
			
		||||
const title = chatConfig.title
 | 
			
		||||
const chatId = chatConfig.chatId
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  winHeight.value = window.innerHeight - navBarRef.value.$el.offsetHeight - bottomBarRef.value.$el.offsetHeight
 | 
			
		||||
  winHeight.value = document.body.offsetHeight - navBarRef.value.$el.offsetHeight - bottomBarRef.value.$el.offsetHeight
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const chatData = ref([])
 | 
			
		||||
const loading = ref(false)
 | 
			
		||||
const finished = ref(false)
 | 
			
		||||
const error = ref(false)
 | 
			
		||||
const onLoad = () => {
 | 
			
		||||
  httpGet('/api/chat/history?chat_id=' + chatId).then(res => {
 | 
			
		||||
    // 加载状态结束
 | 
			
		||||
    loading.value = false;
 | 
			
		||||
    finished.value = true;
 | 
			
		||||
    const data = res.data
 | 
			
		||||
    if (!data || data.length === 0) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const md = require('markdown-it')();
 | 
			
		||||
    for (let i = 0; i < data.length; i++) {
 | 
			
		||||
      if (data[i].type === "prompt") {
 | 
			
		||||
        chatData.value.push(data[i]);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      data[i].orgContent = data[i].content;
 | 
			
		||||
      data[i].content = md.render(data[i].content);
 | 
			
		||||
      chatData.value.push(data[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    nextTick(() => {
 | 
			
		||||
      hl.configure({ignoreUnescapedHTML: true})
 | 
			
		||||
      const blocks = document.querySelector("#message-list-box").querySelectorAll('pre code');
 | 
			
		||||
      blocks.forEach((block) => {
 | 
			
		||||
        hl.highlightElement(block)
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    error.value = true
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 创建 socket 连接
 | 
			
		||||
const prompt = ref('');
 | 
			
		||||
const showStopGenerate = ref(false); // 停止生成
 | 
			
		||||
@@ -229,7 +296,7 @@ const reGenerate = () => {
 | 
			
		||||
<style scoped lang="stylus">
 | 
			
		||||
.mobile-chat {
 | 
			
		||||
  .message-list-box {
 | 
			
		||||
 | 
			
		||||
    overflow-x auto
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .chat-box {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
      <router-view/>
 | 
			
		||||
 | 
			
		||||
      <van-tabbar route v-model="active" @change="onChange">
 | 
			
		||||
        <van-tabbar-item to="/mobile/chat" name="home" icon="chat-o"></van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/chat/list" name="home" icon="chat-o"></van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/setting" name="setting" icon="setting-o"></van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/profile" name="profile" icon="user-o"></van-tabbar-item>
 | 
			
		||||
      </van-tabbar>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user