feat: 更新依赖和移除不必要的文件, 更新歌单管理列表在小屏幕上的显示效果, 修复自定义配置文件加载

- 在 package.json 中移除不再使用的依赖项,并更新部分依赖版本
- 删除多个不再使用的组件和文件,包括 CheckInTemplateHelper.vue、CommonConfigItems.vue、GlobalSettingsConfig.vue 等
- 更新 bun.lockb 文件以反映依赖变更
This commit is contained in:
2025-05-03 20:17:54 +08:00
parent fe5b420d49
commit 70ff05926c
24 changed files with 302 additions and 4181 deletions

View File

@@ -1,155 +0,0 @@
<template>
<div class="checkin-template-helper">
<TemplateHelper :placeholders="checkInPlaceholders" />
<NAlert
type="info"
:show-icon="false"
style="margin-top: 8px;"
>
<template #header>
<div class="alert-header">
<NIcon
:component="Info24Filled"
style="margin-right: 4px;"
/>
签到模板可用变量列表
</div>
</template>
<NDivider style="margin: 6px 0;" />
<div class="placeholder-groups">
<div class="placeholder-group">
<div class="group-title">
用户信息
</div> <div class="placeholder-item">
<code>&#123;&#123;user.name&#125;&#125;</code> - 用户名称
</div>
<div class="placeholder-item">
<code>&#123;&#123;user.uid&#125;&#125;</code> - 用户ID
</div>
</div>
<div class="placeholder-group">
<div class="group-title">
签到信息
</div> <div class="placeholder-item">
<code>&#123;&#123;checkin.points&#125;&#125;</code> - 基础签到积分
</div>
<div class="placeholder-item">
<code>&#123;&#123;checkin.bonusPoints&#125;&#125;</code> - 早鸟额外积分 (普通签到为0)
</div>
<div class="placeholder-item">
<code>&#123;&#123;checkin.totalPoints&#125;&#125;</code> - 总获得积分
</div>
<div class="placeholder-item">
<code>&#123;&#123;checkin.isEarlyBird&#125;&#125;</code> - 是否是早鸟签到 (true/false)
</div>
<div class="placeholder-item">
<code>&#123;&#123;checkin.cooldownSeconds&#125;&#125;</code> - 签到冷却时间()
</div>
<div class="placeholder-item">
<code>&#123;&#123;checkin.time&#125;&#125;</code> - 签到时间对象
</div>
</div>
</div>
<NDivider style="margin: 6px 0;" />
<div class="placeholder-example">
<div class="example-title">
示例模板:
</div> <div class="example-item">
普通签到: <code>&#123;&#123;user.name&#125;&#125; 签到成功获得 &#123;&#123;checkin.totalPoints&#125;&#125; 积分</code>
</div>
<div class="example-item">
早鸟签到: <code>恭喜 &#123;&#123;user.name&#125;&#125; 完成早鸟签到额外获得 &#123;&#123;checkin.bonusPoints&#125;&#125; 积分共获得 &#123;&#123;checkin.totalPoints&#125;&#125; 积分</code>
</div>
<div class="example-item">
条件表达式: <code>&#123;&#123;js: checkin.isEarlyBird ? `恭喜 ${user.name} 获得早鸟奖励!` : `${user.name} 签到成功!`&#125;&#125; 获得 &#123;&#123;checkin.totalPoints&#125;&#125; 积分</code>
</div>
</div>
</NAlert>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { NAlert, NDivider, NIcon } from 'naive-ui';
import { Info24Filled } from '@vicons/fluent';
import TemplateHelper from './TemplateHelper.vue';
// 签到模板的特定占位符
const checkInPlaceholders = [
{ name: '{{user.name}}', description: '用户名称' },
{ name: '{{user.uid}}', description: '用户ID' },
{ name: '{{checkin.points}}', description: '基础签到积分' },
{ name: '{{checkin.bonusPoints}}', description: '早鸟额外积分 (普通签到为0)' },
{ name: '{{checkin.totalPoints}}', description: '总获得积分' },
{ name: '{{checkin.isEarlyBird}}', description: '是否是早鸟签到 (true/false)' },
{ name: '{{checkin.cooldownSeconds}}', description: '签到冷却时间(秒)' },
{ name: '{{checkin.time}}', description: '签到时间对象' }
];
</script>
<style scoped>
.checkin-template-helper {
margin-bottom: 12px;
}
.alert-header {
display: flex;
align-items: center;
font-weight: bold;
}
.placeholder-groups {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.placeholder-group {
flex: 1;
min-width: 200px;
}
.group-title {
font-weight: bold;
margin-bottom: 6px;
font-size: 14px;
}
.placeholder-item {
margin-bottom: 4px;
font-size: 13px;
}
.placeholder-item code {
padding: 1px 4px;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 3px;
font-size: 12px;
}
.placeholder-example {
margin-top: 8px;
}
.example-title {
font-weight: bold;
margin-bottom: 6px;
font-size: 14px;
}
.example-item {
margin-bottom: 4px;
font-size: 13px;
}
.example-item code {
display: block;
padding: 4px 8px;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 3px;
margin-top: 2px;
font-size: 12px;
white-space: nowrap;
overflow: auto;
}
</style>

View File

@@ -1,120 +0,0 @@
<script setup lang="ts">
import { NSpace, NSwitch, NInputNumber, NSelect, NCheckbox, NDivider } from 'naive-ui';
defineProps({
config: {
type: Object,
required: true
},
showLiveOnly: {
type: Boolean,
default: true
},
showDelay: {
type: Boolean,
default: false
},
showUserFilter: {
type: Boolean,
default: false
},
showTianXuan: {
type: Boolean,
default: false
}
});
</script>
<template>
<div class="common-config-section">
<NSpace
vertical
size="medium"
>
<NSpace
align="center"
justify="space-between"
style="width: 100%"
>
<span>启用功能:</span>
<NSwitch v-model:value="config.enabled" />
</NSpace>
<NSpace
v-if="showLiveOnly"
align="center"
justify="space-between"
style="width: 100%"
>
<span>仅直播中开启:</span>
<NSwitch v-model:value="config.onlyDuringLive" />
</NSpace>
<NSpace
v-if="showDelay"
align="center"
justify="space-between"
style="width: 100%"
>
<span>延迟时间 ():</span>
<NInputNumber
v-model:value="config.delaySeconds"
:min="0"
:max="300"
style="width: 120px"
/>
</NSpace>
<NSpace
v-if="showTianXuan"
align="center"
justify="space-between"
style="width: 100%"
>
<span>屏蔽天选时刻:</span>
<NSwitch v-model:value="config.ignoreTianXuan" />
</NSpace>
<template v-if="showUserFilter">
<NDivider title-placement="left">
用户过滤设置
</NDivider>
<NSpace
align="center"
justify="space-between"
style="width: 100%"
>
<span>启用用户过滤:</span>
<NSwitch v-model:value="config.userFilterEnabled" />
</NSpace>
<NSpace
v-if="config.userFilterEnabled"
align="center"
justify="space-between"
style="width: 100%"
>
<span>要求本房间勋章:</span>
<NSwitch v-model:value="config.requireMedal" />
</NSpace>
<NSpace
v-if="config.userFilterEnabled"
align="center"
justify="space-between"
style="width: 100%"
>
<span>要求任意舰长:</span>
<NSwitch v-model:value="config.requireCaptain" />
</NSpace>
</template>
</NSpace>
</div>
</template>
<style scoped>
.common-config-section {
padding: 16px 0;
}
</style>

View File

@@ -1,115 +0,0 @@
<template>
<div class="template-tester">
<NSpace vertical>
<NInput
v-model:value="template"
type="textarea"
placeholder="输入包含表达式的模板"
/>
<NSpace>
<NButton
type="primary"
size="small"
@click="testTemplate"
>
测试模板
</NButton>
<NButton
size="small"
@click="resetTemplate"
>
重置
</NButton>
</NSpace>
<template
v-if="hasResult"
>
<NDivider style="margin: 5px;" />
<NCard
title="结果预览"
size="small"
>
<NInput
type="textarea"
:value="result"
readonly
/>
</NCard>
</template>
</NSpace>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { NSpace, NInput, NInputGroup, NInputGroupLabel, NButton, useMessage, NDivider } from 'naive-ui';
import { evaluateTemplateExpressions } from '@/client/store/autoAction/expressionEvaluator';
import { EventModel } from '@/api/api-models';
import { TriggerType } from '@/client/store/autoAction/types';
import { buildExecutionContext } from '@/client/store/autoAction/utils';
const props = defineProps({
defaultTemplate: {
type: String,
default: ''
},
context: {
type: Object,
required: true
}
});
const template = ref(props.defaultTemplate || '');
const result = ref('');
const hasResult = computed(() => result.value !== '');
const message = useMessage();
function evaluateTemplateForUI(template: string, contextObj: Record<string, any>): string {
const tempContext = buildExecutionContext(contextObj, undefined, TriggerType.DANMAKU);
return evaluateTemplateExpressions(template, tempContext);
}
function testTemplate() {
try {
result.value = evaluateTemplateForUI(template.value, props.context);
} catch (error) {
message.error(`表达式求值错误: ${(error as Error).message}`);
result.value = `[错误] ${(error as Error).message}`;
}
}
function resetTemplate() {
template.value = props.defaultTemplate;
result.value = '';
}
</script>
<style scoped>
.template-tester {
margin-top: 16px;
margin-bottom: 16px;
}
.result-container {
margin-top: 8px;
padding: 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
background-color: #f5f5f5;
}
.result-title {
font-weight: bold;
margin-bottom: 4px;
}
.result-content {
padding: 8px;
background-color: white;
border-radius: 4px;
border: 1px dashed #d9d9d9;
word-break: break-all;
}
</style>

View File

@@ -1,193 +0,0 @@
<script setup lang="ts">
import { EventDataTypes, EventModel } from '@/api/api-models';
import { DanmakuWindowSettings, useDanmakuWindow } from '../../store/useDanmakuWindow';
import { computed } from 'vue';
import { AVATAR_URL } from '@/data/constants';
import { GetGuardColor } from '@/Utils';
export interface BaseDanmakuItemProps {
item: EventModel & { randomId: string; isNew?: boolean; disappearAt?: number; };
setting: DanmakuWindowSettings;
}
const props = defineProps<BaseDanmakuItemProps>();
const emojiData = useDanmakuWindow().emojiData;
// 检查弹幕是否将要消失
const isDisappearing = computed(() => {
return props.item.disappearAt && Date.now() > props.item.disappearAt - 300; // 提前300ms进入消失动画
});
// 计算SC弹幕的颜色类
const scColorClass = computed(() => {
if (props.item.type === EventDataTypes.SC) {
const price = props.item?.price || 0;
if (price === 0) return 'sc-0';
if (price > 0 && price < 50) return 'sc-50';
if (price >= 50 && price < 100) return 'sc-100';
if (price >= 100 && price < 500) return 'sc-500';
if (price >= 500 && price < 1000) return 'sc-1000';
if (price >= 1000 && price < 2000) return 'sc-2000';
if (price >= 2000) return 'sc-max';
}
return '';
});
// 根据类型计算样式
const typeClass = computed(() => {
switch (props.item.type) {
case EventDataTypes.Message: return 'message-item';
case EventDataTypes.Gift: return 'gift-item';
case EventDataTypes.SC: return `sc-item ${scColorClass.value}`;
case EventDataTypes.Guard: return 'guard-item';
case EventDataTypes.Enter: return 'enter-item';
default: return '';
}
});
// 获取舰长颜色
const guardColor = computed(() => GetGuardColor(props.item.guard_level));
// 舰长样式类
const guardLevelClass = computed(() => {
if (props.item.type === EventDataTypes.Guard) {
return `guard-level-${props.item.guard_level || 0}`;
}
return '';
});
// 检查是否需要显示头像
const showAvatar = computed(() => props.setting.showAvatar);
// 解析包含内联表情的消息
const parsedMessage = computed<{ type: 'text' | 'emoji'; content?: string; url?: string; name?: string; }[]>(() => {
// 仅处理非纯表情的普通消息
if (props.item.type !== EventDataTypes.Message || props.item.emoji || !props.item.msg) {
return [];
}
const segments: { type: 'text' | 'emoji'; content?: string; url?: string; name?: string; }[] = [];
let lastIndex = 0;
const regex = /\[([^\]]+)\]/g; // 匹配 [表情名]
let match;
try {
const availableEmojis = emojiData.data || {}; // 确保 emojiData 已加载
while ((match = regex.exec(props.item.msg)) !== null) {
// 添加表情前的文本部分
if (match.index > lastIndex) {
segments.push({ type: 'text', content: props.item.msg.substring(lastIndex, match.index) });
}
const emojiFullName = match[0]; // 完整匹配,例如 "[哈哈]"
const emojiInfo = availableEmojis.inline[emojiFullName] || availableEmojis.plain[emojiFullName];
if (emojiInfo) {
// 找到了表情
segments.push({ type: 'emoji', url: emojiInfo, name: emojiFullName });
} else {
// 未找到表情,当作普通文本处理
segments.push({ type: 'text', content: emojiFullName });
}
lastIndex = regex.lastIndex;
}
// 添加最后一个表情后的文本部分
if (lastIndex < props.item.msg.length) {
segments.push({ type: 'text', content: props.item.msg.substring(lastIndex) });
}
} catch (error) {
console.error("Error parsing message for emojis:", error);
// 解析出错时,返回原始文本
return [{ type: 'text', content: props.item.msg }];
}
// 如果解析后为空(例如,消息只包含无法识别的[]),则返回原始文本
if (segments.length === 0 && props.item.msg) {
return [{ type: 'text', content: props.item.msg }];
}
return segments;
});
// 获取不同类型消息的显示标签
const typeLabel = computed(() => {
switch (props.item.type) {
case EventDataTypes.Message: return ''; // 普通消息不需要标签
case EventDataTypes.Gift: return '【礼物】';
case EventDataTypes.SC: return '【SC】';
case EventDataTypes.Guard: return '【舰长】';
case EventDataTypes.Enter: return '【进场】';
default: return '';
}
});
// 获取礼物或SC的价格文本
const priceText = computed(() => {
if (props.item.type === EventDataTypes.SC ||
(props.item.type === EventDataTypes.Gift && props.item.price > 0)) {
return `${props.item.price || 0}`;
}
return '';
});
// 获取用户名显示
const displayName = computed(() => {
return props.item.uname || '匿名用户';
});
// 获取消息显示内容
const displayContent = computed(() => {
switch (props.item.type) {
case EventDataTypes.Message:
return props.item.msg || '';
case EventDataTypes.Gift:
return `${props.item.num || 1} × ${props.item.msg}`;
case EventDataTypes.SC:
return props.item.msg || '';
case EventDataTypes.Guard:
return props.item.msg || '开通了舰长';
case EventDataTypes.Enter:
return '进入了直播间';
default:
return '';
}
});
// 根据风格及类型获取文本颜色
const textModeColor = computed(() => {
if (props.item.type === EventDataTypes.SC) {
return '#FFD700'; // SC消息金色
} else if (props.item.type === EventDataTypes.Gift) {
return '#FF69B4'; // 礼物消息粉色
} else if (props.item.type === EventDataTypes.Guard) {
return guardColor.value; // 舰长消息使用舰长颜色
} else if (props.item.type === EventDataTypes.Enter) {
return '#67C23A'; // 入场消息绿色
}
return undefined; // 普通消息使用默认颜色
});
// 向外导出所有计算属性
defineExpose({
isDisappearing,
scColorClass,
typeClass,
guardColor,
guardLevelClass,
showAvatar,
parsedMessage,
typeLabel,
priceText,
displayName,
displayContent,
textModeColor
});
</script>
<template>
<slot />
</template>