chat.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. <template>
  2. <!-- <view style="padding-bottom: 248rpx;"> -->
  3. <view style="">
  4. <!-- #ifdef H5 -->
  5. <view style="color: #000;">
  6. <tn-nav-bar backgroundColor="#fff">GPT</tn-nav-bar>
  7. <view :style="{ height: tobheight + 'px' }"></view>
  8. </view>
  9. <!-- #endif -->
  10. <view class="content" @touchmove="">
  11. <view class="msg-list">
  12. <!-- 顶部切换模型内容块 -->
  13. <view class="row">
  14. <block>
  15. <view class="other">
  16. <view class="left" @click="">
  17. <u-image
  18. src="https://dev.iduomi.cc/addons/wike_chatgpt/public/static/storage/presets/mode/1.png"
  19. mode="widthFix" radius="5" width="40" height="40"></u-image>
  20. </view>
  21. <view class="right">
  22. <view class="username">
  23. <view class="name"></view>
  24. <view class="time">{{robotName}}</view>
  25. </view>
  26. <view class="bubble">
  27. <view class="content">
  28. <view style="font-size: 32rpx;">我是您的AI助手,您可以向我提出任何问题~</view>
  29. </view>
  30. </view>
  31. </view>
  32. </view>
  33. </block>
  34. </view>
  35. <block v-for="(row, index) in talkList" :key="index" :id="'msg' + row.id">
  36. <view class="row">
  37. <block>
  38. <view class="my" v-if="row.fromid==1">
  39. <view class="left">
  40. <view class="username">
  41. <view class="name">{{ row.nickname }}</view>
  42. </view>
  43. <u-icon v-if="row.content !='该问题已被隐藏!'" @click="copyText(index)" name="file-text"
  44. color="#9e9e9e82" size="22"></u-icon>
  45. <view v-if="row.type == 1" class="bubble" style="color: #fff;margin-left: 15rpx;">
  46. <rich-text :nodes="row.content" @longtap="copy" :data-text="row.content"
  47. selectable="true"></rich-text>
  48. </view>
  49. </view>
  50. <view class="right">
  51. <u-image :src="row.avatar?row.avatar:'/static/images/head.jpg'" mode="widthFix"
  52. radius="5" width="42" height="42"></u-image>
  53. </view>
  54. </view>
  55. <!-- GPT -->
  56. <view class="other" v-if="row.fromid==-1">
  57. <view class="left" v-if="true" @click="">
  58. <u-image
  59. src="https://dev.iduomi.cc/addons/wike_chatgpt/public/static/storage/presets/mode/1.png"
  60. mode="widthFix" radius="5" width="42" height="42"></u-image>
  61. </view>
  62. <view class="right">
  63. <view class="username" v-if="true">
  64. <view class="name"></view>
  65. <view class="time">{{row.nickname}}</view>
  66. </view>
  67. <view v-if="row.type == 1" class="bubble"
  68. style="display: block;position: relative;">
  69. <view>
  70. <zero-markdown-view v-if="row.done" :themeColor="themeColor"
  71. :markdown="row.content"></zero-markdown-view>
  72. <text v-else @longtap="copy"
  73. :data-text="row.content">{{ row.content.replace(/^\s+|\s+$/g, '') }}</text>
  74. <!-- <text v-if="row.content == '正在思考中...'">{{ second }}s</text> -->
  75. <text class="flash" v-if="row.show_flash">│</text>
  76. </view>
  77. </view>
  78. <view v-if="row.done" class="tn-flex align-center justify-between operate">
  79. <view @click="copyText(index)" hover-class="hoversubmit"
  80. class="tn-flex align-center">
  81. <u-icon name="file-text" top="1" color="#68d7bb" size="20"></u-icon>
  82. <view class="duplicate">复制回答</view>
  83. </view>
  84. </view>
  85. </view>
  86. </view>
  87. </block>
  88. </view>
  89. </block>
  90. </view>
  91. <view class="bottomheight"></view>
  92. <view class="env"></view>
  93. </view>
  94. <view class="box-2">
  95. <view class="flex_col">
  96. <view class="flex_grow">
  97. <u--textarea height="45" @blur="" @focus="focusinput" fixed :showConfirmBar="false"
  98. v-model="content" placeholder="请输入您的问题..." maxlength="-1" border="none"
  99. :cursorSpacing="80"></u--textarea>
  100. </view>
  101. <button class="send" @click.prevent="send(content)">发送</button>
  102. <!-- <button class="send" @click.prevent="test">测试</button> -->
  103. </view>
  104. </view>
  105. </view>
  106. </template>
  107. <script>
  108. import {
  109. sendGpt
  110. } from '@/api/public/index.js';
  111. import uploadUrl from '@/common/config.js'
  112. import {
  113. userInfo,
  114. sysParms
  115. } from '@/api/my/index.js'
  116. export default {
  117. components: {
  118. },
  119. data() {
  120. return {
  121. robotName: '数趣AI小助手',
  122. talkList: [],
  123. thecontent: '',
  124. content: '',
  125. scrollTop: 999999,
  126. scrollAnimation: false,
  127. tobheight: 45,
  128. themeColor: '#007AFF',
  129. codeBgColor: '#26B3A0',
  130. userInfo: {},
  131. freeCount: 5,
  132. freeCountSum: 0
  133. };
  134. },
  135. computed: {
  136. },
  137. onShow() {
  138. if (uni.getStorageSync('clickStudyBtn')) {
  139. uni.removeStorageSync('clickStudyBtn')
  140. }
  141. if (uni.getStorageSync('myScoreId')) {
  142. uni.removeStorageSync('myScoreId')
  143. }
  144. },
  145. async onLoad() {
  146. let ress = await sysParms()
  147. console.log('gpt页系统设置信息返回值', ress.data[6].value);
  148. if (ress.code == 0) {
  149. this.freeCount = ress.data[6].value
  150. this.freeCountSum = ress.data[6].value
  151. }
  152. if (uni.getStorageSync('token')) {
  153. // if (!uni.getStorageSync('hasForbidden').status) {
  154. // return uni.showToast({
  155. // title: uni.getStorageSync('hasForbidden').msg,
  156. // icon: 'none'
  157. // });
  158. // }
  159. this.freeCount = 99999
  160. let res = await userInfo()
  161. console.log('gpt页用户个人信息返回值', res);
  162. if (res.code == 0) {
  163. uni.removeStorageSync('hasForbidden')
  164. this.userInfo = res.data
  165. } else {
  166. // console.log('您的账号已被禁用,请练习管理员', res);
  167. }
  168. }
  169. },
  170. methods: {
  171. async test() {
  172. console.log('sendGpt()66666666666666666');
  173. let res = await sendGpt({
  174. message: '3699+1'
  175. })
  176. if (res.code == 0) {
  177. console.log('sendGpt()', res);
  178. }
  179. },
  180. copy(e) {
  181. var that = this;
  182. var text = e.currentTarget.dataset.text;
  183. uni.setClipboardData({
  184. data: text,
  185. success(res) {
  186. uni.getClipboardData({
  187. success(res) {}
  188. });
  189. }
  190. });
  191. },
  192. focusinput() {
  193. this.showexpand = false;
  194. this.$nextTick(() => {
  195. uni.pageScrollTo({
  196. scrollTop: 9999,
  197. duration: 300
  198. });
  199. });
  200. },
  201. // 发送信息
  202. async send(e) {
  203. if (uni.getStorageSync('hasForbidden').status == 0) {
  204. return uni.showToast({
  205. title: '抱歉,您的账号已被禁用,请联系管理员解封后使用!',
  206. icon: 'none'
  207. });
  208. }
  209. if (this.freeCount <= 0) {
  210. uni.showToast({
  211. title: `抱歉,您的免费次数(${this.freeCountSum}次)已用完!`,
  212. icon: 'none'
  213. });
  214. return;
  215. }
  216. let that = this;
  217. if (that.talkList.length > 1 && !that.talkList[that.talkList.length - 1].done) {
  218. uni.showToast({
  219. title: '正在输入回答,请等待输入完成',
  220. icon: 'none'
  221. });
  222. return;
  223. }
  224. if (!e) {
  225. uni.showToast({
  226. title: '请输入有效的内容',
  227. icon: 'none'
  228. });
  229. return;
  230. }
  231. this.thecontent = e;
  232. // 将当前发送信息 添加到消息列表。
  233. let data = {
  234. id: new Date().getTime(),
  235. content: e,
  236. type: 1,
  237. toid: 666,
  238. fromid: 1,
  239. avatar: this.userInfo.avatar,
  240. nickname: '我',
  241. done: true
  242. };
  243. this.talkList.push(data);
  244. let chat_data = {
  245. id: new Date().getTime(),
  246. content: '正在思考中...',
  247. type: 1,
  248. toid: 666,
  249. fromid: -1,
  250. avatar: 'https://nywhcm.com/addons/wike_aging/public/static/storage/presets/mode/1.png',
  251. nickname: this.robotName,
  252. show_flash: true,
  253. done: false
  254. };
  255. this.talkList.push(chat_data);
  256. this.$nextTick(() => {
  257. // 清空内容框中的内容
  258. this.content = '';
  259. uni.pageScrollTo({
  260. scrollTop: 99999,
  261. duration: 300
  262. });
  263. });
  264. // 修改,方案二
  265. // let res9 = await sendGpt({
  266. // message: that.thecontent
  267. // })
  268. // if (res9.code == 0) {
  269. // console.log('sendGpt()', res9);
  270. // }else{
  271. // }
  272. // 原方案
  273. // let url = 'https://www.ai5566.top/api/chat/send'
  274. let url = uploadUrl.chatUrl
  275. fetch(url, {
  276. method: 'POST',
  277. headers: {
  278. 'Content-Type': 'application/json',
  279. 'Authorization': uni.getStorageSync('token')
  280. },
  281. body: JSON.stringify({
  282. // message:'介绍一下思维定制'
  283. message: that.thecontent
  284. })
  285. }).then(async (resp) => {
  286. let result = await resp.text()
  287. const res = JSON.parse(result)
  288. if ((resp.status >= 200 && resp.status < 300) && res.code == 0) {
  289. that.talkList[that.talkList.length - 1].done = true
  290. that.talkList[that.talkList.length - 1].show_flash = false
  291. that.talkList[that.talkList.length - 1].content = res.data
  292. that.$nextTick(() => {
  293. uni.pageScrollTo({
  294. scrollTop: 9999,
  295. duration: 1000
  296. });
  297. })
  298. that.freeCount--
  299. console.log('游客剩余提问次数', that.freeCount)
  300. // 此处发送记录问答记录的请求
  301. console.log('每次记录问答参数', {
  302. ques_content: that.talkList[that.talkList.length - 2].content,
  303. ai_aswerContent: that.talkList[that.talkList.length - 1].content
  304. })
  305. } else {
  306. that.talkList[that.talkList.length - 1].done = true
  307. that.talkList[that.talkList.length - 1].show_flash = false
  308. that.talkList[that.talkList.length - 1].content = '本次提问由于网络超时出错啦,请稍后重新提问'
  309. uni.showToast({
  310. title: '本次提问由于网络超时出错啦,请稍后重新提问',
  311. icon: 'none'
  312. })
  313. }
  314. }).catch((err) => {
  315. that.talkList[that.talkList.length - 1].done = true
  316. that.talkList[that.talkList.length - 1].show_flash = false
  317. that.talkList[that.talkList.length - 1].content = '本次提问由于网络超时出错啦,请稍后重新提问'
  318. uni.showToast({
  319. title: '本次提问由于网络超时出错啦,请稍后重新提问',
  320. icon: 'none'
  321. })
  322. })
  323. },
  324. // 复制文本
  325. copyText(e) {
  326. uni.setClipboardData({
  327. data: this.talkList[e].content,
  328. success: function() {
  329. // console.log('success');
  330. uni.showToast({
  331. title: '复制成功'
  332. });
  333. }
  334. });
  335. },
  336. }
  337. };
  338. </script>
  339. <style lang="scss" scoped>
  340. @import '@/pages/chat/global.scss';
  341. @import './chat.scss';
  342. </style>