index.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <script setup lang="ts">
  2. import { reactive, onMounted, ref, nextTick } from "vue";
  3. import { getParkingCouponRecordPage } from "@/api/parking-coupon";
  4. import { getStationList } from "@/api/station";
  5. import { useRenderIcon } from "@/components/ReIcon/src/hooks";
  6. import { useStationScope } from "@/hooks/useStationScope";
  7. defineOptions({ name: "AdminParkingCouponRecord" });
  8. const queryRef = ref();
  9. const state = reactive({
  10. formQuery: {
  11. stationId: "",
  12. status: "" as any
  13. },
  14. stationOptions: [] as Array<{ stationId: string; stationName: string }>,
  15. pageQuery: {
  16. pageNum: 1,
  17. pageSize: 10,
  18. total: 0
  19. },
  20. tableData: {
  21. height: 500,
  22. data: [] as Array<any>,
  23. loading: false,
  24. columns: [
  25. { label: "券码", prop: "code", width: 280, fixed: "left" },
  26. { label: "用户ID", prop: "userId", width: 100 },
  27. { label: "站点ID", prop: "stationId", width: 120 },
  28. { label: "关联订单", prop: "orderId", width: 200 },
  29. { label: "状态", prop: "status", width: 100 },
  30. { label: "发放时间", prop: "createTime", width: 180 },
  31. { label: "使用时间", prop: "usedTime", width: 180 },
  32. { label: "过期时间", prop: "expireTime", width: 180 }
  33. ]
  34. }
  35. });
  36. //站点筛选与全局当前站点联动(回调懒引用,规避 loadData 声明顺序的 TDZ 错误)
  37. useStationScope(state.formQuery, (refresh?: boolean) => loadData(refresh));
  38. onMounted(() => {
  39. loadStations();
  40. loadData();
  41. nextTick(() => {
  42. const bodyHeight = document.body.clientHeight;
  43. const queryHeight = queryRef.value?.$el?.clientHeight || 0;
  44. state.tableData.height = bodyHeight - queryHeight - 260;
  45. });
  46. });
  47. const loadStations = () => {
  48. getStationList({ pageNum: 1, pageSize: 200 }).then((res: any) => {
  49. state.stationOptions = res?.list || res?.records || [];
  50. }).catch(() => {});
  51. };
  52. const loadData = (refresh: boolean = false) => {
  53. if (refresh) {
  54. state.pageQuery.pageNum = 1;
  55. }
  56. state.tableData.loading = true;
  57. const params: any = {
  58. pageNum: state.pageQuery.pageNum,
  59. pageSize: state.pageQuery.pageSize
  60. };
  61. if (state.formQuery.stationId) params.stationId = state.formQuery.stationId;
  62. if (state.formQuery.status !== "" && state.formQuery.status !== null && state.formQuery.status !== undefined) {
  63. params.status = state.formQuery.status;
  64. }
  65. getParkingCouponRecordPage(params)
  66. .then((res: any) => {
  67. state.tableData.data = res?.list || res?.records || [];
  68. state.pageQuery.total = res?.total || 0;
  69. })
  70. .catch(() => {
  71. state.tableData.data = [];
  72. })
  73. .finally(() => {
  74. state.tableData.loading = false;
  75. });
  76. };
  77. const handleSizeChange = (size: number) => {
  78. state.pageQuery.pageSize = size;
  79. loadData(true);
  80. };
  81. const handleCurrentChange = (page: number) => {
  82. state.pageQuery.pageNum = page;
  83. loadData();
  84. };
  85. const handleSearch = () => loadData(true);
  86. const handleReset = () => {
  87. state.formQuery = { stationId: "", status: "" };
  88. loadData(true);
  89. };
  90. </script>
  91. <template>
  92. <div class="page-container">
  93. <el-card shadow="hover">
  94. <template #header>
  95. <span class="card-header">停车券发放记录</span>
  96. </template>
  97. <el-form ref="queryRef" :model="state.formQuery" inline class="search-form">
  98. <el-form-item label="站点">
  99. <el-select
  100. v-model="state.formQuery.stationId"
  101. placeholder="选择站点"
  102. clearable
  103. style="width: 200px"
  104. >
  105. <el-option
  106. v-for="item in state.stationOptions"
  107. :key="item.stationId"
  108. :label="item.stationName"
  109. :value="item.stationId"
  110. />
  111. </el-select>
  112. </el-form-item>
  113. <el-form-item label="状态">
  114. <el-select
  115. v-model="state.formQuery.status"
  116. placeholder="状态"
  117. clearable
  118. style="width: 150px"
  119. >
  120. <el-option label="未使用" :value="0" />
  121. <el-option label="已使用" :value="1" />
  122. </el-select>
  123. </el-form-item>
  124. <el-form-item>
  125. <el-button
  126. type="primary"
  127. :icon="useRenderIcon('ri/search-line')"
  128. @click="handleSearch"
  129. >
  130. 查询
  131. </el-button>
  132. <el-button
  133. :icon="useRenderIcon('ri/refresh-line')"
  134. @click="handleReset"
  135. >
  136. 重置
  137. </el-button>
  138. </el-form-item>
  139. </el-form>
  140. <el-table
  141. v-loading="state.tableData.loading"
  142. :data="state.tableData.data"
  143. :height="state.tableData.height"
  144. border
  145. stripe
  146. >
  147. <template #empty>
  148. <el-empty description="暂无数据" />
  149. </template>
  150. <el-table-column
  151. v-for="col in state.tableData.columns"
  152. :key="col.prop"
  153. :prop="col.prop"
  154. :label="col.label"
  155. :width="col.width"
  156. :fixed="(col as any).fixed"
  157. show-overflow-tooltip
  158. >
  159. <template #default="{ row }">
  160. <template v-if="col.prop === 'status'">
  161. <el-tag :type="row.status === 1 ? 'success' : 'info'" size="small">
  162. {{ row.status === 1 ? "已使用" : "未使用" }}
  163. </el-tag>
  164. </template>
  165. <template v-else>
  166. {{ row[col.prop] || "-" }}
  167. </template>
  168. </template>
  169. </el-table-column>
  170. </el-table>
  171. <div class="pagination-container">
  172. <el-pagination
  173. v-model:current-page="state.pageQuery.pageNum"
  174. v-model:page-size="state.pageQuery.pageSize"
  175. :total="state.pageQuery.total"
  176. :page-sizes="[10, 20, 50, 100]"
  177. layout="total, sizes, prev, pager, next, jumper"
  178. @size-change="handleSizeChange"
  179. @current-change="handleCurrentChange"
  180. />
  181. </div>
  182. </el-card>
  183. </div>
  184. </template>
  185. <style scoped lang="scss">
  186. .page-container {
  187. padding: 20px;
  188. }
  189. .card-header { font-size: 16px; font-weight: 600; }
  190. .search-form {
  191. margin-bottom: 16px;
  192. }
  193. .pagination-container {
  194. display: flex;
  195. justify-content: flex-end;
  196. margin-top: 20px;
  197. }
  198. </style>