init
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
page: number
|
||||
pageSize: number
|
||||
total: number
|
||||
loading?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'change', page: number): void
|
||||
}>()
|
||||
|
||||
function goPrev() {
|
||||
if (props.page <= 1 || props.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('change', props.page - 1)
|
||||
}
|
||||
|
||||
function goNext() {
|
||||
if (props.loading || props.page * props.pageSize >= props.total) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('change', props.page + 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="pagination-bar">
|
||||
<span>第 {{ page }} 页,共 {{ Math.max(1, Math.ceil(total / pageSize)) }} 页,合计 {{ total }} 条</span>
|
||||
<div class="actions">
|
||||
<el-button :disabled="page <= 1 || loading" round @click="goPrev">上一页</el-button>
|
||||
<el-button :disabled="page * pageSize >= total || loading" round @click="goNext">下一页</el-button>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pagination-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
margin-top: 14px;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 780px) {
|
||||
.pagination-bar {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,130 @@
|
||||
<script setup lang="ts">
|
||||
import { formatStatusWithRaw } from '@/utils/admin-display'
|
||||
|
||||
const props = defineProps<{
|
||||
status: string
|
||||
}>()
|
||||
|
||||
function resolveTone(status: string) {
|
||||
const normalized = String(status || '').trim().toLowerCase()
|
||||
|
||||
if (['paid', 'link_generated', 'redeemed', 'available', 'delivered', 'success', 'active', 'system_bound', 'binding_completed'].includes(normalized)) {
|
||||
return 'success'
|
||||
}
|
||||
|
||||
if (['claimed', 'role_confirmed', 'redeeming', 'reserved', 'processing', 'admin', 'waiting_user_claim', 'link_opened', 'binding_confirmed', 'binding_in_progress', 'user_binding'].includes(normalized)) {
|
||||
return 'primary'
|
||||
}
|
||||
|
||||
if (['waiting_inventory', 'retry_pending', 'manual_review', 'invalid', 'expired', 'operator', 'pending_binding', 'binding_exception', 'not_started'].includes(normalized)) {
|
||||
return 'warning'
|
||||
}
|
||||
|
||||
if (['closed', 'failed', 'unpaid', 'revoked', 'disabled'].includes(normalized)) {
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
return 'default'
|
||||
}
|
||||
|
||||
function resolveLabel(status: string) {
|
||||
const normalized = String(status || '').trim()
|
||||
|
||||
if (!normalized) {
|
||||
return '-'
|
||||
}
|
||||
|
||||
const labelMap: Record<string, string> = {
|
||||
created: '已创建',
|
||||
paid: '已支付',
|
||||
unpaid: '未支付',
|
||||
failed: '失败',
|
||||
refunded: '已退款',
|
||||
refunding: '退款中',
|
||||
closed: '已关闭',
|
||||
pending_payment: '待支付',
|
||||
waiting_inventory: '待库存',
|
||||
cdk_reserved: '已预占',
|
||||
link_generated: '已生成链接',
|
||||
claimed: '已创建会话',
|
||||
role_confirmed: '已确认角色',
|
||||
redeeming: '兑换中',
|
||||
redeemed: '已兑换',
|
||||
retry_pending: '待重试',
|
||||
manual_review: '人工处理',
|
||||
expired: '已过期',
|
||||
available: '可用',
|
||||
reserved: '已预占',
|
||||
delivered: '已发放',
|
||||
invalid: '已作废',
|
||||
active: '生效中',
|
||||
admin: '管理员',
|
||||
operator: '普通运营',
|
||||
revoked: '已撤销',
|
||||
disabled: '已停用',
|
||||
success: '成功',
|
||||
processing: '处理中',
|
||||
system_bound: '系统已绑定',
|
||||
pending_binding: '待系统绑定',
|
||||
not_started: '未开始',
|
||||
waiting_user_claim: '待用户打开链接',
|
||||
link_opened: '已打开链接',
|
||||
binding_confirmed: '已提交绑定',
|
||||
binding_in_progress: '绑定处理中',
|
||||
binding_completed: '完整绑定成功',
|
||||
binding_exception: '绑定异常',
|
||||
user_binding: '用户绑定中',
|
||||
}
|
||||
|
||||
return formatStatusWithRaw(normalized, labelMap)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="status-tag" :data-tone="resolveTone(props.status)">
|
||||
{{ resolveLabel(props.status) }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.status-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 0 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.status-tag[data-tone='success'] {
|
||||
color: #0f766e;
|
||||
background: #ecfdf3;
|
||||
border-color: #a6f4c5;
|
||||
}
|
||||
|
||||
.status-tag[data-tone='primary'] {
|
||||
color: #175cd3;
|
||||
background: #eff8ff;
|
||||
border-color: #b2ddff;
|
||||
}
|
||||
|
||||
.status-tag[data-tone='warning'] {
|
||||
color: #b54708;
|
||||
background: #fffaeb;
|
||||
border-color: #fedf89;
|
||||
}
|
||||
|
||||
.status-tag[data-tone='danger'] {
|
||||
color: #b42318;
|
||||
background: #fef3f2;
|
||||
border-color: #fecdca;
|
||||
}
|
||||
|
||||
.status-tag[data-tone='default'] {
|
||||
color: #475467;
|
||||
background: #f2f4f7;
|
||||
border-color: #d0d5dd;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user