ConversationHistoryContainer.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <template>
  2. <div class="conversation-history-container">
  3. <div class="conversation-history-left"></div>
  4. <div class="conversation-history-main">
  5. <HistoryName />
  6. <HistorySearchInput @search="handleHistorySearch">
  7. <HistoryTypeDropdown @typeSelected="handleTypeSelected" :list_status="api_status" />
  8. </HistorySearchInput>
  9. <HistoryList
  10. v-if="list_history.length !== 0"
  11. :list="list_history"
  12. :can_loadmore="can_loadmore"
  13. @loadmore="handleListLoadMore"
  14. @active="handleListItemActive"
  15. />
  16. <template v-if="api_status === 1 || api_status === 2">
  17. <div class="infomations-container">
  18. <a-spin :size="32" />
  19. </div>
  20. </template>
  21. <template v-if="api_status === 3 && list_history.length === 0">
  22. <div class="infomations-container">
  23. <a-empty> {{ $t('conversation.history_empty') }} </a-empty>
  24. </div>
  25. </template>
  26. <template v-if="api_status === 4">
  27. <div class="infomations-container">
  28. <a-result status="warning" :title="api_message"> </a-result>
  29. </div>
  30. </template>
  31. <template v-if="api_status === 5">
  32. <div class="infomations-container">
  33. <a-result status="error" :title="api_message"> </a-result>
  34. </div>
  35. </template>
  36. <div class="conversation-history-placeholder"></div>
  37. </div>
  38. <div class="conversation-history-right"></div>
  39. </div>
  40. </template>
  41. <script setup>
  42. import { ref, onMounted } from 'vue';
  43. import HistoryName from '../../modules/conversation-history/HistoryName.vue';
  44. import HistorySearchInput from '../../modules/conversation-history/HistorySearchInput.vue';
  45. import HistoryList from '../../modules/conversation-history/HistoryList.vue';
  46. import HistoryTypeDropdown from '../../modules/conversation-history/HistoryTypeDropdown.vue';
  47. import { apiConversationHistoryList } from '../../modules/conversation-history/api-conversation-history';
  48. import { getTodayZeroTimestamp, ONE_DAY, ONE_MONTH } from '../../utils/datetime';
  49. const emit = defineEmits(['historyActive']);
  50. const page_no = ref(1); // 当前页码
  51. const page_count = ref(50); // 每页显示的数量
  52. const search_text = ref(''); // 搜索字符串
  53. const agent_id = ref('');
  54. const can_loadmore = ref(true); // 是否可以加载更多
  55. // api请求的状态
  56. const api_status = ref(1); // api状态 1 请求未启动 2 请求进心中 3 请求已成功 4 请求失败(网络成功,但是code不等于200) 5 请求出错
  57. const api_message = ref(''); // 请求消息 与 api_status 对应的 message 消息内容
  58. // 历史记录列表数据
  59. const list_history = ref([]); // 历史记录的列表数据
  60. const count_today = ref(0); // 记录今天的数据量
  61. const count_month = ref(0); // 记录本月的数据量
  62. const count_earlier = ref(0); // 记录更早的数据量
  63. const today_zero = getTodayZeroTimestamp(); // 今天零点
  64. const yesterday_zero = today_zero - ONE_DAY; // 昨天零点
  65. const last_month_zero = yesterday_zero - ONE_MONTH; // 上个月(30天之前的)零点
  66. /**
  67. * 将数据进行分类
  68. * 依据时间戳,将列表数据分成三种类型:今天、本月、更早
  69. * 今天:从今天零点开始到现在
  70. * 本月:从今天零点之前,往前推30天
  71. * 更早:在30天之前的数据
  72. * @param res_list
  73. */
  74. function dropListByType(res_list) {
  75. res_list.forEach((item, index) => {
  76. let label_item = null; // label项目(今天、本月、更早以前)
  77. const content_item = item; // 数据项目
  78. const create_time = content_item.updated_time; // 会话创建时间
  79. if (create_time >= today_zero) {
  80. // 今天的数据
  81. if (count_today.value === 0) {
  82. label_item = {
  83. client_field_content_type: 'label',
  84. client_field_timestamp_type: 'today',
  85. id: 'today'
  86. };
  87. }
  88. // 非第0个数据
  89. content_item.client_field_timestamp_type = 'today'; // 客户端自定义字段: 时间类型
  90. content_item.client_field_content_type = 'content'; // 内容类别
  91. count_today.value = count_today.value + 1;
  92. } else if (create_time < today_zero && create_time > last_month_zero) {
  93. // 本月的数据
  94. if (count_month.value === 0) {
  95. label_item = {
  96. client_field_content_type: 'label',
  97. client_field_timestamp_type: 'month',
  98. id: 'month'
  99. };
  100. }
  101. content_item.client_field_timestamp_type = 'month'; // 客户端自定义字段: 时间类型
  102. content_item.client_field_content_type = 'content'; // 内容类别
  103. count_month.value = count_month.value + 1;
  104. } else {
  105. // 更早以前的数据
  106. if (count_earlier.value === 0) {
  107. label_item = {
  108. client_field_content_type: 'label',
  109. client_field_timestamp_type: 'earlier',
  110. id: 'earlier'
  111. };
  112. }
  113. content_item.client_field_timestamp_type = 'earlier'; // 客户端自定义字段: 时间类型
  114. content_item.client_field_content_type = 'content'; // 内容类别
  115. count_earlier.value = count_earlier.value + 1;
  116. }
  117. if (label_item) {
  118. list_history.value.push(label_item);
  119. }
  120. list_history.value.push(content_item);
  121. });
  122. }
  123. /**
  124. * 处理请求参数
  125. */
  126. const formatListOptions = () => {
  127. return {
  128. search: search_text.value,
  129. page: page_no.value,
  130. per_page: page_count.value,
  131. agent_id: agent_id.value
  132. };
  133. };
  134. /**
  135. * 调用api请求
  136. */
  137. const handleApiRequest = () => {
  138. // 处理查询参数
  139. const opts = formatListOptions();
  140. // 进入加载状态
  141. api_status.value = 2;
  142. api_message.value = '';
  143. apiConversationHistoryList(opts)
  144. .then((res) => {
  145. if (res.code / 1 === 200) {
  146. // 成功
  147. const res_list = res.data; // 历史记录列表
  148. if (res_list.length < page_count.value) {
  149. // 数据已经加载完成,不能加载更多了
  150. can_loadmore.value = false;
  151. } else {
  152. can_loadmore.value = true;
  153. }
  154. dropListByType(res_list);
  155. // api请求成功
  156. api_status.value = 3;
  157. api_message.value = 'success';
  158. } else {
  159. // api请求成功,但是业务失败
  160. api_status.value = 4;
  161. api_message.value = res.msg;
  162. }
  163. })
  164. .catch((err) => {
  165. // api请求出错
  166. api_status.value = 5;
  167. api_message.value = err.message;
  168. });
  169. };
  170. /**
  171. * 请求更多数据
  172. */
  173. const handleListLoadMore = () => {
  174. if (api_status.value === 2) {
  175. return;
  176. }
  177. if (!can_loadmore.value) {
  178. // 没有更多了
  179. return;
  180. }
  181. page_no.value = page_no.value + 1; // 页码加1
  182. // 调用api
  183. handleApiRequest();
  184. };
  185. /**
  186. * 点击某个历史记录触发的事件
  187. * @param history_id
  188. */
  189. const handleListItemActive = (history_id) => {
  190. emit('historyActive', {
  191. agent_id: agent_id.value, // agent_id值
  192. target_id: history_id
  193. });
  194. };
  195. /**
  196. * 开始搜索
  197. * @param value
  198. */
  199. const handleHistorySearch = (value) => {
  200. if (api_status.value === 2) {
  201. return;
  202. }
  203. search_text.value = value; // 搜索字符串
  204. page_no.value = 1; // 页码归位
  205. list_history.value = []; // 清空数据
  206. // 调用api
  207. handleApiRequest();
  208. };
  209. /**
  210. * 选定具体的类型,此时应该执行历史记录获取的请求
  211. * 当类型选定后,获取此类型对应的历史记录数据
  212. * @param type_item
  213. */
  214. const handleTypeSelected = (type_item) => {
  215. if (api_status.value === 2) {
  216. return;
  217. }
  218. // 记录Agent ID
  219. agent_id.value = type_item.id;
  220. page_no.value = 1; // 页码归位
  221. list_history.value = []; // 清空数据
  222. // 调用api
  223. handleApiRequest();
  224. };
  225. onMounted(() => {
  226. // // 调用api
  227. // handleApiRequest();
  228. });
  229. </script>
  230. <style lang="css" scoped>
  231. .conversation-history-container {
  232. display: flex;
  233. justify-content: center;
  234. margin-left: auto;
  235. margin-right: auto;
  236. }
  237. .conversation-history-left {
  238. width: 25%;
  239. flex-shrink: 0;
  240. }
  241. .conversation-history-right {
  242. width: 25%;
  243. flex-shrink: 0;
  244. }
  245. .conversation-history-main {
  246. /* width: 60%; */
  247. flex-grow: 1;
  248. height: 100%;
  249. margin-left: auto;
  250. margin-right: auto;
  251. display: flex;
  252. flex-direction: column;
  253. }
  254. /* 底部占位元素 */
  255. .conversation-history-placeholder {
  256. height: 50px;
  257. }
  258. .conversation-history-main .infomations-container {
  259. display: flex;
  260. justify-content: center;
  261. align-items: center;
  262. min-height: 200px;
  263. }
  264. </style>