TEST UPD
- try to do anthore logic of script
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div style="border: 2px solid red; padding: 10px">
|
||||
DEBUG: Template rendered
|
||||
DEBUG: Template rendered
|
||||
</div>
|
||||
<div v-if="loading" class="text-center p-10 text-gray-600">
|
||||
Загружаем таблицу лидеров...
|
||||
@@ -24,6 +24,7 @@
|
||||
:src="statusIcon"
|
||||
/>-->
|
||||
<p class="status" :class="statusClass">{{ statusLabel }}</p>
|
||||
<p class="place" v-if="currentUserPosition <= 3">{{ currentUserPosition }}-е место</p>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
@@ -33,12 +34,19 @@
|
||||
|
||||
<p class="points">{{ currentUserPoints }} баллов</p>
|
||||
|
||||
<template v-if="currentUserPosition > 1">
|
||||
<!-- Мотивационный текст -->
|
||||
<template v-if="currentUserPosition && currentUserPosition > 1">
|
||||
<p class="motivation-text">
|
||||
До {{ currentUserPosition - 1 }}-го места нужно:
|
||||
<strong>{{ pointsToNext }} баллов</strong>
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="!currentUserPosition && sorted.length">
|
||||
<p class="motivation-text">
|
||||
До лидера нужно:
|
||||
<strong>{{ sorted[0].points - currentUserPoints }} баллов</strong>
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Лучший участник -->
|
||||
@@ -47,13 +55,13 @@
|
||||
|
||||
<template v-if="topUser">
|
||||
<div class="initial-circle">
|
||||
{{ topUser.user[0].toUpperCase() }}
|
||||
{{ topUserInitial }}
|
||||
</div>
|
||||
|
||||
<p class="username">
|
||||
<a
|
||||
class="user-link"
|
||||
:href="`/lms/user/${topUser.username}`"
|
||||
:href="userProfileLink(topUser.user)"
|
||||
>
|
||||
{{ topUser.full_name }}
|
||||
</a>
|
||||
@@ -79,10 +87,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Пользователь</th>
|
||||
<th style="min-width: 150px;">Пользователь</th>
|
||||
<th>Баллы активности</th>
|
||||
<th>Общая сумма</th>
|
||||
<th>Бонус (МПГУ)</th>
|
||||
<th>Общая сумма баллов</th>
|
||||
<th>Бонусные баллы (МПГУ)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -97,11 +105,15 @@
|
||||
<td>
|
||||
<div class="flex items-center">
|
||||
<div class="initial-circle-small">
|
||||
{{ item.user[0].toUpperCase() }}
|
||||
{{ getUserInitial(item.user) }}
|
||||
</div>
|
||||
<div>
|
||||
<a :href="`/lms/user/${item.username}`"
|
||||
class="user-link">{{ item.full_name }}</a>
|
||||
<a
|
||||
:href="userProfileLink(item.user)"
|
||||
class="user-link"
|
||||
>
|
||||
{{ item.full_name }}
|
||||
</a>
|
||||
|
||||
<!-- значки
|
||||
<img v-if="index === 0" class="cup-badge" src="/files/gold-cup.png">
|
||||
@@ -119,7 +131,7 @@
|
||||
</table>
|
||||
|
||||
<p class="stats-note">
|
||||
* Бонус — 1 балл за каждые 100 очков (максимум 10)
|
||||
* Бонусные баллы рассчитываются как 1 балл за каждые 100 очков активности (максимум 10)
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -135,117 +147,117 @@ const $user = inject("$user");
|
||||
const currentUserEmail = $user.data.email;
|
||||
|
||||
const loading = ref(true);
|
||||
const sorted = ref([]);
|
||||
|
||||
// Загружаем все Energy Point Log
|
||||
const logs = createResource({
|
||||
const logsResource = createResource({
|
||||
url: "frappe.client.get_list",
|
||||
params: {
|
||||
doctype: "Energy Point Log",
|
||||
fields: ["name", "user", "points"],
|
||||
limit_page_length: 2000
|
||||
fields: ["user", "points"],
|
||||
limit_page_length: 10000 // увеличим лимит для больших данных
|
||||
},
|
||||
auto: false,
|
||||
onSuccess() {
|
||||
});
|
||||
|
||||
// Загружаем данные пользователей
|
||||
const usersResource = createResource({
|
||||
url: "frappe.client.get_list",
|
||||
params: {
|
||||
doctype: "User",
|
||||
fields: ["name", "full_name", "username"],
|
||||
filters: [["enabled", "=", 1]], // только активные пользователи
|
||||
limit_page_length: 1000
|
||||
},
|
||||
auto: false,
|
||||
});
|
||||
|
||||
// Основная функция загрузки данных
|
||||
async function loadData() {
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
// Параллельно загружаем логи и пользователей
|
||||
const [logsData, usersData] = await Promise.all([
|
||||
logsResource.fetch(),
|
||||
usersResource.fetch()
|
||||
]);
|
||||
|
||||
// Создаем карту пользователей для быстрого доступа
|
||||
const usersMap = {};
|
||||
usersData.forEach(user => {
|
||||
usersMap[user.name] = {
|
||||
full_name: user.full_name || user.name,
|
||||
username: user.username
|
||||
};
|
||||
});
|
||||
|
||||
// Суммируем баллы по пользователям
|
||||
const userPoints = {};
|
||||
logsData.forEach(log => {
|
||||
if (!userPoints[log.user]) userPoints[log.user] = 0;
|
||||
userPoints[log.user] += log.points;
|
||||
});
|
||||
|
||||
// Создаем сортированный массив
|
||||
const leaderboard = Object.entries(userPoints)
|
||||
.map(([user, points]) => ({
|
||||
user,
|
||||
points,
|
||||
full_name: usersMap[user]?.full_name || user,
|
||||
username: usersMap[user]?.username || user,
|
||||
bonus: Math.min(Math.floor(points / 100), 10)
|
||||
}))
|
||||
.sort((a, b) => b.points - a.points);
|
||||
|
||||
sorted.value = leaderboard;
|
||||
|
||||
} catch (error) {
|
||||
console.error("Ошибка загрузки данных:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Собираем баллы по пользователям
|
||||
const userPoints = computed(() => {
|
||||
const map = {};
|
||||
|
||||
if (!logs.data) return map;
|
||||
|
||||
logs.data.forEach(entry => {
|
||||
if (!map[entry.user]) map[entry.user] = 0;
|
||||
map[entry.user] += entry.points;
|
||||
});
|
||||
|
||||
return map;
|
||||
});
|
||||
|
||||
// Загружаем данные пользователей (имя + username)
|
||||
const userCache = ref({});
|
||||
|
||||
async function loadUserProfile(email) {
|
||||
if (userCache.value[email]) return userCache.value[email];
|
||||
|
||||
const profile = createResource({
|
||||
url: 'frappe.client.get',
|
||||
params: {
|
||||
doctype: 'User',
|
||||
name: email
|
||||
},
|
||||
auto: true
|
||||
})
|
||||
|
||||
userCache.value[email] = {
|
||||
full_name: profile.message.full_name,
|
||||
username: profile.message.username
|
||||
};
|
||||
|
||||
return userCache.value[email];
|
||||
}
|
||||
|
||||
// Готовим сортированный массив
|
||||
const sorted = ref([]);
|
||||
|
||||
async function buildSorted() {
|
||||
const arr = [];
|
||||
|
||||
for (const [user, points] of Object.entries(userPoints.value)) {
|
||||
const data = await loadUserProfile(user);
|
||||
|
||||
arr.push({
|
||||
user,
|
||||
points,
|
||||
full_name: data.full_name,
|
||||
username: data.username,
|
||||
bonus: Math.min(Math.floor(points / 100), 10)
|
||||
});
|
||||
}
|
||||
|
||||
arr.sort((a, b) => b.points - a.points);
|
||||
|
||||
sorted.value = arr;
|
||||
}
|
||||
|
||||
// Текущий пользователь
|
||||
const currentUserPoints = computed(
|
||||
() => userPoints.value[currentUserEmail] || 0
|
||||
);
|
||||
// Computed свойства
|
||||
const currentUserPoints = computed(() => {
|
||||
const user = sorted.value.find(u => u.user === currentUserEmail);
|
||||
return user ? user.points : 0;
|
||||
});
|
||||
|
||||
const currentUserPosition = computed(() => {
|
||||
const index = sorted.value.findIndex(u => u.user === currentUserEmail);
|
||||
return index === -1 ? null : index + 1;
|
||||
return index >= 0 ? index + 1 : null;
|
||||
});
|
||||
|
||||
const topUser = computed(() => sorted.value[0]);
|
||||
|
||||
const pointsToNext = computed(() => {
|
||||
if (!currentUserPosition.value || currentUserPosition.value <= 1) return 0;
|
||||
const next = sorted.value[currentUserPosition.value - 2];
|
||||
return next.points - currentUserPoints.value;
|
||||
const nextUser = sorted.value[currentUserPosition.value - 2];
|
||||
return nextUser.points - currentUserPoints.value;
|
||||
});
|
||||
|
||||
// Топ-1 участник
|
||||
const topUser = computed(() => sorted.value[0]);
|
||||
|
||||
// UI статусы
|
||||
const statusLabel = computed(() => {
|
||||
if (!currentUserPosition.value) return "Не в рейтинге";
|
||||
if (!currentUserPosition.value) return "Стремитесь выше";
|
||||
|
||||
if (currentUserPosition.value === 1) return "Чемпион";
|
||||
if (currentUserPosition.value === 2) return "Второе место";
|
||||
if (currentUserPosition.value === 3) return "Третье место";
|
||||
if (currentUserPosition.value <= 5) return "В топ-5";
|
||||
if (currentUserPosition.value <= 10) return "В топ-10";
|
||||
|
||||
return "Стремитесь выше";
|
||||
switch (currentUserPosition.value) {
|
||||
case 1: return "Чемпион";
|
||||
case 2: return "Второе место";
|
||||
case 3: return "Третье место";
|
||||
default:
|
||||
if (currentUserPosition.value <= 5) return "В топ-5";
|
||||
if (currentUserPosition.value <= 10) return "В топ-10";
|
||||
return "Стремитесь выше";
|
||||
}
|
||||
});
|
||||
|
||||
const statusIcon = computed(() => {
|
||||
if (currentUserPosition.value === 1) return "/files/gold-cup.png";
|
||||
if (currentUserPosition.value === 2) return "/files/silver-cup.png";
|
||||
if (currentUserPosition.value === 3) return "/files/bronze-cup.png";
|
||||
if (currentUserPosition.value && currentUserPosition.value <= 10) return "/files/star.svg";
|
||||
return "/files/dart-board.svg";
|
||||
});
|
||||
|
||||
@@ -256,14 +268,27 @@ const statusClass = computed(() => {
|
||||
return "";
|
||||
});
|
||||
|
||||
// Загружаем
|
||||
onMounted(async () => {
|
||||
await logs.fetch();
|
||||
await buildSorted();
|
||||
console.log("onMounted");
|
||||
const topUserInitial = computed(() => {
|
||||
return topUser.value ? topUser.value.user[0].toUpperCase() : 'N/A';
|
||||
});
|
||||
|
||||
// Вспомогательные функции
|
||||
function getUserInitial(email) {
|
||||
return email ? email[0].toUpperCase() : '?';
|
||||
}
|
||||
|
||||
function userProfileLink(userEmail) {
|
||||
const user = sorted.value.find(u => u.user === userEmail);
|
||||
return user ? `/lms/user/${user.username}` : '#';
|
||||
}
|
||||
|
||||
// Загружаем данные при монтировании
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* сюда полностью переносите ваш CSS — он совместим */
|
||||
/* Ваш полный CSS стиль здесь */
|
||||
/* Общие стили */
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user