index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <template>
  2. <view class="container">
  3. <!-- <chatCustom @showDr="handleShowDrawer"/> -->
  4. <!-- <view class="cm_ai_container_main" :style="{ paddingBottom: isIphoneX ? '208rpx' : '174rpx', paddingTop:CustomBar+'px' }"> -->
  5. <view class="cm_ai_container_main" :style="{ paddingBottom: isIphoneX ? '208rpx' : '174rpx' }">
  6. <scroll-view class="cm_ai_container" scroll-y="true" show-scrollbar="true" ref="scrollView" id="scrollChatView">
  7. <!--提问回答element-->
  8. <view class="cm_ai_answer_main" id="cm_ai_answer">
  9. <chat-html ref="chatHtml" :messages='messages' @scrollUpdate="scrollToBottom" />
  10. </view>
  11. </scroll-view>
  12. <!--提问文本框-->
  13. <view class="cm_ai_content" :style="{ height: isIphoneX ? (120+68) +'rpx' : (120+34) +'rpx', paddingBottom: isIphoneX ? '68rpx' : '34rpx' }">
  14. <view class="cm_ai_input">
  15. <input class="cm_ai_textarea" v-model="questionTextarea" cursor-spacing="30" confirm-type="send" maxlength="200"
  16. placeholder="请输入您想了解的内容" @confirm="handleAskQuestion" />
  17. <view class="cm_ai_button" :class="isLoading ? 'none' : ''" @click="handleAskQuestion">
  18. <text class="iconfont icon-fasong"></text>
  19. </view>
  20. </view>
  21. </view>
  22. </view>
  23. <!-- 对话记录 -->
  24. <!-- <chatDrawer :rightDrawer="isRightDrawer"/> -->
  25. </view>
  26. </template>
  27. <script>
  28. import { mapState, mapMutations } from 'vuex'
  29. import chatCustom from './components/chat-custom' //地址信息
  30. import chatDrawer from './components/chat-drawer' //地址信息
  31. import chatHtml from './components/chat-html' //地址信息
  32. export default {
  33. components: {
  34. chatCustom,
  35. chatDrawer,
  36. chatHtml
  37. },
  38. data() {
  39. return {
  40. StaticUrl: this.$Static,
  41. isIphoneX: this.$store.state.isIphoneX,
  42. CustomBar:this.CustomBar,// 顶部导航栏高度
  43. isRightDrawer:false,
  44. isLoading: false,
  45. nvabarData: { //顶部自定义导航
  46. haveBack:true,
  47. haveHome:true,
  48. showCapsule:1, // 是否显示左上角图标 1表示显示 0表示不显示,
  49. showSearch: 0,
  50. title: '', // 导航栏 中间的标题
  51. bgColor: '#f5f4f6 ', // 导航栏 中间的标题
  52. textLeft:this.$store.state.isIphone
  53. },
  54. chatParams: {
  55. userId: '',
  56. question: ''
  57. },
  58. questionTextarea: '',
  59. probeChatId: '',
  60. probeIndex: 0,
  61. messages: [],
  62. }
  63. },
  64. onLoad(option) {
  65. },
  66. filters: {
  67. },
  68. computed: {
  69. ...mapState(['hasLogin', 'userInfo', ])
  70. },
  71. methods: {
  72. // 初始化
  73. async initGetStotage() {
  74. const userInfo = await this.$api.getStorage()
  75. this.chatParams.userId = userInfo.userId
  76. this.questionTextarea = ''
  77. this.probeIndex = 0
  78. this.messages = []
  79. },
  80. // 发送
  81. async handleAskQuestion() {
  82. if (!this.hasLogin) {
  83. this.$util.msg('请您登陆后使用AI助手', 2000)
  84. setTimeout(() => {
  85. this.$api.navigateTo('/pages/login/login')
  86. }, 2000)
  87. return
  88. } else {
  89. this.chatParams.question = this.questionTextarea
  90. if (this.isLoading) {
  91. return
  92. }
  93. if (!this.chatParams.question) {
  94. this.$util.msg('请输入内容', 2000)
  95. return
  96. }
  97. this.messages.push({
  98. question: this.chatParams.question,
  99. from: 'me',
  100. typing: false,
  101. currentLength: 0
  102. })
  103. if (this.probeIndex === 0) {
  104. this.messages.push({
  105. question: `老板,稍等一下哈,为你查询${this.chatParams.question}的相关信息。`,
  106. from: 'bot',
  107. typing: false,
  108. currentLength: 0
  109. })
  110. }
  111. this.questionTextarea = ''
  112. this.isLoading = true
  113. setTimeout(() => {
  114. if (this.probeIndex === 0) {
  115. this.handleUserNewChat(this.chatParams)
  116. } else {
  117. this.handleUserSecondChat({ chatId: this.probeChatId, ...this.chatParams })
  118. }
  119. }, 1000)
  120. }
  121. },
  122. //初次提问
  123. async handleUserNewChat(chatParams) {
  124. try {
  125. const res = await this.UserService.userNewChat(chatParams)
  126. const data = res.data
  127. this.probeIndex++
  128. this.probeChatId = data.chatId
  129. this.messages.push({ question: data.result, from: 'bot', typing: false, currentLength: 0 })
  130. this.isLoading = false
  131. } catch (error) {
  132. console.log('error',error)
  133. const msgMap = {
  134. '-1':`您好,目前没有找到与${chatParams.question}相关的信息,可以换个说法试试。`,
  135. '-2':'您的此次对话已超出对话轮次上限,可以刷新页面或新建对话重试。',
  136. '-3':'您的单日对话次数已超出上限,请明日再来尝试提问。'
  137. }
  138. this.messages.push({ question: msgMap[error.code], from: 'bot', typing: false, currentLength: 0 })
  139. this.isLoading = false
  140. }
  141. },
  142. // 追问
  143. async handleUserSecondChat(chatParams) {
  144. try {
  145. const res = await this.UserService.userSecondChat(chatParams)
  146. const data = res.data
  147. this.messages.push({ question: data.result, from: 'bot', typing: false, currentLength: 0 })
  148. this.isLoading = false
  149. } catch (error) {
  150. console.log('error',error)
  151. }
  152. },
  153. handleShowDrawer(){
  154. this.isRightDrawer = true
  155. },
  156. scrollToBottom(flag) {
  157. // console.log('flag',flag)
  158. // this.$nextTick( async () => {
  159. // const scrollChatView = await this.$util.boundingClientRect(this, '#scrollChatView', false)
  160. // // console.log('scrollChatView',scrollChatView.height)
  161. // uni.pageScrollTo({
  162. // duration: 300, //过渡时间必须为0,uniapp bug,否则运行到手机会报错
  163. // scrollTop: scrollChatView.height,
  164. // })
  165. // // this.$refs.scrollView.scrollTop = lastCHatMain.top + lastCHatMain.height
  166. // })
  167. },
  168. //滑动到最底部
  169. async handleScrollUpdate(flag) {
  170. if (flag) {
  171. this.$refs.scrollView.scrollIntoView('#lastElementId', {
  172. behavior: 'smooth' // 平滑滚动
  173. })
  174. }
  175. }
  176. },
  177. onPullDownRefresh() {
  178. // 下拉刷新
  179. setTimeout(() => {
  180. this.probeIndex = 0
  181. this.messages = []
  182. uni.stopPullDownRefresh()
  183. }, 200)
  184. },
  185. onShow() {
  186. this.initGetStotage()
  187. }
  188. }
  189. </script>
  190. <style lang="scss">
  191. page {
  192. width: 100%;
  193. height: 100%;
  194. background-color: #e6ebf7 !important;
  195. }
  196. .cm_ai_container_main {
  197. width: 100%;
  198. height: 100%;
  199. box-sizing: border-box;
  200. background-image: radial-gradient(circle at 14% 85%, #e7ecf7 0, rgba(231, 236, 247, 0) 37%), radial-gradient(circle at 3.4% 3.7%, rgba(245, 237, 241, .5) 0, rgba(245, 237, 241, 0) 28%), radial-gradient(circle at 100% 18%, #e8ebea 0, hsla(160, 7%, 92%, 0) 30%), linear-gradient(180deg, #f5f4f6, #e6ebf7);
  201. .cm_ai_content {
  202. width: 100%;
  203. padding:20rpx 24rpx 0 24rpx;
  204. background-color: #e6ebf7 !important;
  205. box-sizing: border-box;
  206. position: fixed;
  207. left: 0;
  208. bottom: 0;
  209. .cm_ai_input {
  210. display: flex;
  211. align-items: center;
  212. justify-content: space-between;
  213. width: 100%;
  214. height: 100%;
  215. background-color: #FFFFFF;
  216. box-shadow: 0 16rpx 20rpx 0 rgba(174, 167, 223, .2);
  217. border-radius: 50rpx;
  218. box-sizing: border-box;
  219. padding: 10rpx 100rpx 10rpx 10rpx;
  220. position: relative;
  221. .cm_ai_textarea {
  222. width: 100%;
  223. height: 80rpx !important;
  224. font-size: 30rpx;
  225. line-height: 80rpx;
  226. background-color: transparent;
  227. border: none;
  228. box-shadow: none;
  229. overflow: auto;
  230. scrollbar-width: none;
  231. resize: none;
  232. box-sizing: border-box;
  233. padding-left: 24rpx;
  234. }
  235. .cm_ai_button {
  236. width: 100rpx;
  237. height: 100rpx;
  238. line-height: 100rpx;
  239. border-radius: 20rpx;
  240. display: inline-flex;
  241. align-items: center;
  242. justify-content: center;
  243. font-size: 24rpx;
  244. position: absolute;
  245. right: 0;
  246. &.none {
  247. background-image: radial-gradient(circle at 14% 85%, #e7ecf7 0, rgba(231, 236, 247, 0) 37%);
  248. .icon-fasong {
  249. color: #e6e6e6;
  250. }
  251. }
  252. .icon-fasong {
  253. font-size: 50rpx;
  254. color: #ff5b00;
  255. }
  256. }
  257. }
  258. }
  259. .cm_ai_container {
  260. width: 100%;
  261. height: 100%;
  262. display: flex;
  263. flex-direction: column;
  264. box-sizing: border-box;
  265. padding: 0 24rpx;
  266. .cm_ai_answer_main {
  267. width: 100%;
  268. min-height: 600rpx;
  269. overflow-y: auto;
  270. flex: 9;
  271. }
  272. }
  273. }
  274. </style>