|
|
@@ -3,7 +3,8 @@ import {
|
|
|
generateQrCodes,
|
|
|
queryQrCodes,
|
|
|
downloadQrCodesByDate,
|
|
|
- getQrCodeScanRecords
|
|
|
+ getQrCodeScanRecords,
|
|
|
+ getQrCodeInfo
|
|
|
} from '@/services/api'
|
|
|
import { getQrCodeTypeConfig } from '@/enums'
|
|
|
import { useDateFormat } from '@vueuse/core'
|
|
|
@@ -76,6 +77,11 @@ const selectedQrCode = ref(null)
|
|
|
const batchDownloadDialog = ref(false)
|
|
|
const downloadDate = ref(null)
|
|
|
|
|
|
+// 详情对话框
|
|
|
+const detailDialog = ref(false)
|
|
|
+const detailLoading = ref(false)
|
|
|
+const qrCodeDetail = ref(null)
|
|
|
+
|
|
|
// 获取二维码类型配置(使用枚举)
|
|
|
const getTypeConfig = (type) => {
|
|
|
return getQrCodeTypeConfig(type)
|
|
|
@@ -298,6 +304,28 @@ const copyToClipboard = (text) => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+// 查看详情
|
|
|
+const viewDetail = async (qrCode) => {
|
|
|
+ try {
|
|
|
+ detailDialog.value = true
|
|
|
+ detailLoading.value = true
|
|
|
+ qrCodeDetail.value = null
|
|
|
+
|
|
|
+ const response = await getQrCodeInfo(qrCode.id)
|
|
|
+ qrCodeDetail.value = response
|
|
|
+ } catch (error) {
|
|
|
+ detailDialog.value = false
|
|
|
+ toast.add({
|
|
|
+ severity: 'error',
|
|
|
+ summary: '错误',
|
|
|
+ detail: error.message || '获取详情失败',
|
|
|
+ life: 3000
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ detailLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
fetchData()
|
|
|
})
|
|
|
@@ -366,9 +394,11 @@ onMounted(() => {
|
|
|
{{ formatDate(slotProps.data.createdAt) }}
|
|
|
</template>
|
|
|
</Column>
|
|
|
- <Column header="操作" style="min-width: 150px">
|
|
|
+ <Column header="操作" style="min-width: 200px">
|
|
|
<template #body="slotProps">
|
|
|
<div class="flex gap-1">
|
|
|
+ <Button icon="pi pi-eye" severity="info" size="small" text rounded v-tooltip.top="'查看详情'"
|
|
|
+ @click="viewDetail(slotProps.data)" />
|
|
|
<Button icon="pi pi-chart-line" label="扫描记录" size="small" text style="white-space: nowrap"
|
|
|
@click="viewScanRecords(slotProps.data)" />
|
|
|
<Button icon="pi pi-download" severity="danger" size="small" text rounded v-tooltip.top="'下载'"
|
|
|
@@ -485,5 +515,164 @@ onMounted(() => {
|
|
|
<Button label="下载" @click="handleBatchDownload" />
|
|
|
</template>
|
|
|
</Dialog>
|
|
|
+
|
|
|
+ <!-- 详情对话框 -->
|
|
|
+ <Dialog v-model:visible="detailDialog" :modal="true" header="二维码详情" :style="{ width: '750px' }" position="center">
|
|
|
+ <div v-if="detailLoading" class="py-10 text-center text-gray-500">详情加载中...</div>
|
|
|
+ <div v-else-if="qrCodeDetail" class="space-y-4">
|
|
|
+ <!-- 二维码基本信息 -->
|
|
|
+ <div class="border rounded p-4">
|
|
|
+ <h4 class="font-semibold mb-3">二维码信息</h4>
|
|
|
+ <div class="grid grid-cols-2 gap-4">
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">二维码编号</div>
|
|
|
+ <div class="font-mono text-sm break-all">{{ qrCodeDetail.qrCode || '-' }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">类型</div>
|
|
|
+ <div>
|
|
|
+ <Tag :severity="getTypeConfig(qrCodeDetail.qrType).severity">
|
|
|
+ <i :class="`pi ${getTypeConfig(qrCodeDetail.qrType).icon} mr-1`"></i>
|
|
|
+ {{ getTypeConfig(qrCodeDetail.qrType).label }}
|
|
|
+ </Tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">激活状态</div>
|
|
|
+ <div>
|
|
|
+ <Tag :value="qrCodeDetail.isActivated ? '已激活' : '未激活'"
|
|
|
+ :severity="qrCodeDetail.isActivated ? 'success' : 'secondary'" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">扫描次数</div>
|
|
|
+ <div class="font-semibold text-lg text-blue-600">{{ qrCodeDetail.scanCount || 0 }} 次</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">创建时间</div>
|
|
|
+ <div>{{ formatDate(qrCodeDetail.createdAt) }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">更新时间</div>
|
|
|
+ <div>{{ formatDate(qrCodeDetail.updatedAt) }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 关联信息 -->
|
|
|
+ <div v-if="qrCodeDetail.info" class="border rounded p-4">
|
|
|
+ <h4 class="font-semibold mb-3">关联信息</h4>
|
|
|
+
|
|
|
+ <!-- 人员信息 -->
|
|
|
+ <div v-if="qrCodeDetail.qrType === 'person'" class="grid grid-cols-2 gap-4">
|
|
|
+ <div v-if="qrCodeDetail.info.photoUrl" class="col-span-2 text-center mb-2">
|
|
|
+ <img :src="qrCodeDetail.info.photoUrl" alt="照片" class="w-32 h-32 object-cover rounded mx-auto" />
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">姓名</div>
|
|
|
+ <div class="font-medium">{{ qrCodeDetail.info.name || '-' }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">性别</div>
|
|
|
+ <div class="font-medium">{{ qrCodeDetail.info.gender === 'male' ? '男' : qrCodeDetail.info.gender ===
|
|
|
+ 'female'
|
|
|
+ ? '女' : '其他' }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">电话</div>
|
|
|
+ <div>
|
|
|
+ <a v-if="qrCodeDetail.info.phone" :href="`tel:${qrCodeDetail.info.phone}`"
|
|
|
+ class="text-blue-600 hover:underline">
|
|
|
+ {{ qrCodeDetail.info.phone }}
|
|
|
+ </a>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">紧急联系人</div>
|
|
|
+ <div class="font-medium">{{ qrCodeDetail.info.emergencyContactName || '-' }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">紧急联系人电话</div>
|
|
|
+ <div>
|
|
|
+ <a v-if="qrCodeDetail.info.emergencyContactPhone"
|
|
|
+ :href="`tel:${qrCodeDetail.info.emergencyContactPhone}`" class="text-blue-600 hover:underline">
|
|
|
+ {{ qrCodeDetail.info.emergencyContactPhone }}
|
|
|
+ </a>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">紧急联系人邮箱</div>
|
|
|
+ <div>
|
|
|
+ <a v-if="qrCodeDetail.info.emergencyContactEmail"
|
|
|
+ :href="`mailto:${qrCodeDetail.info.emergencyContactEmail}`" class="text-blue-600 hover:underline">
|
|
|
+ {{ qrCodeDetail.info.emergencyContactEmail }}
|
|
|
+ </a>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="qrCodeDetail.info.specialNote" class="col-span-2">
|
|
|
+ <div class="text-sm text-gray-500">特别说明</div>
|
|
|
+ <div class="whitespace-pre-wrap">{{ qrCodeDetail.info.specialNote }}</div>
|
|
|
+ </div>
|
|
|
+ <div v-if="qrCodeDetail.info.remark" class="col-span-2">
|
|
|
+ <div class="text-sm text-gray-500">备注</div>
|
|
|
+ <div class="whitespace-pre-wrap">{{ qrCodeDetail.info.remark }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 宠物/物品信息 -->
|
|
|
+ <div v-else-if="qrCodeDetail.qrType === 'pet' || qrCodeDetail.qrType === 'goods'"
|
|
|
+ class="grid grid-cols-2 gap-4">
|
|
|
+ <div v-if="qrCodeDetail.info.photoUrl" class="col-span-2 text-center mb-2">
|
|
|
+ <img :src="qrCodeDetail.info.photoUrl" alt="照片" class="w-32 h-32 object-cover rounded mx-auto" />
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">{{ qrCodeDetail.qrType === 'pet' ? '名称' : '物品名称' }}</div>
|
|
|
+ <div class="font-medium">{{ qrCodeDetail.info.name || '-' }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">联系人</div>
|
|
|
+ <div class="font-medium">{{ qrCodeDetail.info.contactName || '-' }}</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">联系电话</div>
|
|
|
+ <div>
|
|
|
+ <a v-if="qrCodeDetail.info.contactPhone" :href="`tel:${qrCodeDetail.info.contactPhone}`"
|
|
|
+ class="text-blue-600 hover:underline">
|
|
|
+ {{ qrCodeDetail.info.contactPhone }}
|
|
|
+ </a>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="text-sm text-gray-500">联系邮箱</div>
|
|
|
+ <div>
|
|
|
+ <a v-if="qrCodeDetail.info.contactEmail" :href="`mailto:${qrCodeDetail.info.contactEmail}`"
|
|
|
+ class="text-blue-600 hover:underline">
|
|
|
+ {{ qrCodeDetail.info.contactEmail }}
|
|
|
+ </a>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="qrCodeDetail.info.remark" class="col-span-2">
|
|
|
+ <div class="text-sm text-gray-500">备注</div>
|
|
|
+ <div class="whitespace-pre-wrap">{{ qrCodeDetail.info.remark }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 未激活提示 -->
|
|
|
+ <div v-else class="border rounded p-4 text-center text-gray-500">
|
|
|
+ <i class="pi pi-info-circle text-2xl mb-2"></i>
|
|
|
+ <div>该二维码尚未激活,暂无关联信息</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <Button label="关闭" @click="detailDialog = false" />
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
</div>
|
|
|
</template>
|