mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-07 02:46:55 +08:00
feat: 更新商品管理功能,添加虚拟礼物多Key支持和排序功能
- 在商品模型中添加密钥选择模式和虚拟密钥列表 - 更新商品展示组件,支持置顶标记和价格徽章 - 优化商品管理视图,添加排序功能和清空筛选条件的功能 - 改进礼物添加表单,增加输入验证和错误提示
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { GoodsTypes, ResponsePointGoodModel } from '@/api/api-models';
|
||||
import { FILE_BASE_URL, IMGUR_URL } from '@/data/constants';
|
||||
import { NAlert, NCard, NEllipsis, NEmpty, NFlex, NIcon, NImage, NTag, NText } from 'naive-ui';
|
||||
import { VehicleShip20Filled } from '@vicons/fluent';
|
||||
import { VehicleShip20Filled, Pin16Filled } from '@vicons/fluent';
|
||||
|
||||
const props = defineProps<{
|
||||
goods: ResponsePointGoodModel | undefined;
|
||||
@@ -22,77 +22,143 @@
|
||||
v-else
|
||||
embedded
|
||||
:style="props.contentStyle"
|
||||
size="small"
|
||||
class="goods-card"
|
||||
:class="{ 'pinned-card': goods.isPinned }"
|
||||
>
|
||||
<!-- 商品封面 -->
|
||||
<template #cover>
|
||||
<NImage
|
||||
:src="goods.cover ? FILE_BASE_URL + goods.cover : emptyCover"
|
||||
:fallback-src="emptyCover"
|
||||
height="150"
|
||||
object-fit="cover"
|
||||
:preview-disabled="!goods.cover"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="cover-container">
|
||||
<NImage
|
||||
:src="goods.cover ? FILE_BASE_URL + goods.cover : emptyCover"
|
||||
:fallback-src="emptyCover"
|
||||
height="150"
|
||||
object-fit="cover"
|
||||
:preview-disabled="!goods.cover"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<!-- 置顶标记 -->
|
||||
<div
|
||||
v-if="goods.isPinned"
|
||||
class="pin-badge"
|
||||
>
|
||||
<NIcon :component="Pin16Filled" />
|
||||
</div>
|
||||
|
||||
<!-- 价格徽章 -->
|
||||
<div class="price-badge">
|
||||
<NText class="price-text">
|
||||
🪙 {{ goods.price > 0 ? goods.price : '免费' }}
|
||||
</NText>
|
||||
</div>
|
||||
|
||||
<!-- 标签容器 -->
|
||||
<div class="tags-badge">
|
||||
<!-- 商品类型标签 -->
|
||||
<NTag
|
||||
size="small"
|
||||
:bordered="true"
|
||||
style="background-color: transparent;"
|
||||
:style="{
|
||||
color: goods.type == GoodsTypes.Physical ? '#006633' : '#0066cc',
|
||||
borderColor: goods.type == GoodsTypes.Physical ? '#009966' : '#3399ff',
|
||||
backgroundColor: goods.type == GoodsTypes.Physical ? '#c2e6d290' : '#c2d6eb90'
|
||||
}"
|
||||
>
|
||||
{{ goods.type == GoodsTypes.Physical ? '实物' : '虚拟' }}
|
||||
</NTag>
|
||||
<!-- 状态标签 -->
|
||||
<NTag
|
||||
v-if="goods.count == 0"
|
||||
size="small"
|
||||
type="error"
|
||||
:bordered="false"
|
||||
style="color: #ffffff; background-color: rgba(255, 85, 85, 0.7);"
|
||||
>
|
||||
已售完
|
||||
</NTag>
|
||||
|
||||
<!-- 舰长限制标签 -->
|
||||
<NTag
|
||||
v-if="goods.allowGuardLevel > 0"
|
||||
size="small"
|
||||
type="warning"
|
||||
:bordered="false"
|
||||
style="color: #333333; background-color: rgba(255, 204, 0, 0.7);"
|
||||
>
|
||||
{{ goods.allowGuardLevel === 1 ? '总督' : goods.allowGuardLevel === 2 ? '提督' : '舰长' }}专属
|
||||
</NTag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 商品信息头部 -->
|
||||
<template #header-extra>
|
||||
<NFlex justify="space-between">
|
||||
<NFlex>
|
||||
<NText depth="3">
|
||||
库存:
|
||||
</NText>
|
||||
<NText v-if="goods.count && goods.count > 0">
|
||||
{{ goods.count }}
|
||||
</NText>
|
||||
<NText
|
||||
v-else-if="goods.count == 0"
|
||||
style="color: #5f5f5f;"
|
||||
<!-- 商品信息头部 - 改为水平布局 -->
|
||||
<template #header>
|
||||
<NFlex vertical>
|
||||
<!-- 标题行:左侧标题,右侧库存 -->
|
||||
<NFlex
|
||||
justify="space-between"
|
||||
align="center"
|
||||
class="title-row"
|
||||
>
|
||||
<NFlex
|
||||
align="center"
|
||||
class="title-container"
|
||||
>
|
||||
无
|
||||
</NText>
|
||||
<NText v-else>
|
||||
∞
|
||||
</NText>
|
||||
<NEllipsis
|
||||
strong
|
||||
class="goods-title"
|
||||
:line-clamp="1"
|
||||
>
|
||||
{{ goods.name }}
|
||||
</NEllipsis>
|
||||
</NFlex>
|
||||
|
||||
<NFlex
|
||||
align="center"
|
||||
class="stock-info"
|
||||
>
|
||||
<NText
|
||||
depth="3"
|
||||
size="small"
|
||||
>
|
||||
库存:
|
||||
</NText>
|
||||
<NText
|
||||
v-if="goods.count && goods.count > 0"
|
||||
size="small"
|
||||
>
|
||||
{{ goods.count }}
|
||||
</NText>
|
||||
<NText
|
||||
v-else-if="goods.count == 0"
|
||||
size="small"
|
||||
type="error"
|
||||
>
|
||||
无
|
||||
</NText>
|
||||
<NText
|
||||
v-else
|
||||
size="small"
|
||||
>
|
||||
∞
|
||||
</NText>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</template>
|
||||
|
||||
<!-- 商品标题 -->
|
||||
<template #header>
|
||||
<NFlex
|
||||
align="center"
|
||||
:size="5"
|
||||
>
|
||||
<!-- 售罄标签 -->
|
||||
<NTag
|
||||
v-if="goods.count == 0"
|
||||
size="small"
|
||||
type="error"
|
||||
:bordered="false"
|
||||
>
|
||||
已售完
|
||||
</NTag>
|
||||
|
||||
<!-- 商品类型标签 -->
|
||||
<NTag
|
||||
size="small"
|
||||
:bordered="goods.type != GoodsTypes.Physical"
|
||||
>
|
||||
{{ goods.type == GoodsTypes.Physical ? '实物' : '虚拟' }}
|
||||
</NTag>
|
||||
|
||||
<!-- 商品名称 -->
|
||||
<NEllipsis>
|
||||
{{ goods.name }}
|
||||
</NEllipsis>
|
||||
</NFlex>
|
||||
</template>
|
||||
|
||||
<!-- 商品描述和标签 -->
|
||||
<NFlex vertical>
|
||||
<NEllipsis :line-clamp="2">
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="8"
|
||||
class="content-section"
|
||||
>
|
||||
<!-- 描述文本 -->
|
||||
<NEllipsis
|
||||
:line-clamp="2"
|
||||
class="description-text"
|
||||
>
|
||||
<NText
|
||||
:depth="goods.description ? 1 : 3"
|
||||
:italic="!goods.description"
|
||||
@@ -101,30 +167,24 @@
|
||||
</NText>
|
||||
</NEllipsis>
|
||||
|
||||
<!-- 标签展示 -->
|
||||
<NFlex wrap>
|
||||
<!-- 舰长限制标签 -->
|
||||
<NTag
|
||||
v-if="goods.allowGuardLevel > 0"
|
||||
size="tiny"
|
||||
:color="{ color: '#5f5f5f', textColor: 'gold' }"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="VehicleShip20Filled" />
|
||||
</template>
|
||||
仅限舰长
|
||||
</NTag>
|
||||
|
||||
<!-- 商品标签 -->
|
||||
<NTag
|
||||
v-for="tag in goods.tags"
|
||||
:key="tag"
|
||||
:bordered="false"
|
||||
size="tiny"
|
||||
>
|
||||
{{ tag }}
|
||||
</NTag>
|
||||
</NFlex>
|
||||
<!-- 用户自定义标签展示 -->
|
||||
<div
|
||||
v-if="goods.tags && goods.tags.length > 0"
|
||||
class="tags-container"
|
||||
>
|
||||
<div class="tags-wrapper">
|
||||
<NTag
|
||||
v-for="tag in goods.tags"
|
||||
:key="tag"
|
||||
:bordered="false"
|
||||
size="tiny"
|
||||
class="user-tag"
|
||||
style="color: #f0f0f0; background-color: rgba(100, 100, 110, 0.7);"
|
||||
>
|
||||
{{ tag }}
|
||||
</NTag>
|
||||
</div>
|
||||
</div>
|
||||
</NFlex>
|
||||
|
||||
<!-- 自定义页脚 -->
|
||||
@@ -137,10 +197,118 @@
|
||||
<style scoped>
|
||||
.goods-card {
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.goods-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.pinned-card {
|
||||
border: 2px solid var(--primary-color);
|
||||
box-shadow: 0 2px 10px rgba(var(--primary-color-rgb), 0.15);
|
||||
}
|
||||
|
||||
.cover-container {
|
||||
position: relative;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.pin-badge {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--error-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||
color: white;
|
||||
transform: rotate(45deg);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.price-badge {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
border-top-left-radius: 6px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tags-badge {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
padding: 4px 8px;
|
||||
border-top-right-radius: 6px;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.price-text {
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.title-row {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.title-container {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.goods-title {
|
||||
font-size: 1em;
|
||||
line-height: 1.3;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.description-text {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.tags-container {
|
||||
position: relative;
|
||||
max-height: 40px;
|
||||
overflow: hidden;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.tags-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.user-tag {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.user-tag:hover {
|
||||
transform: translateY(-2px);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.stock-info {
|
||||
font-size: 0.85em;
|
||||
color: var(--text-color-3);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user