xtraderClient/src/components/MarketCard.vue
2026-02-08 11:41:39 +08:00

266 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<v-card class="market-card" elevation="0" :rounded="'lg'" @click="navigateToDetail">
<div class="market-card-content">
<!-- Top Section -->
<div class="top-section">
<!-- Market Image and Title -->
<div class="image-title-container">
<v-avatar class="market-image" :size="40" color="#f0f0f0" rounded="sm">
<v-img v-if="props.imageUrl" :src="props.imageUrl" cover />
</v-avatar>
<v-card-title class="market-title" :text="true" :shrink="true">
{{ marketTitle }}
</v-card-title>
</div>
<!-- Chance Container -->
<div class="chance-container">
<v-progress-circular
class="progress-bar"
:size="60"
:width="4"
:value="chanceValue"
:color="progressColor"
:background="'#e0e0e0'"
>
<template v-slot:default>
<span class="chance-value">{{ chanceValue }}%</span>
</template>
</v-progress-circular>
<span class="chance-label">chance</span>
</div>
</div>
<!-- Options Section -->
<div class="options-section">
<v-btn class="option-yes" :color="'#e6f9e6'" :rounded="'sm'" :text="true">
<span class="option-text-yes">Yes</span>
</v-btn>
<v-btn class="option-no" :color="'#ffe6e6'" :rounded="'sm'" :text="true">
<span class="option-text-no">No</span>
</v-btn>
</div>
<!-- Bottom Section -->
<div class="bottom-section">
<span class="market-info">{{ marketInfo }}</span>
<div class="icons-container">
<v-icon class="gift-icon" size="16">mdi-gift</v-icon>
<v-icon class="bookmark-icon" size="16">mdi-bookmark</v-icon>
</div>
</div>
</div>
</v-card>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const props = defineProps({
marketTitle: {
type: String,
default: 'Mamdan opens city-owned grocery store b...',
},
chanceValue: {
type: Number,
default: 17,
},
marketInfo: {
type: String,
default: '$155k Vol.',
},
id: {
type: String,
default: '1',
},
/** 市场图片 URL由卡片传入供详情页展示 */
imageUrl: {
type: String,
default: '',
},
/** 分类标签,如 "Economy · World" */
category: {
type: String,
default: '',
},
/** 结算/到期日期,如 "Mar 31, 2026" */
expiresAt: {
type: String,
default: '',
},
})
// 计算进度条颜色,从红色(0%)到绿色(100%)
const progressColor = computed(() => {
// 红色在HSL中是0度绿色是120度
const hue = (props.chanceValue / 100) * 120
return `hsl(${hue}, 100%, 50%)`
})
// 跳转到交易详情页面,将标题、图片等通过 query 传入
const navigateToDetail = () => {
router.push({
path: `/trade-detail/${props.id}`,
query: {
title: props.marketTitle,
imageUrl: props.imageUrl || undefined,
category: props.category || undefined,
marketInfo: props.marketInfo || undefined,
expiresAt: props.expiresAt || undefined,
chance: String(props.chanceValue),
},
})
}
</script>
<style scoped>
.market-card {
position: relative;
width: 310px;
height: 160px;
background-color: #ffffff;
border-radius: 8px;
border: 1px solid #e7e7e7;
padding: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.market-card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
border-color: #d0d0d0;
}
.market-card-content {
display: flex;
flex-direction: column;
height: 100%;
gap: 12px;
}
/* Top Section */
.top-section {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.image-title-container {
display: flex;
align-items: flex-start;
gap: 12px;
flex: 1;
min-width: 0;
}
.market-image {
flex-shrink: 0;
}
.market-title {
flex: 1;
min-width: 0;
font-family: 'Inter', sans-serif;
font-size: 14px;
font-weight: 500;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.chance-container {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
width: 60px;
height: 60px;
}
.progress-bar {
margin-bottom: 2px;
}
.chance-value {
font-family: 'Inter', sans-serif;
font-size: 12px;
font-weight: 600;
color: #000000;
}
.chance-label {
font-family: 'Inter', sans-serif;
font-size: 10px;
font-weight: normal;
color: #808080;
margin-top: 4px;
}
/* Options Section */
.options-section {
display: flex;
gap: 12px;
}
.option-yes {
flex: 1;
background-color: #e6f9e6;
height: 40px;
}
.option-text-yes {
font-family: 'Inter', sans-serif;
font-size: 16px;
font-weight: 500;
color: #008000;
}
.option-no {
flex: 1;
background-color: #ffe6e6;
height: 40px;
}
.option-text-no {
font-family: 'Inter', sans-serif;
font-size: 16px;
font-weight: 500;
color: #ff0000;
}
/* Bottom Section */
.bottom-section {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: auto;
}
.market-info {
font-family: 'Inter', sans-serif;
font-size: 12px;
font-weight: normal;
color: #808080;
}
.icons-container {
display: flex;
gap: 16px;
}
.gift-icon {
color: #808080;
}
.bookmark-icon {
color: #808080;
}
</style>