ActivityRegistrationReview.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <template>
  2. <div class="registration-review admin-page">
  3. <div class="header">
  4. <h2>活动报名审核</h2>
  5. <div class="filters">
  6. <el-select v-model="activityId" placeholder="选择活动" @change="loadList" style="width: 200px;" clearable>
  7. <el-option v-for="a in activityList" :key="a.id" :label="a.title" :value="a.id" />
  8. </el-select>
  9. <el-input v-model="keyword" placeholder="搜索用户/孩子ID..." prefix-icon="el-icon-search" style="width:200px" clearable @keyup.enter.native="loadList" @clear="loadList" />
  10. <el-select v-model="statusFilter" placeholder="状态筛选" @change="loadList" style="width: 130px;" clearable>
  11. <el-option label="全部状态" value="" />
  12. <el-option label="待审核" value="pending" />
  13. <el-option label="已通过" value="approved" />
  14. <el-option label="已拒绝" value="rejected" />
  15. </el-select>
  16. </div>
  17. </div>
  18. <div class="table-scroll-wrap-sm">
  19. <el-table :max-height="tableHeight" :data="filteredList" v-loading="loading" border stripe>
  20. <el-table-column prop="id" label="ID" width="60" />
  21. <el-table-column prop="userId" label="用户ID" width="70" />
  22. <el-table-column prop="childId" label="孩子ID" width="70" />
  23. <el-table-column prop="status" label="状态" width="90">
  24. <template slot-scope="{ row }">
  25. <el-tag :type="row.status === 'approved' ? 'success' : row.status === 'rejected' ? 'danger' : 'warning'">
  26. {{ row.status === 'approved' ? '已通过' : row.status === 'rejected' ? '已拒绝' : '待审核' }}
  27. </el-tag>
  28. </template>
  29. </el-table-column>
  30. <el-table-column prop="registeredAt" label="报名时间" width="160">
  31. <template slot-scope="{ row }">
  32. {{ formatTime(row.registeredAt || row.createdAt) }}
  33. </template>
  34. </el-table-column>
  35. <el-table-column label="操作" width="200" fixed="right">
  36. <template slot-scope="{ row }">
  37. <el-button v-if="row.status === 'pending'" type="success" size="mini" @click="handleApprove(row)">通过</el-button>
  38. <el-button v-if="row.status === 'pending'" type="danger" size="mini" @click="showRejectDialog(row)">拒绝</el-button>
  39. <span v-else style="color: #999;">已处理</span>
  40. </template>
  41. </el-table-column>
  42. </el-table>
  43. </div>
  44. <el-dialog title="拒绝原因" :visible.sync="rejectDialogVisible" width="400px">
  45. <el-input v-model="rejectReason" type="textarea" :rows="3" placeholder="请输入拒绝原因" />
  46. <span slot="footer">
  47. <el-button @click="rejectDialogVisible = false">取消</el-button>
  48. <el-button type="danger" @click="handleReject">确认拒绝</el-button>
  49. </span>
  50. </el-dialog>
  51. </div>
  52. </template>
  53. <script>
  54. import { getActivityList } from '@/api/activity'
  55. import { getRegistrationList, approveRegistration, rejectRegistration } from '@/api/activity'
  56. export default {
  57. name: 'ActivityRegistrationReview',
  58. data() {
  59. return {
  60. activityList: [],
  61. list: [],
  62. loading: false,
  63. keyword: '',
  64. activityId: null,
  65. statusFilter: '',
  66. rejectDialogVisible: false,
  67. rejectReason: '',
  68. currentRow: null
  69. }
  70. },
  71. computed: {
  72. tableHeight() {
  73. return window.innerHeight - 300
  74. },
  75. filteredList() {
  76. if (!this.keyword) return this.list
  77. var kw = this.keyword.toLowerCase()
  78. return this.list.filter(function(item) {
  79. return (item.userId && String(item.userId).includes(kw)) ||
  80. (item.childId && String(item.childId).includes(kw))
  81. })
  82. }
  83. },
  84. mounted() {
  85. this.loadActivities()
  86. },
  87. methods: {
  88. formatTime(t) {
  89. if (!t) return '-'
  90. return t.replace ? t.replace('T', ' ').substring(0, 19) : t
  91. },
  92. async loadActivities() {
  93. try {
  94. const res = await getActivityList({ page: 1, size: 100 })
  95. if (res.code === 200) this.activityList = (res.data && res.data.records) || res.data || []
  96. } catch (e) { console.error(e) }
  97. },
  98. async loadList() {
  99. if (!this.activityId) return this.$message.warning('请先选择活动')
  100. this.loading = true
  101. try {
  102. const params = { activityId: this.activityId }
  103. if (this.statusFilter) params.status = this.statusFilter
  104. const res = await getRegistrationList(params)
  105. if (res.code === 200) this.list = res.data || []
  106. } catch (e) { console.error(e) }
  107. this.loading = false
  108. },
  109. async handleApprove(row) {
  110. try {
  111. const res = await approveRegistration({ registrationId: row.id })
  112. if (res.code === 200) {
  113. this.$message.success('已通过')
  114. this.loadList()
  115. } else {
  116. this.$message.error(res.message || '操作失败')
  117. }
  118. } catch (e) { this.$message.error('操作失败') }
  119. },
  120. showRejectDialog(row) {
  121. this.currentRow = row
  122. this.rejectReason = ''
  123. this.rejectDialogVisible = true
  124. },
  125. async handleReject() {
  126. try {
  127. const res = await rejectRegistration({ registrationId: this.currentRow.id, rejectReason: this.rejectReason })
  128. if (res.code === 200) {
  129. this.$message.success('已拒绝')
  130. this.rejectDialogVisible = false
  131. this.loadList()
  132. } else {
  133. this.$message.error(res.message || '操作失败')
  134. }
  135. } catch (e) { this.$message.error('操作失败') }
  136. }
  137. }
  138. }
  139. </script>
  140. <style scoped>
  141. .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
  142. .header h2 { margin: 0; }
  143. .filters { display: flex; align-items: center; gap: 12px; }
  144. </style>