morePopup.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <template>
  2. <popup v-model:show="showMore" class="more-popup" round>
  3. <div class="more-content">
  4. <!-- 搜索框 -->
  5. <!-- <div class="search-bar">
  6. <el-icon class="search-icon">
  7. <Search />
  8. </el-icon>
  9. <input
  10. v-model="keyword"
  11. class="search-input"
  12. type="text"
  13. placeholder="请输入病虫害名称"
  14. />
  15. </div> -->
  16. <!-- 类型切换 -->
  17. <!-- <div class="type-tabs">
  18. <div
  19. class="tab-item all-tab"
  20. :class="{ active: activeType === 'all' }"
  21. @click="changeType('all')"
  22. >
  23. 全部
  24. </div>
  25. <div
  26. class="tab-item"
  27. :class="{ active: activeType === 'disease' }"
  28. @click="changeType('disease')"
  29. >
  30. 病害
  31. </div>
  32. <div
  33. class="tab-item"
  34. :class="{ active: activeType === 'pest' }"
  35. @click="changeType('pest')"
  36. >
  37. 虫害
  38. </div>
  39. </div> -->
  40. <!-- 病虫害列表 -->
  41. <div class="card-grid">
  42. <div
  43. v-for="(item, key) in filteredList"
  44. :key="key"
  45. class="card-item"
  46. @click="showExample(filteredList, item, key)"
  47. >
  48. <div class="thumb-wrap">
  49. <img class="thumb" :src="item.image" :alt="item.name" />
  50. </div>
  51. <div class="card-name">{{ item.name || "病害" }}</div>
  52. </div>
  53. <div v-if="!filteredList.length" class="empty-text">暂无数据</div>
  54. </div>
  55. </div>
  56. </popup>
  57. <!-- 示例照片轮播组件 -->
  58. <example-popup
  59. v-model:show="showExamplePopup"
  60. :images="exampleList.map(item => item.image)"
  61. :start-index="exampleStartIndex"
  62. :title="exampleTitle"
  63. />
  64. </template>
  65. <script setup>
  66. import { ref, computed } from "vue";
  67. import { Popup } from "vant";
  68. import { Search } from "@element-plus/icons-vue";
  69. import ExamplePopup from "./examplePopup.vue";
  70. const showMore = ref(false);
  71. const keyword = ref("");
  72. const activeType = ref("all"); // all / disease / pest
  73. // 病虫害数据(后续可通过接口或外部传入)
  74. const items = ref([
  75. // 示例数据,占位用,后续可替换为接口返回
  76. {
  77. id: 1,
  78. name: "蒂蛀虫",
  79. type: "pest",
  80. image: "https://birdseye-img-ali-cdn.sysuimars.com/birdseye-look-mini/94379/1768801082504.png",
  81. images: [
  82. "https://birdseye-img-ali-cdn.sysuimars.com/birdseye-look-mini/94379/1768801082504.png",
  83. ],
  84. },
  85. ]);
  86. const filteredList = computed(() => {
  87. let list = items.value || [];
  88. if (activeType.value !== "all") {
  89. list = list.filter((it) => it.type === activeType.value);
  90. }
  91. if (keyword.value.trim()) {
  92. const k = keyword.value.trim().toLowerCase();
  93. list = list.filter((it) => (it.name || "").toLowerCase().includes(k));
  94. }
  95. return list;
  96. });
  97. const openPopup = () => {
  98. showMore.value = true;
  99. };
  100. const changeType = (type) => {
  101. activeType.value = type;
  102. };
  103. // 预留给外部设置数据的能力
  104. const setItems = (list) => {
  105. items.value = Array.isArray(list) ? list : [];
  106. };
  107. // 示例轮播相关
  108. const showExamplePopup = ref(false);
  109. const exampleList = ref([]);
  110. const exampleStartIndex = ref(0);
  111. const exampleTitle = ref("示例图");
  112. const showExample = (list, item, index) => {
  113. exampleList.value = list;
  114. exampleStartIndex.value = index;
  115. exampleTitle.value = item.name || "示例图";
  116. showExamplePopup.value = true;
  117. };
  118. defineExpose({
  119. openPopup,
  120. setItems,
  121. });
  122. </script>
  123. <style lang="scss" scoped>
  124. .more-popup {
  125. width: calc(100% - 40px);
  126. border-radius: 16px;
  127. background: #fff;
  128. padding: 16px 0 20px 16px;
  129. box-sizing: border-box;
  130. max-height: 90%;
  131. overflow: hidden;
  132. }
  133. .more-content {
  134. display: flex;
  135. flex-direction: column;
  136. max-height: 100%;
  137. }
  138. .search-bar {
  139. display: flex;
  140. align-items: center;
  141. border: 0.5px solid rgba(0, 0, 0, 0.2);
  142. border-radius: 20px;
  143. padding: 6px 12px;
  144. margin-bottom: 16px;
  145. margin-right: 16px;
  146. .search-icon {
  147. font-size: 18px;
  148. color: #c0c4cc;
  149. margin-right: 6px;
  150. }
  151. .search-input {
  152. flex: 1;
  153. border: none;
  154. outline: none;
  155. background: transparent;
  156. font-size: 14px;
  157. color: rgba(0, 0, 0, 0.5);
  158. }
  159. .search-input::placeholder {
  160. color: rgba(0, 0, 0, 0.5);
  161. }
  162. }
  163. .type-tabs {
  164. display: flex;
  165. gap: 10px;
  166. margin-bottom: 16px;
  167. padding-right: 16px;
  168. .tab-item {
  169. flex: 1;
  170. text-align: center;
  171. height: 32px;
  172. line-height: 32px;
  173. border-radius: 999px;
  174. font-size: 15px;
  175. background: rgba(218, 218, 218, 0.2);
  176. color: #000;
  177. &.all-tab {
  178. flex: none;
  179. width: 73px;
  180. }
  181. }
  182. .tab-item.active {
  183. background: #2199f8;
  184. color: #fff;
  185. }
  186. }
  187. .card-grid {
  188. padding-right: 16px;
  189. display: grid;
  190. grid-template-columns: repeat(3, 1fr);
  191. grid-row-gap: 12px;
  192. grid-column-gap: 5px;
  193. margin-top: 4px;
  194. padding-bottom: 4px;
  195. overflow-y: auto;
  196. /* 让列表区域在内容较多时内部滚动 */
  197. max-height: 70vh;
  198. .card-item {
  199. display: flex;
  200. flex-direction: column;
  201. align-items: center;
  202. }
  203. .thumb-wrap {
  204. width: 100%;
  205. border-radius: 8px;
  206. overflow: hidden;
  207. background: #f5f5f5;
  208. }
  209. .thumb {
  210. width: 100%;
  211. height: 76px;
  212. object-fit: cover;
  213. display: block;
  214. }
  215. .card-name {
  216. margin-top: 5px;
  217. font-size: 12px;
  218. color: #000;
  219. text-align: center;
  220. }
  221. .empty-text {
  222. grid-column: 1 / -1;
  223. text-align: center;
  224. font-size: 14px;
  225. color: #999;
  226. padding: 16px 0;
  227. }
  228. }
  229. </style>