personList.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <template>
  2. <view class="page_person_list">
  3. <CommonHeader :title="headerTitle" @back="goBack"></CommonHeader>
  4. <SearchBar v-model="searchWord" @search="handleSearch" :isFixed="true" :top="searchBarTop + 'rpx'" :border="false"></SearchBar>
  5. <scroll-view scroll-y class="person_list" :style="{ paddingTop: contentPaddingTop + 'rpx' }">
  6. <view v-for="(person, index) in filteredList" :key="person.userId || person.id" class="person_item">
  7. <view class="person_info">
  8. <text class="person_name">{{ person.thirdName || person.name }}</text>
  9. <text class="person_code">({{ person.thirdCode || person.userAccount || '' }})</text>
  10. </view>
  11. <view class="person_action" @click="openDeleteModal(index)">
  12. <text class="delete_text">删除</text>
  13. </view>
  14. </view>
  15. <view v-if="filteredList.length === 0" class="empty_state">
  16. <text class="empty_text">暂无人员</text>
  17. </view>
  18. </scroll-view>
  19. <ConfirmModal
  20. :visible="showDeleteModal"
  21. title="提示"
  22. :content="`确定要删除【${deletePersonName}】吗?`"
  23. cancelText="取消"
  24. confirmText="确定"
  25. @cancel="closeDeleteModal"
  26. @confirm="confirmDelete"
  27. ></ConfirmModal>
  28. </view>
  29. </template>
  30. <script setup>
  31. import { ref, computed, onMounted } from 'vue';
  32. import CommonHeader from '@/components/common-header.vue';
  33. import SearchBar from '@/components/search-bar.vue';
  34. import ConfirmModal from '@/components/confirm-modal.vue';
  35. import { useSafeArea } from '@/common/safeArea';
  36. const { statusBarHeight, initSafeArea } = useSafeArea();
  37. const HEADER_CONTENT_HEIGHT = 174;
  38. const SEARCHBAR_HEIGHT = 60;
  39. const SPACING = 24;
  40. const searchBarTop = computed(() => statusBarHeight.value + HEADER_CONTENT_HEIGHT);
  41. const contentPaddingTop = computed(() => statusBarHeight.value + HEADER_CONTENT_HEIGHT + SEARCHBAR_HEIGHT + SPACING);
  42. const searchWord = ref('');
  43. const personList = ref([]);
  44. const objectTypeLabel = ref('');
  45. const showDeleteModal = ref(false);
  46. const deleteIndex = ref(-1);
  47. const deletePersonName = ref('');
  48. const filteredList = computed(() => {
  49. console.log(personList.value)
  50. if (!searchWord.value) return personList.value;
  51. const keyword = searchWord.value.toLowerCase();
  52. return personList.value.filter(person => {
  53. const name = (person.thirdName || person.name || '').toLowerCase();
  54. const code = (person.thirdCode || person.userAccount || '').toLowerCase();
  55. return name.includes(keyword) || code.includes(keyword);
  56. });
  57. });
  58. const headerTitle = computed(() => {
  59. return `${objectTypeLabel.value || ''} 已选${personList.value.length}人`;
  60. });
  61. const handleSearch = (keyword) => {
  62. searchWord.value = keyword;
  63. };
  64. const openDeleteModal = (index) => {
  65. const person = personList.value[index];
  66. deletePersonName.value = person.thirdName || person.name || '';
  67. deleteIndex.value = index;
  68. showDeleteModal.value = true;
  69. };
  70. const closeDeleteModal = () => {
  71. showDeleteModal.value = false;
  72. deleteIndex.value = -1;
  73. deletePersonName.value = '';
  74. };
  75. const confirmDelete = () => {
  76. if (deleteIndex.value >= 0) {
  77. personList.value.splice(deleteIndex.value, 1);
  78. }
  79. closeDeleteModal();
  80. };
  81. const goBack = () => {
  82. uni.setStorageSync('personListResult', JSON.stringify({
  83. users: personList.value
  84. }));
  85. uni.navigateBack();
  86. };
  87. onMounted(() => {
  88. initSafeArea();
  89. const data = uni.getStorageSync('personListData');
  90. if (data) {
  91. try {
  92. const parsed = JSON.parse(data);
  93. const users = parsed.users || [];
  94. const seen = new Set();
  95. personList.value = users.filter(user => {
  96. const userId = user.userId || user.id;
  97. if (!userId || seen.has(userId)) return false;
  98. seen.add(userId);
  99. return true;
  100. });
  101. objectTypeLabel.value = parsed.tab || '';
  102. } catch (e) {
  103. console.error('解析人员列表数据失败:', e);
  104. }
  105. }
  106. });
  107. </script>
  108. <style lang="scss">
  109. .page_person_list {
  110. display: flex;
  111. flex-direction: column;
  112. min-height: 100vh;
  113. }
  114. .person_list {
  115. flex: 1;
  116. padding-left: 24rpx;
  117. padding-right: 24rpx;
  118. padding-bottom: 24rpx;
  119. box-sizing: border-box;
  120. }
  121. .person_item {
  122. display: flex;
  123. align-items: center;
  124. justify-content: space-between;
  125. height: 86rpx;
  126. border-bottom: 2rpx solid #F3F3F3;
  127. .person_info {
  128. display: flex;
  129. align-items: center;
  130. .person_name {
  131. font-size: 28rpx;
  132. color: #666;
  133. }
  134. .person_code {
  135. font-size: 28rpx;
  136. color: #666;
  137. margin-left: 16rpx;
  138. }
  139. }
  140. .person_action {
  141. .delete_text {
  142. font-size: 28rpx;
  143. color: #F56C6C;
  144. }
  145. }
  146. }
  147. .empty_state {
  148. display: flex;
  149. flex-direction: column;
  150. align-items: center;
  151. padding: 100rpx 0;
  152. .empty_text {
  153. font-size: 28rpx;
  154. color: #999999;
  155. }
  156. }
  157. </style>