manage.vue 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. <template>
  2. <div>
  3. <i class="icon icon-chat-setting" @click="toggleShow"></i>
  4. <div class="manage" :class="[isH5 ? 'manage-h5' : '']" v-if="show" ref="dialog">
  5. <header :class="['manage-header', currentTab === 'onlyMute' ? 'currentModel' : '']">
  6. <i class="icon icon-back" v-if="isH5 && !currentTab" @click="toggleShow"></i>
  7. <aside class="manage-header-left">
  8. <i class="icon icon-back" v-if="currentTab" @click="() =>{
  9. currentModel = 'not_mute'
  10. setTab('')
  11. }"></i>
  12. <main v-if="currentTab !== 'onlyMute'">
  13. <h1>{{ TabName }} <span v-if="currentTab === 'member'"> {{ groupDetail.memberNum || 0 }}{{ $t(`TUIChat.manage.人`) }} </span></h1>
  14. </main>
  15. <n-tabs
  16. v-else
  17. justify-content="center"
  18. style="margin-left: -14Px;flex: 1; --n-tab-padding: 6px 0; --n-tab-gap: 34px; --n-tab-text-color: #000; --n-tab-text-color-hover: #0f0f0f; --n-tab-text-color-active: #000; --n-tab-font-weight-active: 600; --n-bar-color: #198cfe"
  19. :bar-width="20"
  20. :value="currentModel"
  21. @update:value="
  22. (val: any) => {
  23. currentModel = val;
  24. mutePage = 1
  25. muteSearch = ''
  26. getUserList()
  27. }
  28. "
  29. >
  30. <n-tab-pane name="not_mute" tab="未禁言"></n-tab-pane>
  31. <n-tab-pane name="mute" tab="已禁言"></n-tab-pane>
  32. </n-tabs>
  33. </aside>
  34. <span v-if="currentTab !== 'onlyMute'">
  35. <i v-if="!isH5" class="icon icon-close" @click="toggleShow"></i>
  36. </span>
  37. </header>
  38. <main :class="['main']" style="background-color: #f4f5f9; height: 100%" v-if="!currentTab">
  39. <ManageName class="space-top" :isAuth="isAuth" :isH5="isH5" :data="conversation.groupProfile" @update="updateProfile" style="background-color: #fff" />
  40. <div class="userInfo space-top" style="background-color: #fff">
  41. <header class="userInfo-header" @click="setTab('member')">
  42. <label>{{ $t(`TUIChat.manage.群成员`) }}</label>
  43. <p>
  44. <span> {{ groupDetail.memberNum || 0 }}{{ $t(`TUIChat.manage.人`) }} </span>
  45. <i class="icon icon-right"></i>
  46. </p>
  47. </header>
  48. <ol>
  49. <!-- @click="handleMemberProfileShow(item)" -->
  50. <dl v-for="(item, index) in userInfo?.list?.slice(0, showUserNum)" :key="index">
  51. <dt>
  52. <img class="avatar" :src="item?.avatar || 'https://oss.dayaedu.com/news-info/07/1690787574969.png'" onerror="this.src='https://oss.dayaedu.com/news-info/07/1690787574969.png'" />
  53. </dt>
  54. <dd>{{ item?.nickname || item?.userID }}</dd>
  55. </dl>
  56. <!-- v-if="isShowAddMember" -->
  57. <dl v-if="currentUserDetail.groupRoleType === 'Owner'">
  58. <dt class="avatar" @click="toggleMask('add')">+</dt>
  59. </dl>
  60. <!-- <dl v-if="conversation.groupProfile.selfInfo.role === 'Owner'">
  61. <dt class="avatar" @click="toggleMask('remove')">-</dt>
  62. </dl> -->
  63. </ol>
  64. </div>
  65. <ul class="content space-top" @click="editLableName = ''" style="background-color: #fff">
  66. <li @click.stop="setTab('notification')">
  67. <aside>
  68. <label>{{ $t(`TUIChat.manage.群公告`) }}</label>
  69. <article>{{ conversation.groupProfile.notification }}</article>
  70. </aside>
  71. <i class="icon icon-right end"></i>
  72. </li>
  73. <!-- <li v-if="isAdmin && isSetMuteTime" @click.stop="setTab('admin')">
  74. <label>{{ $t(`TUIChat.manage.群管理`) }}</label>
  75. <i class="icon icon-right"></i>
  76. </li>
  77. <li>
  78. <label>{{ $t(`TUIChat.manage.群ID`) }}</label>
  79. <div class="groupID">
  80. <span>{{ conversation.groupProfile.groupID }}</span>
  81. <i
  82. class="icon icon-msg-copy"
  83. @click="handleGroupIDCopy"
  84. :title="$t('TUIChat.复制')"
  85. ></i>
  86. </div>
  87. </li>
  88. <li>
  89. <label>{{ $t(`TUIChat.manage.群头像`) }}</label>
  90. <img
  91. class="avatar"
  92. :src="
  93. conversation?.groupProfile?.avatar ||
  94. 'https://oss.dayaedu.com/news-info/07/1690775328089.png'
  95. "
  96. onerror="this.src='https://oss.dayaedu.com/news-info/07/1690775328089.png'"
  97. />
  98. </li>
  99. <li>
  100. <label>{{ $t(`TUIChat.manage.群类型`) }}</label>
  101. <span>
  102. {{
  103. $t(`TUIChat.manage.${typeName[conversation.groupProfile.type]}`)
  104. }}
  105. </span>
  106. </li>
  107. <li>
  108. <label>{{ $t(`TUIChat.manage.加群方式`) }}</label>
  109. <span>
  110. {{
  111. $t(
  112. `TUIChat.manage.${
  113. typeName[conversation.groupProfile.joinOption]
  114. }`
  115. )
  116. }}
  117. </span>
  118. </li> -->
  119. </ul>
  120. <div v-if="currentUserDetail.groupRoleType === 'Owner' || currentUserDetail.groupRoleType === 'Admin'" class="admin-content space-top" style="background-color: #fff; padding-top: 12px;border-top: 1Px solid #f4f5f9;">
  121. <aside>
  122. <label>学生禁言</label>
  123. </aside>
  124. <Slider :open="groupDetail.configJson.mute" @change="setAllMuteTime" />
  125. </div>
  126. <div v-if="currentUserDetail.groupRoleType === 'Owner' || currentUserDetail.groupRoleType === 'Admin'" class="admin-content space-top" style="background-color: #fff; padding-top: 12px;border-top: 1Px solid #f4f5f9;" @click.stop="() => {
  127. userInfo.muteList = []
  128. setTab('onlyMute')
  129. }">
  130. <aside>
  131. <label>禁言名单</label>
  132. </aside>
  133. <i class="icon icon-right end"></i>
  134. </div>
  135. <div v-if="currentUserDetail.groupRoleType === 'Owner' && userInfo?.list.length > 1" class="admin-content space-top" style="background-color: #fff;padding-top: 12px; border-top: 1Px solid #f4f5f9;" @click.stop="toggleMask('changeOwner')">
  136. <aside>
  137. <label>移交群主</label>
  138. </aside>
  139. <i class="icon icon-right end"></i>
  140. </div>
  141. <ul class="footer space-top" style="overflow: hidden; background-color: #f4f5f9;">
  142. <!-- <li v-if="currentUserDetail.groupRoleType === 'Owner' && userInfo?.list.length > 1" @click.stop="toggleMask('changeOwner')">移交群主</li> -->
  143. <li v-if="currentUserDetail.groupRoleType === 'Owner'" @click.stop="dismiss(conversation.groupProfile)">解散群聊</li>
  144. <li v-else @click.stop="quit(conversation.groupProfile)">退出群组</li>
  145. </ul>
  146. </main>
  147. <ManageMember v-else-if="currentTab === 'member'" :self="conversation.groupProfile.selfInfo" :list="userInfo.list" :total="~~conversation.groupProfile.memberCount" @more="getMember('more')" @del="submit" @handleMemberProfileShow="handleMemberProfileShow" />
  148. <!-- :isShowDel="conversation.groupProfile.selfInfo.role === 'Owner'" -->
  149. <MemeberProfile v-else-if="currentTab === 'profile'" :userInfo="currentMember" />
  150. <ManageNotification ref="manageNotificationRef" v-else-if="currentTab === 'notification' || currentTab === 'notificationAdd' || currentTab === 'notificationUpdate'" :isAuth="isAuth" :data="conversation.groupProfile" @update="updateProfile" @changeStatus="onNotificationChangeStatus" />
  151. <ManageNotificationDetail ref="manageNotificationDetailRef" v-else-if="currentTab === 'notificationDetail' || currentTab === 'notificationAddDetail' || currentTab === 'notificationUpdateDetail'" :noticeId="noticeId" :isAuth="isAuth" :data="conversation.groupProfile" @changeStatus="onNotificationChangeStatus" />
  152. <main class="admin" v-else-if="currentTab === 'admin'">
  153. <div class="admin-list" v-if="isAdmin">
  154. <label>{{ $t(`TUIChat.manage.群管理员`) }}</label>
  155. <ol>
  156. <dl v-for="(item, index) in member.admin" :key="index">
  157. <dt>
  158. <img class="avatar" :src="item?.avatar || 'https://oss.dayaedu.com/news-info/07/1690787574969.png'" onerror="this.src='https://oss.dayaedu.com/news-info/07/1690787574969.png'" />
  159. </dt>
  160. <dd>{{ item?.nick || item?.userID }}</dd>
  161. </dl>
  162. <dl>
  163. <dt class="avatar" @click="toggleMask('addAdmin')">+</dt>
  164. </dl>
  165. <dl>
  166. <dt class="avatar" v-if="member.admin.length > 0" @click="toggleMask('removeAdmin')">-</dt>
  167. </dl>
  168. </ol>
  169. </div>
  170. <div class="admin-content space-top" v-if="isSetMuteTime">
  171. <aside>
  172. <label>{{ $t(`TUIChat.manage.学生禁言`) }}</label>
  173. <p>
  174. {{ $t(`TUIChat.manage.学生禁言开启后,只允许群主和管理员发言。`) }}
  175. </p>
  176. </aside>
  177. <Slider :open="conversation.groupProfile.muteAllMembers" @change="setAllMuteTime" />
  178. </div>
  179. <div class="admin-list last" v-if="isSetMuteTime">
  180. <label>{{ $t(`TUIChat.manage.单独禁言人员`) }}</label>
  181. <ol>
  182. <dl v-for="(item, index) in member.muteMember" :key="index">
  183. <dt>
  184. <img class="avatar" :src="item?.avatar || 'https://oss.dayaedu.com/news-info/07/1690787574969.png'" onerror="this.src='https://oss.dayaedu.com/news-info/07/1690787574969.png'" />
  185. </dt>
  186. <dd>{{ item?.nick || item?.userID }}</dd>
  187. </dl>
  188. <dl>
  189. <dt class="avatar" @click="toggleMask('addMute')">+</dt>
  190. </dl>
  191. <dl>
  192. <dt class="avatar" v-if="member.muteMember.length > 0" @click="toggleMask('removeMute')">-</dt>
  193. </dl>
  194. </ol>
  195. </div>
  196. </main>
  197. <ManageMute v-else-if="currentTab === 'onlyMute'" :currentModel="currentModel"
  198. :total="muteTotal"
  199. :self="conversation.groupProfile.selfInfo" :list="userInfo.muteList"
  200. :conversation="conversation"
  201. :muteLoading="muteLoading"
  202. @more="getUserList('more')"
  203. @del="submit"
  204. @back="() => {
  205. setTab('');
  206. currentModel = 'not_mute'
  207. }"
  208. @search="(keyword) => {
  209. mutePage = 1
  210. muteSearch = keyword
  211. userInfo.muteList = []
  212. getUserList()
  213. }"
  214. @handleMemberProfileShow="handleMemberProfileShow" />
  215. <MaskTUI :show="mask" @update:show="(e) => (mask = e)">
  216. <Transfer :title="$t(`TUIChat.manage.${transferTitle}`)" :list="transferList" :isSearch="isSearch" :isRadio="isRadio" :selectedList="selectedList" @submit="submit" @cancel="cancel" @search="handleSearchMember" :isH5="isH5" />
  217. </MaskTUI>
  218. <DialogTUI :title="$t(`TUIChat.manage.删除成员`)" :show="delDialogShow" :isH5="isH5" :center="true" :isHeaderShow="!isH5" @submit="handleManage(userList, 'remove')" @update:show="(e) => (delDialogShow = e)">
  219. <p v-if="userList.length === 1" class="delDialog-title">
  220. {{ $t(`TUIChat.manage.确定从群聊中删除该成员?`) }}
  221. </p>
  222. <p v-if="userList.length > 1" class="delDialog-title">
  223. {{ $t(`TUIChat.manage.确定从群聊中删除所选成员?`) }}
  224. </p>
  225. </DialogTUI>
  226. <DialogTUI title="退出群聊" :show="quitDialogShow" :isH5="isH5" :center="true" :isHeaderShow="!isH5" @submit="handleManage([], 'quit')" @update:show="(e) => (quitDialogShow = e)">
  227. <p class="delDialog-title">是否退出群聊?</p>
  228. </DialogTUI>
  229. <DialogTUI title="解散群聊" :show="dimmisDialogShow" :isH5="isH5" :center="true" :isHeaderShow="!isH5" @submit="handleManage([], 'dismiss')" @update:show="(e) => (dimmisDialogShow = e)">
  230. <p class="delDialog-title">是否解散群聊?</p>
  231. </DialogTUI>
  232. </div>
  233. </div>
  234. </template>
  235. <script lang="ts">
  236. import TUIMessage from "../../../components/messageTUI/index";
  237. import { defineComponent, watchEffect, reactive, toRefs, computed, watch, ref, onMounted } from "vue";
  238. import { onClickOutside } from "@vueuse/core";
  239. import MaskTUI from "../../../components/maskTUI/mask.vue";
  240. import Transfer from "../../../components/transferTUI/index.vue";
  241. import Slider from "../../../components/sliderTUI/index.vue";
  242. import ManageName from "./manage-name.vue";
  243. import ManageNotification from "./manage-notification.vue";
  244. import ManageNotificationDetail from "./manage-notification-detail.vue";
  245. import ManageMember from "./manage-member.vue";
  246. import MemeberProfile from "./member-profile.vue";
  247. import ManageMute from './manage-mute.vue'
  248. import DialogTUI from "../../../components/dialogTUi/index.vue";
  249. import { imGroupChangeGroupOwner, imGroupDetail, imGroupDismiss, imGroupMemberPage, imGroupMemberSaveImAll, imGroupMemberUserDetail, imGroupMuteAll, imGroupQuit, imUserFriendPage } from "../../../../api";
  250. import Vuex from "vuex";
  251. import { handleErrorPrompts } from "../../utils";
  252. import useClipboard from "vue-clipboard3";
  253. import { eventGlobal } from "@/helpers";
  254. const manage = defineComponent({
  255. components: {
  256. MaskTUI,
  257. Transfer,
  258. Slider,
  259. ManageName,
  260. ManageNotification,
  261. ManageNotificationDetail,
  262. ManageMember,
  263. MemeberProfile,
  264. ManageMute,
  265. DialogTUI,
  266. },
  267. props: {
  268. userInfo: {
  269. type: Object,
  270. default: () => ({
  271. isGroup: false,
  272. list: [],
  273. }),
  274. },
  275. conversation: {
  276. type: Object,
  277. default: () => ({}),
  278. },
  279. show: {
  280. type: Boolean,
  281. default: () => false,
  282. },
  283. isH5: {
  284. type: Boolean,
  285. default: () => false,
  286. },
  287. },
  288. setup(props: any, ctx: any) {
  289. const types: any = manage.TUIServer.TUICore.TIM.TYPES;
  290. const { GroupServer } = manage;
  291. const { t } = manage.TUIServer.TUICore.config.i18n.useI18n();
  292. const data: any = reactive({
  293. conversation: {},
  294. userInfo: {
  295. isGroup: false,
  296. list: [],
  297. muteList: []
  298. },
  299. isShowMuteTimeInput: false,
  300. editLableName: "",
  301. mask: false,
  302. currentTab: "",
  303. noticeId: "", // 查看公告详情时
  304. transferType: "",
  305. isSearch: false,
  306. isRadio: false,
  307. transferList: [],
  308. selectedList: [],
  309. isMuteTime: false,
  310. show: false,
  311. typeName: {
  312. [types.GRP_WORK]: "好友工作群",
  313. [types.GRP_PUBLIC]: "陌生人社交群",
  314. [types.GRP_MEETING]: "临时会议群",
  315. [types.GRP_AVCHATROOM]: "直播群",
  316. [types.JOIN_OPTIONS_FREE_ACCESS]: "自由加入",
  317. [types.JOIN_OPTIONS_NEED_PERMISSION]: "需要验证",
  318. [types.JOIN_OPTIONS_DISABLE_APPLY]: "禁止加群",
  319. },
  320. delDialogShow: false,
  321. quitDialogShow: false,
  322. dimmisDialogShow: false,
  323. userList: [],
  324. transferTitle: "",
  325. member: {
  326. admin: [],
  327. member: [],
  328. muteMember: [],
  329. },
  330. currentMember: {},
  331. classGroupDetail: {}, // 群详情
  332. page: 1, // 当前默认查询第一页数据
  333. currentUserDetail: {} as any, // 用户信息
  334. mutePage: 1,
  335. muteSearch: '',
  336. muteLoading: false,
  337. muteTotal: 0,
  338. groupDetail: {} as any,
  339. currentModel: 'not_mute'
  340. });
  341. const dialog: any = ref();
  342. const manageNotificationRef: any = ref()
  343. const manageNotificationDetailRef: any = ref()
  344. watchEffect(() => {
  345. data.conversation = props.conversation;
  346. data.userInfo = props.userInfo;
  347. data.show = props.show;
  348. });
  349. const VuexStore = ((window as any)?.TUIKitTUICore?.isOfficial && (Vuex as any)?.useStore()) || {};
  350. const TabName = computed(() => {
  351. let name = "";
  352. switch (data.currentTab) {
  353. case "notification":
  354. name = "群公告";
  355. break;
  356. case "notificationAdd":
  357. case "notificationAddDetail":
  358. name = '添加群公告';
  359. break;
  360. case "notificationUpdate":
  361. case "notificationUpdateDetail":
  362. name = '修改群公告';
  363. break;
  364. case "notificationDetail":
  365. name = "公告详情";
  366. break;
  367. case "member":
  368. name = "群成员";
  369. break;
  370. case "profile":
  371. name = "群成员";
  372. break;
  373. default:
  374. name = "群管理";
  375. break;
  376. }
  377. return name;
  378. });
  379. watch(
  380. () => data.userInfo.list,
  381. (newValue: any, oldValue: any) => {
  382. data.member = {
  383. admin: [],
  384. member: [],
  385. muteMember: [],
  386. };
  387. // TIM.TYPES.GRP_MBR_ROLE_ADMIN(群管理员),
  388. // TIM.TYPES.GRP_MBR_ROLE_MEMBER(群普通成员),
  389. // TIM.TYPES.GRP_MBR_ROLE_CUSTOM(自定义群成员角色,仅社群支持)
  390. newValue.map((item: any) => {
  391. switch (item?.groupRoleType) {
  392. case "Admin":
  393. data.member.admin.push(item);
  394. break;
  395. case "Member":
  396. data.member.member.push(item);
  397. break;
  398. default:
  399. break;
  400. }
  401. return item;
  402. });
  403. const time: number = new Date().getTime();
  404. data.member.muteMember = newValue.filter((item: any) => item?.muteUntil * 1000 - time > 0);
  405. },
  406. { deep: true }
  407. );
  408. const isDismissGroupAuth = computed(() => {
  409. const { conversation } = data;
  410. const userRole = conversation?.groupProfile?.selfInfo.role;
  411. const groupType = conversation?.groupProfile?.type;
  412. const isOwner = userRole === types.GRP_MBR_ROLE_OWNER;
  413. const isWork = groupType === types.GRP_WORK;
  414. return isOwner && !isWork;
  415. });
  416. const isShowAddMember = computed(() => {
  417. const { conversation } = data;
  418. const groupType = conversation?.groupProfile?.type;
  419. const isWork = groupType === types.GRP_WORK;
  420. if (isWork) {
  421. return true;
  422. }
  423. return false;
  424. });
  425. const showUserNum = computed(() => {
  426. let num = 3;
  427. if (!isShowAddMember.value) {
  428. num += 1;
  429. }
  430. if ((data.conversation as any).groupProfile.selfInfo.role !== "Owner") {
  431. num += 1;
  432. }
  433. return num;
  434. });
  435. const isAuth = computed(() => {
  436. const { conversation } = data;
  437. const userRole = conversation?.groupProfile?.selfInfo.role;
  438. const isOwner = userRole === types.GRP_MBR_ROLE_OWNER;
  439. const isAdmin = userRole === types.GRP_MBR_ROLE_ADMIN;
  440. return isOwner || isAdmin;
  441. });
  442. const isAdmin = computed(() => {
  443. const { conversation } = data;
  444. const groupType = conversation?.groupProfile?.type;
  445. const userRole = conversation?.groupProfile?.selfInfo.role;
  446. const isOwner = userRole === types.GRP_MBR_ROLE_OWNER;
  447. const isWork = groupType === types.GRP_WORK;
  448. const isAVChatRoom = groupType === types.GRP_AVCHATROOM;
  449. if (!isWork && !isAVChatRoom && isOwner) {
  450. return true;
  451. }
  452. return false;
  453. });
  454. const isSetMuteTime = computed(() => {
  455. const { conversation } = data;
  456. const groupType = conversation?.groupProfile?.type;
  457. const isWork = groupType === types.GRP_WORK;
  458. if (isWork || !isAuth.value) {
  459. return false;
  460. }
  461. return true;
  462. });
  463. const getMember = async (type?: string) => {
  464. try {
  465. const { conversation } = data;
  466. // console.log(conversation, "getMember -------");
  467. const options: any = {
  468. groupId: conversation?.groupProfile?.groupID,
  469. rows: 100,
  470. page: type && type === "more" ? data.page + 1 : data.page,
  471. // offset: type && type === "more" ? data.userInfo.list.length : 0,
  472. };
  473. await imGroupMemberPage(options).then((res: any) => {
  474. const rows = res.data.rows || [];
  475. rows.forEach((row: any) => {
  476. row.nick = row.nickname;
  477. });
  478. if (type && type === "more") {
  479. data.userInfo.list = [...data.userInfo.list, ...rows];
  480. } else {
  481. data.userInfo.list = rows;
  482. }
  483. });
  484. // GroupServer.getGroupMemberList(options)
  485. } catch {
  486. //
  487. }
  488. };
  489. // 禁言
  490. const getUserList = async (type?: string) => {
  491. data.muteLoading = true;
  492. try {
  493. const { conversation } = data;
  494. const options: any = {
  495. groupId: conversation?.groupProfile?.groupID,
  496. rows: 100,
  497. groupMute: data.currentModel === 'not_mute' ? false : true,
  498. groupRoleTypes: ['Member'],
  499. page: type && type === "more" ? data.mutePage + 1 : data.mutePage,
  500. keyword: data.muteSearch
  501. };
  502. await imGroupMemberPage(options).then((res: any) => {
  503. const rows = res.data.rows || [];
  504. rows.forEach((row: any) => {
  505. row.nick = row.nickname;
  506. });
  507. if (type && type === "more") {
  508. data.userInfo.muteList = [...data.userInfo.list, ...rows];
  509. } else {
  510. data.userInfo.muteList = rows;
  511. }
  512. data.muteTotal = res.data.total || 0;
  513. });
  514. } catch {
  515. //
  516. }
  517. data.muteLoading = false;
  518. };
  519. const addMember = async (userIDList: any) => {
  520. const { conversation } = data;
  521. // const options: any = {
  522. // groupID: conversation.groupProfile.groupID,
  523. // userIDList,
  524. // };
  525. // await GroupServer.addGroupMember(options);
  526. const params: any = [];
  527. userIDList.forEach((id: any) => {
  528. params.push({
  529. groupId: conversation.groupProfile.groupID,
  530. imUserId: id,
  531. });
  532. });
  533. // console.log(params, userIDList, "userIDList");
  534. // return;
  535. try {
  536. await imGroupMemberSaveImAll(params);
  537. getGroupDetail();
  538. getMember();
  539. } catch {
  540. //
  541. }
  542. };
  543. const deleteMember = (user: any) => {
  544. const { conversation } = data;
  545. const options: any = {
  546. groupID: conversation.groupProfile.groupID,
  547. userIDList: [user.userID],
  548. };
  549. GroupServer.deleteGroupMember(options);
  550. };
  551. const changeOwner = async (userID: any) => {
  552. // const options: any = {
  553. // groupID: data.conversation.groupProfile.groupID,
  554. // newOwnerID: userID,
  555. // };
  556. // const imResponse = await GroupServer.changeGroupOwner(options);
  557. // data.conversation.groupProfile = imResponse.data.group;
  558. console.log(data.conversation.groupProfile, userID);
  559. // 腾讯IM切换人之后
  560. await imGroupChangeGroupOwner({
  561. oldOwner: data.conversation.groupProfile.ownerID,
  562. groupId: data.conversation.groupProfile.groupID,
  563. newOwner: userID,
  564. });
  565. toggleShow();
  566. data.conversation.groupProfile = {};
  567. TUIMessage({
  568. message: "转交成功",
  569. isH5: false,
  570. type: "success",
  571. });
  572. };
  573. const quit = async (group: any) => {
  574. data.quitDialogShow = true;
  575. };
  576. const dismiss = async (group: any) => {
  577. data.dimmisDialogShow = true;
  578. // console.log(manage.TUIServer.deleteConversation, "manage.TUIServer");
  579. // manage.TUIServer.deleteConversation(data.conversation.conversationID);
  580. // manage.TUIServer.store.conversation = {};
  581. // toggleShow();
  582. // await GroupServer.dismissGroup(group.groupID);
  583. // manage.TUIServer.store.conversation = {};
  584. // (window as any)?.TUIKitTUICore?.isOfficial && VuexStore?.commit && VuexStore?.commit("handleTask", 5);
  585. };
  586. const handleAdmin = async (user: any) => {
  587. const { conversation } = data;
  588. let role = "";
  589. switch (user.role) {
  590. case types.GRP_MBR_ROLE_ADMIN:
  591. role = types.GRP_MBR_ROLE_MEMBER;
  592. break;
  593. case types.GRP_MBR_ROLE_MEMBER:
  594. role = types.GRP_MBR_ROLE_ADMIN;
  595. break;
  596. }
  597. const options: any = {
  598. groupID: conversation.groupProfile.groupID,
  599. userID: user.userID,
  600. role,
  601. };
  602. await GroupServer.setGroupMemberRole(options);
  603. getMember();
  604. };
  605. const setMemberMuteTime = async (userID: string, type?: string) => {
  606. const { conversation } = data;
  607. const options: any = {
  608. groupID: conversation.groupProfile.groupID,
  609. userID,
  610. muteTime: type === "add" ? 60 * 60 * 24 * 30 : 0,
  611. };
  612. await GroupServer.setGroupMemberMuteTime(options);
  613. if (type === "add") {
  614. (window as any)?.TUIKitTUICore?.isOfficial && VuexStore?.commit && VuexStore?.commit("handleTask", 4);
  615. }
  616. getMember();
  617. };
  618. const kickedOut = async (userIDList: any) => {
  619. const { conversation } = data;
  620. const options: any = {
  621. groupID: conversation.groupProfile.groupID,
  622. userIDList,
  623. reason: "",
  624. };
  625. await GroupServer.deleteGroupMember(options);
  626. getMember();
  627. };
  628. const edit = (labelName: string) => {
  629. data.editLableName = labelName;
  630. };
  631. /** 群公告修改 */
  632. const onNotificationChangeStatus = (type: string) => {
  633. if(type === "add") {
  634. data.currentTab = 'notificationAdd'
  635. } else if(type === "edit") {
  636. data.currentTab = 'notificationUpdate'
  637. } else if(type === "submit") {
  638. data.currentTab = 'notification'
  639. } else if(type === "addDetail") {
  640. data.currentTab = 'notificationAddDetail'
  641. } else if(type === "editDetail") {
  642. data.currentTab = 'notificationUpdateDetail'
  643. } else if(type === "submitDetail") {
  644. data.currentTab = 'notificationDetail'
  645. } else if(type === "deleteDetail") {
  646. data.currentTab = ""
  647. }
  648. }
  649. const updateProfile = async (params: any) => {
  650. const { key, value } = params;
  651. const options: any = {
  652. groupID: data.conversation.groupProfile.groupID,
  653. [key]: value,
  654. };
  655. const res = await GroupServer.updateGroupProfile(options);
  656. const { conversation } = manage.TUIServer.store;
  657. conversation.groupProfile = res.data.group;
  658. manage.TUIServer.store.conversation = {};
  659. manage.TUIServer.store.conversation = conversation;
  660. data.editLableName = "";
  661. };
  662. const setTab = (tabName: string) => {
  663. if(data.currentTab === "notificationAdd" || data.currentTab === "notificationUpdate") {
  664. manageNotificationRef.value?.onCloseEdit()
  665. data.currentTab = 'notification'
  666. return
  667. }
  668. if(data.currentTab === "notificationAddDetail" || data.currentTab === "notificationUpdateDetail") {
  669. manageNotificationDetailRef.value?.onCloseEdit()
  670. data.currentTab = 'notificationDetail'
  671. return
  672. }
  673. if(tabName === 'onlyMute') {
  674. getUserList()
  675. }
  676. data.currentTab = tabName;
  677. data.editLableName = "";
  678. if (data.currentTab === "member") {
  679. data.transferType = "remove";
  680. }
  681. if (!data.currentTab) {
  682. data.transferType = "";
  683. }
  684. };
  685. const handleSearchMember = async (value: string) => {
  686. let imResponse: any = {};
  687. let imMemberResponse: any = {};
  688. const options: any = {
  689. groupID: data.conversation.groupProfile.groupID,
  690. userIDList: [value],
  691. };
  692. switch (data.transferType) {
  693. case "add":
  694. try {
  695. imMemberResponse = await GroupServer.getGroupMemberProfile(options);
  696. data.transferList = data.transferList.filter((item: any) => item.userID !== imResponse.data[0]?.userID);
  697. data.transferList = [...data.transferList, ...imResponse.data];
  698. if (imMemberResponse?.data?.memberList.length > 0) {
  699. data.transferList = data.transferList.map((item: any) => {
  700. if (item.userID === imMemberResponse?.data?.memberList[0].userID) {
  701. item.isDisabled = true;
  702. }
  703. return item;
  704. });
  705. }
  706. } catch (error) {
  707. const message = t("TUIChat.manage.该用户不存在");
  708. handleErrorPrompts(message, props);
  709. }
  710. break;
  711. case "remove":
  712. try {
  713. imResponse = await GroupServer.getGroupMemberProfile(options);
  714. if (imResponse.data.memberList.length === 0) {
  715. const message = t("TUIChat.manage.该用户不在群组内");
  716. return handleErrorPrompts(message, props);
  717. }
  718. data.transferList = data.transferList.filter(
  719. (item: any) =>
  720. // eslint-disable-next-line no-unsafe-optional-chaining
  721. item.userID !== imResponse?.data?.memberList[0]?.userID
  722. );
  723. data.transferList = [
  724. ...data.transferList,
  725. // eslint-disable-next-line no-unsafe-optional-chaining
  726. ...imResponse?.data?.memberList,
  727. ];
  728. } catch (error) {
  729. const message = t("TUIChat.manage.该用户不存在");
  730. handleErrorPrompts(message, props);
  731. }
  732. break;
  733. default:
  734. break;
  735. }
  736. };
  737. const submit = (userList: any) => {
  738. console.log(userList, data.transferType, " data.transferType");
  739. if(userList.length <= 0) return
  740. if (data.transferType === "remove") {
  741. data.userList = userList;
  742. data.delDialogShow = !data.delDialogShow;
  743. } else {
  744. handleManage(userList, data.transferType);
  745. }
  746. data.mask = false;
  747. };
  748. const friendList = async () => {
  749. const list = await imUserFriendPage({ page: 1, rows: 999 });
  750. console.log(list, "lits");
  751. const fristList = list.data.rows || [];
  752. fristList.forEach((item: any) => {
  753. item.nick = item.friendNickname;
  754. });
  755. return fristList.filter((item: any) => !data.userInfo.list.some((infoItem: any) => infoItem.imUserId === item.imUserId));
  756. };
  757. const cancel = () => {
  758. toggleMask();
  759. };
  760. const toggleMask = async (type?: string) => {
  761. data.selectedList = [];
  762. switch (type) {
  763. case "add":
  764. data.isRadio = false;
  765. data.transferList = await friendList();
  766. data.transferTitle = "添加成员";
  767. break;
  768. case "remove":
  769. data.isRadio = false;
  770. data.transferList = data.userInfo.list.filter(
  771. (item: any) =>
  772. // eslint-disable-next-line no-unsafe-optional-chaining
  773. item.userID !== data.conversation?.groupProfile?.selfInfo.userID
  774. );
  775. data.transferTitle = "删除成员";
  776. break;
  777. case "addAdmin":
  778. data.isRadio = true;
  779. data.transferList = data.member.member;
  780. data.transferTitle = "新增管理员";
  781. break;
  782. case "removeAdmin":
  783. data.isRadio = true;
  784. data.transferList = data.member.admin;
  785. data.transferTitle = "移除管理员";
  786. break;
  787. case "changeOwner":
  788. data.isRadio = true;
  789. data.transferList = [...data.member.admin, ...data.member.member].filter(item => item.roleType !== "STUDENT");
  790. data.transferTitle = "转让群组";
  791. console.log(data.transferList, "data.transferList");
  792. break;
  793. case "addMute":
  794. data.isRadio = true;
  795. data.transferList = data.member.member;
  796. if (data.conversation.groupProfile.selfInfo.role === "Owner") {
  797. data.transferList = [...data.member.admin, ...data.member.member];
  798. }
  799. data.transferTitle = "新增禁言用户";
  800. break;
  801. case "removeMute":
  802. data.isRadio = true;
  803. data.transferList = data.member.muteMember;
  804. data.transferTitle = "移除禁言用户";
  805. break;
  806. default:
  807. break;
  808. }
  809. data.transferType = type;
  810. data.mask = !data.mask;
  811. };
  812. onClickOutside(dialog, () => {
  813. data.show = false;
  814. });
  815. const toggleShow = () => {
  816. if (!GroupServer) {
  817. const message = t("TUIChat.manage.请先注册 TUIGroup 模块");
  818. return handleErrorPrompts(message, props);
  819. }
  820. data.show = !data.show;
  821. if (!data.show) {
  822. data.currentTab = "";
  823. }
  824. if (data.show) {
  825. getMember();
  826. }
  827. };
  828. // 禁言
  829. const setAllMuteTime = async (value: boolean) => {
  830. // updateProfile({ key: "muteAllMembers", value });
  831. // (window as any)?.TUIKitTUICore?.isOfficial && VuexStore?.commit && VuexStore?.commit("handleTask", 4);
  832. try {
  833. await imGroupMuteAll({
  834. groupId: data.conversation.groupProfile.groupID,
  835. muteAll: value,
  836. });
  837. getGroupDetail();
  838. } catch {
  839. //
  840. }
  841. };
  842. const handleManage = (userList: any, type: any) => {
  843. const userIDList: any = [];
  844. userList.map((item: any) => {
  845. userIDList.push(item.imUserId);
  846. return item;
  847. });
  848. switch (type) {
  849. case "add":
  850. addMember(userIDList);
  851. break;
  852. case "remove":
  853. kickedOut(userIDList);
  854. break;
  855. case "addAdmin":
  856. handleAdmin(userList[0]);
  857. break;
  858. case "removeAdmin":
  859. handleAdmin(userList[0]);
  860. break;
  861. case "changeOwner":
  862. changeOwner(userIDList[0]);
  863. break;
  864. case "addMute":
  865. setMemberMuteTime(userIDList[0], "add");
  866. break;
  867. case "removeMute":
  868. setMemberMuteTime(userIDList[0], "remove");
  869. break;
  870. case "quit":
  871. // 退出群聊
  872. imGroupQuit({
  873. id: data.conversation.groupProfile.groupID,
  874. }).then(() => {
  875. eventGlobal.emit("removeGroup", data.conversation.groupProfile.groupID);
  876. manage.TUIServer.deleteConversation(data.conversation.conversationID);
  877. manage.TUIServer.store.conversation = {};
  878. toggleShow();
  879. });
  880. break;
  881. case "dismiss":
  882. // 解散群
  883. imGroupDismiss({
  884. id: data.conversation.groupProfile.groupID,
  885. })
  886. .then(() => {
  887. eventGlobal.emit("removeGroup", data.conversation.groupProfile.groupID);
  888. manage.TUIServer.deleteConversation(data.conversation.conversationID);
  889. manage.TUIServer.store.conversation = {};
  890. toggleShow();
  891. })
  892. .catch((err: any) => {
  893. TUIMessage({
  894. message: err.message,
  895. isH5: false,
  896. type: "error",
  897. });
  898. });
  899. break;
  900. default:
  901. break;
  902. }
  903. };
  904. const handleGroupIDCopy = async () => {
  905. try {
  906. const { toClipboard } = useClipboard();
  907. await toClipboard(data?.conversation?.groupProfile?.groupID);
  908. } catch (error) {
  909. handleErrorPrompts(error, data.env);
  910. }
  911. };
  912. const handleMemberProfileShow = (user: any) => {
  913. data.currentMember = user;
  914. setTab("profile");
  915. };
  916. const getGroupMemberUserDetail = async () => {
  917. try {
  918. const res = await imGroupMemberUserDetail({
  919. groupId: data?.conversation?.groupProfile?.groupID,
  920. imUserId: data?.conversation?.groupProfile?.selfInfo.userID,
  921. });
  922. data.currentUserDetail = res.data;
  923. } catch {
  924. //
  925. }
  926. };
  927. /** 获取群详情 */
  928. const getGroupDetail = async () => {
  929. try {
  930. const res = await imGroupDetail({ id: data?.conversation?.groupProfile?.groupID });
  931. const tdata = res.data;
  932. tdata.configJson = tdata.configJson ? JSON.parse(tdata.configJson) : {};
  933. data.groupDetail = tdata;
  934. } catch {
  935. //
  936. }
  937. };
  938. watch(
  939. () => data.show,
  940. () => {
  941. if (data.show) {
  942. try {
  943. getGroupDetail();
  944. getGroupMemberUserDetail();
  945. } catch {
  946. //
  947. }
  948. }
  949. }
  950. );
  951. onMounted(() => {
  952. eventGlobal.on('handleNotice', (id: any) => {
  953. data.show = !data.show;
  954. data.noticeId = id
  955. data.currentTab = "notificationDetail"
  956. if (data.show) {
  957. getMember();
  958. }
  959. })
  960. try {
  961. getGroupDetail();
  962. getGroupMemberUserDetail();
  963. // console.log(data?.conversation, "data?.conversation?");
  964. // console.log(data.userInfo.list, "data.userInfo.list");
  965. } catch {
  966. //
  967. }
  968. });
  969. return {
  970. ...toRefs(data),
  971. isDismissGroupAuth,
  972. isShowAddMember,
  973. isSetMuteTime,
  974. isAdmin,
  975. isAuth,
  976. addMember,
  977. deleteMember,
  978. changeOwner,
  979. quit,
  980. dismiss,
  981. handleAdmin,
  982. setMemberMuteTime,
  983. kickedOut,
  984. edit,
  985. onNotificationChangeStatus,
  986. updateProfile,
  987. setTab,
  988. TabName,
  989. getMember,
  990. getUserList,
  991. handleSearchMember,
  992. submit,
  993. cancel,
  994. toggleMask,
  995. toggleShow,
  996. setAllMuteTime,
  997. handleManage,
  998. showUserNum,
  999. dialog,
  1000. manageNotificationRef,
  1001. manageNotificationDetailRef,
  1002. handleGroupIDCopy,
  1003. handleMemberProfileShow,
  1004. };
  1005. },
  1006. });
  1007. export default manage;
  1008. </script>
  1009. <style lang="scss" scoped src="./style/index.scss"></style>