导入 AKSRT 主题开发源码

This commit is contained in:
Claude Code committed 2026-07-03 22:50:34 +08:00
1 parent 9681dd3d48
commit 1268a55dd0
595 files changed
+127705

No files matched your search

@@ -0,0 +1,89 @@
<template>
<n-drawer :show="show" :width="680" @update:show="$emit('update:show', $event)">
<n-drawer-content title="充值卡详情" closable>
<n-spin :show="loading">
<template v-if="detail.card">
<n-descriptions bordered :column="1" size="small" label-placement="left">
<n-descriptions-item label="卡号">{{ detail.card.code || '-' }}</n-descriptions-item>
<n-descriptions-item label="面额">{{ detail.card.amount || 0 }}</n-descriptions-item>
<n-descriptions-item label="余额">{{ detail.card.balance || 0 }}</n-descriptions-item>
<n-descriptions-item label="状态">{{ detail.card.status_label || detail.card.status }}</n-descriptions-item>
<n-descriptions-item label="创建时间">{{ detail.card.created_at || '-' }}</n-descriptions-item>
<n-descriptions-item label="过期时间">{{ detail.card.expires_at || '-' }}</n-descriptions-item>
<n-descriptions-item label="使用时间">{{ detail.card.used_at || '-' }}</n-descriptions-item>
<n-descriptions-item label="使用者">
{{ detail.card.used_by_user?.display_name || '-' }}
</n-descriptions-item>
</n-descriptions>
<div class="aksrt-charge-drawer__section">
<div class="aksrt-charge-drawer__title">备注</div>
<n-alert type="info" :show-icon="false">
{{ detail.card.note || '暂无备注' }}
</n-alert>
</div>
</template>
<n-empty v-else description="暂无充值卡详情" />
</n-spin>
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useMessage } from 'naive-ui'
import api from '@/api'
const props = defineProps({
show: { type: Boolean, default: false },
cardId: { type: [Number, String], default: null },
})
defineEmits(['update:show'])
const message = useMessage()
const loading = ref(false)
const detail = ref({ card: null })
watch(
() => [props.show, props.cardId],
async ([visible, id]) => {
if (visible && id) {
await loadDetail()
}
if (!visible) {
detail.value = { card: null }
}
},
)
async function loadDetail() {
if (!props.cardId) {
return
}
loading.value = true
try {
const res = await api.request(`/payment/charge-cards/${props.cardId}`)
detail.value = res?.data || { card: null }
} catch (error) {
message.error(error?.message || '加载充值卡详情失败')
} finally {
loading.value = false
}
}
</script>
<style scoped>
.aksrt-charge-drawer__section {
margin-top: 20px;
}
.aksrt-charge-drawer__title {
margin-bottom: 10px;
font-size: 14px;
font-weight: 600;
color: #1f2937;
}
</style>
@@ -0,0 +1,175 @@
<template>
<n-drawer :show="show" :width="720" @update:show="$emit('update:show', $event)">
<n-drawer-content title="返佣详情" closable>
<n-spin :show="loading">
<template v-if="detail.record">
<n-descriptions bordered :column="1" size="small" label-placement="left">
<n-descriptions-item label="订单号">{{ detail.record.order_number || '-' }}</n-descriptions-item>
<n-descriptions-item label="返佣对象">{{ detail.record.user?.display_name || '-' }}</n-descriptions-item>
<n-descriptions-item label="来源用户">{{ detail.record.source_user?.display_name || '-' }}</n-descriptions-item>
<n-descriptions-item label="返佣金额">{{ detail.record.amount || 0 }}</n-descriptions-item>
<n-descriptions-item label="类型">{{ detail.record.type_label || detail.record.type }}</n-descriptions-item>
<n-descriptions-item label="状态">{{ detail.record.status_label || detail.record.status }}</n-descriptions-item>
<n-descriptions-item label="创建时间">{{ detail.record.created_at || '-' }}</n-descriptions-item>
<n-descriptions-item label="结算时间">{{ detail.record.settled_at || '-' }}</n-descriptions-item>
</n-descriptions>
<div class="aksrt-rebate-drawer__section">
<div class="aksrt-rebate-drawer__title">备注</div>
<n-alert type="info" :show-icon="false">
{{ detail.record.note || '暂无备注' }}
</n-alert>
</div>
<div class="aksrt-rebate-drawer__section">
<div class="aksrt-rebate-drawer__title">处理记录</div>
<div v-if="detail.history?.length" class="aksrt-rebate-drawer__timeline">
<div v-for="(entry, index) in detail.history" :key="index" class="aksrt-rebate-drawer__timeline-item">
<div class="aksrt-rebate-drawer__timeline-head">
<strong>{{ entry.event || '-' }}</strong>
<span>{{ entry.time || '-' }}</span>
</div>
<p>{{ entry.note || '无备注' }}</p>
<small>{{ entry.operator_name || '系统' }}</small>
</div>
</div>
<n-empty v-else description="暂无处理记录" />
</div>
<div v-if="detail.record.status === 'pending'" class="aksrt-rebate-drawer__section">
<div class="aksrt-rebate-drawer__title">处理返佣</div>
<n-space vertical :size="12">
<n-input
v-model:value="form.note"
type="textarea"
:rows="3"
placeholder="记录结算说明或取消原因"
/>
<n-space>
<n-button type="primary" :loading="submitting === 'settle'" @click="handleAction('settle')">
结算返佣
</n-button>
<n-button type="warning" secondary :loading="submitting === 'cancel'" @click="handleAction('cancel')">
取消返佣
</n-button>
</n-space>
</n-space>
</div>
</template>
<n-empty v-else description="暂无返佣详情" />
</n-spin>
</n-drawer-content>
</n-drawer>
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
import { useMessage } from 'naive-ui'
import api from '@/api'
const props = defineProps({
show: { type: Boolean, default: false },
rebateId: { type: [Number, String], default: null },
})
const emit = defineEmits(['update:show', 'updated'])
const message = useMessage()
const loading = ref(false)
const submitting = ref('')
const detail = ref({ record: null, history: [] })
const form = reactive({ note: '' })
watch(
() => [props.show, props.rebateId],
async ([visible, id]) => {
if (visible && id) {
await loadDetail()
}
if (!visible) {
detail.value = { record: null, history: [] }
form.note = ''
}
},
)
async function loadDetail() {
if (!props.rebateId) {
return
}
loading.value = true
try {
const res = await api.request(`/payment/rebate/${props.rebateId}`)
detail.value = res?.data || { record: null, history: [] }
form.note = ''
} catch (error) {
message.error(error?.message || '加载返佣详情失败')
} finally {
loading.value = false
}
}
async function handleAction(action) {
if (!props.rebateId) {
return
}
submitting.value = action
try {
await api.request(`/payment/rebate/${props.rebateId}/${action}`, {
method: 'POST',
data: { note: form.note },
})
message.success(action === 'settle' ? '返佣已结算' : '返佣已取消')
await loadDetail()
emit('updated')
} catch (error) {
message.error(error?.message || '处理失败')
} finally {
submitting.value = ''
}
}
</script>
<style scoped>
.aksrt-rebate-drawer__section {
margin-top: 20px;
}
.aksrt-rebate-drawer__title {
margin-bottom: 10px;
font-size: 14px;
font-weight: 600;
color: #1f2937;
}
.aksrt-rebate-drawer__timeline {
display: grid;
gap: 12px;
}
.aksrt-rebate-drawer__timeline-item {
padding: 12px;
border: 1px solid #e5e7eb;
border-radius: 12px;
background: #f8fafc;
}
.aksrt-rebate-drawer__timeline-head {
display: flex;
justify-content: space-between;
gap: 12px;
margin-bottom: 6px;
}
.aksrt-rebate-drawer__timeline-item p {
margin: 0 0 6px;
color: #111827;
white-space: pre-wrap;
}
.aksrt-rebate-drawer__timeline-item small {
color: #6b7280;
}
</style>