index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. <template>
  2. <view class="group_settings_container">
  3. <custom-nav-bar title="我的群聊" />
  4. <view class="group_settings_content">
  5. <!-- <view class="setting_row info_row">
  6. <view class="group_avatar" @click="updateGroupAvatar">
  7. <my-avatar :src="storeCurrentConversation.faceURL" :isGroup="true" size="46" />
  8. <image v-if="isOwner" class="edit_icon" src="../../../static/images/group_setting_edit.png" alt="" />
  9. </view>
  10. <view class="group_info">
  11. <view class="group_info_name">
  12. <text class="group_name">{{ storeCurrentConversation.showName }}({{
  13. storeCurrentGroup.memberCount
  14. }})</text>
  15. <image v-if="isOwner || isAdmin" @click="toUpdateGroupName" style="width: 24rpx; height: 24rpx"
  16. src="../../../static/images/group_edit.png" alt="" />
  17. </view>
  18. <text @click="copyGroupID" class="sub_title">{{
  19. storeCurrentConversation.groupID
  20. }}</text>
  21. </view>
  22. <image @click="toGroupQr" style="margin-right: 6rpx; width: 18px; height: 18px"
  23. src="../../../static/images/group_setting_qrcode.png" alt="" />
  24. </view> -->
  25. <view class="setting_row">
  26. <setting-item @click="isOwner || isAdmin ? toUpdateGroupName() : ''" title="群名称">
  27. <text class="sub_title">{{ storeCurrentConversation.showName }}</text>
  28. </setting-item>
  29. <setting-item title="群头像">
  30. <view class="group_avatar" @click="updateGroupAvatar">
  31. <my-avatar :src="storeCurrentConversation.faceURL" :isGroup="true" size="30" />
  32. <image v-if="isOwner" class="edit_icon" src="../../../static/images/group_setting_edit.png" alt="" />
  33. </view>
  34. </setting-item>
  35. <setting-item title="群ID">
  36. <text @click="copyGroupID" class="sub_title">{{ storeCurrentConversation.groupID }}</text>
  37. </setting-item>
  38. <setting-item title="群邀请码" :border="false">
  39. <image @click="toGroupQr" style="margin-right: 6rpx; width: 18px; height: 18px"
  40. src="../../../static/images/group_setting_qrcode.png" alt="" />
  41. </setting-item>
  42. </view>
  43. <group-member-row v-if="isJoinGroup" :isNomal="!isAdmin && !isOwner" :groupID="storeCurrentConversation.groupID"
  44. :memberCount="storeCurrentGroup.memberCount" :groupMemberList="groupMemberList" />
  45. <!-- <view class="setting_row">
  46. <search-action-row />
  47. </view> -->
  48. <view v-if="isJoinGroup" class="setting_row">
  49. <setting-item @click="handleHistory" title="历史记录"></setting-item>
  50. <setting-item title="聊天置顶" :loading="switchLoading.pin" @switch="changePin"
  51. :switchValue="storeCurrentConversation.isPinned" :is_switch="true" />
  52. <!-- <setting-item
  53. title="消息免打扰"
  54. :loading="switchLoading.opt"
  55. @switch="changeOpt($event, 2)"
  56. :switchValue="storeCurrentConversation.recvMsgOpt === 2"
  57. :is_switch="true"
  58. :border="false"
  59. /> -->
  60. <setting-item @click="toUpdatePage" title="我在群里的昵称" :border="false">
  61. <text class="sub_title">{{ storeCurrentMemberInGroup.nickname }}</text>
  62. </setting-item>
  63. </view>
  64. <view v-if="isJoinGroup" class="setting_row">
  65. <setting-item v-if="isOwner || isAdmin" @click="toGroupManage" title="群管理" />
  66. <setting-item v-if="isOwner" @click="toSetMute" title="禁言成员" />
  67. <setting-item v-if="isOwner" @click="toSetAdmin" title="设置管理员" />
  68. <setting-item @click="toGroupAnnouncement" title="群公告" :border="false"/>
  69. </view>
  70. <view class="group_row" @click="() => (confirmType = 'Clear')"> 清空聊天记录 </view>
  71. <view class="group_row" v-if="isJoinGroup" @click="() => (confirmType = isOwner ? 'Dismiss' : 'Quit')">
  72. {{ isOwner ? '解散群聊' : '退出群聊' }}
  73. </view>
  74. <u-modal :content="getConfirmContent" asyncClose :show="confirmType !== null" showCancelButton @confirm="confirm"
  75. @cancel="() => (confirmType = null)"></u-modal>
  76. </view>
  77. <u-toast ref="uToast"></u-toast>
  78. <action-sheet :groupID="storeCurrentConversation.groupID" :visible.sync="actionSheetVisible" />
  79. </view>
  80. </template>
  81. <script>
  82. import { mapGetters } from "vuex";
  83. import { GroupMemberListTypes } from "../../../constant";
  84. import IMSDK, {
  85. GroupMemberRole,
  86. GroupStatus,
  87. GroupVerificationType,
  88. IMMethods,
  89. MessageReceiveOptType,
  90. } from "openim-uniapp-polyfill";
  91. import CustomNavBar from "../../../components/CustomNavBar/index.vue";
  92. import MyAvatar from "../../../components/MyAvatar/index.vue";
  93. import SettingItem from "../../../components/SettingItem/index.vue";
  94. import GroupMemberRow from "./components/GroupMemberRow.vue";
  95. import ActionSheet from "./components/ActionSheet.vue";
  96. import SearchActionRow from "../singleSettings/components/SearchActionRow.vue";
  97. import { getPurePath } from "../../../util/common";
  98. import { premissionCheck } from "@/js_sdk/wa-permission/permission.js"
  99. const ConfirmTypes = {
  100. Clear: "Clear",
  101. Dismiss: "Dismiss",
  102. Quit: "Quit",
  103. };
  104. export default {
  105. components: {
  106. CustomNavBar,
  107. MyAvatar,
  108. SettingItem,
  109. GroupMemberRow,
  110. ActionSheet,
  111. SearchActionRow,
  112. },
  113. props: {},
  114. data() {
  115. return {
  116. actionSheetVisible: false,
  117. confirmType: null,
  118. switchLoading: {
  119. pin: false,
  120. opt: false,
  121. mute: false,
  122. },
  123. groupMemberList: [],
  124. isJoinGroup: true
  125. };
  126. },
  127. onLoad() {
  128. this.setIMListener();
  129. this.groupMemberDeletedHandler({ isInitail: true })
  130. },
  131. onUnload() {
  132. this.disposeIMListener();
  133. },
  134. watch: {
  135. "storeCurrentGroup.memberCount"() {
  136. this.getGroupMemberList();
  137. },
  138. },
  139. computed: {
  140. ...mapGetters([
  141. "storeCurrentConversation",
  142. "storeCurrentMemberInGroup",
  143. "storeCurrentGroup",
  144. ]),
  145. getConfirmContent() {
  146. if (this.confirmType === ConfirmTypes.Clear) {
  147. return "确定要清空聊天记录吗?";
  148. }
  149. if (this.confirmType === ConfirmTypes.Quit) {
  150. return "确定要退出当前群聊吗?";
  151. }
  152. if (this.confirmType === ConfirmTypes.Dismiss) {
  153. return "确定要解散当前群聊吗?";
  154. }
  155. return "";
  156. },
  157. isOwner() {
  158. return this.storeCurrentMemberInGroup.roleLevel === GroupMemberRole.Owner;
  159. },
  160. isAdmin() {
  161. return this.storeCurrentMemberInGroup.roleLevel === GroupMemberRole.Admin;
  162. },
  163. getGroupVerStr() {
  164. if (
  165. this.storeCurrentGroup.needVerification ===
  166. GroupVerificationType.ApplyNeedInviteNot
  167. ) {
  168. return "群成员邀请无需验证";
  169. }
  170. if (
  171. this.storeCurrentGroup.needVerification === GroupVerificationType.AllNot
  172. ) {
  173. return "允许所有人加群";
  174. }
  175. return "需要发送验证消息";
  176. },
  177. getGroupTypeStr() {
  178. return "工作群";
  179. },
  180. isAllMuted() {
  181. return this.storeCurrentGroup.status === GroupStatus.Muted;
  182. },
  183. },
  184. methods: {
  185. handleHistory() {
  186. uni.navigateTo({
  187. url: '/pages_im/pages/conversation/searchMessage/index'
  188. });
  189. },
  190. getGroupMemberList() {
  191. IMSDK.asyncApi(IMSDK.IMMethods.GetGroupMemberList, IMSDK.uuid(), {
  192. groupID: this.storeCurrentConversation.groupID,
  193. filter: 0,
  194. offset: 0,
  195. count: !this.isAdmin && !this.isOwner ? 9 : 8,
  196. }).then(({ data }) => {
  197. this.groupMemberList = [...data];
  198. }).catch((err) => {
  199. console.log(err);
  200. });
  201. },
  202. toGroupManage() {
  203. uni.navigateTo({
  204. url: "/pages_im/pages/conversation/groupManage/index",
  205. });
  206. },
  207. toMemberAuthority() {
  208. uni.navigateTo({
  209. url: "/pages_im/pages/conversation/memberAuthority/index",
  210. });
  211. },
  212. toSearchMessage() {
  213. uni.navigateTo({
  214. url: "/pages_im/pages/conversation/searchMessage/index",
  215. });
  216. },
  217. toGroupAnnouncement() {
  218. uni.navigateTo({
  219. url: `/pages_im/pages/conversation/groupAnnouncement/index`,
  220. });
  221. },
  222. toSetMute() {
  223. uni.navigateTo({
  224. url: `/pages_im/pages/conversation/groupMemberList/index?type=${GroupMemberListTypes.Mute}&groupID=${this.storeCurrentGroup.groupID}`,
  225. });
  226. },
  227. toSetAdmin() {
  228. uni.navigateTo({
  229. url: `/pages_im/pages/conversation/groupMemberList/index?type=${GroupMemberListTypes.SetAdmin}&groupID=${this.storeCurrentGroup.groupID}`,
  230. });
  231. },
  232. toUpdatePage() {
  233. uni.navigateTo({
  234. url: `/pages_im/pages/conversation/updateGroupOrNickname/index?sourceInfo=${JSON.stringify(
  235. this.storeCurrentMemberInGroup,
  236. )}`,
  237. });
  238. },
  239. toUpdateGroupName() {
  240. if (!this.isAdmin && !this.isOwner) {
  241. return;
  242. }
  243. uni.navigateTo({
  244. url: `/pages_im/pages/conversation/updateGroupOrNickname/index?sourceInfo=${JSON.stringify(
  245. this.storeCurrentGroup,
  246. )}`,
  247. });
  248. },
  249. toGroupQr() {
  250. uni.navigateTo({
  251. url: `/pages_im/pages/common/userOrGroupQrCode/index?sourceInfo=${JSON.stringify(
  252. this.storeCurrentGroup,
  253. )}`,
  254. });
  255. },
  256. toSetBg() {
  257. uni.$u.route("/pages_im/pages/conversation/setChatBackgroup/index");
  258. },
  259. toSetFontSize() {
  260. uni.$u.route("/pages_im/pages/conversation/setFontSize/index");
  261. },
  262. copyGroupID() {
  263. uni.setClipboardData({
  264. data: this.storeCurrentGroup.groupID,
  265. success: () => {
  266. uni.hideToast();
  267. this.$nextTick(() => {
  268. uni.$u.toast("复制成功");
  269. });
  270. },
  271. });
  272. },
  273. showActionSheet() {
  274. if (!this.isAdmin && !this.isOwner) {
  275. return;
  276. }
  277. this.actionSheetVisible = true;
  278. },
  279. async updateGroupAvatar() {
  280. if (!this.isAdmin && !this.isOwner) {
  281. return;
  282. }
  283. let result = await premissionCheck("EXTERNAL_STORAGE");
  284. if (result != 1) {
  285. return;
  286. }
  287. uni.chooseImage({
  288. count: 1,
  289. sizeType: ["compressed"],
  290. success: async ({ tempFilePaths }) => {
  291. const path = tempFilePaths[0];
  292. const nameIdx = path.lastIndexOf("/") + 1;
  293. const typeIdx = path.lastIndexOf(".") + 1;
  294. const fileName = path.slice(nameIdx);
  295. const fileType = path.slice(typeIdx);
  296. try {
  297. const {
  298. data: { url },
  299. } = await IMSDK.asyncApi(IMMethods.UploadFile, IMSDK.uuid(), {
  300. filepath: getPurePath(tempFilePaths[0]),
  301. name: fileName,
  302. contentType: fileType,
  303. uuid: IMSDK.uuid(),
  304. });
  305. await IMSDK.asyncApi(IMSDK.IMMethods.SetGroupInfo, IMSDK.uuid(), {
  306. groupID: this.storeCurrentConversation.groupID,
  307. faceURL: url,
  308. });
  309. uni.$u.toast("修改成功");
  310. } catch (error) {
  311. uni.$u.toast("修改失败");
  312. }
  313. },
  314. });
  315. },
  316. changePin(isPinned) {
  317. console.log("--聊天置顶--", isPinned);
  318. this.switchLoading.pin = true;
  319. IMSDK.asyncApi(IMSDK.IMMethods.PinConversation, IMSDK.uuid(), {
  320. conversationID: this.storeCurrentConversation.conversationID,
  321. isPinned,
  322. })
  323. .then(() => {
  324. uni.$u.toast("操作成功")
  325. this.storeCurrentConversation.isPinned = isPinned;
  326. })
  327. .catch(() => {
  328. uni.$u.toast("操作失败")
  329. this.storeCurrentConversation.isPinned = !isPinned;
  330. })
  331. .finally(() => (this.switchLoading.pin = false));
  332. },
  333. changeOpt(notNomal, type) {
  334. this.switchLoading.opt = true;
  335. IMSDK.asyncApi(
  336. IMSDK.IMMethods.SetConversationRecvMessageOpt,
  337. IMSDK.uuid(),
  338. {
  339. conversationID: this.storeCurrentConversation.conversationID,
  340. opt: notNomal ? type : MessageReceiveOptType.Nomal,
  341. },
  342. )
  343. .then(() => uni.$u.toast("操作成功"))
  344. .catch(() => uni.$u.toast("操作失败"))
  345. .finally(() => (this.switchLoading.opt = false));
  346. },
  347. changeMute(isMute) {
  348. this.switchLoading.mute = true;
  349. IMSDK.asyncApi(IMSDK.IMMethods.ChangeGroupMute, IMSDK.uuid(), {
  350. groupID: this.storeCurrentGroup.groupID,
  351. isMute,
  352. })
  353. .then(() => uni.$u.toast("禁言成功"))
  354. .catch(() => uni.$u.toast("禁言失败"))
  355. .finally(() => (this.switchLoading.mute = false));
  356. },
  357. confirm() {
  358. let funcName = "";
  359. let sourceID = this.storeCurrentConversation.groupID;
  360. if (this.confirmType === ConfirmTypes.Clear) {
  361. sourceID = this.storeCurrentConversation.conversationID;
  362. funcName = IMSDK.IMMethods.ClearConversationAndDeleteAllMsg;
  363. }
  364. if (this.confirmType === ConfirmTypes.Quit) {
  365. funcName = IMSDK.IMMethods.QuitGroup;
  366. }
  367. if (this.confirmType === ConfirmTypes.Dismiss) {
  368. funcName = IMSDK.IMMethods.DismissGroup;
  369. }
  370. IMSDK.asyncApi(funcName, IMSDK.uuid(), sourceID)
  371. .then(() => {
  372. uni.$u.toast("操作成功");
  373. if (this.confirmType === ConfirmTypes.Clear) {
  374. this.$store.commit("message/SET_HISTORY_MESSAGE_LIST", []);
  375. this.$store.commit("message/SET_PREVIEW_IMAGE_LIST", []);
  376. } else {
  377. setTimeout(
  378. () =>
  379. uni.switchTab({
  380. url: "/pages/conversation/conversationList/index",
  381. }),
  382. 250,
  383. );
  384. }
  385. })
  386. .catch(() => uni.$u.toast("操作失败"))
  387. .finally(() => (this.confirmType = null));
  388. },
  389. groupMemberInfoChangeHandler({ data }) {
  390. if (data.groupID === this.groupMemberList[0]?.groupID) {
  391. const idx = this.groupMemberList.findIndex(
  392. (member) => member.userID === data.userID,
  393. );
  394. if (idx > -1) {
  395. this.getGroupMemberList();
  396. }
  397. }
  398. },
  399. groupMemberDeletedHandler({ data, isInitail }) {
  400. if (isInitail || data?.groupID === this.groupMemberList[0]?.groupID) {
  401. const idx = this.groupMemberList.findIndex(
  402. (member) => member.userID === data?.userID,
  403. );
  404. if (isInitail || idx > -1) {
  405. this.getGroupMemberList();
  406. IMSDK.asyncApi(
  407. IMMethods.IsJoinGroup,
  408. IMSDK.uuid(),
  409. this.storeCurrentConversation.groupID
  410. ).then((res) => {
  411. this.isJoinGroup = res.data
  412. });
  413. }
  414. }
  415. },
  416. setIMListener() {
  417. uni.$on(IMSDK.IMEvents.OnGroupMemberInfoChanged, this.groupMemberInfoChangeHandler)
  418. IMSDK.subscribe(IMSDK.IMEvents.OnGroupMemberAdded, this.groupMemberInfoChangeHandler)
  419. IMSDK.subscribe(IMSDK.IMEvents.OnGroupMemberDeleted, this.groupMemberDeletedHandler)
  420. },
  421. disposeIMListener() {
  422. uni.$off(IMSDK.IMEvents.OnGroupMemberInfoChanged, this.groupMemberInfoChangeHandler)
  423. IMSDK.unsubscribe(IMSDK.IMEvents.OnGroupMemberAdded, this.groupMemberInfoChangeHandler)
  424. IMSDK.unsubscribe(IMSDK.IMEvents.OnGroupMemberDeleted, this.groupMemberDeletedHandler)
  425. },
  426. },
  427. };
  428. </script>
  429. <style lang="scss" scoped>
  430. .group_settings_container {
  431. @include colBox(false);
  432. height: 100vh;
  433. background-color: #f6f6f6;
  434. .group_settings_content {
  435. overflow-y: auto;
  436. }
  437. .setting_row {
  438. background-color: #fff;
  439. margin: 24rpx;
  440. border-radius: 6px;
  441. overflow: hidden;
  442. }
  443. .group_row {
  444. height: 44px;
  445. line-height: 44px;
  446. background-color: #fff;
  447. border-radius: 6px;
  448. text-align: center;
  449. margin: 24rpx;
  450. color: #D32414
  451. }
  452. .group_avatar {
  453. margin-right: 16rpx;
  454. position: relative;
  455. .edit_icon {
  456. position: absolute;
  457. right: -6rpx;
  458. bottom: -6rpx;
  459. width: 11px;
  460. height: 11px;
  461. }
  462. }
  463. .group_info {
  464. min-height: 46px;
  465. display: flex;
  466. flex: 1;
  467. flex-direction: column;
  468. align-items: flex-start;
  469. justify-content: space-between;
  470. &_name {
  471. display: flex;
  472. flex-direction: row;
  473. align-items: center;
  474. justify-content: center;
  475. .group_name {
  476. // @include nomalEllipsis();
  477. font-size: 34rpx;
  478. max-width: 380rpx;
  479. margin-right: 24rpx;
  480. }
  481. }
  482. }
  483. .sub_title {
  484. @include nomalEllipsis();
  485. margin-bottom: 0;
  486. font-size: 28rpx;
  487. color: #757575;
  488. }
  489. .info_row {
  490. @include vCenterBox();
  491. padding: 36rpx 44rpx;
  492. }
  493. }
  494. </style>