index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. <template>
  2. <view class="content">
  3. <image class="bg-img" src="/static/image/home/orange_home_top_bg.png"></image>
  4. <view class="topbox ">
  5. <view class="status-bar"></view>
  6. <view class="topbox-a">消息</view>
  7. </view>
  8. <Dialog
  9. :visible="showDialog"
  10. :styleConfig="styleConfig"
  11. :handleClose="handleClose">
  12. <view
  13. v-for="(item, index) in chatList"
  14. :key="index"
  15. class="chat-container"
  16. @click.stop="handleContentClick(item)">
  17. <image
  18. class="item-icon"
  19. v-if="item.imgType === 'SINGLE'"
  20. src="../../assets/icon/singlePerson.svg"/>
  21. <image class="item-icon" v-else src="../../assets/icon/multiPerson.svg" />
  22. <view>{{ item.content }}</view>
  23. </view>
  24. </Dialog>
  25. <mescroll-body ref="mescrollRef" top="120rpx" bottom="0" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption" :up="upOption">
  26. <view class="TUI-conversation">
  27. <!-- <view class="create-group" @click="handleShow"> + 发起聊天</view> -->
  28. <myNotice v-for="(item,index) in noticeList" :key="index" :item="item"></myNotice>
  29. <TUIConversationList
  30. :noticeList='noticeList'
  31. :currentID="currrentConversationID"
  32. :conversationList="conversationList"
  33. @handleGotoItem="handleCurrrentConversation"/>
  34. </view>
  35. </mescroll-body>
  36. </view>
  37. </template>
  38. <script lang="ts">
  39. import { getLastAndReadStatus } from "@/api/user.js"
  40. import { getSopCourseStudyList } from "@/api/courseAnswer.js"
  41. import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
  42. import { defineComponent, reactive, toRefs, computed, onMounted,watch } from "vue";
  43. import { onNavigationBarButtonTap, onShow, onUnload } from "@dcloudio/uni-app";
  44. import TUIConversationList from "./conversation-list";
  45. import Dialog from "./components/dialog.vue";
  46. import store from "@/store";
  47. import { TUIConversationServer, TUIProfileServer } from "../../TUICore/server";
  48. import {getOrderIdByIm} from '@/api/inquiryOrder.js'
  49. import { isLogin,updateMsgDot } from "@/utils/common";
  50. import { showLoginPage } from "@/utils/login";
  51. import myNotice from "../../components/myNotice.vue";
  52. const TUIConversation = defineComponent({
  53. name: "TUIConversation",
  54. mixins: [ MescrollMixin], //mescroll-body写在子组件时
  55. components: {
  56. TUIConversationList,
  57. Dialog,
  58. myNotice
  59. },
  60. setup(props) {
  61. const timStore = store.state.timStore;
  62. // uni.$TUIKit.TUIConversationServer = new TUIConversationServer();
  63. // uni.$TUIKit.TUIProfileServer = new TUIProfileServer();
  64. // const { t } = uni.$TUIKit.config.i18n.useI18n();
  65. const data: any = reactive({
  66. //conversationList: [],
  67. conversationList: computed(() => timStore.conversationList),
  68. currrentConversationID: "",
  69. open: false,
  70. searchUserID: "",
  71. selectedList: [],
  72. searchUserList: [],
  73. step: 1,
  74. showDialog: false,
  75. unredCount:0,
  76. item: {
  77. flow: "out",
  78. status: "success",
  79. },
  80. styleConfig: {
  81. width: "150px",
  82. // height: '160px',
  83. padding: "16px 16px 0px",
  84. top: "8px",
  85. right: "8px",
  86. },
  87. chatList: [
  88. {
  89. imgType: "SINGLE",
  90. type: uni.$TIM.TYPES.CONV_C2C,
  91. id: 1,
  92. content: "发起会话",
  93. },
  94. {
  95. imgType: "GROUP",
  96. type: uni.$TIM.TYPES.GRP_WORK,
  97. id: 1,
  98. content: "工作群",
  99. },
  100. {
  101. imgType: "GROUP",
  102. type: uni.$TIM.TYPES.GRP_PUBLIC,
  103. id: 2,
  104. content: "社交群",
  105. },
  106. {
  107. imgType: "GROUP",
  108. type: uni.$TIM.TYPES.GRP_MEETING,
  109. id: 3,
  110. content: "会议群",
  111. },
  112. ],
  113. noticeLen: 0,
  114. mescroll:null,
  115. downOption: { //下拉刷新
  116. use:true,
  117. auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
  118. },
  119. upOption: {
  120. onScroll:false,
  121. auto: false,
  122. use: true, // 是否启用上拉加载; 默认true
  123. page: {
  124. pae: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
  125. size: 10 // 每页数据的数量,默认10
  126. },
  127. noMoreSize: 10, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示
  128. textNoMore:"",
  129. empty: {
  130. use : false ,
  131. icon:'https://cos.his.cdwjyyh.com/fs/20240423/cf4a86b913a04341bb44e34bb4d37aa2.png',
  132. tip: '暂无数据'
  133. }
  134. },
  135. dataList: [],
  136. sysmsg: '',
  137. noticeList: [],
  138. });
  139. const newMsgUpdate = computed(() => { return store.getters['newMsg/updateTime']});
  140. // 监听在线推送通知更新
  141. watch(newMsgUpdate, (newVal: any, oldVal: any) => {
  142. if (newVal) {
  143. console.log('接收到在线推送通知更新:', newVal);
  144. // 在这里处理更新逻辑
  145. if(isLogin()) {
  146. getLastAndReadmsg()
  147. data.mescroll.resetUpScroll()
  148. }
  149. }
  150. });
  151. onUnload(() => {
  152. uni.$TUIKit.TUIConversationServer.destroyed();
  153. });
  154. onNavigationBarButtonTap(() => {
  155. data.showDialog = !data.showDialog;
  156. });
  157. onShow(() => {
  158. if(isLogin()) {
  159. uni.$emit('refreshIM');
  160. store.commit("timStore/setConversationID", "");
  161. data.mescroll && data.mescroll.resetUpScroll();
  162. //getLastAndReadmsg();
  163. updateMsgDot();
  164. } else {
  165. showLoginPage()
  166. }
  167. });
  168. // 切换当前会话
  169. const handleCurrrentConversation = (value: any) => {
  170. if(value.lastMessage.cloudCustomData!=null && value.lastMessage.cloudCustomData!=''){
  171. try{
  172. var json=JSON.parse(value.lastMessage.cloudCustomData)
  173. store.commit("timStore/setImType", json.imType);
  174. store.commit("timStore/setOrderType", json.orderType);
  175. store.commit("timStore/setOrderId", json.orderId);
  176. store.commit("timStore/setFollowId", json.followId);
  177. store.commit("timStore/setType", json.type);
  178. }
  179. catch(e){
  180. }
  181. }
  182. data.currrentConversationID = value.conversationID;
  183. store.commit("timStore/setConversationID", value.conversationID);
  184. //uni.$TUIKit.TUIChatServer.updateStore(value.conversationID)
  185. uni.navigateTo({
  186. url: `../TUIChat/index?conversationName=${handleItemName(value)}`,
  187. });
  188. uni.$TUIKit.TUIConversationServer.setMessageRead(value.conversationID);
  189. const curConversation = data.conversationList.filter((item: any) => {
  190. return item.conversationID === value.conversationID;
  191. });
  192. store.commit("timStore/setConversation", curConversation);
  193. uni.$TUIKit.TUIConversationServer.getConversationProfile(
  194. value.conversationID
  195. ).then((res: any) => {
  196. // 通知 TUIChat 关闭当前会话
  197. store.commit("timStore/setConversation", res.data.conversation);
  198. // uni.$TUIKit.getStore()['TUIChat'].conversation = res.data.conversation;
  199. });
  200. };
  201. const handleShow = () => {
  202. data.showDialog = true;
  203. };
  204. // dialog 内部有效区域点击
  205. const handleContentClick = (item) => {
  206. data.showDialog = false;
  207. uni.navigateTo({
  208. url: `../TUIConversation/create?title=${item.content}&type=${item.type}`,
  209. });
  210. };
  211. // 关闭 dialog
  212. const handleClose = () => {
  213. data.showDialog = false;
  214. };
  215. const handleItemName = (item: any) => {
  216. let name = "";
  217. switch (item.type) {
  218. case uni.$TIM.TYPES.CONV_C2C:
  219. name = item?.userProfile.nick || item?.userProfile?.userID || "";
  220. break;
  221. case uni.$TIM.TYPES.CONV_GROUP:
  222. name = item.groupProfile.name || item?.groupProfile?.groupID || "";
  223. break;
  224. case uni.$TIM.TYPES.CONV_SYSTEM:
  225. name = "系统通知";
  226. break;
  227. }
  228. return name;
  229. };
  230. const mescrollInit = (mescroll: any)=> {
  231. data.mescroll = mescroll;
  232. if(isLogin()) {
  233. data.mescroll.resetUpScroll()
  234. }
  235. }
  236. /*下拉刷新的回调 */
  237. const downCallback = (mescroll: any)=>{
  238. mescroll.resetUpScroll()
  239. }
  240. const upCallback = (page: any)=> {
  241. //联网加载数据
  242. // let that = this;
  243. let param = {
  244. pageNum: page.num,
  245. pageSize: page.size
  246. };
  247. getSopCourseStudyList(param).then(res => {
  248. if(res.code==200){ //设置列表数据
  249. if (page.num == 1) {
  250. data.dataList = res.data.list;
  251. } else {
  252. data.dataList = data.dataList.concat(res.data.list);
  253. }
  254. data.mescroll.endBySize(res.data.list.length, res.data.total);
  255. }
  256. else{
  257. uni.showToast({
  258. icon:'none',
  259. title: "请求失败",
  260. });
  261. data.dataList = [];
  262. data.mescroll.endErr();
  263. }
  264. data.noticeList = uni.$u.deepClone(data.dataList);
  265. if(data.sysmsg){
  266. data.noticeList.push(data.sysmsg)
  267. }
  268. });
  269. getLastAndReadmsg()
  270. }
  271. const getLastAndReadmsg = ()=> {
  272. getLastAndReadStatus().then(res=>{
  273. if(res.code == 200) {
  274. data.sysmsg = res.data && res.data.id ? res.data : ''
  275. if(res.data && res.data.id) {
  276. data.sysmsg.mytype = 'other'
  277. }
  278. } else {
  279. data.sysmsg = ''
  280. }
  281. data.noticeList = uni.$u.deepClone(data.dataList)
  282. if(data.sysmsg) {
  283. data.noticeList.push(data.sysmsg)
  284. }
  285. })
  286. }
  287. return {
  288. ...toRefs(data),
  289. handleCurrrentConversation,
  290. handleContentClick,
  291. handleItemName,
  292. handleClose,
  293. handleShow,
  294. mescrollInit,
  295. downCallback,
  296. upCallback,
  297. getLastAndReadmsg,
  298. newMsgUpdate
  299. };
  300. },
  301. });
  302. export default TUIConversation;
  303. </script>
  304. <style lang="scss" scoped>
  305. .content {
  306. width: 100%;
  307. box-sizing: border-box;
  308. font-family: PingFang SC, PingFang SC;
  309. font-weight: 400;
  310. font-size: 24rpx;
  311. color: #999999;
  312. // background-image: url("@/static/image/home/home_top_bg.png");
  313. background-repeat: no-repeat;
  314. background-size: 100%;
  315. position: relative;
  316. z-index: 2;
  317. .bg-img{
  318. position: absolute;
  319. width: 100%;
  320. height: 524rpx;
  321. top: 0;
  322. left: 0;
  323. right: 0;
  324. bottom: 0;
  325. z-index: 0;
  326. }
  327. .topbox{
  328. position: absolute;
  329. top: 0;
  330. z-index: 1;
  331. color: #222;
  332. font-size: 36rpx;
  333. width: 100%;
  334. text-align: center;
  335. .topbox-a{
  336. }
  337. .status-bar{
  338. height: var(--status-bar-height);
  339. }
  340. }
  341. }
  342. .TUI-conversation {
  343. // background-color: #fff;
  344. // margin: 20rpx;
  345. .create-group {
  346. font-weight: 800px;
  347. padding: 10px;
  348. font-size: 14px;
  349. text-align: center;
  350. }
  351. }
  352. .chat-container {
  353. display: flex;
  354. align-items: center;
  355. margin-bottom: 16px;
  356. color: #444444;
  357. .item-icon {
  358. display: inline-block;
  359. width: 21px;
  360. height: 21px;
  361. margin-right: 12px;
  362. }
  363. }
  364. </style>