mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-10 20:36:55 +08:00
feat: 更新商品管理功能,添加虚拟礼物多Key支持和排序功能
- 在商品模型中添加密钥选择模式和虚拟密钥列表 - 更新商品展示组件,支持置顶标记和价格徽章 - 优化商品管理视图,添加排序功能和清空筛选条件的功能 - 改进礼物添加表单,增加输入验证和错误提示
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { copyToClipboard, getImageUploadModel } from '@/Utils'
|
||||
import { DisableFunction, EnableFunction, useAccount } from '@/api/account'
|
||||
import { FunctionTypes, GoodsStatus, GoodsTypes, PointGoodsModel, ResponsePointGoodModel } from '@/api/api-models'
|
||||
import { FunctionTypes, GoodsStatus, GoodsTypes, UploadPointGoodsModel, ResponsePointGoodModel, KeySelectionMode } from '@/api/api-models'
|
||||
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
||||
import EventFetcherStatusCard from '@/components/EventFetcherStatusCard.vue'
|
||||
import PointGoodsItem from '@/components/manage/PointGoodsItem.vue'
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
UploadFileInfo,
|
||||
useDialog,
|
||||
useMessage,
|
||||
NDynamicTags,
|
||||
} from 'naive-ui'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import PointOrderManage from './PointOrderManage.vue'
|
||||
@@ -76,13 +77,21 @@ const defaultGoodsModel = {
|
||||
status: GoodsStatus.Normal,
|
||||
maxBuyCount: 1,
|
||||
isAllowRebuy: false,
|
||||
isPinned: false,
|
||||
setting: {
|
||||
allowGuardLevel: 0
|
||||
},
|
||||
} as PointGoodsModel,
|
||||
virtualKeys: [],
|
||||
keySelectionMode: KeySelectionMode.None,
|
||||
currentKeyIndex: 0,
|
||||
name: '',
|
||||
price: 0,
|
||||
tags: [],
|
||||
description: ''
|
||||
} as UploadPointGoodsModel,
|
||||
fileList: [],
|
||||
} as { goods: PointGoodsModel; fileList: UploadFileInfo[] }
|
||||
const currentGoodsModel = ref<{ goods: PointGoodsModel; fileList: UploadFileInfo[] }>(
|
||||
} as { goods: UploadPointGoodsModel; fileList: UploadFileInfo[] }
|
||||
const currentGoodsModel = ref<{ goods: UploadPointGoodsModel; fileList: UploadFileInfo[] }>(
|
||||
JSON.parse(JSON.stringify(defaultGoodsModel))
|
||||
)
|
||||
|
||||
@@ -478,37 +487,29 @@ onMounted(() => { })
|
||||
>
|
||||
<template #footer>
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="8"
|
||||
style="width: 100%"
|
||||
>
|
||||
<span>价格: {{ item.price }}</span>
|
||||
<NFlex
|
||||
justify="space-between"
|
||||
:gap="8"
|
||||
<NButton
|
||||
type="info"
|
||||
size="small"
|
||||
@click="onUpdateClick(item)"
|
||||
>
|
||||
<NButton
|
||||
type="info"
|
||||
size="small"
|
||||
@click="onUpdateClick(item)"
|
||||
>
|
||||
修改
|
||||
</NButton>
|
||||
<NButton
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="onSetShelfClick(item, GoodsStatus.Discontinued)"
|
||||
>
|
||||
下架
|
||||
</NButton>
|
||||
<NButton
|
||||
type="error"
|
||||
size="small"
|
||||
@click="onDeleteClick(item)"
|
||||
>
|
||||
删除
|
||||
</NButton>
|
||||
</NFlex>
|
||||
修改
|
||||
</NButton>
|
||||
<NButton
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="onSetShelfClick(item, GoodsStatus.Discontinued)"
|
||||
>
|
||||
下架
|
||||
</NButton>
|
||||
<NButton
|
||||
type="error"
|
||||
size="small"
|
||||
@click="onDeleteClick(item)"
|
||||
>
|
||||
删除
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</template>
|
||||
</PointGoodsItem>
|
||||
@@ -629,25 +630,24 @@ onMounted(() => { })
|
||||
确定要重置此页面内容?
|
||||
</NPopconfirm>
|
||||
</template>
|
||||
<NScrollbar style="max-height: 80vh">
|
||||
<NForm
|
||||
ref="formRef"
|
||||
:model="currentGoodsModel"
|
||||
:rules="rules"
|
||||
style="width: 100%"
|
||||
<div class="scrollable-container">
|
||||
<NScrollbar
|
||||
style="max-height: 70vh; padding-right: 12px;"
|
||||
class="goods-scrollbar"
|
||||
>
|
||||
<!-- 基本信息分组 -->
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 8px 0 16px"
|
||||
>
|
||||
基本信息
|
||||
</NDivider>
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="12"
|
||||
style="margin-bottom: 16px"
|
||||
<NForm
|
||||
ref="formRef"
|
||||
:model="currentGoodsModel"
|
||||
:rules="rules"
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- 基本信息分组 -->
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 8px 0 16px"
|
||||
>
|
||||
基本信息
|
||||
</NDivider>
|
||||
<NFormItem
|
||||
path="goods.name"
|
||||
label="名称"
|
||||
@@ -693,20 +693,23 @@ onMounted(() => { })
|
||||
/>
|
||||
</NFlex>
|
||||
</NFormItem>
|
||||
</NFlex>
|
||||
|
||||
<!-- 详细描述分组 -->
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 16px 0"
|
||||
>
|
||||
详细描述
|
||||
</NDivider>
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="12"
|
||||
style="margin-bottom: 16px"
|
||||
>
|
||||
<NFormItem
|
||||
path="goods.isPinned"
|
||||
label="置顶显示"
|
||||
>
|
||||
<NCheckbox v-model:checked="currentGoodsModel.goods.isPinned">
|
||||
在礼物列表中置顶显示
|
||||
</NCheckbox>
|
||||
</NFormItem>
|
||||
|
||||
<!-- 详细描述分组 -->
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin-top: 0;"
|
||||
>
|
||||
详细描述
|
||||
</NDivider>
|
||||
<NFormItem
|
||||
path="goods.description"
|
||||
label="描述"
|
||||
@@ -737,6 +740,7 @@ onMounted(() => { })
|
||||
<NFormItem
|
||||
path="goods.cover"
|
||||
label="封面"
|
||||
style="margin-bottom: 16px;"
|
||||
>
|
||||
<NFlex
|
||||
vertical
|
||||
@@ -766,20 +770,14 @@ onMounted(() => { })
|
||||
</NUpload>
|
||||
</NFlex>
|
||||
</NFormItem>
|
||||
</NFlex>
|
||||
|
||||
<!-- 兑换规则分组 -->
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 16px 0"
|
||||
>
|
||||
兑换规则
|
||||
</NDivider>
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="12"
|
||||
style="margin-bottom: 16px"
|
||||
>
|
||||
<!-- 兑换规则分组 -->
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 16px 0"
|
||||
>
|
||||
兑换规则
|
||||
</NDivider>
|
||||
<NFormItem
|
||||
path="goods.type"
|
||||
label="礼物类型"
|
||||
@@ -806,6 +804,7 @@ onMounted(() => { })
|
||||
<NFormItem
|
||||
path="goods.guardFree"
|
||||
label="特殊权限"
|
||||
style="margin-bottom: 16px;"
|
||||
>
|
||||
<NFlex
|
||||
vertical
|
||||
@@ -891,21 +890,15 @@ onMounted(() => { })
|
||||
</NRadioGroup>
|
||||
</NFlex>
|
||||
</NFormItem>
|
||||
</NFlex>
|
||||
|
||||
<!-- 礼物类型特定配置 -->
|
||||
<template v-if="currentGoodsModel.goods.type == GoodsTypes.Physical">
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 16px 0"
|
||||
>
|
||||
实物礼物配置
|
||||
</NDivider>
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="12"
|
||||
style="margin-bottom: 16px"
|
||||
>
|
||||
<!-- 礼物类型特定配置 -->
|
||||
<template v-if="currentGoodsModel.goods.type == GoodsTypes.Physical">
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 16px 0"
|
||||
>
|
||||
实物礼物配置
|
||||
</NDivider>
|
||||
<NFormItem
|
||||
path="goods.maxBuyCount"
|
||||
label="最大兑换数量"
|
||||
@@ -920,6 +913,7 @@ onMounted(() => { })
|
||||
<NFormItem
|
||||
path="address"
|
||||
label="收货地址"
|
||||
style="margin-bottom: 16px;"
|
||||
>
|
||||
<NFlex
|
||||
vertical
|
||||
@@ -977,23 +971,67 @@ onMounted(() => { })
|
||||
</NCheckbox>
|
||||
</NFormItem>
|
||||
</template>
|
||||
</NFlex>
|
||||
</template>
|
||||
<template v-else>
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 16px 0"
|
||||
>
|
||||
虚拟礼物配置
|
||||
</NDivider>
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="12"
|
||||
style="margin-bottom: 16px"
|
||||
>
|
||||
</template>
|
||||
<template v-else>
|
||||
<NDivider
|
||||
title-placement="left"
|
||||
style="margin: 16px 0"
|
||||
>
|
||||
虚拟礼物配置
|
||||
</NDivider>
|
||||
<NFormItem
|
||||
path="goods.keySelectionMode"
|
||||
label="密钥选择模式"
|
||||
>
|
||||
<NRadioGroup v-model:value="currentGoodsModel.goods.keySelectionMode">
|
||||
<NRadioButton :value="KeySelectionMode.None">
|
||||
不使用
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="KeySelectionMode.Random">
|
||||
随机选择
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="KeySelectionMode.Sequential">
|
||||
顺序选择
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<!-- 添加多Key支持配置 -->
|
||||
<NFormItem
|
||||
v-if="currentGoodsModel.goods.keySelectionMode != KeySelectionMode.None"
|
||||
path="goods.virtualKeys"
|
||||
label="礼物密钥列表 (可选)"
|
||||
>
|
||||
<template #label>
|
||||
礼物密钥列表
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
添加多个密钥,用户购买时会根据选择模式分配一个密钥. 可以留空
|
||||
</NTooltip>
|
||||
</template>
|
||||
<NFlex
|
||||
vertical
|
||||
:gap="8"
|
||||
>
|
||||
<NDynamicTags
|
||||
v-model:value="currentGoodsModel.goods.virtualKeys"
|
||||
placeholder="输入密钥后按Enter添加"
|
||||
/>
|
||||
<NText
|
||||
depth="3"
|
||||
style="margin-top: 4px; display: block"
|
||||
>
|
||||
已添加 {{ (currentGoodsModel.goods.virtualKeys || []).length }} 个密钥
|
||||
</NText>
|
||||
</NFlex>
|
||||
</NFormItem>
|
||||
|
||||
|
||||
<NFormItem
|
||||
path="goods.content"
|
||||
required
|
||||
style="margin-bottom: 16px;"
|
||||
>
|
||||
<template #label>
|
||||
礼物内容
|
||||
@@ -1001,36 +1039,40 @@ onMounted(() => { })
|
||||
<template #trigger>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
虚拟礼物的具体内容, 网盘链接什么之类的
|
||||
虚拟礼物的具体内容,可使用 {key} 作为占位符
|
||||
</NTooltip>
|
||||
</template>
|
||||
<NInput
|
||||
v-model:value="currentGoodsModel.goods.content"
|
||||
type="textarea"
|
||||
placeholder="写这里咯"
|
||||
placeholder="写这里咯,可使用 {key} 作为占位符,购买时会自动替换为上面密钥列表中的一个"
|
||||
maxlength="10000"
|
||||
show-count
|
||||
clearable
|
||||
/>
|
||||
</NFormItem>
|
||||
</NFlex>
|
||||
</template>
|
||||
|
||||
<NFlex
|
||||
justify="center"
|
||||
style="margin-top: 24px"
|
||||
</template>
|
||||
</NForm>
|
||||
<!-- 添加一个底部间距,让滚动更自然 -->
|
||||
<div style="height: 16px;" />
|
||||
</NScrollbar>
|
||||
<div class="scroll-shadow-top" />
|
||||
<div class="scroll-shadow-bottom" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<NFlex
|
||||
justify="center"
|
||||
>
|
||||
<NButton
|
||||
type="primary"
|
||||
size="large"
|
||||
:loading="isUpdating"
|
||||
@click="updateGoods"
|
||||
>
|
||||
<NButton
|
||||
type="primary"
|
||||
size="large"
|
||||
:loading="isUpdating"
|
||||
@click="updateGoods"
|
||||
>
|
||||
{{ currentGoodsModel.goods.id ? '修改' : '创建' }}
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</NForm>
|
||||
</NScrollbar>
|
||||
{{ currentGoodsModel.goods.id ? '修改' : '创建' }}
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</template>
|
||||
</NModal>
|
||||
</template>
|
||||
|
||||
@@ -1059,6 +1101,60 @@ onMounted(() => { })
|
||||
}
|
||||
|
||||
.goods-modal :deep(.n-card-content) {
|
||||
padding: 0 20px 20px;
|
||||
padding: 0 20px 8px;
|
||||
}
|
||||
|
||||
.goods-modal :deep(.n-card-footer) {
|
||||
padding: 12px 20px 16px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
background-color: var(--action-color);
|
||||
}
|
||||
|
||||
.scrollable-container {
|
||||
position: relative;
|
||||
background-color: var(--body-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.goods-scrollbar {
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--card-color);
|
||||
}
|
||||
|
||||
.goods-scrollbar :deep(.n-scrollbar-rail) {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.goods-scrollbar :deep(.n-scrollbar-content) {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.scroll-shadow-top {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 12px;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.06), transparent);
|
||||
z-index: 1;
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
}
|
||||
|
||||
.scroll-shadow-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 12px;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.06), transparent);
|
||||
z-index: 1;
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
NCheckboxGroup,
|
||||
NDivider,
|
||||
NFlex,
|
||||
NForm,
|
||||
NFormItem,
|
||||
NIcon,
|
||||
NInput,
|
||||
NInputGroup,
|
||||
@@ -61,7 +63,12 @@ const setting = computed({
|
||||
})
|
||||
|
||||
// 添加礼物表单模型
|
||||
const addGiftModel = ref<{ name: string; point: number }>({ name: '', point: 1 })
|
||||
const addGiftModel = ref<{ name: string; point: number; nameError: string; pointError: string }>({
|
||||
name: '',
|
||||
point: 1,
|
||||
nameError: '',
|
||||
pointError: ''
|
||||
})
|
||||
|
||||
// 是否可以编辑设置
|
||||
const canEdit = computed(() => {
|
||||
@@ -101,25 +108,60 @@ async function updateSettings() {
|
||||
|
||||
// 添加礼物积分规则
|
||||
async function addGift() {
|
||||
// 重置错误信息
|
||||
addGiftModel.value.nameError = ''
|
||||
addGiftModel.value.pointError = ''
|
||||
|
||||
// 表单验证
|
||||
if (!addGiftModel.value.name) {
|
||||
message.error('请输入礼物名称')
|
||||
return
|
||||
let hasError = false
|
||||
|
||||
if (!addGiftModel.value.name.trim()) {
|
||||
addGiftModel.value.nameError = '请输入礼物名称'
|
||||
hasError = true
|
||||
} else if (setting.value.giftPercentMap[addGiftModel.value.name] !== undefined) {
|
||||
addGiftModel.value.nameError = '此礼物名称已存在'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (addGiftModel.value.point > 2147483647) {
|
||||
message.error('积分不能超过2147483647')
|
||||
if (!addGiftModel.value.point) {
|
||||
addGiftModel.value.pointError = '请输入积分数量'
|
||||
hasError = true
|
||||
} else if (addGiftModel.value.point <= 0) {
|
||||
addGiftModel.value.pointError = '积分必须大于0'
|
||||
hasError = true
|
||||
} else if (addGiftModel.value.point > 2147483647) {
|
||||
addGiftModel.value.pointError = '积分不能超过2147483647'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
return
|
||||
}
|
||||
|
||||
// 添加礼物积分规则
|
||||
setting.value.giftPercentMap[addGiftModel.value.name] = addGiftModel.value.point
|
||||
const success = await updateGift()
|
||||
isLoading.value = true
|
||||
|
||||
// 添加成功后清空表单
|
||||
if (success) {
|
||||
addGiftModel.value = { name: '', point: 1 }
|
||||
showAddGiftModal.value = false
|
||||
try {
|
||||
const success = await updateGift()
|
||||
// 添加成功后清空表单
|
||||
if (success) {
|
||||
addGiftModel.value = { name: '', point: 1, nameError: '', pointError: '' }
|
||||
showAddGiftModal.value = false
|
||||
message.success('礼物添加成功')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('添加礼物失败:', error)
|
||||
message.error('添加礼物失败,请重试')
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理键盘按下事件
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter' && !isLoading.value) {
|
||||
addGift()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,14 +443,20 @@ async function SaveComboSetting() {
|
||||
vertical
|
||||
:gap="12"
|
||||
>
|
||||
<NButton
|
||||
type="primary"
|
||||
:disabled="!canEdit"
|
||||
class="add-gift-button"
|
||||
@click="showAddGiftModal = true"
|
||||
<NFlex
|
||||
justify="space-between"
|
||||
align="center"
|
||||
>
|
||||
添加礼物
|
||||
</NButton>
|
||||
<span class="section-title">自定义礼物列表</span>
|
||||
<NButton
|
||||
type="primary"
|
||||
:disabled="!canEdit"
|
||||
class="add-gift-button"
|
||||
@click="showAddGiftModal = true"
|
||||
>
|
||||
添加礼物
|
||||
</NButton>
|
||||
</NFlex>
|
||||
|
||||
<NList bordered>
|
||||
<NEmpty
|
||||
@@ -422,47 +470,61 @@ async function SaveComboSetting() {
|
||||
>
|
||||
<NFlex
|
||||
align="center"
|
||||
:gap="8"
|
||||
justify="space-between"
|
||||
style="width: 100%"
|
||||
>
|
||||
<NTag
|
||||
:bordered="false"
|
||||
size="small"
|
||||
type="success"
|
||||
<NFlex
|
||||
align="center"
|
||||
:gap="8"
|
||||
>
|
||||
{{ item[0] }}
|
||||
</NTag>
|
||||
<NInputGroup
|
||||
style="width: 200px"
|
||||
:disabled="!canEdit"
|
||||
>
|
||||
<NInputNumber
|
||||
:value="setting.giftPercentMap[item[0]]"
|
||||
:disabled="!canEdit"
|
||||
min="0"
|
||||
@update:value="(v) => (setting.giftPercentMap[item[0]] = v ?? 0)"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!canEdit"
|
||||
@click="updateSettings"
|
||||
<NTag
|
||||
:bordered="false"
|
||||
size="medium"
|
||||
type="success"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NPopconfirm @positive-click="deleteGift(item[0])">
|
||||
<template #trigger>
|
||||
<NButton
|
||||
type="error"
|
||||
text
|
||||
{{ item[0] }}
|
||||
</NTag>
|
||||
</NFlex>
|
||||
|
||||
<NFlex
|
||||
align="center"
|
||||
:gap="12"
|
||||
>
|
||||
<NInputGroup
|
||||
style="width: 180px"
|
||||
:disabled="!canEdit"
|
||||
>
|
||||
<NInputNumber
|
||||
:value="setting.giftPercentMap[item[0]]"
|
||||
:disabled="!canEdit"
|
||||
min="0"
|
||||
@update:value="(v) => (setting.giftPercentMap[item[0]] = v ? v : 0)"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
size="small"
|
||||
:disabled="!canEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Delete24Regular" />
|
||||
</template>
|
||||
更新
|
||||
</NButton>
|
||||
</template>
|
||||
确定要删除这个礼物吗?
|
||||
</NPopconfirm>
|
||||
</NInputGroup>
|
||||
<NPopconfirm @positive-click="deleteGift(item[0])">
|
||||
<template #trigger>
|
||||
<NButton
|
||||
type="error"
|
||||
size="small"
|
||||
:disabled="!canEdit"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Delete24Regular" />
|
||||
</template>
|
||||
删除
|
||||
</NButton>
|
||||
</template>
|
||||
确定要删除这个礼物吗?
|
||||
</NPopconfirm>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</NListItem>
|
||||
</NList>
|
||||
@@ -475,45 +537,73 @@ async function SaveComboSetting() {
|
||||
v-model:show="showAddGiftModal"
|
||||
preset="card"
|
||||
title="添加礼物"
|
||||
style="max-width: 400px"
|
||||
style="max-width: 480px"
|
||||
:mask-closable="false"
|
||||
>
|
||||
<NFlex
|
||||
align="center"
|
||||
vertical
|
||||
:gap="12"
|
||||
>
|
||||
<NForm>
|
||||
<NAlert
|
||||
title="注意"
|
||||
type="warning"
|
||||
closable
|
||||
style="margin-bottom: 16px"
|
||||
>
|
||||
这里填写的积分是指这个礼物直接对应多少积分, 而不是兑换比例
|
||||
<template #icon>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
这里填写的积分是指这个礼物直接对应多少积分,而不是兑换比例
|
||||
</NAlert>
|
||||
|
||||
<NInputGroup class="modal-input">
|
||||
<NInputGroupLabel> 礼物名称 </NInputGroupLabel>
|
||||
<NFormItem
|
||||
label="礼物名称"
|
||||
:validation-status="addGiftModel.nameError ? 'error' : undefined"
|
||||
:feedback="addGiftModel.nameError"
|
||||
required
|
||||
>
|
||||
<NInput
|
||||
v-model:value="addGiftModel.name"
|
||||
placeholder="礼物名称"
|
||||
placeholder="请输入礼物名称"
|
||||
clearable
|
||||
autofocus
|
||||
@keydown="handleKeyDown"
|
||||
/>
|
||||
</NInputGroup>
|
||||
</NFormItem>
|
||||
|
||||
<NInputGroup class="modal-input">
|
||||
<NInputGroupLabel> 给予积分 </NInputGroupLabel>
|
||||
<NFormItem
|
||||
label="给予积分"
|
||||
:validation-status="addGiftModel.pointError ? 'error' : undefined"
|
||||
:feedback="addGiftModel.pointError"
|
||||
required
|
||||
>
|
||||
<NInputNumber
|
||||
v-model:value="addGiftModel.point"
|
||||
placeholder="积分数量"
|
||||
min="0"
|
||||
placeholder="请输入积分数量"
|
||||
min="1"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@keydown="handleKeyDown"
|
||||
/>
|
||||
</NInputGroup>
|
||||
</NFormItem>
|
||||
|
||||
<NButton
|
||||
type="info"
|
||||
:loading="isLoading"
|
||||
@click="addGift"
|
||||
<NFlex
|
||||
justify="end"
|
||||
:gap="12"
|
||||
style="margin-top: 24px"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NFlex>
|
||||
<NButton
|
||||
@click="showAddGiftModal = false"
|
||||
>
|
||||
取消
|
||||
</NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
:loading="isLoading"
|
||||
:disabled="!addGiftModel.name || !addGiftModel.point || addGiftModel.point <= 0"
|
||||
@click="addGift"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</NForm>
|
||||
</NModal>
|
||||
</template>
|
||||
</NFlex>
|
||||
@@ -539,16 +629,31 @@ async function SaveComboSetting() {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.gift-card {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.add-gift-button {
|
||||
max-width: 200px;
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.modal-input {
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: var(--error-color, #d03050);
|
||||
font-size: 12px;
|
||||
margin-top: -6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 响应式布局优化 */
|
||||
|
||||
Reference in New Issue
Block a user