mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
feat: 更新API模型和组件以支持售罄自动下架功能
- 在api-models.ts中为设置添加shouldDiscontinueWhenSoldOut字段 - 在PointSettings.vue中新增售罄自动下架的选项 - 在多个组件中调整按钮文本和状态逻辑 - 在PointUserHistoryView.vue中添加主播筛选功能
This commit is contained in:
@@ -228,6 +228,7 @@ export interface Setting_Point {
|
|||||||
scPointPercent: number // double maps to number in TypeScript
|
scPointPercent: number // double maps to number in TypeScript
|
||||||
giftPointPercent: number // double maps to number in TypeScript
|
giftPointPercent: number // double maps to number in TypeScript
|
||||||
giftAllowType: SettingPointGiftAllowType
|
giftAllowType: SettingPointGiftAllowType
|
||||||
|
shouldDiscontinueWhenSoldOut: boolean
|
||||||
|
|
||||||
// 签到系统设置
|
// 签到系统设置
|
||||||
enableCheckIn: boolean // 是否启用签到功能
|
enableCheckIn: boolean // 是否启用签到功能
|
||||||
|
|||||||
@@ -94,13 +94,43 @@ const historyColumn: DataTableColumns<ResponsePointHisrotyModel> = [
|
|||||||
: null,
|
: null,
|
||||||
])
|
])
|
||||||
case PointFrom.Manual:
|
case PointFrom.Manual:
|
||||||
return h(
|
return h(NFlex, { align: 'center' }, () => [
|
||||||
|
h(
|
||||||
NTag,
|
NTag,
|
||||||
{ type: row.point > 0 ? 'success' : 'error', bordered: false, size: 'small' },
|
{ type: row.point > 0 ? 'success' : 'error', bordered: false, size: 'small' },
|
||||||
() => '主播' + (row.point > 0 ? '赠予' : '扣除'),
|
() => '主播' + (row.point > 0 ? '赠予' : '扣除'),
|
||||||
|
),
|
||||||
|
row.extra?.user
|
||||||
|
? h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
tag: 'a',
|
||||||
|
href: '/@' + row.extra.user?.name,
|
||||||
|
target: '_blank',
|
||||||
|
text: true,
|
||||||
|
type: 'info',
|
||||||
|
},
|
||||||
|
() => row.extra.user?.name,
|
||||||
)
|
)
|
||||||
|
: null,
|
||||||
|
])
|
||||||
case PointFrom.Use:
|
case PointFrom.Use:
|
||||||
return h(NTag, { type: 'warning', bordered: false, size: 'small' }, () => '使用')
|
return h(NFlex, { align: 'center' }, () => [
|
||||||
|
h(NTag, { type: 'warning', bordered: false, size: 'small' }, () => '使用'),
|
||||||
|
row.extra?.user
|
||||||
|
? h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
tag: 'a',
|
||||||
|
href: '/@' + row.extra.user?.name,
|
||||||
|
target: '_blank',
|
||||||
|
text: true,
|
||||||
|
type: 'success',
|
||||||
|
},
|
||||||
|
() => row.extra.user?.name,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
])
|
||||||
case PointFrom.CheckIn:
|
case PointFrom.CheckIn:
|
||||||
return h(NFlex, { align: 'center' }, () => [
|
return h(NFlex, { align: 'center' }, () => [
|
||||||
h(NTag, { type: 'success', bordered: false, size: 'small' }, () => '签到'),
|
h(NTag, { type: 'success', bordered: false, size: 'small' }, () => '签到'),
|
||||||
@@ -131,12 +161,12 @@ const historyColumn: DataTableColumns<ResponsePointHisrotyModel> = [
|
|||||||
case PointFrom.Danmaku:
|
case PointFrom.Danmaku:
|
||||||
switch (row.type) {
|
switch (row.type) {
|
||||||
case EventDataTypes.Guard:
|
case EventDataTypes.Guard:
|
||||||
return h(NFlex, { justify: 'center', align: 'center' }, () => [
|
return h(NFlex, { align: 'center' }, () => [
|
||||||
h(NTag, { type: 'error', size: 'small' }, () => '上舰'),
|
h(NTag, { type: 'error', size: 'small' }, () => '上舰'),
|
||||||
row.extra?.danmaku.msg,
|
row.extra?.danmaku.msg,
|
||||||
])
|
])
|
||||||
case EventDataTypes.Gift:
|
case EventDataTypes.Gift:
|
||||||
return h(NFlex, { justify: 'center', align: 'center' }, () => [
|
return h(NFlex, { align: 'center' }, () => [
|
||||||
h(NTag, { type: 'info', size: 'small', style: { margin: '0' } }, () => '礼物'),
|
h(NTag, { type: 'info', size: 'small', style: { margin: '0' } }, () => '礼物'),
|
||||||
row.extra?.danmaku.msg,
|
row.extra?.danmaku.msg,
|
||||||
h(
|
h(
|
||||||
@@ -146,7 +176,7 @@ const historyColumn: DataTableColumns<ResponsePointHisrotyModel> = [
|
|||||||
),
|
),
|
||||||
])
|
])
|
||||||
case EventDataTypes.SC:
|
case EventDataTypes.SC:
|
||||||
return h(NFlex, { justify: 'center' }, () => [
|
return h(NFlex, { align: 'center' }, () => [
|
||||||
h(NTag, { type: 'warning', size: 'small', style: { margin: '0' } }, () => 'SC'),
|
h(NTag, { type: 'warning', size: 'small', style: { margin: '0' } }, () => 'SC'),
|
||||||
row.extra?.danmaku.price,
|
row.extra?.danmaku.price,
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ const defaultSettingPoint: Setting_Point = {
|
|||||||
maxBonusPoints: 0,
|
maxBonusPoints: 0,
|
||||||
allowSelfCheckIn: false,
|
allowSelfCheckIn: false,
|
||||||
requireAuth: false,
|
requireAuth: false,
|
||||||
|
shouldDiscontinueWhenSoldOut: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应式设置对象
|
// 响应式设置对象
|
||||||
@@ -262,6 +263,20 @@ async function SaveComboSetting() {
|
|||||||
</NCheckbox>
|
</NCheckbox>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
|
||||||
|
<NFlex
|
||||||
|
align="center"
|
||||||
|
:gap="12"
|
||||||
|
>
|
||||||
|
<span>其他: </span>
|
||||||
|
<NCheckbox
|
||||||
|
v-model:checked="setting.shouldDiscontinueWhenSoldOut"
|
||||||
|
:disabled="!canEdit"
|
||||||
|
@update:checked="updateSettings"
|
||||||
|
>
|
||||||
|
礼物售罄时自动下架
|
||||||
|
</NCheckbox>
|
||||||
|
</NFlex>
|
||||||
|
|
||||||
<!-- 积分来源设置 -->
|
<!-- 积分来源设置 -->
|
||||||
<NFlex
|
<NFlex
|
||||||
align="center"
|
align="center"
|
||||||
|
|||||||
@@ -328,9 +328,10 @@ onMounted(async () => {
|
|||||||
<NButton
|
<NButton
|
||||||
type="primary"
|
type="primary"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
|
:disabled="!addPointCount || addPointCount === 0"
|
||||||
@click="givePoint"
|
@click="givePoint"
|
||||||
>
|
>
|
||||||
{{ addPointCount > 0 ? '给予' : '扣除' }}
|
{{ !addPointCount || addPointCount === 0 ? '确定' : (addPointCount > 0 ? '给予' : '扣除') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NModal>
|
</NModal>
|
||||||
|
|||||||
@@ -577,9 +577,10 @@ onMounted(async () => {
|
|||||||
<NButton
|
<NButton
|
||||||
type="primary"
|
type="primary"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
|
:disabled="!addPointCount || addPointCount === 0"
|
||||||
@click="givePoint"
|
@click="givePoint"
|
||||||
>
|
>
|
||||||
{{ addPointCount > 0 ? '给予' : '扣除' }}
|
{{ !addPointCount || addPointCount === 0 ? '确定' : (addPointCount > 0 ? '给予' : '扣除') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NModal>
|
</NModal>
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ResponsePointHisrotyModel } from '@/api/api-models'
|
import { ResponsePointHisrotyModel, PointFrom } from '@/api/api-models'
|
||||||
import PointHistoryCard from '@/components/manage/PointHistoryCard.vue'
|
import PointHistoryCard from '@/components/manage/PointHistoryCard.vue'
|
||||||
import { POINT_API_URL } from '@/data/constants'
|
import { POINT_API_URL } from '@/data/constants'
|
||||||
import { useBiliAuth } from '@/store/useBiliAuth'
|
import { useBiliAuth } from '@/store/useBiliAuth'
|
||||||
import { NButton, NEmpty, NFlex, NSpin, useMessage } from 'naive-ui'
|
import { NButton, NEmpty, NFlex, NSelect, NSpin, useMessage } from 'naive-ui'
|
||||||
import { onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const useAuth = useBiliAuth()
|
const useAuth = useBiliAuth()
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
|
|
||||||
const history = ref<ResponsePointHisrotyModel[]>([])
|
const history = ref<ResponsePointHisrotyModel[]>([])
|
||||||
|
const streamerFilter = ref<string | null>('')
|
||||||
|
|
||||||
// 定义加载完成的事件
|
// 定义加载完成的事件
|
||||||
const emit = defineEmits(['dataLoaded'])
|
const emit = defineEmits(['dataLoaded'])
|
||||||
@@ -42,6 +43,7 @@ async function getHistories() {
|
|||||||
// 提供给父组件调用的重置方法
|
// 提供给父组件调用的重置方法
|
||||||
function reset() {
|
function reset() {
|
||||||
history.value = []
|
history.value = []
|
||||||
|
streamerFilter.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 暴露方法给父组件
|
// 暴露方法给父组件
|
||||||
@@ -53,20 +55,74 @@ defineExpose({
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
history.value = await getHistories()
|
history.value = await getHistories()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 根据主播名称筛选历史记录
|
||||||
|
const filteredHistory = computed(() => {
|
||||||
|
if (streamerFilter.value === '' || streamerFilter.value === null) {
|
||||||
|
return history.value
|
||||||
|
}
|
||||||
|
return history.value.filter(item => {
|
||||||
|
// 只筛选主播操作、弹幕来源和签到
|
||||||
|
if ([PointFrom.Manual, PointFrom.Danmaku, PointFrom.CheckIn].includes(item.from)) {
|
||||||
|
// 精确匹配主播名称
|
||||||
|
return item.extra?.user?.name === streamerFilter.value
|
||||||
|
}
|
||||||
|
// 如果是使用积分的记录,则始终显示
|
||||||
|
if (item.from === PointFrom.Use) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 其他类型的记录,在筛选时隐藏
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算可选的主播列表
|
||||||
|
const streamerOptions = computed(() => {
|
||||||
|
const names = new Set<string>()
|
||||||
|
history.value.forEach(item => {
|
||||||
|
if ([PointFrom.Manual, PointFrom.Danmaku, PointFrom.CheckIn].includes(item.from) && item.extra?.user?.name) {
|
||||||
|
names.add(item.extra.user.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 添加"全部主播"选项
|
||||||
|
const options = [{ label: '全部主播', value: '' }]
|
||||||
|
names.forEach(name => {
|
||||||
|
options.push({ label: name, value: name })
|
||||||
|
})
|
||||||
|
return options
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpin :show="isLoading">
|
<NSpin :show="isLoading">
|
||||||
<NFlex justify="end" style="margin-bottom: 10px">
|
<NFlex
|
||||||
<NButton size="small" type="primary" @click="getHistories">刷新记录</NButton>
|
justify="end"
|
||||||
|
align="center"
|
||||||
|
style="margin-bottom: 10px"
|
||||||
|
>
|
||||||
|
<NSelect
|
||||||
|
v-model:value="streamerFilter"
|
||||||
|
:options="streamerOptions"
|
||||||
|
placeholder="按主播筛选"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
style="max-width: 200px; margin-right: 10px"
|
||||||
|
/>
|
||||||
|
<NButton
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="getHistories"
|
||||||
|
>
|
||||||
|
刷新记录
|
||||||
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
<NEmpty
|
<NEmpty
|
||||||
v-if="history.length == 0"
|
v-if="filteredHistory.length == 0"
|
||||||
description="暂无积分记录"
|
description="暂无符合条件的积分记录"
|
||||||
/>
|
/>
|
||||||
<PointHistoryCard
|
<PointHistoryCard
|
||||||
v-else
|
v-else
|
||||||
:histories="history"
|
:histories="filteredHistory"
|
||||||
/>
|
/>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user