296 lines
7.7 KiB
Vue
296 lines
7.7 KiB
Vue
<template>
|
||
<el-dialog
|
||
v-model="visible"
|
||
:title="dialogTitle"
|
||
width="600px"
|
||
:close-on-click-modal="false"
|
||
@close="handleClose"
|
||
>
|
||
<div v-if="detailData" class="detail-content">
|
||
<table class="detail-table">
|
||
<!-- 优惠码特有字段 -->
|
||
<tr v-if="type === 'code'">
|
||
<td class="label">优惠码</td>
|
||
<td class="value">{{ detailData.code }}</td>
|
||
</tr>
|
||
|
||
<!-- 名称 -->
|
||
<tr>
|
||
<td class="label">{{ type === 'code' ? '名称' : '代金券名称' }}</td>
|
||
<td class="value">{{ detailData.name }}</td>
|
||
</tr>
|
||
|
||
<!-- 备注 -->
|
||
<tr>
|
||
<td class="label">备注</td>
|
||
<td class="value secondary">{{ detailData.note || '无' }}</td>
|
||
</tr>
|
||
|
||
<!-- 优惠类型(仅优惠码) -->
|
||
<tr v-if="type === 'code'" class="alternate">
|
||
<td class="label">优惠类型</td>
|
||
<td class="value">
|
||
<span :class="['type-tag', detailData.percentage ? 'percentage' : 'amount']">
|
||
{{ detailData.percentage ? '百分比折扣' : '固定金额' }}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 优惠值/面额 -->
|
||
<tr :class="type === 'code' ? '' : 'alternate'">
|
||
<td class="label">{{ type === 'code' ? '优惠值' : '面额' }}</td>
|
||
<td class="value">
|
||
<span v-if="detailData.percentage" class="highlight-value percentage">
|
||
{{ (detailData.percentage / 100).toFixed(0) }}%
|
||
</span>
|
||
<span v-else class="highlight-value amount">
|
||
¥{{ (detailData.amount / 100).toFixed(2) }}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 最低消费 -->
|
||
<tr>
|
||
<td class="label">最低消费</td>
|
||
<td class="value">¥{{ (detailData.minAmount / 100).toFixed(2) }}</td>
|
||
</tr>
|
||
|
||
<!-- 最大抵扣 -->
|
||
<tr>
|
||
<td class="label">最大抵扣</td>
|
||
<td class="value">
|
||
<span v-if="detailData.maxAmount">¥{{ (detailData.maxAmount / 100).toFixed(2) }}</span>
|
||
<span v-else class="secondary">无限制</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 最大使用次数 -->
|
||
<tr class="alternate">
|
||
<td class="label">最大使用次数</td>
|
||
<td class="value">
|
||
<span v-if="detailData.maxTimes">{{ detailData.maxTimes }}</span>
|
||
<span v-else class="secondary">无限制</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 单用户次数 -->
|
||
<tr>
|
||
<td class="label">单用户次数</td>
|
||
<td class="value">
|
||
<span v-if="detailData.userTimes">{{ detailData.userTimes }}</span>
|
||
<span v-else class="secondary">无限制</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 有效期(仅代金券) -->
|
||
<tr v-if="type === 'coupon'" class="alternate">
|
||
<td class="label">有效期(天)</td>
|
||
<td class="value">
|
||
{{ detailData.duration ? (detailData.duration / 86400).toFixed(0) + '天' : '-' }}
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 有效期开始 -->
|
||
<tr :class="type === 'coupon' ? '' : 'alternate'">
|
||
<td class="label">{{ type === 'code' ? '有效期开始' : '发放时间开始' }}</td>
|
||
<td class="value">{{ formatISODate(detailData.startTime) }}</td>
|
||
</tr>
|
||
|
||
<!-- 有效期结束 -->
|
||
<tr :class="type === 'coupon' ? 'alternate' : ''">
|
||
<td class="label">{{ type === 'code' ? '有效期结束' : '发放时间结束' }}</td>
|
||
<td class="value">{{ formatISODate(detailData.endTime) }}</td>
|
||
</tr>
|
||
|
||
<!-- 续费可用 -->
|
||
<tr :class="type === 'coupon' ? '' : 'alternate'">
|
||
<td class="label">续费可用</td>
|
||
<td class="value">
|
||
<span :class="['status-icon', detailData.renew ? 'success' : 'danger']">
|
||
{{ detailData.renew ? '✓ 是' : '✗ 否' }}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 同类型可叠加 -->
|
||
<tr :class="type === 'coupon' ? 'alternate' : ''">
|
||
<td class="label">同类型可叠加</td>
|
||
<td class="value">
|
||
<span :class="['status-icon', detailData.canStacking ? 'success' : 'danger']">
|
||
{{ detailData.canStacking ? '✓ 是' : '✗ 否' }}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 其他类型可叠加 -->
|
||
<tr :class="type === 'coupon' ? '' : 'alternate'">
|
||
<td class="label">其他类型可叠加</td>
|
||
<td class="value">
|
||
<span :class="['status-icon', detailData.canCombine ? 'success' : 'danger']">
|
||
{{ detailData.canCombine ? '✓ 是' : '✗ 否' }}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
|
||
<!-- 创建时间 -->
|
||
<tr :class="type === 'coupon' ? 'alternate' : ''">
|
||
<td class="label">创建时间</td>
|
||
<td class="value timestamp">{{ formatISODate(detailData.CreatedAt) }}</td>
|
||
</tr>
|
||
|
||
<!-- 更新时间 -->
|
||
<tr>
|
||
<td class="label">更新时间</td>
|
||
<td class="value timestamp">{{ formatISODate(detailData.UpdatedAt) }}</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
|
||
<template #footer>
|
||
<el-button @click="handleClose">关闭</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed } from 'vue'
|
||
|
||
const props = defineProps({
|
||
modelValue: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
type: {
|
||
type: String,
|
||
required: true,
|
||
validator: (value) => ['code', 'coupon'].includes(value)
|
||
},
|
||
detailData: {
|
||
type: Object,
|
||
default: null
|
||
}
|
||
})
|
||
|
||
const emit = defineEmits(['update:modelValue'])
|
||
|
||
const visible = computed({
|
||
get: () => props.modelValue,
|
||
set: (val) => emit('update:modelValue', val)
|
||
})
|
||
|
||
const dialogTitle = computed(() => {
|
||
return props.type === 'code' ? '优惠码详情' : '代金券详情'
|
||
})
|
||
|
||
// 格式化ISO 8601日期字符串
|
||
const formatISODate = (isoStr) => {
|
||
if (!isoStr) return '-'
|
||
try {
|
||
const date = new Date(isoStr)
|
||
const year = date.getFullYear()
|
||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||
const day = String(date.getDate()).padStart(2, '0')
|
||
const hours = String(date.getHours()).padStart(2, '0')
|
||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||
const seconds = String(date.getSeconds()).padStart(2, '0')
|
||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||
} catch {
|
||
return isoStr
|
||
}
|
||
}
|
||
|
||
const handleClose = () => {
|
||
emit('update:modelValue', false)
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.detail-content {
|
||
max-height: 500px;
|
||
overflow-y: auto;
|
||
padding: 10px;
|
||
}
|
||
|
||
.detail-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
.detail-table tr {
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.detail-table tr.alternate {
|
||
background-color: #fafafa;
|
||
}
|
||
|
||
.detail-table td {
|
||
padding: 12px 8px;
|
||
}
|
||
|
||
.detail-table .label {
|
||
width: 140px;
|
||
color: #606266;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.detail-table .value {
|
||
color: #303133;
|
||
}
|
||
|
||
.detail-table .value.secondary {
|
||
color: #606266;
|
||
}
|
||
|
||
.detail-table .value.timestamp {
|
||
color: #909399;
|
||
font-size: 13px;
|
||
}
|
||
|
||
/* 类型标签 */
|
||
.type-tag {
|
||
padding: 2px 8px;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
display: inline-block;
|
||
}
|
||
|
||
.type-tag.percentage {
|
||
background-color: #f0f9ff;
|
||
color: #67c23a;
|
||
}
|
||
|
||
.type-tag.amount {
|
||
background-color: #eff6ff;
|
||
color: #409eff;
|
||
}
|
||
|
||
/* 突出显示的值 */
|
||
.highlight-value {
|
||
font-weight: bold;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.highlight-value.percentage {
|
||
color: #67c23a;
|
||
}
|
||
|
||
.highlight-value.amount {
|
||
color: #f56c6c;
|
||
}
|
||
|
||
/* 状态图标 */
|
||
.status-icon.success {
|
||
color: #67c23a;
|
||
}
|
||
|
||
.status-icon.danger {
|
||
color: #f56c6c;
|
||
}
|
||
|
||
.secondary {
|
||
color: #909399;
|
||
}
|
||
</style>
|
||
|