mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
add songrequest options
This commit is contained in:
12
src/Utils.ts
12
src/Utils.ts
@@ -21,3 +21,15 @@ export function copyToClipboard(text: string) {
|
|||||||
message.warning('当前环境不支持自动复制, 请手动选择并复制')
|
message.warning('当前环境不支持自动复制, 请手动选择并复制')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export function objectsToCSV(arr: any[]) {
|
||||||
|
const array = [Object.keys(arr[0])].concat(arr)
|
||||||
|
return array
|
||||||
|
.map((row) => {
|
||||||
|
return Object.values(row)
|
||||||
|
.map((value) => {
|
||||||
|
return typeof value === 'string' ? JSON.stringify(value) : value
|
||||||
|
})
|
||||||
|
.toString()
|
||||||
|
})
|
||||||
|
.join('\n')
|
||||||
|
}
|
||||||
|
|||||||
@@ -117,7 +117,15 @@ export interface SongsInfo {
|
|||||||
tags?: string[]
|
tags?: string[]
|
||||||
createTime: number
|
createTime: number
|
||||||
updateTime: number
|
updateTime: number
|
||||||
paidSong: boolean
|
//paidSong: boolean
|
||||||
|
options?: SongRequestOption
|
||||||
|
}
|
||||||
|
export interface SongRequestOption{
|
||||||
|
needJianzhang: boolean;
|
||||||
|
needTidu: boolean;
|
||||||
|
needZongdu: boolean;
|
||||||
|
scMinPrice?: number;
|
||||||
|
fanMedalMinLevel?: number;
|
||||||
}
|
}
|
||||||
export enum SongLanguage {
|
export enum SongLanguage {
|
||||||
Chinese, // 中文
|
Chinese, // 中文
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SongAuthorInfo, SongFrom, SongLanguage, SongsInfo, UserInfo } from '@/api/api-models'
|
import { SongAuthorInfo, SongFrom, SongLanguage, SongsInfo, SongRequestOption } from '@/api/api-models'
|
||||||
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
||||||
import { SONG_API_URL } from '@/data/constants'
|
import { SONG_API_URL } from '@/data/constants'
|
||||||
import { refDebounced, useDebounceFn, useLocalStorage } from '@vueuse/core'
|
import { refDebounced, useDebounceFn, useLocalStorage } from '@vueuse/core'
|
||||||
@@ -21,6 +21,9 @@ import {
|
|||||||
NFormItem,
|
NFormItem,
|
||||||
NIcon,
|
NIcon,
|
||||||
NInput,
|
NInput,
|
||||||
|
NInputGroup,
|
||||||
|
NInputGroupLabel,
|
||||||
|
NInputNumber,
|
||||||
NList,
|
NList,
|
||||||
NListItem,
|
NListItem,
|
||||||
NModal,
|
NModal,
|
||||||
@@ -170,7 +173,7 @@ function createColumns(): DataTableColumns<SongsInfo> {
|
|||||||
width: 300,
|
width: 300,
|
||||||
sorter: 'default',
|
sorter: 'default',
|
||||||
render(data) {
|
render(data) {
|
||||||
return h(NSpace, { size: 5 }, () => [h(NText, () => data.name), h(NText, { depth: '3' }, () => data.translateName)])
|
return h(NSpace, { size: 5 }, () => [h(NText, { style: { color: data.options?.scMinPrice ? '#c36767' : '' } }, () => data.name), h(NText, { depth: '3' }, () => data.translateName)])
|
||||||
},
|
},
|
||||||
title: '曲名',
|
title: '曲名',
|
||||||
},
|
},
|
||||||
@@ -198,6 +201,24 @@ function createColumns(): DataTableColumns<SongsInfo> {
|
|||||||
return h(NEllipsis, () => data.description)
|
return h(NEllipsis, () => data.description)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '要求',
|
||||||
|
key: 'options',
|
||||||
|
resizable: true,
|
||||||
|
render(data) {
|
||||||
|
return data.options
|
||||||
|
? h(NSpace, {}, () => [
|
||||||
|
data.options?.needJianzhang ? h(NTag, { color: { textColor: 'white', color: GetGuardColor(3), borderColor: 'white' }, size: 'small' }, () => '舰长') : null,
|
||||||
|
data.options?.needTidu ? h(NTag, { color: { textColor: 'white', color: GetGuardColor(2), borderColor: 'white' }, size: 'small' }, () => '提督') : null,
|
||||||
|
data.options?.needZongdu ? h(NTag, { color: { textColor: 'white', color: GetGuardColor(1), borderColor: 'white' }, size: 'small' }, () => '总督') : null,
|
||||||
|
data.options?.scMinPrice
|
||||||
|
? h(NTag, { color: { textColor: 'white', color: GetSCColor(data.options.scMinPrice), borderColor: 'white' }, size: 'small' }, () => 'SC | ' + data.options?.scMinPrice)
|
||||||
|
: null,
|
||||||
|
data.options?.fanMedalMinLevel ? h(NTag, { type: 'info', size: 'small' }, () => '粉丝牌 | ' + data.options?.fanMedalMinLevel) : null,
|
||||||
|
])
|
||||||
|
: null
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '标签',
|
title: '标签',
|
||||||
key: 'tags',
|
key: 'tags',
|
||||||
@@ -483,6 +504,33 @@ async function delSong(song: SongsInfo) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
function GetSCColor(price: number): string {
|
||||||
|
if (price === 0) return `#2a60b2`
|
||||||
|
if (price > 0 && price < 30) return `#2a60b2`
|
||||||
|
if (price >= 30 && price < 50) return `#2a60b2`
|
||||||
|
if (price >= 50 && price < 100) return `#427d9e`
|
||||||
|
if (price >= 100 && price < 500) return `#c99801`
|
||||||
|
if (price >= 500 && price < 1000) return `#e09443`
|
||||||
|
if (price >= 1000 && price < 2000) return `#e54d4d`
|
||||||
|
if (price >= 2000) return `#ab1a32`
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
function GetGuardColor(level: number | null | undefined): string {
|
||||||
|
if (level) {
|
||||||
|
switch (level) {
|
||||||
|
case 1: {
|
||||||
|
return 'rgb(122, 4, 35)'
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
return 'rgb(157, 155, 255)'
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
return 'rgb(104, 136, 241)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
songsInternal.value = props.songs
|
songsInternal.value = props.songs
|
||||||
@@ -531,16 +579,65 @@ onMounted(() => {
|
|||||||
<NFormItem path="tags" label="标签">
|
<NFormItem path="tags" label="标签">
|
||||||
<NSelect v-model:value="updateSongModel.tags" filterable multiple clearable tag placeholder="可选,按回车确认" :options="tagsSelectOption" />
|
<NSelect v-model:value="updateSongModel.tags" filterable multiple clearable tag placeholder="可选,按回车确认" :options="tagsSelectOption" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="paidSong" label="付费歌曲">
|
<NFormItem path="options">
|
||||||
<NCheckbox v-model:checked="updateSongModel.paidSong">
|
<template #label>
|
||||||
是否付费歌曲
|
点歌设置
|
||||||
<NTooltip>
|
<NTooltip>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NIcon :component="Info24Filled" />
|
<NIcon :component="Info24Filled" />
|
||||||
</template>
|
</template>
|
||||||
用于区分是否可以从网页进行点歌
|
这个不是控制是否允许点歌的! 启用后将会覆盖点歌功能中的设置, 用于单独设置歌曲要求
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
</NCheckbox>
|
</template>
|
||||||
|
<NSpace vertical>
|
||||||
|
<NCheckbox
|
||||||
|
:checked="updateSongModel.options != undefined"
|
||||||
|
@update:checked="(checked: boolean) => {updateSongModel.options = checked ? {
|
||||||
|
needJianzhang: false,
|
||||||
|
needTidu: false,
|
||||||
|
needZongdu: false
|
||||||
|
} as SongRequestOption : undefined}"
|
||||||
|
>
|
||||||
|
是否启用
|
||||||
|
</NCheckbox>
|
||||||
|
<template v-if="updateSongModel.options != undefined">
|
||||||
|
<NSpace>
|
||||||
|
<NCheckbox v-model:checked="updateSongModel.options.needJianzhang"> 需要舰长 </NCheckbox>
|
||||||
|
<NCheckbox v-model:checked="updateSongModel.options.needTidu"> 需要提督 </NCheckbox>
|
||||||
|
<NCheckbox v-model:checked="updateSongModel.options.needZongdu"> 需要总督 </NCheckbox>
|
||||||
|
</NSpace>
|
||||||
|
<NSpace align="center">
|
||||||
|
<NCheckbox
|
||||||
|
:checked="updateSongModel.options.scMinPrice != undefined"
|
||||||
|
@update:checked="(checked: boolean) => {if(updateSongModel.options) updateSongModel.options.scMinPrice = checked ? 30 : undefined}"
|
||||||
|
>
|
||||||
|
需要SC
|
||||||
|
</NCheckbox>
|
||||||
|
<NInputGroup v-if="updateSongModel.options?.scMinPrice" style="width: 200px">
|
||||||
|
<NInputGroupLabel> SC最低价格 </NInputGroupLabel>
|
||||||
|
<NInputNumber v-model:value="updateSongModel.options.scMinPrice" min="30" />
|
||||||
|
</NInputGroup>
|
||||||
|
</NSpace>
|
||||||
|
<NSpace align="center">
|
||||||
|
<NCheckbox
|
||||||
|
:checked="updateSongModel.options.fanMedalMinLevel != undefined"
|
||||||
|
@update:checked="(checked: boolean) => {if(updateSongModel.options) updateSongModel.options.fanMedalMinLevel = checked ? 5 : undefined}"
|
||||||
|
>
|
||||||
|
需要粉丝牌
|
||||||
|
<NTooltip>
|
||||||
|
<template #trigger>
|
||||||
|
<NIcon :component="Info24Filled" />
|
||||||
|
</template>
|
||||||
|
这个即使不开也会遵循全局点歌设置的粉丝牌等级
|
||||||
|
</NTooltip>
|
||||||
|
</NCheckbox>
|
||||||
|
<NInputGroup v-if="updateSongModel.options?.fanMedalMinLevel" style="width: 200px">
|
||||||
|
<NInputGroupLabel> 最低等级 </NInputGroupLabel>
|
||||||
|
<NInputNumber v-model:value="updateSongModel.options.fanMedalMinLevel" min="0" />
|
||||||
|
</NInputGroup>
|
||||||
|
</NSpace>
|
||||||
|
</template>
|
||||||
|
</NSpace>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="url" label="链接">
|
<NFormItem path="url" label="链接">
|
||||||
<NInput v-model:value="updateSongModel.url" placeholder="可选, 后缀为mp3、wav、ogg时将会尝试播放, 否则会在新页面打开" :disabled="updateSongModel.from != SongFrom.Custom" />
|
<NInput v-model:value="updateSongModel.url" placeholder="可选, 后缀为mp3、wav、ogg时将会尝试播放, 否则会在新页面打开" :disabled="updateSongModel.from != SongFrom.Custom" />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { objectsToCSV } from '@/Utils'
|
||||||
import { useAccount } from '@/api/account'
|
import { useAccount } from '@/api/account'
|
||||||
import { SongFrom, SongLanguage, SongsInfo } from '@/api/api-models'
|
import { SongFrom, SongLanguage, SongRequestOption, SongsInfo } from '@/api/api-models'
|
||||||
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
||||||
import SongList from '@/components/SongList.vue'
|
import SongList from '@/components/SongList.vue'
|
||||||
import { FETCH_API, SONG_API_URL } from '@/data/constants'
|
import { FETCH_API, SONG_API_URL } from '@/data/constants'
|
||||||
@@ -15,6 +16,9 @@ import {
|
|||||||
NFormItem,
|
NFormItem,
|
||||||
NIcon,
|
NIcon,
|
||||||
NInput,
|
NInput,
|
||||||
|
NInputGroup,
|
||||||
|
NInputGroupLabel,
|
||||||
|
NInputNumber,
|
||||||
NModal,
|
NModal,
|
||||||
NPagination,
|
NPagination,
|
||||||
NSelect,
|
NSelect,
|
||||||
@@ -30,6 +34,8 @@ import {
|
|||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { Option } from 'naive-ui/es/transfer/src/interface'
|
import { Option } from 'naive-ui/es/transfer/src/interface'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import { saveAs } from 'file-saver'
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const accountInfo = useAccount()
|
const accountInfo = useAccount()
|
||||||
@@ -324,6 +330,34 @@ async function getSongs() {
|
|||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
function exportData() {
|
||||||
|
const text = objectsToCSV(
|
||||||
|
songs.value.map((s) => ({
|
||||||
|
id: s.id,
|
||||||
|
名称: s.name,
|
||||||
|
翻译名称: s.translateName,
|
||||||
|
作者: s.author?.join('/') ?? '未知',
|
||||||
|
创建于: format(s.createTime, 'yyyy-MM-dd HH:mm:ss'),
|
||||||
|
更新于: format(s.updateTime, 'yyyy-MM-dd HH:mm:ss'),
|
||||||
|
描述: s.description,
|
||||||
|
来自: from(s.from),
|
||||||
|
语言: s.language.map((l) => songSelectOption.find((o) => o.value == l)?.label).join(','),
|
||||||
|
标签: s.tags?.join(',') ?? '',
|
||||||
|
链接: s.url,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
const from = (f: SongFrom) => {
|
||||||
|
switch (f) {
|
||||||
|
case SongFrom.Custom:
|
||||||
|
return '手动添加'
|
||||||
|
case SongFrom.Netease:
|
||||||
|
return '网易云'
|
||||||
|
case SongFrom.FiveSing:
|
||||||
|
return '5sing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveAs(new Blob([text], { type: 'text/plain;charset=utf-8' }), `歌单_${format(Date.now(), 'yyyy-MM-dd HH:mm:ss')}_${accountInfo.value?.name}_.csv`)
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getSongs()
|
await getSongs()
|
||||||
@@ -333,6 +367,7 @@ onMounted(async () => {
|
|||||||
<template>
|
<template>
|
||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton @click="showModal = true" type="primary"> 添加歌曲 </NButton>
|
<NButton @click="showModal = true" type="primary"> 添加歌曲 </NButton>
|
||||||
|
<NButton @click="exportData" type="primary" secondary> 导出为 CSV </NButton>
|
||||||
<NButton
|
<NButton
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
@click="
|
@click="
|
||||||
@@ -367,16 +402,65 @@ onMounted(async () => {
|
|||||||
<NFormItem path="url" label="链接">
|
<NFormItem path="url" label="链接">
|
||||||
<NInput v-model:value="addSongModel.url" placeholder="可选, 后缀为mp3、wav、ogg时将会尝试播放, 否则会在新页面打开" />
|
<NInput v-model:value="addSongModel.url" placeholder="可选, 后缀为mp3、wav、ogg时将会尝试播放, 否则会在新页面打开" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="paidSong" label="付费歌曲">
|
<NFormItem path="options">
|
||||||
<NCheckbox v-model:checked="addSongModel.paidSong">
|
<template #label>
|
||||||
是否付费歌曲
|
点歌设置
|
||||||
<NTooltip>
|
<NTooltip>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NIcon :component="Info24Filled" />
|
<NIcon :component="Info24Filled" />
|
||||||
</template>
|
</template>
|
||||||
用于区分是否可以从网页进行点歌
|
这个不是控制是否允许点歌的! 启用后将会覆盖点歌功能中的设置, 用于单独设置歌曲要求
|
||||||
</NTooltip>
|
</NTooltip>
|
||||||
</NCheckbox>
|
</template>
|
||||||
|
<NSpace vertical>
|
||||||
|
<NCheckbox
|
||||||
|
:checked="addSongModel.options != undefined"
|
||||||
|
@update:checked="(checked: boolean) => {addSongModel.options = checked ? {
|
||||||
|
needJianzhang: false,
|
||||||
|
needTidu: false,
|
||||||
|
needZongdu: false
|
||||||
|
} as SongRequestOption : undefined}"
|
||||||
|
>
|
||||||
|
是否启用
|
||||||
|
</NCheckbox>
|
||||||
|
<template v-if="addSongModel.options != undefined">
|
||||||
|
<NSpace>
|
||||||
|
<NCheckbox v-model:checked="addSongModel.options.needJianzhang"> 需要舰长 </NCheckbox>
|
||||||
|
<NCheckbox v-model:checked="addSongModel.options.needTidu"> 需要提督 </NCheckbox>
|
||||||
|
<NCheckbox v-model:checked="addSongModel.options.needZongdu"> 需要总督 </NCheckbox>
|
||||||
|
</NSpace>
|
||||||
|
<NSpace align="center">
|
||||||
|
<NCheckbox
|
||||||
|
:checked="addSongModel.options.scMinPrice != undefined"
|
||||||
|
@update:checked="(checked: boolean) => {if(addSongModel.options) addSongModel.options.scMinPrice = checked ? 30 : undefined}"
|
||||||
|
>
|
||||||
|
需要SC
|
||||||
|
</NCheckbox>
|
||||||
|
<NInputGroup v-if="addSongModel.options?.scMinPrice" style="width: 200px">
|
||||||
|
<NInputGroupLabel> SC最低价格 </NInputGroupLabel>
|
||||||
|
<NInputNumber v-model:value="addSongModel.options.scMinPrice" min="30" />
|
||||||
|
</NInputGroup>
|
||||||
|
</NSpace>
|
||||||
|
<NSpace align="center">
|
||||||
|
<NCheckbox
|
||||||
|
:checked="addSongModel.options.fanMedalMinLevel != undefined"
|
||||||
|
@update:checked="(checked: boolean) => {if(addSongModel.options) addSongModel.options.fanMedalMinLevel = checked ? 5 : undefined}"
|
||||||
|
>
|
||||||
|
需要粉丝牌
|
||||||
|
<NTooltip>
|
||||||
|
<template #trigger>
|
||||||
|
<NIcon :component="Info24Filled" />
|
||||||
|
</template>
|
||||||
|
这个即使不开也会遵循全局点歌设置的粉丝牌等级
|
||||||
|
</NTooltip>
|
||||||
|
</NCheckbox>
|
||||||
|
<NInputGroup v-if="addSongModel.options?.fanMedalMinLevel" style="width: 200px">
|
||||||
|
<NInputGroupLabel> 最低等级 </NInputGroupLabel>
|
||||||
|
<NInputNumber v-model:value="addSongModel.options.fanMedalMinLevel" min="0" />
|
||||||
|
</NInputGroup>
|
||||||
|
</NSpace>
|
||||||
|
</template>
|
||||||
|
</NSpace>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</NForm>
|
</NForm>
|
||||||
<NButton type="primary" @click="addCustomSong"> 添加 </NButton>
|
<NButton type="primary" @click="addCustomSong"> 添加 </NButton>
|
||||||
|
|||||||
Reference in New Issue
Block a user