|
@@ -258,6 +258,16 @@
|
|
|
<div class="text-sm opacity-80">Total</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <!-- History Button -->
|
|
|
+ <div class="mt-6">
|
|
|
+ <button
|
|
|
+ class="btn btn-secondary btn-lg gradient-bg border-0 text-white shadow-lg btn-glow"
|
|
|
+ @click="showHistoryDialog = true"
|
|
|
+ >
|
|
|
+ <i class="fas fa-history mr-2"></i>
|
|
|
+ View History
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<div class="space-y-8 relative z-10">
|
|
@@ -590,7 +600,7 @@
|
|
|
<!-- Add Reward Modal -->
|
|
|
<div class="modal" :class="{ 'modal-open': showAddRewardDialog }">
|
|
|
<div
|
|
|
- class="modal-box w-11/12 max-w-4xl glass-effect border border-white/20"
|
|
|
+ class="modal-box w-11/12 max-w-4xl bg-gradient-to-br from-gray-900/95 to-black/95 backdrop-blur-xl border border-white/20 shadow-2xl"
|
|
|
>
|
|
|
<h3 class="font-bold text-3xl mb-8 text-white text-center">
|
|
|
<i class="fas fa-gift text-purple-300 mr-2"></i>
|
|
@@ -667,12 +677,17 @@
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="modal-backdrop" @click="closeModal"></div>
|
|
|
+ <div
|
|
|
+ class="modal-backdrop bg-black/50 backdrop-blur-sm"
|
|
|
+ @click="closeModal"
|
|
|
+ ></div>
|
|
|
</div>
|
|
|
|
|
|
<!-- Password Verification Modal -->
|
|
|
<div class="modal" :class="{ 'modal-open': showPasswordDialog }">
|
|
|
- <div class="modal-box max-w-md glass-effect border border-white/20">
|
|
|
+ <div
|
|
|
+ class="modal-box max-w-md bg-gradient-to-br from-gray-900/95 to-black/95 backdrop-blur-xl border border-white/20 shadow-2xl"
|
|
|
+ >
|
|
|
<h3 class="font-bold text-2xl mb-6 text-white text-center">
|
|
|
<i class="fas fa-shield-alt text-red-300 mr-2"></i>
|
|
|
Final Confirmation
|
|
@@ -751,7 +766,147 @@
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="modal-backdrop" @click="closePasswordModal"></div>
|
|
|
+ <div
|
|
|
+ class="modal-backdrop bg-black/50 backdrop-blur-sm"
|
|
|
+ @click="closePasswordModal"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- History Modal -->
|
|
|
+ <div class="modal" :class="{ 'modal-open': showHistoryDialog }">
|
|
|
+ <div
|
|
|
+ class="modal-box w-11/12 max-w-5xl bg-gradient-to-br from-gray-900/95 to-black/95 backdrop-blur-xl border border-white/20 shadow-2xl"
|
|
|
+ >
|
|
|
+ <div class="flex justify-between items-center mb-4">
|
|
|
+ <h3 class="font-bold text-2xl text-white">
|
|
|
+ <i class="fas fa-history text-blue-300 mr-2"></i>
|
|
|
+ Airdrop History
|
|
|
+ </h3>
|
|
|
+ <button
|
|
|
+ class="btn btn-circle btn-sm bg-white/20 border-0 hover:bg-white/30"
|
|
|
+ @click="closeHistoryModal"
|
|
|
+ >
|
|
|
+ <i class="fas fa-times text-white"></i>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Loading State -->
|
|
|
+ <div v-if="isLoadingHistory" class="text-center py-8">
|
|
|
+ <div class="text-4xl mb-2 animate-bounce-slow">⏳</div>
|
|
|
+ <p class="text-purple-200">Loading history...</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- History Content -->
|
|
|
+ <div
|
|
|
+ v-else-if="historyData.length > 0"
|
|
|
+ class="space-y-3 max-h-[75vh] overflow-y-auto"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ v-for="item in historyData"
|
|
|
+ :key="item.id"
|
|
|
+ class="bg-white/10 rounded-lg p-4 backdrop-blur-sm border border-white/20"
|
|
|
+ >
|
|
|
+ <!-- Header Row -->
|
|
|
+ <div class="flex justify-between items-center mb-3">
|
|
|
+ <div class="flex items-center space-x-3">
|
|
|
+ <h4 class="text-lg font-bold text-white">
|
|
|
+ {{ item.reason }}
|
|
|
+ </h4>
|
|
|
+ <div
|
|
|
+ :class="[
|
|
|
+ 'badge badge-xs',
|
|
|
+ item.status === 1 ? 'badge-success' : 'badge-error'
|
|
|
+ ]"
|
|
|
+ >
|
|
|
+ {{ item.status === 1 ? '✓' : '✗' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="flex items-center space-x-3 text-xs text-purple-300"
|
|
|
+ >
|
|
|
+ <span>
|
|
|
+ <i class="fas fa-calendar mr-1"></i>
|
|
|
+ {{ formatDate(item.createTime) }}
|
|
|
+ </span>
|
|
|
+ <span class="text-purple-400">#{{ item.id.slice(-8) }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Rewards List - Compact -->
|
|
|
+ <div class="flex flex-wrap gap-2">
|
|
|
+ <div
|
|
|
+ v-for="reward in parseGoodList(item.goodList)"
|
|
|
+ :key="reward.id"
|
|
|
+ class="flex items-center space-x-2 px-3 py-2 bg-white/10 rounded-lg border border-white/20"
|
|
|
+ >
|
|
|
+ <div class="w-6 h-6 icon-container">
|
|
|
+ <img
|
|
|
+ :src="getItemIcon(reward.id)"
|
|
|
+ :alt="getItemName(reward.id)"
|
|
|
+ class="w-5 h-5 item-icon"
|
|
|
+ @error="handleImageError"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <span class="text-sm font-medium text-white">
|
|
|
+ {{ getItemName(reward.id) }}
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ class="text-xs text-purple-200 bg-purple-500/20 px-2 py-1 rounded"
|
|
|
+ >
|
|
|
+ ×{{ reward.count }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Empty State -->
|
|
|
+ <div v-else class="text-center py-8">
|
|
|
+ <div class="text-6xl mb-3 animate-bounce-slow">📜</div>
|
|
|
+ <p class="text-purple-200">No history found</p>
|
|
|
+ <p class="text-purple-300 text-sm mt-1">
|
|
|
+ Start your first airdrop to see history here
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Pagination - Compact -->
|
|
|
+ <div
|
|
|
+ v-if="historyData.length > 0"
|
|
|
+ class="flex justify-center items-center space-x-3 mt-4 pt-3 border-t border-white/20"
|
|
|
+ >
|
|
|
+ <button
|
|
|
+ class="btn btn-sm btn-outline border-white/30 text-white hover:bg-white/10"
|
|
|
+ @click="changePage(currentPage - 1)"
|
|
|
+ :disabled="currentPage <= 1"
|
|
|
+ >
|
|
|
+ <i class="fas fa-chevron-left"></i>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <div class="flex items-center space-x-2">
|
|
|
+ <span class="text-sm text-white">Page</span>
|
|
|
+ <input
|
|
|
+ type="number"
|
|
|
+ v-model.number="currentPage"
|
|
|
+ min="1"
|
|
|
+ class="input input-bordered input-xs w-16 text-center bg-white/10 border-white/30 text-white"
|
|
|
+ @change="loadHistory"
|
|
|
+ />
|
|
|
+ <span class="text-sm text-white">/ {{ totalPages }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <button
|
|
|
+ class="btn btn-sm btn-outline border-white/30 text-white hover:bg-white/10"
|
|
|
+ @click="changePage(currentPage + 1)"
|
|
|
+ :disabled="currentPage >= totalPages"
|
|
|
+ >
|
|
|
+ <i class="fas fa-chevron-right"></i>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="modal-backdrop bg-black/50 backdrop-blur-sm"
|
|
|
+ @click="closeHistoryModal"
|
|
|
+ ></div>
|
|
|
</div>
|
|
|
|
|
|
<!-- Toast Container -->
|
|
@@ -833,6 +988,11 @@
|
|
|
type: "alert-info",
|
|
|
message: "",
|
|
|
},
|
|
|
+ showHistoryDialog: false,
|
|
|
+ historyData: [],
|
|
|
+ currentPage: 1,
|
|
|
+ totalPages: 1,
|
|
|
+ isLoadingHistory: false,
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
@@ -852,6 +1012,13 @@
|
|
|
components: {
|
|
|
Toast,
|
|
|
},
|
|
|
+ watch: {
|
|
|
+ showHistoryDialog(newVal) {
|
|
|
+ if (newVal) {
|
|
|
+ this.loadHistory();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
methods: {
|
|
|
// Parse addresses
|
|
|
parseAddresses() {
|
|
@@ -1156,6 +1323,92 @@
|
|
|
}, 4000);
|
|
|
}, 100);
|
|
|
},
|
|
|
+
|
|
|
+ // Load history data
|
|
|
+ async loadHistory() {
|
|
|
+ this.isLoadingHistory = true;
|
|
|
+ try {
|
|
|
+ const response = await fetch(
|
|
|
+ `${API_BASE_URL}/pog-service/callback/add/good/page?page=${this.currentPage}`,
|
|
|
+ {
|
|
|
+ method: "GET",
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ },
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const result = await response.json();
|
|
|
+
|
|
|
+ if (response.ok && result.success) {
|
|
|
+ this.historyData = result.data.content || [];
|
|
|
+ // Assuming the API returns total pages or we can calculate it
|
|
|
+ // For now, we'll set a default total pages
|
|
|
+ this.totalPages = Math.max(
|
|
|
+ 1,
|
|
|
+ Math.ceil(this.historyData.length / 10)
|
|
|
+ );
|
|
|
+ this.showToast("History loaded successfully", "alert-success");
|
|
|
+ } else {
|
|
|
+ this.showToast(
|
|
|
+ result.message || "Failed to load history",
|
|
|
+ "alert-error"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("History loading error:", error);
|
|
|
+ this.showToast(
|
|
|
+ "Network error. Please check your connection and try again.",
|
|
|
+ "alert-error"
|
|
|
+ );
|
|
|
+ } finally {
|
|
|
+ this.isLoadingHistory = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // Change page
|
|
|
+ changePage(newPage) {
|
|
|
+ if (newPage >= 1 && newPage <= this.totalPages) {
|
|
|
+ this.currentPage = newPage;
|
|
|
+ this.loadHistory();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // Parse good list from JSON string
|
|
|
+ parseGoodList(goodListString) {
|
|
|
+ try {
|
|
|
+ return JSON.parse(goodListString);
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Error parsing good list:", error);
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // Format date - Display UTC time directly
|
|
|
+ formatDate(dateString) {
|
|
|
+ try {
|
|
|
+ const date = new Date(dateString);
|
|
|
+ // Format as UTC time: YYYY-MM-DD HH:mm:ss
|
|
|
+ const year = date.getUTCFullYear();
|
|
|
+ const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
|
+ const day = String(date.getUTCDate()).padStart(2, "0");
|
|
|
+ const hours = String(date.getUTCHours()).padStart(2, "0");
|
|
|
+ const minutes = String(date.getUTCMinutes()).padStart(2, "0");
|
|
|
+ const seconds = String(date.getUTCSeconds()).padStart(2, "0");
|
|
|
+
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} UTC`;
|
|
|
+ } catch (error) {
|
|
|
+ return dateString;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // Close history modal
|
|
|
+ closeHistoryModal() {
|
|
|
+ this.showHistoryDialog = false;
|
|
|
+ this.historyData = [];
|
|
|
+ this.currentPage = 1;
|
|
|
+ this.totalPages = 1;
|
|
|
+ },
|
|
|
},
|
|
|
|
|
|
mounted() {
|