更新项目配置,删除不必要的文件,优化依赖项,修复类型定义,添加新歌单样式

This commit is contained in:
2025-03-31 16:32:57 +08:00
parent 891a922ab1
commit 73c738b42d
28 changed files with 2687 additions and 1072 deletions

View File

@@ -1,139 +1,167 @@
<script setup lang="ts">
import { getImageUploadModel } from '@/Utils';
import { QueryPostAPI } from '@/api/query';
import { TemplateConfig, TemplateConfigImageItem } from '@/data/VTsuruTypes'
import { FILE_BASE_URL, VTSURU_API_URL } from '@/data/constants';
import { NButton, NEmpty, NForm, NFormItem, NInput, NUpload, UploadFileInfo, useMessage } from 'naive-ui'
import { onMounted, ref } from 'vue'
import { getImageUploadModel } from '@/Utils';
import { QueryPostAPI } from '@/api/query';
import { ConfigItemDefinition, TemplateConfigImageItem } from '@/data/VTsuruTypes';
import { FILE_BASE_URL, VTSURU_API_URL } from '@/data/constants';
import { NButton, NColorPicker, NEmpty, NForm, NFormItem, NGrid, NInput, NInputNumber, NSlider, NUpload, UploadFileInfo, useMessage } from 'naive-ui';
import { onMounted, ref } from 'vue';
const message = useMessage()
const message = useMessage();
const props = defineProps<{
configData: any
config: TemplateConfig<any> | undefined
}>()
const props = defineProps<{
name?: string;
configData: any;
config: ConfigItemDefinition[] | undefined;
}>();
const fileList = ref<{ [key: string]: UploadFileInfo[] }>({})
const fileList = ref<{ [key: string]: UploadFileInfo[]; }>({});
const isUploading = ref(false)
const isUploading = ref(false);
function OnFileListChange(key: string, files: UploadFileInfo[]) {
if (files.length == 1) {
var file = files[0]
if ((file.file?.size ?? 0) > 10 * 1024 * 1024) {
message.error('文件大小不能超过10MB')
fileList.value[key] = []
function OnFileListChange(key: string, files: UploadFileInfo[]) {
if (files.length == 1) {
var file = files[0];
if ((file.file?.size ?? 0) > 10 * 1024 * 1024) {
message.error('文件大小不能超过10MB');
fileList.value[key] = [];
}
}
}
}
async function onSubmit() {
try {
isUploading.value = true
let images = {} as {
[key: string]: {
existImages: string[],
newImagesBase64: string[],
}
}
for (const item of props.config!.items) {
if (item.type == 'image') {
const key = (item as TemplateConfigImageItem<any>).key
images[key] = await getImageUploadModel(fileList.value[key])
}
}
const resp = await QueryPostAPI<any>(VTSURU_API_URL + 'set-config', {
name: props.config!.name,
json: JSON.stringify(props.configData),
images: images,
})
if (resp.code == 200) {
message.success('已保存至服务器')
props.config?.items.forEach(item => {
switch (item.type) {
case 'image':
item.onUploaded?.(resp.data[item.key], props.configData)
break
async function onSubmit() {
try {
isUploading.value = true;
let images = {} as {
[key: string]: {
existImages: string[],
newImagesBase64: string[],
};
};
for (const item of props.config!) {
if (item.type == 'image') {
const key = (item as TemplateConfigImageItem<any>).key;
images[key] = await getImageUploadModel(fileList.value[key]);
}
})
} else {
message.error('保存失败: ' + resp.message)
}
const resp = await QueryPostAPI<any>(VTSURU_API_URL + 'set-config', {
name: props.name,
json: JSON.stringify(props.configData),
images: images,
public: 'true',
});
if (resp.code == 200) {
message.success('已保存至服务器');
props.config?.forEach(item => {
if (item.type === 'render') {
item.onUploaded?.(props.configData[item.key], props.configData);
}
else {
item.onUploaded?.call(item, props.configData[item.key], props.configData);
}
});
} else {
message.error('保存失败: ' + resp.message);
}
} catch (err) {
message.error('保存失败: ' + err);
}
finally {
isUploading.value = false;
}
} catch (err) {
message.error('保存失败: ' + err)
}
finally {
isUploading.value = false
}
}
function getItems() { }
onMounted(() => {
props.config?.items.forEach(item => {
if (item.type == 'image') {
const configItem = props.configData[item.key]
if (configItem) {
fileList.value[item.key] = configItem.map((i: string) => ({
id: i,
thumbnailUrl: FILE_BASE_URL + i,
name: '',
status: 'finished',
}))
function getItems() { }
onMounted(() => {
props.config?.forEach(item => {
if (item.default && !props.configData[item.key]) {
props.configData[item.key] = item.default;
}
else {
fileList.value[item.key] = []
if (item.type == 'image') {
const configItem = props.configData[item.key];
if (configItem) {
fileList.value[item.key] = configItem.map((i: string) => ({
id: i,
thumbnailUrl: FILE_BASE_URL + i,
name: '',
status: 'finished',
}));
}
else {
fileList.value[item.key] = [];
}
}
}
})
})
});
});
</script>
<template>
<NEmpty
v-if="!config"
v-if="!config || config.length == 0"
description="此模板不支持配置"
/>
<NForm v-else>
<NFormItem
v-for="item in config.items"
:key="item.name.toString()"
:label="item.name.toString()"
<NGrid
x-gap="10"
y-gap="10"
cols="1 600:2 1200:3 1600:4"
>
<component
:is="item.render(configData)"
v-if="item.type == 'render'"
/>
<template v-else-if="item.type == 'string'">
<NInput
v-if="item.data"
<NFormItemGi
v-for="item in config"
:key="item.name.toString()"
:label="item.name.toString()"
>
<component
:is="item.render(configData)"
v-if="item.type == 'render'"
/>
<template v-else-if="item.type == 'string'">
<NInput
:value="configData[item.key]"
:placeholder="item.placeholder"
@update:value="configData[item.key] = $event"
:type="item.inputType"
/>
</template>
<NColorPicker
v-else-if="item.type == 'color'"
:value="configData[item.key]"
:show-alpha="item.showAlpha ?? false"
@update:value="configData[item.key] = $event"
/>
<NInput
v-else
v-model:value="configData[item.key]"
<NInputNumber
v-else-if="item.type == 'number'"
:value="configData[item.key]"
:min="item.min"
@update:value="configData[item.key] = $event"
/>
</template>
<NUpload
v-else-if="item.type == 'image'"
v-model:file-list="fileList[item.key]"
accept=".png,.jpg,.jpeg,.gif,.svg,.webp,.ico"
list-type="image-card"
:default-upload="false"
:max="item.imageLimit"
im
@update:file-list="file => OnFileListChange(item.key, file)"
>
上传图片
</NUpload>
</NFormItem>
<NFormItem>
<NButton
type="primary"
:loading="isUploading"
@click="onSubmit"
>
提交
</NButton>
</NFormItem>
<NSlider
v-else-if="item.type == 'sliderNumber'"
:value="configData[item.key]"
:min="item.min"
:max="item.max"
:step="item.step"
@update:value="configData[item.key] = $event"
/>
<NUpload
v-else-if="item.type == 'image'"
v-model:file-list="fileList[item.key]"
accept=".png,.jpg,.jpeg,.gif,.svg,.webp,.ico"
list-type="image-card"
:default-upload="false"
:max="item.imageLimit"
im
@update:file-list="file => OnFileListChange(item.key, file)"
>
上传图片
</NUpload>
</NFormItemGi>
</NGrid>
<NButton
type="primary"
:loading="isUploading"
@click="onSubmit"
>
提交
</NButton>
</NForm>
</template>

View File

@@ -1,18 +1,15 @@
<script setup lang="ts">
import { SongFrom, SongLanguage, SongRequestOption, SongsInfo } from '@/api/api-models'
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
import { SONG_API_URL } from '@/data/constants'
import FiveSingIcon from '@/svgs/fivesing.svg'
import NeteaseIcon from '@/svgs/netease.svg'
import { SongFrom, SongRequestOption, SongsInfo } from '@/api/api-models';
import { QueryGetAPI, QueryPostAPI } from '@/api/query';
import { SONG_API_URL } from '@/data/constants';
import {
Delete24Filled,
Info24Filled,
NotepadEdit20Filled,
Play24Filled,
SquareArrowForward24Filled,
} from '@vicons/fluent'
import { refDebounced, useLocalStorage } from '@vueuse/core'
import { List } from 'linqts'
Play24Filled
} from '@vicons/fluent';
import { refDebounced, useLocalStorage } from '@vueuse/core';
import { List } from 'linqts';
import {
DataTableBaseColumn,
DataTableColumns,
@@ -42,9 +39,10 @@ import {
NText,
NTooltip,
useMessage,
} from 'naive-ui'
import { VNodeChild, computed, h, onMounted, ref, watch } from 'vue'
import SongPlayer from './SongPlayer.vue'
} from 'naive-ui';
import { VNodeChild, computed, h, onMounted, ref, watch } from 'vue';
import SongPlayer from './SongPlayer.vue';
import { GetPlayButton } from '@/Utils';
const props = defineProps<{
songs: SongsInfo[]
@@ -393,72 +391,6 @@ function createColumns(): DataTableColumns<SongsInfo> {
]
}
function GetPlayButton(song: SongsInfo) {
switch (song.from) {
case SongFrom.FiveSing: {
return h(NTooltip, null, {
trigger: () =>
h(
h(
NButton,
{
size: 'small',
color: '#00BBB3',
ghost: true,
onClick: () => {
window.open(`http://5sing.kugou.com/bz/${song.id}.html`)
},
},
{
icon: () => h(FiveSingIcon, { class: 'svg-icon fivesing' }),
},
),
),
default: () => '在5sing打开',
})
}
case SongFrom.Netease:
return h(NTooltip, null, {
trigger: () =>
h(
NButton,
{
size: 'small',
color: '#C20C0C',
ghost: true,
onClick: () => {
window.open(`https://music.163.com/#/song?id=${song.id}`)
},
},
{
icon: () => h(NeteaseIcon, { class: 'svg-icon netease' }),
},
),
default: () => '在网易云打开',
})
case SongFrom.Custom:
return song.url
? h(NTooltip, null, {
trigger: () =>
h(
NButton,
{
size: 'small',
color: '#6b95bd',
ghost: true,
onClick: () => {
window.open(song.url)
},
},
{
icon: () => h(NIcon, { component: SquareArrowForward24Filled }),
},
),
default: () => '打开链接',
})
: null
}
}
function renderCell(value: string | number) {
if (!value) {
return h(NText, { depth: 3 }, { default: () => '未填写' })

View File

@@ -2,7 +2,7 @@
import { useAccount } from '@/api/account';
import { useLoadingBarStore } from '@/store/useLoadingBarStore'
import { useStorage } from '@vueuse/core';
import { NSpin, useLoadingBar, useMessage } from 'naive-ui'
import { NSpin, useLoadingBar, useMessage, useModal } from 'naive-ui'
import { onMounted } from 'vue'
import { useRoute } from 'vue-router';
@@ -14,6 +14,7 @@ onMounted(() => {
window.$loadingBar = useLoadingBar()
window.$message = useMessage()
window.$route = useRoute()
window.$modal = useModal()
const providerStore = useLoadingBarStore()
providerStore.setLoadingBar(window.$loadingBar)
})