index.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. <template>
  2. <div style="display: flex; justify-content: center" class="main-content-wrapper">
  3. <a-card :bordered="false" style="width: 1200px" class="formMount">
  4. <a-space>
  5. <a-input-search
  6. v-model:value="searchFormState.postTitle"
  7. placeholder="请输入名称关键词"
  8. enter-button
  9. allowClear
  10. @search="onSearch"
  11. />
  12. <a-select
  13. v-model:value="typeValue"
  14. show-search
  15. placeholder="所有分类"
  16. style="width: 200px"
  17. :options="typeOptions"
  18. :filter-option="filterOption"
  19. @change="handleChange"
  20. ></a-select>
  21. <a-radio-group v-model:value="searchFormState.sortOrder" button-style="solid">
  22. <a-radio-button
  23. v-for="module in moduleTypeList"
  24. :key="module.id"
  25. :value="module.id"
  26. @click="moduleClock(module.id, module.type)"
  27. >
  28. {{ module.title }}
  29. </a-radio-button>
  30. </a-radio-group>
  31. <a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.sortOrder)">
  32. <template #icon><plus-outlined /></template>
  33. 创建新主题
  34. </a-button>
  35. </a-space>
  36. <a-table
  37. ref="table"
  38. class="mt-2"
  39. :columns="columns"
  40. :dataSource="tableData"
  41. :row-key="(record) => record.id"
  42. :custom-row="customRow"
  43. :pagination="false"
  44. >
  45. <template #bodyCell="{ column, record }">
  46. <template v-if="column.dataIndex === 'postTitle'">
  47. <div class="forum-list-title">{{ record.postTitle }}</div>
  48. <div class="forum-list-type">{{ record.typeName }}</div>
  49. <div class="forum-list-content one-line" v-html="record.postContent"></div>
  50. </template>
  51. <template v-if="column.dataIndex === 'lastReplyUserAvatar'">
  52. <a-tooltip :title="record.lastReplyUserNickName" placement="top">
  53. <a-avatar :src="record.lastReplyUserAvatar"></a-avatar>
  54. </a-tooltip>
  55. </template>
  56. <template v-if="column.dataIndex === 'lastReplyTime'">
  57. <div>{{ formatDateTime(record.lastReplyTime) }}</div>
  58. </template>
  59. </template>
  60. </a-table>
  61. <div style="text-align: center; cursor: pointer" class="mt-2" @click="moreList">{{ moreText }}</div>
  62. <Form ref="formRef" @successful="loadData(pagination.value)" />
  63. </a-card>
  64. </div>
  65. </template>
  66. <script setup name="forumList">
  67. import forumApi from '@/api/forum/forumApi'
  68. import Form from './form.vue'
  69. import { parseTime } from '@/utils/exam'
  70. import { useRoute, useRouter } from 'vue-router'
  71. const route = useRoute()
  72. const router = useRouter()
  73. const formRef = ref()
  74. let searchFormState = reactive({
  75. sortOrder: 0,
  76. postTitle: '',
  77. postType: route.query.postType ?? null
  78. })
  79. const table = ref(null)
  80. const moduleTypeList = ref([
  81. {
  82. title: '最新',
  83. id: 0,
  84. type: 1,
  85. state: 0
  86. },
  87. {
  88. title: '热门',
  89. id: 1,
  90. type: 1,
  91. state: 1
  92. },
  93. {
  94. title: '我发布的',
  95. id: 2,
  96. type: 2,
  97. state: 1
  98. },
  99. {
  100. title: '我回复的',
  101. id: 3,
  102. type: 2,
  103. state: 2
  104. },
  105. {
  106. title: '关于我的',
  107. id: 4,
  108. type: 2,
  109. state: 3
  110. },
  111. {
  112. title: '我点赞的',
  113. id: 5,
  114. type: 2,
  115. state: 4
  116. }
  117. ])
  118. const columns = [
  119. {
  120. title: '主题',
  121. dataIndex: 'postTitle'
  122. },
  123. {
  124. title: '最后回复人',
  125. dataIndex: 'lastReplyUserAvatar',
  126. align: 'center',
  127. width: 120
  128. },
  129. {
  130. title: '回复量',
  131. dataIndex: 'replyCount',
  132. align: 'center',
  133. width: 100
  134. },
  135. {
  136. title: '浏览量',
  137. dataIndex: 'viewCount',
  138. align: 'center',
  139. width: 100
  140. },
  141. {
  142. title: '最后回复时间',
  143. dataIndex: 'lastReplyTime',
  144. align: 'center',
  145. width: 120
  146. }
  147. ]
  148. const typeValue = ref('所有分类')
  149. const typeOptions = ref([])
  150. const handleChange = (value) => {
  151. exType.value = false
  152. searchFormState.typeId = value
  153. if(searchFormState.sortOrder > 1){
  154. searchFormState.sortOrder = 0
  155. }
  156. loadData(pagination.value)
  157. }
  158. const filterOption = (input, option) => {
  159. return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
  160. }
  161. function formatDateTime(val) {
  162. if (!val) return ''
  163. return parseTime(val, '{y}-{m}-{d} {h}:{i}:{s}')
  164. }
  165. // 查询
  166. const onSearch = () => {
  167. exType.value = false
  168. loadData(pagination.value)
  169. }
  170. function customRow(record) {
  171. return {
  172. onClick: () => itemSelect(record)
  173. }
  174. }
  175. function itemSelect(record) {
  176. router.push({
  177. path: '/forum/detail',
  178. query: {
  179. postId: record.postId,
  180. postType: route.query.postType ?? ''
  181. }
  182. })
  183. }
  184. function getTypeList() {
  185. forumApi.forumTypeList().then((data) => {
  186. typeOptions.value = data.map((r) => {
  187. return {
  188. label: r.typeName,
  189. value: r.typeId,
  190. ...r
  191. }
  192. })
  193. })
  194. }
  195. const exType = ref(false)
  196. const tableData = ref([])
  197. const tableTotal = ref(0)
  198. const loadData = (parameter, a) => {
  199. if (exType.value) {
  200. let postExtend = moduleTypeList.value.filter((r) => r.id == searchFormState.sortOrder)[0]?.state
  201. return forumApi.moreList(Object.assign(parameter, { postExtend: postExtend })).then((data) => {
  202. tableTotal.value = data.total
  203. if (a) {
  204. tableData.value = Object.assign(tableData.value, data.records)
  205. } else {
  206. if (data) {
  207. tableData.value = data.records
  208. } else {
  209. tableData.value = []
  210. }
  211. }
  212. })
  213. } else {
  214. return forumApi.forumList(Object.assign(parameter, searchFormState)).then((data) => {
  215. tableTotal.value = data.total
  216. if (a) {
  217. tableData.value = tableData.value.concat(data.records)
  218. } else {
  219. if (data) {
  220. tableData.value = data.records
  221. } else {
  222. tableData.value = []
  223. }
  224. }
  225. })
  226. }
  227. }
  228. const pagination = ref({
  229. current: 1,
  230. size: 10
  231. })
  232. // 切换应用标签查询菜单列表
  233. const moduleClock = (value, t) => {
  234. exType.value = false
  235. searchFormState.sortOrder = value
  236. pagination.value.current = 1
  237. moreText.value = '加载更多'
  238. if (t == 2) {
  239. exType.value = true
  240. typeValue.value = '所有分类'
  241. }
  242. loadData(pagination.value)
  243. }
  244. const moreText = ref()
  245. const moreList = () => {
  246. if (tableTotal.value > pagination.value.current * pagination.value.size) {
  247. pagination.value.current += 1
  248. loadData(pagination.value, 1)
  249. moreText.value = '加载更多'
  250. } else {
  251. moreText.value = '全部加载完成'
  252. }
  253. }
  254. // 定义滚动函数
  255. const handleScroll = () => {
  256. const tableContainer = window.document.querySelector('.main-content-wrapper')
  257. const scrollPosition = tableContainer.scrollTop
  258. const isBottom = tableContainer.scrollHeight - scrollPosition - 20 < tableContainer.clientHeight
  259. if (isBottom) {
  260. if (tableTotal.value > pagination.value.current * pagination.value.size) {
  261. pagination.value.current += 1
  262. loadData(pagination.value, 1)
  263. moreText.value = '加载更多'
  264. } else {
  265. moreText.value = '全部加载完成'
  266. }
  267. console.log('加载更多')
  268. }
  269. }
  270. // 添加scroll监听
  271. onMounted(() => {
  272. getTypeList()
  273. loadData(pagination.value)
  274. nextTick(() => {
  275. if (table.value) {
  276. const tableContainer = window.document.querySelector('.main-content-wrapper')
  277. tableContainer.addEventListener('scroll', handleScroll)
  278. }
  279. })
  280. })
  281. // 移除scroll监听
  282. onBeforeUnmount(() => {
  283. nextTick(() => {
  284. if (table.value) {
  285. const tableContainer = window.document.querySelector('.main-content-wrapper')
  286. tableContainer.removeEventListener('scroll', handleScroll)
  287. }
  288. })
  289. })
  290. </script>
  291. <style scoped>
  292. .forum-list-title {
  293. font-size: 16px;
  294. font-weight: bold;
  295. }
  296. .forum-list-type {
  297. font-size: 12px;
  298. }
  299. .forum-list-content {
  300. font-size: 14px;
  301. color: #696969;
  302. }
  303. .one-line {
  304. display: -webkit-box;
  305. -webkit-box-orient: vertical;
  306. -webkit-line-clamp: 1;
  307. overflow: hidden;
  308. }
  309. </style>