mirror of
https://github.com/PhaseII-eAmusement-Network/PhaseWeb3-Vue.git
synced 2026-08-25 02:24:20 -05:00
This commit is contained in:
545
package-lock.json
generated
545
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
||||
"@rushstack/eslint-patch": "^1.1.4",
|
||||
"@vuepic/vue-datepicker": "^11.0.1",
|
||||
"axios": "^0.27.0",
|
||||
"chart.js": "^3.6.0",
|
||||
"chart.js": "^4.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"js-cookie": "^3.0.5",
|
||||
@@ -20,6 +20,7 @@
|
||||
"particles.js": "^2.0.0",
|
||||
"pinia": "^2.0.13",
|
||||
"vue": "^3.0.0",
|
||||
"vue-chartjs": "^5.3.2",
|
||||
"vue-router": "^4.0.0",
|
||||
"vue3-easy-data-table": "^1.5.47"
|
||||
},
|
||||
|
||||
191
src/components/Charts/UserNotesRadar.vue
Normal file
191
src/components/Charts/UserNotesRadar.vue
Normal file
@@ -0,0 +1,191 @@
|
||||
<script setup>
|
||||
import { watch, ref, onMounted, computed } from "vue";
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
RadialLinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Filler,
|
||||
Tooltip,
|
||||
Legend,
|
||||
} from "chart.js";
|
||||
import { Radar } from "vue-chartjs";
|
||||
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import PillTag from "@/components/PillTag.vue";
|
||||
import { APIGetAchievements } from "@/stores/api/profile";
|
||||
|
||||
ChartJS.register(
|
||||
RadialLinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Filler,
|
||||
Tooltip,
|
||||
Legend
|
||||
);
|
||||
|
||||
const props = defineProps({
|
||||
profile: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
game: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
version: {
|
||||
type: Number,
|
||||
default: 9,
|
||||
},
|
||||
});
|
||||
|
||||
const userProfile = ref(props.profile);
|
||||
const version = ref(props.version);
|
||||
const loading = ref(true);
|
||||
const loadingKey = ref(0);
|
||||
const chartData = ref({
|
||||
labels: ["Notes", "Peak", "Scratch", "Sof-Lan", "Charge", "Chord"],
|
||||
datasets: [
|
||||
{
|
||||
label: "SP",
|
||||
backgroundColor: "rgba(22, 95, 250, 0.2)",
|
||||
borderColor: "rgba(22, 95, 250, 1)",
|
||||
pointBackgroundColor: "rgba(22, 95, 250, 1)",
|
||||
pointBorderColor: "#fff",
|
||||
pointHoverBackgroundColor: "#fff",
|
||||
pointHoverBorderColor: "rgba(22, 95, 250, 1)",
|
||||
data: [],
|
||||
},
|
||||
{
|
||||
label: "DP",
|
||||
backgroundColor: "rgba(250, 170, 22, 0.2)",
|
||||
borderColor: "rgba(250, 170, 22, 1)",
|
||||
pointBackgroundColor: "rgba(250, 170, 22, 1)",
|
||||
pointBorderColor: "#fff",
|
||||
pointHoverBackgroundColor: "#fff",
|
||||
pointHoverBorderColor: "rgba(250, 170, 22, 1)",
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.version,
|
||||
() => {
|
||||
userProfile.value = props.profile;
|
||||
version.value = props.version;
|
||||
loadData();
|
||||
}
|
||||
);
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
const data = await APIGetAchievements(
|
||||
props.game,
|
||||
props.version,
|
||||
userProfile.value,
|
||||
[
|
||||
["notes_radar", 0],
|
||||
["notes_radar", 1],
|
||||
]
|
||||
);
|
||||
|
||||
const reorderData = (originalData) => {
|
||||
const [notes, peak, scratch, sof_lan, charge, chord] = originalData;
|
||||
return [
|
||||
notes / 100,
|
||||
peak / 100,
|
||||
scratch / 100,
|
||||
sof_lan / 100,
|
||||
charge / 100,
|
||||
chord / 100,
|
||||
];
|
||||
};
|
||||
|
||||
if (data[0]?.achievementId === 0) {
|
||||
chartData.value.datasets[0].data = reorderData(data[0].data.radar_score);
|
||||
}
|
||||
if (data[1]?.achievementId === 1) {
|
||||
chartData.value.datasets[1].data = reorderData(data[1].data.radar_score);
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
loadingKey.value += 1;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch arcade data:", error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
const chartOptions = {
|
||||
responsive: false,
|
||||
maintainAspectRatio: true,
|
||||
scales: {
|
||||
r: {
|
||||
ticks: {
|
||||
stepSize: 30,
|
||||
callback: function (value) {
|
||||
return value;
|
||||
},
|
||||
},
|
||||
pointLabels: {
|
||||
font: {
|
||||
size: 15,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const spTotalScore = computed(() => {
|
||||
return chartData.value.datasets[0].data
|
||||
.reduce((sum, value) => sum + value, 0)
|
||||
.toFixed(2);
|
||||
});
|
||||
|
||||
const dpTotalScore = computed(() => {
|
||||
return chartData.value.datasets[1].data
|
||||
.reduce((sum, value) => sum + value, 0)
|
||||
.toFixed(2);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CardBox v-if="chartData.datasets[0]" class="my-6">
|
||||
<div class="grid lg:grid-cols-2 gap-4">
|
||||
<CardBox color-prop="bg-slate-800 dark:bg-slate-800">
|
||||
<PillTag color="info" label="SP Radar" class="mb-2" />
|
||||
<div class="w-full grid place-content-center text-center">
|
||||
<Radar
|
||||
:key="loadingKey"
|
||||
class="bg-slate-100 p-2 rounded-lg"
|
||||
:data="{
|
||||
labels: chartData.labels,
|
||||
datasets: [chartData.datasets[0]],
|
||||
}"
|
||||
:options="chartOptions"
|
||||
/>
|
||||
<span class="text-lg">Total score: {{ spTotalScore }}</span>
|
||||
</div>
|
||||
</CardBox>
|
||||
<CardBox color-prop="bg-slate-800 dark:bg-slate-800">
|
||||
<PillTag color="info" label="DP Radar" class="mb-2" />
|
||||
<div class="w-full grid place-content-center text-center">
|
||||
<Radar
|
||||
:key="loadingKey"
|
||||
class="bg-slate-100 p-2 rounded-lg"
|
||||
:data="{
|
||||
labels: chartData.labels,
|
||||
datasets: [chartData.datasets[1]],
|
||||
}"
|
||||
:options="chartOptions"
|
||||
/>
|
||||
<span class="text-lg">Total score: {{ dpTotalScore }}</span>
|
||||
</div>
|
||||
</CardBox>
|
||||
</div>
|
||||
</CardBox>
|
||||
</template>
|
||||
21
src/components/Charts/radar.config.js
Normal file
21
src/components/Charts/radar.config.js
Normal file
@@ -0,0 +1,21 @@
|
||||
export const data = {
|
||||
//labels: ["Notes", "Chord", "Peak", "Charge", "Scratch", "Sof-Lan"],
|
||||
labels: ["Notes", "Peak", "Scratch", "Sof-Lan", "Charge", "Chord"],
|
||||
datasets: [
|
||||
{
|
||||
label: "SP",
|
||||
backgroundColor: "rgba(179,181,198,0.2)",
|
||||
borderColor: "rgba(179,181,198,1)",
|
||||
pointBackgroundColor: "rgba(179,181,198,1)",
|
||||
pointBorderColor: "#fff",
|
||||
pointHoverBackgroundColor: "#fff",
|
||||
pointHoverBorderColor: "rgba(179,181,198,1)",
|
||||
data: [65, 59, 90, 81, 56, 55],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const options = {
|
||||
responsive: false,
|
||||
maintainAspectRatio: true,
|
||||
};
|
||||
@@ -48,3 +48,42 @@ export async function APIUpdateProfile(game, version, newProfile) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function APIGetAchievements(
|
||||
game,
|
||||
version,
|
||||
userId = null,
|
||||
achievements = []
|
||||
) {
|
||||
if (!userId) {
|
||||
while (!mainStore.userId) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||
}
|
||||
userId = mainStore.userId;
|
||||
}
|
||||
|
||||
var formattedAchievements = "";
|
||||
for (const achievement of achievements) {
|
||||
const achievementType = achievement[0];
|
||||
const achievementId = achievement[1];
|
||||
formattedAchievements += `${achievementType}:${achievementId},`;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await mainStore.callApi(
|
||||
`/profile/${game}/achievements?version=${version}&userId=${userId}`,
|
||||
"GET",
|
||||
null,
|
||||
{
|
||||
achievements: formattedAchievements.substring(
|
||||
0,
|
||||
formattedAchievements.length - 1
|
||||
),
|
||||
}
|
||||
);
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
console.log("Error fetching achievements:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
mdiChartAreasplineVariant,
|
||||
mdiChartTimeline,
|
||||
mdiStickerOutline,
|
||||
mdiChartDonutVariant,
|
||||
} from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBoxWidget from "@/components/CardBoxWidget.vue";
|
||||
@@ -22,10 +23,11 @@ import FormControl from "@/components/FormControl.vue";
|
||||
import PillTag from "@/components/PillTag.vue";
|
||||
import JubilityTable from "@/components/Tables/JubilityTable.vue";
|
||||
import UserSticker from "@/components/UserSticker.vue";
|
||||
import UserNotesRadar from "@/components/Charts/UserNotesRadar.vue";
|
||||
|
||||
import { APIGetProfile } from "@/stores/api/profile";
|
||||
import { APIGetArcade } from "@/stores/api/arcade";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import { GameConstants, getGameInfo } from "@/constants";
|
||||
import { getIIDXDan } from "@/constants/danClass.js";
|
||||
import { getGitadoraColor, getJubilityColor } from "@/constants/skillColor";
|
||||
const ASSET_PATH = import.meta.env.VITE_ASSET_PATH;
|
||||
@@ -540,6 +542,24 @@ async function generateTimeline(myProfile) {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-if="
|
||||
thisGame.id == GameConstants.IIDX &&
|
||||
versionForm.currentVersion >= 29
|
||||
"
|
||||
>
|
||||
<SectionTitleLine
|
||||
:icon="mdiChartDonutVariant"
|
||||
title="Notes Radar"
|
||||
main
|
||||
/>
|
||||
<UserNotesRadar
|
||||
:game="thisGame.id"
|
||||
:version="versionForm.currentVersion"
|
||||
:profile="profileUserId"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-if="myProfile?.timeline">
|
||||
<SectionTitleLine :icon="mdiChartTimeline" title="Timeline" main />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user