完成我的成长脚印UI
This commit is contained in:
@@ -11,7 +11,7 @@ const bgs = ref(["../static/app-bg.png", "../static/app-bg2.png"]);
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="background">
|
<view class="background">
|
||||||
<image class="bg-image" :src="bgs[type]" mode="aspectFill" />
|
<image class="bg-image" :src="bgs[type]" mode="widthFix" />
|
||||||
<view class="bg-overlay" v-if="type === 0"></view>
|
<view class="bg-overlay" v-if="type === 0"></view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -27,11 +27,8 @@ const bgs = ref(["../static/app-bg.png", "../static/app-bg2.png"]);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bg-image {
|
.bg-image {
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-overlay {
|
.bg-overlay {
|
||||||
@@ -42,8 +39,8 @@ const bgs = ref(["../static/app-bg.png", "../static/app-bg2.png"]);
|
|||||||
top: 0;
|
top: 0;
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
to bottom,
|
to bottom,
|
||||||
rgba(26, 26, 26, 0.8),
|
rgba(26, 26, 26, 0.2),
|
||||||
rgba(0, 0, 0, 0.8)
|
rgba(0, 0, 0, 0.2)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
const activeTab = ref("member");
|
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ id: "member", image: "../static/tab-vip.png" },
|
{ image: "../static/tab-vip.png" },
|
||||||
{ id: "growth", image: "../static/tab-grow.png" },
|
{ image: "../static/tab-grow.png" },
|
||||||
{ id: "shop", image: "../static/tab-mall.png" },
|
{ image: "../static/tab-mall.png" },
|
||||||
];
|
];
|
||||||
|
|
||||||
function handleTabClick(tabId) {
|
function handleTabClick(index) {
|
||||||
activeTab.value = tabId;
|
if (index === 1) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: "/pages/my-growth",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,10 +19,9 @@ function handleTabClick(tabId) {
|
|||||||
<image class="footer-bg" src="../static/tab-bg.png" mode="widthFix" />
|
<image class="footer-bg" src="../static/tab-bg.png" mode="widthFix" />
|
||||||
<view
|
<view
|
||||||
v-for="(tab, index) in tabs"
|
v-for="(tab, index) in tabs"
|
||||||
:key="tab.id"
|
:key="index"
|
||||||
class="tab-item"
|
class="tab-item"
|
||||||
:class="{ active: activeTab === tab.id }"
|
@click="handleTabClick(index)"
|
||||||
@click="handleTabClick(tab.id)"
|
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
:src="tab.image"
|
:src="tab.image"
|
||||||
|
|||||||
87
src/components/Avatar.vue
Normal file
87
src/components/Avatar.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
onClick: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
frame: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
rank: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="avatar" @click="onClick">
|
||||||
|
<image
|
||||||
|
v-if="frame"
|
||||||
|
src="../static/avatar-frame.png"
|
||||||
|
mode="widthFix"
|
||||||
|
class="avatar-frame"
|
||||||
|
/>
|
||||||
|
<image
|
||||||
|
v-if="rank === 1"
|
||||||
|
src="../static/champ1.png"
|
||||||
|
mode="widthFix"
|
||||||
|
class="avatar-rank"
|
||||||
|
/>
|
||||||
|
<image
|
||||||
|
v-if="rank === 2"
|
||||||
|
src="../static/champ2.png"
|
||||||
|
mode="widthFix"
|
||||||
|
class="avatar-rank"
|
||||||
|
/>
|
||||||
|
<image
|
||||||
|
v-if="rank === 3"
|
||||||
|
src="../static/champ3.png"
|
||||||
|
mode="widthFix"
|
||||||
|
class="avatar-rank"
|
||||||
|
/>
|
||||||
|
<view v-if="rank > 3" class="rank-view">{{ rank }}</view>
|
||||||
|
<image :src="src" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.avatar {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.avatar-frame {
|
||||||
|
position: absolute;
|
||||||
|
width: 55px;
|
||||||
|
height: 55px;
|
||||||
|
}
|
||||||
|
.avatar-rank,
|
||||||
|
.rank-view {
|
||||||
|
position: absolute;
|
||||||
|
width: 20px;
|
||||||
|
height: 15px;
|
||||||
|
top: -6px;
|
||||||
|
right: -4px;
|
||||||
|
}
|
||||||
|
.rank-view {
|
||||||
|
background-color: #6d6d6d;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-top-left-radius: 50%;
|
||||||
|
border-bottom-right-radius: 50%;
|
||||||
|
}
|
||||||
|
.avatar > image:last-child {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,7 +7,7 @@ defineProps({
|
|||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
bgType: {
|
bgType: {
|
||||||
type: String,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
import Avatar from "@/components/Avatar.vue";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
showRank: {
|
showRank: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -8,11 +9,11 @@ const props = defineProps({
|
|||||||
user: {
|
user: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
nickName:'',
|
nickName: "",
|
||||||
lvl:0,
|
lvl: 0,
|
||||||
points:0,
|
points: 0,
|
||||||
rankLvl:0,
|
rankLvl: 0,
|
||||||
lvlPoints:0,
|
lvlPoints: 0,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -33,10 +34,7 @@ const toUserPage = () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="container" :style="{ width: containerWidth }">
|
<view class="container" :style="{ width: containerWidth }">
|
||||||
<view class="avatar" @click="toUserPage">
|
<Avatar frame="true" src="../static/avatar.png" :onClick="toUserPage" />
|
||||||
<image src="../static/avatar-frame.png" mode="widthFix" />
|
|
||||||
<image src="../static/avatar.png" mode="widthFix" />
|
|
||||||
</view>
|
|
||||||
<view class="user-details">
|
<view class="user-details">
|
||||||
<view class="user-name">
|
<view class="user-name">
|
||||||
<text>{{ user.nickName }}</text>
|
<text>{{ user.nickName }}</text>
|
||||||
@@ -72,25 +70,6 @@ const toUserPage = () => {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar > image:first-child {
|
|
||||||
position: absolute;
|
|
||||||
width: 55px;
|
|
||||||
height: 55px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar > image {
|
|
||||||
width: 45px;
|
|
||||||
height: 45px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-details {
|
.user-details {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -165,7 +165,6 @@ onMounted(() => {
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<AppFooter />
|
<AppFooter />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import SButton from "@/components/SButton.vue";
|
|||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { loginAPI } from "@/apis";
|
import { loginAPI } from "@/apis";
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
// 使用actions方法
|
|
||||||
const { updateUser, updateToken } = store;
|
const { updateUser } = store;
|
||||||
const agree = ref(false);
|
const agree = ref(false);
|
||||||
|
|
||||||
const handleAgree = () => {
|
const handleAgree = () => {
|
||||||
@@ -31,7 +31,6 @@ const handleLogin = () => {
|
|||||||
const { code } = loginRes;
|
const { code } = loginRes;
|
||||||
const result = await loginAPI(nickName, avatarUrl, code);
|
const result = await loginAPI(nickName, avatarUrl, code);
|
||||||
updateUser(result.user);
|
updateUser(result.user);
|
||||||
updateToken(result.token, result.expires);
|
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
|
|||||||
225
src/pages/my-growth.vue
Normal file
225
src/pages/my-growth.vue
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
<script setup>
|
||||||
|
import Container from "@/components/Container.vue";
|
||||||
|
import Avatar from "@/components/Avatar.vue";
|
||||||
|
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const selectedIndex = ref(0);
|
||||||
|
|
||||||
|
const handleSelect = (index) => {
|
||||||
|
selectedIndex.value = index;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Container title="我的成长脚印">
|
||||||
|
<view class="tabs">
|
||||||
|
<view
|
||||||
|
v-for="(rankType, index) in ['排位赛', '好友约战', '射馆练习']"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
color: index === selectedIndex ? '#000' : '#fff',
|
||||||
|
backgroundColor: index === selectedIndex ? '#FFD947' : 'transparent',
|
||||||
|
}"
|
||||||
|
@tap="handleSelect(index)"
|
||||||
|
>
|
||||||
|
{{ rankType }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="contents">
|
||||||
|
<view
|
||||||
|
:style="{
|
||||||
|
display: selectedIndex !== 2 ? 'flex' : 'none',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<view>
|
||||||
|
<view class="contest-header">
|
||||||
|
<text>1V1</text>
|
||||||
|
<text>2025.01.21 14:09:23</text>
|
||||||
|
<image src="../static/back.png" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="contest-1v1">
|
||||||
|
<view class="player">
|
||||||
|
<Avatar frame src="../static/avatar.png" />
|
||||||
|
<text>选手1</text>
|
||||||
|
<image src="../static/winner-badge.png" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="player">
|
||||||
|
<Avatar frame src="../static/avatar.png" />
|
||||||
|
<text>选手2</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<view class="contest-header">
|
||||||
|
<text>1V1</text>
|
||||||
|
<text>2025.01.21 14:09:23</text>
|
||||||
|
<image src="../static/back.png" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="contest-1v1">
|
||||||
|
<view class="player">
|
||||||
|
<Avatar frame src="../static/avatar.png" />
|
||||||
|
<text>选手1</text>
|
||||||
|
<image src="../static/winner-badge.png" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="player">
|
||||||
|
<Avatar frame src="../static/avatar.png" />
|
||||||
|
<text>选手2</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<view class="contest-header">
|
||||||
|
<text>5v5</text>
|
||||||
|
<text>2025.01.21 14:09:23</text>
|
||||||
|
<image src="../static/back.png" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="contest-multi">
|
||||||
|
<view class="player">
|
||||||
|
<Avatar :rank="1" src="../static/avatar.png" />
|
||||||
|
<text>选手1</text>
|
||||||
|
</view>
|
||||||
|
<view class="player">
|
||||||
|
<Avatar :rank="2" src="../static/avatar.png" />
|
||||||
|
<text>选手2</text>
|
||||||
|
</view>
|
||||||
|
<view class="player">
|
||||||
|
<Avatar :rank="3" src="../static/avatar.png" />
|
||||||
|
<text>选手3</text>
|
||||||
|
</view>
|
||||||
|
<view class="player">
|
||||||
|
<Avatar :rank="4" src="../static/avatar.png" />
|
||||||
|
<text>选手4</text>
|
||||||
|
</view>
|
||||||
|
<view class="player">
|
||||||
|
<Avatar :rank="5" src="../static/avatar.png" />
|
||||||
|
<text>选手5</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
:style="{
|
||||||
|
display: selectedIndex === 2 ? 'flex' : 'none',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
v-for="(_, index) in new Array(6).fill(0)"
|
||||||
|
:key="index"
|
||||||
|
class="practice-record"
|
||||||
|
>
|
||||||
|
<text>单组练习 2025.01.21 14:09:23</text>
|
||||||
|
<image src="../static/back.png" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</Container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tabs {
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
font-size: 15px;
|
||||||
|
padding: 15px;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.tabs > view {
|
||||||
|
width: 33.3%;
|
||||||
|
padding: 7px 10px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
.contents > view {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.contest-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 7px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: linear-gradient(180deg, #323845 0%, #2e2e39 100%);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.contest-header > text:first-child {
|
||||||
|
color: #ffd947;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.contest-header > text:nth-child(2) {
|
||||||
|
color: #fff9;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
.contest-header > image {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 10px;
|
||||||
|
width: 15px;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
.player {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: #fff9;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.player > text {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.player > image:last-child {
|
||||||
|
position: absolute;
|
||||||
|
width: 60px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.contest-1v1,
|
||||||
|
.contest-multi {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.contest-1v1 > view {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.contest-1v1 > view:first-child {
|
||||||
|
background-color: #364469;
|
||||||
|
}
|
||||||
|
.contest-1v1 > view:last-child {
|
||||||
|
background-color: #692735;
|
||||||
|
}
|
||||||
|
.contest-multi > view {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
.contest-multi > view:nth-child(1) {
|
||||||
|
background-color: #364469;
|
||||||
|
}
|
||||||
|
.contest-multi > view:nth-child(2) {
|
||||||
|
background-color: #692735;
|
||||||
|
}
|
||||||
|
.contest-multi > view:nth-child(3) {
|
||||||
|
background-color: #934b4b;
|
||||||
|
}
|
||||||
|
.contest-multi > view:nth-child(4) {
|
||||||
|
background-color: #a98b69;
|
||||||
|
}
|
||||||
|
.contest-multi > view:nth-child(5) {
|
||||||
|
background-color: #8268a2;
|
||||||
|
}
|
||||||
|
.practice-record {
|
||||||
|
color: #fff9;
|
||||||
|
border-bottom: 1px solid #fff9;
|
||||||
|
padding: 15px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.practice-record > image {
|
||||||
|
width: 15px;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 261 KiB After Width: | Height: | Size: 266 KiB |
BIN
src/static/winner-badge.png
Normal file
BIN
src/static/winner-badge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
Reference in New Issue
Block a user