CommonListPage.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <template>
  2. <!-- 资讯详情页 -->
  3. <div class="main-background">
  4. <div class="nav-placeholder"></div>
  5. <!-- 新闻 -->
  6. <section class="main-section main-background main-background-type0 small-h">
  7. <div class="content mb-2">
  8. <!-- 路径 -->
  9. <a-breadcrumb>
  10. <a-breadcrumb-item><a href="" @click="navTo('/')">首页</a></a-breadcrumb-item>
  11. <a-breadcrumb-item>{{ title }}</a-breadcrumb-item>
  12. </a-breadcrumb>
  13. </div>
  14. <div class="content mb-2">
  15. <!-- 搜素栏 -->
  16. <div class="row mt-3">
  17. <!-- 左栏 -->
  18. <div class="col-sm-12 col-md-6 col-lg-6">
  19. <!-- 分类 -->
  20. <TagBar
  21. :tags="tagsData || []"
  22. :margin="[30, 70]"
  23. v-model:selectedTag="selectedTag"
  24. />
  25. </div>
  26. <!-- 右栏 -->
  27. <div class="col-sm-12 col-md-6 col-lg-6 d-flex flex-row justify-content-end">
  28. <Dropdown
  29. v-for="(drop, k) in dropDownNames" :key="k"
  30. :selectedValue="dropDownValues[k] || drop.defaultSelectedValue"
  31. :options="drop.options"
  32. @update:selectedValue="(v) => handleChangeDropDownValue(k, v)"
  33. />
  34. <SimpleInput v-if="showSearch" v-model="searchText" placeholder="请输入关键词" @enter="handleSearch">
  35. <template #suffix>
  36. <img
  37. class="search-icon"
  38. src="@/assets/images/news/IconSearch.png"
  39. alt="搜索"
  40. @click="newsLoader.loadData(undefined, true)"
  41. />
  42. </template>
  43. </SimpleInput>
  44. </div>
  45. </div>
  46. </div>
  47. <div class="content news-list">
  48. <!-- 新闻列表 -->
  49. <SimplePageContentLoader :loader="newsLoader">
  50. <div
  51. v-for="(item, k) in newsLoader.list.value"
  52. :key="item.id"
  53. class="item user-select-none main-clickable"
  54. :style="{ width: rowWidth }"
  55. @click="navTo('/news/detail', { id: item.id })"
  56. >
  57. <img :src="item.image" alt="新闻图片" />
  58. <TitleDescBlock
  59. :title="item.title"
  60. :desc="item.desc || item.title"
  61. :date="DateUtils.formatDate(item.publish_at, DateUtils.FormatStrings.YearCommon)"
  62. @click="handleShowDetail(item)"
  63. />
  64. </div>
  65. </SimplePageContentLoader>
  66. <!-- 分页 -->
  67. <Pagination
  68. v-model:currentPage="newsLoader.page.value"
  69. :totalPages="newsLoader.totalPages.value"
  70. />
  71. </div>
  72. </section>
  73. </div>
  74. </template>
  75. <script setup lang="ts">
  76. import { computed, onMounted, ref, watch, type PropType } from 'vue';
  77. import { useSimplePagerDataLoader } from '@/composeable/SimplePagerDataLoader';
  78. import { usePageAction } from '@/composeable/PageAction';
  79. import DateUtils from '@/common/utils/DateUtils';
  80. import TagBar from '../content/TagBar.vue';
  81. import Dropdown from '../controls/Dropdown.vue';
  82. import SimpleInput from '../controls/SimpleInput.vue';
  83. import SimplePageContentLoader from '@/components/content/SimplePageContentLoader.vue';
  84. import Pagination from '../controls/Pagination.vue';
  85. import TitleDescBlock from '../parts/TitleDescBlock.vue';
  86. const { navTo } = usePageAction();
  87. export interface DropdownCommonItem {
  88. value: number;
  89. title: string;
  90. }
  91. export interface DropDownNames {
  92. options: (string|DropdownCommonItem)[],
  93. defaultSelectedValue: number|string,
  94. }
  95. const props = defineProps({
  96. title: {
  97. type: String,
  98. default: '',
  99. },
  100. dropDownNames: {
  101. type: Object as PropType<DropDownNames[]>,
  102. default: null,
  103. },
  104. showSearch: {
  105. type: Boolean,
  106. default: true,
  107. },
  108. tagsData: {
  109. type: Object as PropType<{
  110. id: number,
  111. name: string,
  112. }[]>,
  113. default: null,
  114. },
  115. pageSize: {
  116. type: Number,
  117. default: 8,
  118. },
  119. rowCount: {
  120. type: Number,
  121. default: 2,
  122. },
  123. rowType: {
  124. type: Number,
  125. default: 1,
  126. },
  127. defaultSelectTag: {
  128. type: Number,
  129. default: 1,
  130. },
  131. load: {
  132. type: Function as PropType<(
  133. page: number,
  134. pageSize: number,
  135. selectedTag: number,
  136. searchText: string,
  137. dropDownValues: number[],
  138. ) => Promise<{
  139. page: number,
  140. total: number,
  141. data: any[],
  142. }>>,
  143. required: true,
  144. },
  145. })
  146. const rowWidth = computed(() => {
  147. switch (props.rowCount) {
  148. case 2:
  149. return `calc(50% - 100px)`;
  150. case 3:
  151. return `calc(33% - 100px)`;
  152. case 4:
  153. return `calc(25% - 100px)`;
  154. }
  155. });
  156. const rowMargin = computed(() => {
  157. switch (props.rowCount) {
  158. case 2:
  159. return 30;
  160. case 3:
  161. return 30;
  162. case 4:
  163. return 30;
  164. }
  165. return '0';
  166. });
  167. const searchText = ref('');
  168. const dropDownValues = ref<any>([]);
  169. function handleSearch() {
  170. newsLoader.loadData(undefined, true);
  171. }
  172. function handleChangeDropDownValue(index: number, value: number) {
  173. dropDownValues.value[index] = value;
  174. newsLoader.loadData(undefined, true);
  175. }
  176. function handleShowDetail(item: any) {
  177. navTo('/news/detail', { id: item.id });
  178. }
  179. const newsLoader = useSimplePagerDataLoader(props.pageSize, (page, size) => props.load(
  180. page, size,
  181. selectedTag.value,
  182. searchText.value,
  183. dropDownValues.value,
  184. ));
  185. //子分类
  186. const selectedTag = ref(props.defaultSelectTag);
  187. watch(selectedTag, () => {
  188. newsLoader.loadData(undefined, true);
  189. })
  190. onMounted(() => {
  191. newsLoader.loadData(undefined, true);
  192. });
  193. </script>
  194. <style lang="scss">
  195. .search-icon {
  196. width: 20px;
  197. height: 20px;
  198. cursor: pointer;
  199. }
  200. </style>