|
|
@@ -10,6 +10,7 @@ import {
|
|
|
resetPassword,
|
|
|
} from "@/services/api";
|
|
|
import { vipLevelToText, VipLevel } from "@/types/vip";
|
|
|
+import { getShareRecords, ShareRecord } from "@/services/shareApi";
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
const priceStore = usePriceStore();
|
|
|
@@ -57,6 +58,17 @@ const isResetPasswordLoading = ref(false);
|
|
|
const editUserError = ref("");
|
|
|
const resetPasswordError = ref("");
|
|
|
|
|
|
+// 邀请记录相关状态
|
|
|
+const shareRecords = ref<ShareRecord[]>([]);
|
|
|
+const shareRecordsLoading = ref(false);
|
|
|
+const shareRecordsError = ref("");
|
|
|
+const shareRecordsPagination = ref({
|
|
|
+ page: 0,
|
|
|
+ size: 6,
|
|
|
+ total: 0,
|
|
|
+ totalPages: 0
|
|
|
+});
|
|
|
+
|
|
|
// 使用动态价格配置
|
|
|
const membershipPlans = computed(() => priceStore.getMembershipPlans);
|
|
|
|
|
|
@@ -349,6 +361,35 @@ const handleQueryOrder = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// 加载邀请记录
|
|
|
+const loadShareRecords = async (page = 0) => {
|
|
|
+ if (!isLoginUser.value) return;
|
|
|
+
|
|
|
+ shareRecordsLoading.value = true;
|
|
|
+ shareRecordsError.value = "";
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await getShareRecords({
|
|
|
+ page,
|
|
|
+ size: shareRecordsPagination.value.size,
|
|
|
+ status: true // 只获取成功的邀请记录
|
|
|
+ });
|
|
|
+
|
|
|
+ shareRecords.value = response.content;
|
|
|
+ shareRecordsPagination.value = {
|
|
|
+ page: response.metadata.page,
|
|
|
+ size: response.metadata.size,
|
|
|
+ total: response.metadata.total,
|
|
|
+ totalPages: Math.ceil(response.metadata.total / response.metadata.size)
|
|
|
+ };
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error("加载邀请记录失败:", error);
|
|
|
+ shareRecordsError.value = error.message || "加载邀请记录失败";
|
|
|
+ } finally {
|
|
|
+ shareRecordsLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
// 加载价格配置的函数
|
|
|
const loadPriceConfig = async () => {
|
|
|
if (isLoginUser.value && !priceStore.isPriceConfigLoaded) {
|
|
|
@@ -366,6 +407,7 @@ watch(
|
|
|
(newValue) => {
|
|
|
if (newValue) {
|
|
|
loadPriceConfig();
|
|
|
+ loadShareRecords();
|
|
|
}
|
|
|
},
|
|
|
{ immediate: true }
|
|
|
@@ -455,6 +497,105 @@ onMounted(async () => {
|
|
|
</button>
|
|
|
</div>
|
|
|
|
|
|
+ <!-- 邀请记录展示区域 -->
|
|
|
+ <div
|
|
|
+ v-if="isLoginUser"
|
|
|
+ class="rounded-2xl bg-white/5 border border-white/10 p-4"
|
|
|
+ >
|
|
|
+ <div class="flex items-center justify-between mb-4">
|
|
|
+ <h3 class="text-lg font-semibold text-white/90">邀请记录</h3>
|
|
|
+ <button
|
|
|
+ @click="loadShareRecords(0)"
|
|
|
+ :disabled="shareRecordsLoading"
|
|
|
+ class="px-3 py-1.5 text-sm text-white/60 hover:text-white/80 transition disabled:opacity-50"
|
|
|
+ >
|
|
|
+ {{ shareRecordsLoading ? "加载中..." : "刷新" }}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 邀请记录列表 -->
|
|
|
+ <div v-if="shareRecordsLoading" class="text-center py-8">
|
|
|
+ <div class="w-8 h-8 mx-auto border-2 border-white/20 border-t-brand rounded-full animate-spin mb-2"></div>
|
|
|
+ <p class="text-white/60 text-sm">加载中...</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else-if="shareRecordsError" class="text-center py-8">
|
|
|
+ <div class="w-12 h-12 mx-auto bg-red-500/20 rounded-full flex items-center justify-center mb-3">
|
|
|
+ <svg class="w-6 h-6 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <p class="text-red-400 text-sm mb-3">{{ shareRecordsError }}</p>
|
|
|
+ <button
|
|
|
+ @click="loadShareRecords(0)"
|
|
|
+ class="px-4 py-2 bg-red-500/20 text-red-400 rounded-lg hover:bg-red-500/30 transition text-sm"
|
|
|
+ >
|
|
|
+ 重试
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else-if="shareRecords.length === 0" class="text-center py-8">
|
|
|
+ <div class="w-12 h-12 mx-auto bg-white/10 rounded-full flex items-center justify-center mb-3">
|
|
|
+ <svg class="w-6 h-6 text-white/40" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <p class="text-white/60 text-sm">暂无邀请记录</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else class="space-y-3">
|
|
|
+ <div
|
|
|
+ v-for="record in shareRecords"
|
|
|
+ :key="record.id"
|
|
|
+ class="bg-white/5 rounded-lg p-3 border border-white/10"
|
|
|
+ >
|
|
|
+ <div class="flex items-center justify-between mb-2">
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <span class="text-sm font-medium text-white/90">{{ record.inviterName }}</span>
|
|
|
+ <span class="px-2 py-0.5 rounded text-xs font-medium bg-green-500/20 text-green-400">
|
|
|
+ 成功
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <span class="text-xs text-white/50">
|
|
|
+ {{ new Date(record.createdAt).toLocaleDateString() }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="text-xs text-white/60">
|
|
|
+ <p v-if="record.resourceName">资源名称: {{ record.resourceName }}</p>
|
|
|
+ <p v-else>资源ID: {{ record.resourceId }}</p>
|
|
|
+ <p v-if="record.invitedUserId">被邀请用户ID: {{ record.invitedUserId }}</p>
|
|
|
+ <p v-if="record.teamName">团队: {{ record.teamName }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分页控件 -->
|
|
|
+ <div v-if="shareRecordsPagination.totalPages > 1" class="flex items-center justify-between pt-4 border-t border-white/10">
|
|
|
+ <div class="text-xs text-white/60">
|
|
|
+ 共 {{ shareRecordsPagination.total }} 条记录
|
|
|
+ </div>
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <button
|
|
|
+ @click="loadShareRecords(shareRecordsPagination.page - 1)"
|
|
|
+ :disabled="shareRecordsPagination.page === 0 || shareRecordsLoading"
|
|
|
+ class="px-3 py-1.5 text-sm border border-white/20 text-white/70 rounded hover:bg-white/5 transition disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
+ >
|
|
|
+ 上一页
|
|
|
+ </button>
|
|
|
+ <span class="text-sm text-white/60">
|
|
|
+ {{ shareRecordsPagination.page + 1 }} / {{ shareRecordsPagination.totalPages }}
|
|
|
+ </span>
|
|
|
+ <button
|
|
|
+ @click="loadShareRecords(shareRecordsPagination.page + 1)"
|
|
|
+ :disabled="shareRecordsPagination.page >= shareRecordsPagination.totalPages - 1 || shareRecordsLoading"
|
|
|
+ class="px-3 py-1.5 text-sm border border-white/20 text-white/70 rounded hover:bg-white/5 transition disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
+ >
|
|
|
+ 下一页
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<div
|
|
|
v-if="isLoginUser"
|
|
|
class="rounded-2xl overflow-hidden border border-white/10 divide-y divide-white/10"
|