OrdersView.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <template>
  2. <div class="orders-page">
  3. <div class="filter-bar">
  4. <el-radio-group v-model="activeFilter" @change="doFilter">
  5. <el-radio-button value="all">全部</el-radio-button>
  6. <el-radio-button value="unpaid">未支付</el-radio-button>
  7. <el-radio-button value="cancelled">已取消</el-radio-button>
  8. <el-radio-button value="completed">已完成</el-radio-button>
  9. </el-radio-group>
  10. </div>
  11. <div v-loading="orderStore.loading" class="order-list">
  12. <div v-for="order in orderStore.orders" :key="order.id" class="order-card">
  13. <div class="order-top">
  14. <span class="order-title">{{ order.postTitle }}</span>
  15. <el-tag :type="statusType(order.status)" size="small">{{ order.status }}</el-tag>
  16. </div>
  17. <div class="order-meta">
  18. <span>{{ order.expertName }}</span>
  19. <span class="order-amount">¥{{ order.amount }}</span>
  20. </div>
  21. <div class="order-bottom">
  22. <span class="order-time">{{ formatDateTime(order.createTime) }}</span>
  23. <el-button v-if="order.status === '未支付'" size="small" type="primary">去支付</el-button>
  24. </div>
  25. </div>
  26. <EmptyState v-if="!orderStore.loading && orderStore.orders.length === 0" description="暂无订单" />
  27. </div>
  28. </div>
  29. </template>
  30. <script setup lang="ts">
  31. import { ref, onMounted } from 'vue'
  32. import { useOrderStore } from '../store'
  33. import EmptyState from '../components/EmptyState.vue'
  34. import { formatDateTime } from '../util/format'
  35. const orderStore = useOrderStore()
  36. const activeFilter = ref('all')
  37. function doFilter() {
  38. orderStore.fetchOrders(activeFilter.value)
  39. }
  40. function statusType(status: string): string {
  41. if (status === 'completed') return 'success'
  42. if (status === 'unpaid') return 'warning'
  43. if (status === 'cancelled') return 'info'
  44. return ''
  45. }
  46. onMounted(() => {
  47. orderStore.fetchOrders()
  48. })
  49. </script>
  50. <style scoped>
  51. .orders-page {
  52. padding: 0;
  53. }
  54. .filter-bar {
  55. padding: 12px 16px;
  56. overflow-x: auto;
  57. }
  58. .order-list {
  59. padding: 0 16px;
  60. }
  61. .order-card {
  62. background: var(--color-card, #fff);
  63. border-radius: 8px;
  64. padding: 12px 16px;
  65. margin-bottom: 10px;
  66. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  67. }
  68. .order-top {
  69. display: flex;
  70. align-items: center;
  71. justify-content: space-between;
  72. margin-bottom: 6px;
  73. }
  74. .order-title {
  75. font-size: 14px;
  76. font-weight: 600;
  77. flex: 1;
  78. overflow: hidden;
  79. text-overflow: ellipsis;
  80. white-space: nowrap;
  81. margin-right: 8px;
  82. }
  83. .order-meta {
  84. display: flex;
  85. justify-content: space-between;
  86. font-size: 13px;
  87. color: var(--color-text-secondary, #999);
  88. margin-bottom: 6px;
  89. }
  90. .order-amount {
  91. color: var(--color-primary, #db2777);
  92. font-weight: 600;
  93. }
  94. .order-bottom {
  95. display: flex;
  96. justify-content: space-between;
  97. align-items: center;
  98. }
  99. .order-time {
  100. font-size: 12px;
  101. color: var(--color-text-secondary, #999);
  102. }
  103. </style>