index.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <view class="page_container">
  3. <custom-nav-bar title="视频会议" />
  4. <view class="action_row">
  5. <view class="action_item" @click="joinMeeting">
  6. <image src="https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/meeting_join.png" mode="" />
  7. <text>加入会议</text>
  8. </view>
  9. <view class="action_item" @click="createQuickMeeting">
  10. <image src="https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/meeting_quick.png" mode="" />
  11. <text>快速会议</text>
  12. </view>
  13. <view class="action_item" @click="reserveMeeting">
  14. <image src="https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/meeting_reserve.png" mode="" />
  15. <text>预约会议</text>
  16. </view>
  17. </view>
  18. <view v-if="!isLoading" class="record_list">
  19. <view class="record_item" v-for="item in records" :key="item.info.systemGenerated.meetingID"
  20. @click="toDetals(item)">
  21. <view class="title_row">
  22. <view class="title">
  23. {{ item.info.creatorDefinedMeeting.title }}
  24. </view>
  25. <view class="icon" :style="{
  26. 'background-color':
  27. item.state * 1000 ? '#0089FF' : '#FFB300',
  28. }">
  29. {{ item.state * 1000 ? '未开始' : '已开始' }} </view>
  30. </view>
  31. <view class="sub_title">
  32. <text>{{ item.startTime + "-" + item.endTime }}</text>
  33. <text>{{ ' 发起人:' + item.info.systemGenerated.creatorNickname }}</text>
  34. </view>
  35. </view>
  36. </view>
  37. <view v-else class="loading">
  38. <u-loading-icon></u-loading-icon>
  39. </view>
  40. </view>
  41. </template>
  42. <script>
  43. import { mapGetters } from "vuex";
  44. import CustomNavBar from "../../../components/CustomNavBar/index.vue";
  45. import IMSDK from "openim-uniapp-polyfill";
  46. import dayjs from "dayjs";
  47. import { meetingModule } from "../../../util/imCommon";
  48. import { getMeetings, createImmediateMeeting } from '../../../api/meeting'
  49. import config from "../../../common/config";
  50. export default {
  51. components: {
  52. CustomNavBar,
  53. },
  54. data() {
  55. return {
  56. isRequestMeeting: false,
  57. isLoading: false,
  58. records: [],
  59. };
  60. },
  61. computed: {
  62. ...mapGetters(["storeSelfInfo"]),
  63. },
  64. onShow() {
  65. this.getMeetingRecords();
  66. IMSDK.subscribe("dismiss", this.getMeetingRecords);
  67. },
  68. methods: {
  69. getMeetingRecords() {
  70. this.isLoading = true
  71. getMeetings({
  72. userID: this.storeSelfInfo.userID,
  73. status: ["Scheduled", "In-Progress"],
  74. })
  75. .then(async (data) => {
  76. console.log('getMeetings', data)
  77. let meetingDetails = data.meetingDetails
  78. meetingDetails = (meetingDetails ?? []).filter((item) =>
  79. Boolean(item.info?.creatorDefinedMeeting?.hostUserID),
  80. );
  81. if (meetingDetails.length > 0) {
  82. const { data } = await IMSDK.asyncApi(
  83. IMSDK.IMMethods.GetUsersInfo,
  84. IMSDK.uuid(),
  85. meetingDetails.map(
  86. (item) => item.info?.creatorDefinedMeeting?.hostUserID,
  87. ),
  88. );
  89. meetingDetails.map((meeting) => {
  90. const findUser = data.find(
  91. (user) =>
  92. user.userID === meeting.info?.creatorDefinedMeeting?.hostUserID,
  93. );
  94. meeting.hostFaceURL = findUser?.faceURL;
  95. meeting.startTime = dayjs(meeting.info?.creatorDefinedMeeting
  96. ?.scheduledTime * 1000).format("M-DD HH:mm");
  97. meeting.endTime = dayjs((meeting.info?.creatorDefinedMeeting
  98. ?.scheduledTime + meeting.info?.creatorDefinedMeeting
  99. ?.meetingDuration) * 1000).format("HH:mm");
  100. meeting.state = Date.now() < meeting.info?.creatorDefinedMeeting?.scheduledTime * 1000
  101. });
  102. this.records = meetingDetails;
  103. console.log('meetingDetails', meetingDetails)
  104. }
  105. })
  106. .finally(() => {
  107. this.isLoading = false
  108. })
  109. },
  110. toDetals(record) {
  111. uni.$u.route("/pages_im/pages/common/meetingDetails/index", {
  112. meetingData: JSON.stringify(record)
  113. });
  114. },
  115. reserveMeeting() {
  116. uni.$u.route("/pages_im/pages/common/reserveMeeting/index", {
  117. isUpdate: false,
  118. });
  119. },
  120. joinMeeting() {
  121. uni.$u.route("/pages_im/pages/common/joinMeeting/index");
  122. },
  123. createQuickMeeting() {
  124. if (this.isRequestMeeting) return;
  125. this.isRequestMeeting = true;
  126. const params = {
  127. creatorUserID: this.storeSelfInfo.userID,
  128. creatorDefinedMeetingInfo: {
  129. title: this.storeSelfInfo.nickname + '发起的视频会议',
  130. scheduledTime: dayjs().unix(),
  131. meetingDuration: 3600,
  132. password: "",
  133. },
  134. setting: {
  135. canParticipantsEnableCamera: true,
  136. canParticipantsUnmuteMicrophone: true,
  137. canParticipantsShareScreen: true,
  138. disableCameraOnJoin: true,
  139. disableMicrophoneOnJoin: true,
  140. },
  141. };
  142. createImmediateMeeting(params).then((data) => {
  143. const meetingData = {
  144. liveURL: data.liveKit?.url,
  145. token: data.liveKit?.token,
  146. roomID: data.detail?.info?.systemGenerated?.meetingID,
  147. imToken: uni.getStorageSync("IMToken"),
  148. baseURL: config.getApiUrl()
  149. };
  150. meetingModule.startMeeting(meetingData);
  151. setTimeout(() => {
  152. this.getMeetingRecords();
  153. }, 500);
  154. }).finally(() => {
  155. this.isRequestMeeting = false
  156. })
  157. },
  158. },
  159. onBackPress(options) {
  160. uni.switchTab({
  161. url: "/pages_im/pages/conversation/conversationList/index",
  162. });
  163. return true;
  164. },
  165. };
  166. </script>
  167. <style lang="scss" scoped>
  168. .page_container {
  169. .action_row {
  170. display: flex;
  171. justify-content: space-between;
  172. margin: 0 32rpx;
  173. padding: 48rpx 0 32rpx;
  174. border-bottom: 1px solid rgba(126, 134, 142, 0.16);
  175. .action_item {
  176. display: flex;
  177. flex-direction: column;
  178. align-items: center;
  179. padding: 0 20rpx;
  180. font-size: 28rpx;
  181. color: #16191c;
  182. image {
  183. width: 50px;
  184. height: 50px;
  185. margin-bottom: 12rpx;
  186. }
  187. }
  188. }
  189. .record_list {
  190. flex: 1;
  191. .record_item {
  192. padding: 24rpx 42rpx;
  193. .title_row {
  194. display: flex;
  195. align-items: center;
  196. margin-bottom: 12rpx;
  197. .title {
  198. @include nomalEllipsis();
  199. max-width: 50vw;
  200. }
  201. .icon {
  202. padding: 0 12rpx;
  203. height: 40rpx;
  204. line-hight: 40rpx;
  205. font-size: 24rpx;
  206. color: #fff;
  207. margin-left: 16rpx;
  208. text-align: center;
  209. border-radius: 8rpx;
  210. }
  211. }
  212. .sub_title {
  213. font-size: 24rpx;
  214. color: #666;
  215. text:first-child {
  216. margin-right: 24rpx;
  217. }
  218. }
  219. }
  220. }
  221. .loading {
  222. flex: 1;
  223. display: flex;
  224. align-items: center;
  225. justify-content: center;
  226. }
  227. }
  228. </style>