index.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <template>
  2. <div class="container">
  3. <van-index-bar class="list">
  4. <template v-for="(group, groupIndex) in memberGroups" :key="group.index">
  5. <van-index-anchor :index="group.index" />
  6. <van-checkbox-group v-model="checked">
  7. <van-cell-group inset>
  8. <van-cell
  9. v-for="(item, index) in group.members"
  10. :key="item.id"
  11. clickable
  12. @click="toggle(groupIndex, index)"
  13. >
  14. <template #icon>
  15. <van-checkbox checked-color="#4765DD"
  16. :name="item"
  17. :ref="el => setCheckboxRef(groupIndex, index, el)"
  18. @click.stop
  19. />
  20. </template>
  21. <template #title>
  22. <div class="cell-item">
  23. <van-image class="img-icon" round :src="item.avatar" />
  24. <div>{{ item.nickname }}</div>
  25. </div>
  26. </template>
  27. </van-cell>
  28. </van-cell-group>
  29. </van-checkbox-group>
  30. </template>
  31. </van-index-bar>
  32. <div class="footer-box">
  33. <div class="avatar-list">
  34. <van-image
  35. v-for="item in checked"
  36. :key="item.id"
  37. class="img-icon"
  38. round
  39. :src="item.avatar"
  40. />
  41. </div>
  42. <div class="btn" :class="checked.length == 0?'':'active-btn'" @click="submit">完成({{ checked.length }})</div>
  43. </div>
  44. </div>
  45. </template>
  46. <script setup>
  47. import { userList } from "@/api/path/im.api";
  48. import {getFirstLetter} from "@/utils/utils";
  49. import { useWalletStore } from "@/stores/modules/walletStore";
  50. const router = useRouter();
  51. const walletStore = useWalletStore();
  52. const checked = ref([]);
  53. const memberGroups = ref([]);
  54. const getuserList = async () => {
  55. const res = await userList({ uuid: walletStore.account });
  56. const groupedMap = {};
  57. res.data.forEach(user => {
  58. const name = user.nickname || '';
  59. const firstLetter = getFirstLetter(name); // 获取首字母
  60. if (!groupedMap[firstLetter]) {
  61. groupedMap[firstLetter] = [];
  62. }
  63. groupedMap[firstLetter].push({...user});
  64. });
  65. // 转为数组并按 index 排序
  66. const groupedList = Object.keys(groupedMap)
  67. .sort()
  68. .map(letter => ({
  69. index: letter,
  70. members: groupedMap[letter]
  71. }));
  72. memberGroups.value = groupedList;
  73. console.log(memberGroups.value)
  74. };
  75. const checkboxRefs = ref([]);
  76. onBeforeUpdate(() => {
  77. checkboxRefs.value = [];
  78. });
  79. const setCheckboxRef = (groupIndex, index, el) => {
  80. if (!checkboxRefs.value[groupIndex]) {
  81. checkboxRefs.value[groupIndex] = [];
  82. }
  83. checkboxRefs.value[groupIndex][index] = el;
  84. };
  85. // 切换选中
  86. const toggle = (groupIndex, index) => {
  87. checkboxRefs.value[groupIndex]?.[index]?.toggle();
  88. };
  89. const submit = () => {
  90. if(checked.value.length == 0) return;
  91. console.log("已选择成员:", checked.value);
  92. router.push('detail')
  93. };
  94. onMounted(() => {
  95. getuserList();
  96. });
  97. </script>
  98. <style lang="less" scoped>
  99. .container{
  100. display: flex;
  101. flex-direction: column;
  102. height: 100%;
  103. }
  104. .list{
  105. flex: 1;
  106. overflow: auto;
  107. :deep(.van-cell-group--inset){
  108. border-radius:12px !important;
  109. }
  110. :deep(.van-cell){
  111. padding: 12px 16px !important;
  112. }
  113. :deep(.van-cell:after){
  114. left: 90px;
  115. }
  116. :deep(.van-index-anchor--sticky){
  117. background: #F7F8FA !important;
  118. color: #4765DD !important;
  119. }
  120. :deep(.van-index-bar__index){
  121. font-weight: 400 !important;
  122. font-size: 10px !important;
  123. color: #1D2129 !important;
  124. margin-bottom: 8px !important;
  125. }
  126. :deep(.van-index-bar__index--active){
  127. color: #4765DD !important;
  128. }
  129. .cell-item{
  130. display: flex;
  131. align-items: center;
  132. margin-left: 12px;
  133. font-family: PingFang SC, PingFang SC;
  134. font-weight: 500;
  135. font-size: 15px;
  136. color: #000000;
  137. .img-icon{
  138. width: 32px;
  139. height: 32px;
  140. flex-shrink: 0;
  141. margin-right: 12px;
  142. }
  143. }
  144. }
  145. .list::-webkit-scrollbar{
  146. width: 0;
  147. }
  148. .footer-box {
  149. display: flex;
  150. justify-content: space-between;
  151. align-items: center;
  152. margin-top: 16px;
  153. height: 54px;
  154. background: #ffffff;
  155. padding: 0 16px;
  156. box-sizing: border-box;
  157. font-family: PingFang SC, PingFang SC;
  158. font-weight: 400;
  159. font-size: 15px;
  160. color: #8d8d8d;
  161. .avatar-list {
  162. display: flex;
  163. overflow-x: auto;
  164. flex: 1;
  165. .img-icon {
  166. width: 32px;
  167. height: 32px;
  168. flex-shrink: 0;
  169. margin-right: 4px;
  170. }
  171. }
  172. .avatar-list::-webkit-scrollbar{
  173. height: 0;
  174. }
  175. // .selected-count {
  176. // margin-left: 16px;
  177. // white-space: nowrap;
  178. // }
  179. .btn{
  180. margin-left: 16px;
  181. height: 25px;
  182. line-height: 25px;
  183. padding: 0 6px;
  184. background: #F2F2F2;
  185. border-radius: 4px;
  186. box-sizing: border-box;
  187. font-family: PingFang SC, PingFang SC;
  188. font-weight: 400;
  189. font-size: 12px;
  190. color: #8D8D8D;
  191. }
  192. .active-btn{
  193. background: #4765DD;
  194. color: #FFFFFF;
  195. }
  196. }
  197. </style>