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
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { Download, Refresh, Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { exportServiceApplications, getServiceApplications, updateServiceApplicationStatus } from '../api/admin'
import { TALENT_CARD_LEVELS } from '../utils/cardLevels'
import { saveBlob } from '../utils/excel'
 
const loading = ref(false)
const processingId = ref<number | string | null>(null)
const rows = ref<Record<string, any>[]>([])
const filters = reactive({ applicationType: '', keyword: '', serviceKeyword: '', cardLevel: '', status: '', submittedTime: [] as string[] })
const pagination = reactive({ page: 1, size: 10, total: 0 })
 
const appointmentTypes = [
  { label: '体检预约', value: 'MEDICAL_RESERVATION' },
  { label: '医院快捷通道', value: 'FAST_TRACK' },
  { label: '酒店预约', value: 'HOTEL_RESERVATION' },
  { label: '配偶就业', value: 'SPOUSE_EMPLOYMENT' },
  { label: '学生托管', value: 'CHILD_ENTRUSTMENT' },
]
const cardLevels = TALENT_CARD_LEVELS
const statusOptions = ['待处理', '已处理', '已驳回', '待审核', '审核通过', '审核不通过', '已取消']
 
function queryParams(size = pagination.size) {
  return { page: pagination.page, size, applicationType: filters.applicationType || undefined, keyword: filters.keyword || undefined, talentKeyword: filters.keyword || undefined, serviceKeyword: filters.serviceKeyword || undefined, merchantName: filters.serviceKeyword || undefined, hospitalName: filters.serviceKeyword || undefined, cardLevel: filters.cardLevel || undefined, status: filters.status || undefined, submittedStart: filters.submittedTime?.[0], submittedEnd: filters.submittedTime?.[1] }
}
async function loadData() { loading.value = true; try { const result = await getServiceApplications(queryParams() as any); rows.value = (result.records || []) as Record<string, any>[]; pagination.total = result.total || 0 } finally { loading.value = false } }
function search() { pagination.page = 1; loadData() }
function resetFilters() { Object.assign(filters, { applicationType: '', keyword: '', serviceKeyword: '', cardLevel: '', status: '', submittedTime: [] }); search() }
function text(value: unknown) { return value === undefined || value === null || value === '' ? '-' : String(value) }
// 后端返回 ISO 时间(2026-09-01T11:29:35),列表统一显示成 "2026-09-01 11:29:35"。
function formatDateTime(value: unknown) { return typeof value === 'string' && value ? value.replace('T', ' ').slice(0, 19) : '-' }
async function handle(row: Record<string, any>, status = '已处理') { processingId.value = row.id; try { await updateServiceApplicationStatus(row.id, status, '管理员', status === '已驳回' ? '后台驳回' : ''); ElMessage.success('状态已更新'); await loadData() } finally { processingId.value = null } }
async function download() { const blob = await exportServiceApplications(queryParams() as any); saveBlob(blob, '预约申请列表.xlsx') }
onMounted(loadData)
</script>
 
<template>
  <div class="page-stack prototype-page">
    <div class="toolbar"><div><h2>预约服务管理</h2><p>查看、处理、导出体检、快捷通道、酒店、配偶就业、学生托管预约申请。</p></div><el-button :icon="Refresh" :loading="loading" @click="loadData">刷新</el-button></div>
    <section class="panel">
      <el-form class="filter-form" :model="filters" label-width="84px">
        <el-form-item label="预约类型"><el-select v-model="filters.applicationType" clearable placeholder="全部"><el-option v-for="item in appointmentTypes" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-form-item>
        <el-form-item label="关键词"><el-input v-model="filters.keyword" clearable placeholder="姓名、手机号、卡号、申请编号" /></el-form-item>
        <el-form-item label="服务机构"><el-input v-model="filters.serviceKeyword" clearable placeholder="医院、酒店或机构名称" /></el-form-item>
        <el-form-item label="卡片等级"><el-select v-model="filters.cardLevel" clearable placeholder="全部"><el-option label="全部" value="" /><el-option v-for="level in cardLevels" :key="level" :label="level" :value="level" /></el-select></el-form-item>
        <el-form-item label="状态"><el-select v-model="filters.status" clearable placeholder="全部"><el-option v-for="status in statusOptions" :key="status" :label="status" :value="status" /></el-select></el-form-item>
        <el-form-item label="提交时间"><el-date-picker v-model="filters.submittedTime" type="daterange" value-format="YYYY-MM-DD" start-placeholder="开始日期" end-placeholder="结束日期" /></el-form-item>
        <div class="toolbar-actions"><el-button type="primary" :icon="Search" @click="search">查询</el-button><el-button :icon="Refresh" @click="resetFilters">重置</el-button><el-button v-permission="'admin.appointment-management.export'" :icon="Download" @click="download">导出</el-button></div>
      </el-form>
      <el-table v-loading="loading" :data="rows" border empty-text="暂无预约申请数据">
        <el-table-column prop="applicationNo" label="申请单号" min-width="130" />
        <el-table-column label="类型" min-width="120"><template #default="{ row }">{{ text(row.applicationTypeName || row.applicationType) }}</template></el-table-column>
        <el-table-column prop="talentName" label="持卡人" min-width="110" />
        <el-table-column prop="talentMobile" label="手机号" min-width="120" />
        <el-table-column prop="talentLevel" label="等级" min-width="110" />
        <el-table-column label="服务机构" min-width="150" show-overflow-tooltip><template #default="{ row }">{{ text(row.serviceName || row.merchantName || row.hospitalName) }}</template></el-table-column>
        <el-table-column label="预约内容" min-width="150" show-overflow-tooltip><template #default="{ row }">{{ text(row.appointmentContent || row.productName || row.packageName) }}</template></el-table-column>
        <el-table-column label="预约时间" min-width="150"><template #default="{ row }">{{ text(row.appointmentTime || row.expectedTime) }}</template></el-table-column>
        <el-table-column prop="submittedAt" label="提交时间" min-width="170">
          <template #default="{ row }">{{ formatDateTime(row.submittedAt) }}</template>
        </el-table-column>
        <el-table-column prop="status" label="状态" min-width="110" />
        <el-table-column label="操作" width="170" fixed="right"><template #default="{ row }"><el-button link type="primary" :loading="processingId === row.id" @click="handle(row)">处理</el-button><el-button link type="danger" :loading="processingId === row.id" @click="handle(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, prev, pager, next" :total="pagination.total" @change="loadData" /></div>
    </section>
  </div>
</template>