yeg
2026-09-18 70ea0911ce7519ca802266078624e9fed3559a2c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
<script setup lang="ts">
import { onMounted, reactive, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Refresh, Search } from '@element-plus/icons-vue'
import { getAdminProducts } from '../api/admin'
import type { Product } from '../types/admin'
 
const route = useRoute()
const router = useRouter()
const loading = ref(false)
const products = ref<Product[]>([])
 
const merchantTypes = [
  '餐饮服务',
  '电影院',
  '大剧院',
  '酒店服务',
  '免费体检',
  '就医绿色通道',
  '金融服务',
  '学生托管',
  '公寓租赁服务',
  '停车服务',
  '洗车服务',
  '景区服务',
  '购房优惠',
  '购车优惠',
]
 
const filters = reactive({
  merchantId: undefined as number | string | undefined,
  merchantName: '',
  contactMobile: '',
  productName: '',
  merchantType: '',
  status: undefined as number | undefined,
  createdTime: [] as string[],
})
 
const pagination = reactive({
  page: 1,
  size: 10,
  total: 0,
})
 
function auditStatusText(status?: number) {
  if (status === 2) return '审核通过'
  if (status === 3) return '已驳回'
  return '待审核'
}
 
function amountText(row: Product) {
  const isHotel = row.merchantType === '酒店服务' || row.merchantType === '酒店'
  if (isHotel && row.salePrice !== undefined && row.originalPrice !== undefined) {
    return `${formatAmount(row.salePrice)} - ${formatAmount(row.originalPrice)}`
  }
  return formatAmount(row.salePrice ?? row.originalPrice)
}
 
function formatAmount(amount?: number) {
  if (amount === undefined || amount === null) return ''
  return Number(amount).toFixed(2).replace(/\.00$/, '')
}
 
// 销量是计数:0 也要显示成 0,不能因为 0 变空白让人以为没统计出来。
function salesText(row: Product) {
  const count = row.salesCount
  return count === undefined || count === null ? 0 : count
}
 
function formatDateTime(value?: string) {
  return value ? value.replace('T', ' ') : ''
}
 
async function loadData() {
  loading.value = true
  try {
    const result = await getAdminProducts({
      page: pagination.page,
      size: pagination.size,
      merchantId: filters.merchantId,
      merchantName: filters.merchantName || undefined,
      contactMobile: filters.contactMobile || undefined,
      keyword: filters.productName || undefined,
      type: filters.merchantType || undefined,
      status: filters.status,
      createdStart: filters.createdTime?.[0],
      createdEnd: filters.createdTime?.[1],
    })
    products.value = result.records
    pagination.total = result.total
  } catch {
    products.value = []
    pagination.total = 0
  } finally {
    loading.value = false
  }
}
 
function syncRouteMerchant() {
  const merchantId = route.query.merchantId
  const merchantName = route.query.merchantName
  filters.merchantId = typeof merchantId === 'string' && merchantId ? Number(merchantId) : undefined
  filters.merchantName = typeof merchantName === 'string' ? merchantName : ''
}
 
function search() {
  pagination.page = 1
  loadData()
}
 
function resetFilters() {
  filters.merchantId = undefined
  filters.merchantName = ''
  filters.contactMobile = ''
  filters.productName = ''
  filters.merchantType = ''
  filters.status = undefined
  filters.createdTime = []
  router.replace({ path: '/products' })
  search()
}
 
function viewDetail(row: Product) {
  router.push(`/products/${row.id}`)
}
 
watch(
  () => [route.query.merchantId, route.query.merchantName],
  () => {
    syncRouteMerchant()
    search()
  },
)
 
onMounted(async () => {
  syncRouteMerchant()
  await loadData()
})
</script>
 
<template>
  <div class="page-stack prototype-page product-audit-page">
    <section class="panel">
      <div class="panel-header">
        <h3>查询表格</h3>
      </div>
 
      <el-form class="product-audit-filter-form" :model="filters" label-width="74px">
        <el-form-item label="商家">
          <el-input v-model="filters.merchantName" placeholder="请输入商家名称" clearable />
        </el-form-item>
        <el-form-item label="联系电话">
          <el-input v-model="filters.contactMobile" placeholder="请输入商家联系电话" clearable />
        </el-form-item>
        <el-form-item label="团单名称">
          <el-input v-model="filters.productName" placeholder="请输入团单名称" clearable />
        </el-form-item>
        <el-form-item label="商家类型">
          <el-select v-model="filters.merchantType" placeholder="全部" clearable>
            <el-option label="全部" value="" />
            <el-option v-for="type in merchantTypes" :key="type" :label="type" :value="type" />
          </el-select>
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="filters.status" placeholder="全部" clearable>
            <el-option label="全部" :value="undefined" />
            <el-option label="待审核" :value="1" />
            <el-option label="审核通过" :value="2" />
            <el-option label="已驳回" :value="3" />
          </el-select>
        </el-form-item>
        <el-form-item label="创建时间">
          <el-date-picker
            v-model="filters.createdTime"
            type="daterange"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            range-separator="至"
            value-format="YYYY-MM-DD"
          />
        </el-form-item>
        <div class="product-audit-filter-actions">
          <el-button type="primary" :icon="Search" @click="search">查询</el-button>
          <el-button :icon="Refresh" @click="resetFilters">重置</el-button>
        </div>
      </el-form>
 
      <el-table
        v-loading="loading"
        :data="products"
        border
        class="product-audit-table"
        empty-text="暂无团单数据"
      >
        <el-table-column type="index" label="编号" width="58" align="center" />
        <el-table-column prop="merchantName" label="商家名称" min-width="150" show-overflow-tooltip />
        <el-table-column prop="contactMobile" label="联系电话" width="128" align="center">
          <template #default="{ row }">{{ row.contactMobile || '-' }}</template>
        </el-table-column>
        <el-table-column prop="merchantType" label="商家类型" width="130">
          <template #default="{ row }">{{ row.merchantType || '-' }}</template>
        </el-table-column>
        <el-table-column prop="productName" label="商品名称" min-width="120" show-overflow-tooltip />
        <el-table-column label="商品金额" width="120" align="center">
          <template #default="{ row }">{{ amountText(row) }}</template>
        </el-table-column>
        <el-table-column prop="salesCount" label="销量" width="110" align="center">
          <template #default="{ row }">{{ salesText(row) }}</template>
        </el-table-column>
        <el-table-column label="提交修改时间" width="145" align="center">
          <template #default="{ row }">{{ formatDateTime(row.submitTime || row.createdAt) }}</template>
        </el-table-column>
        <el-table-column label="状态" width="120" align="center">
          <template #default="{ row }">{{ auditStatusText(row.auditStatus) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="180" fixed="right" align="center">
          <template #default="{ row }">
            <el-button v-permission="'admin.products.view'" link type="primary" @click="viewDetail(row)">查看</el-button>
          </template>
        </el-table-column>
      </el-table>
 
      <div class="pagination-row">
        <el-pagination
          v-model:current-page="pagination.page"
          v-model:page-size="pagination.size"
          background
          layout="total, sizes, prev, pager, next"
          :page-sizes="[10, 20, 50]"
          :total="pagination.total"
          @change="loadData"
        />
      </div>
    </section>
  </div>
</template>