Skip to content

Commit 14fb675

Browse files
committed
feat(dashboard): 添加弹幕/字幕小部件入口和说明
1 parent 9447e3b commit 14fb675

3 files changed

Lines changed: 161 additions & 4 deletions

File tree

dashboard/src/components/layout/Sidebar.vue

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@
4040
</el-menu-item>
4141
</el-sub-menu>
4242

43+
<!-- 小部件分组 -->
44+
<el-sub-menu index="widget-group">
45+
<template #title>
46+
<el-icon><Grid /></el-icon>
47+
<span>小部件</span>
48+
</template>
49+
<el-menu-item index="/danmaku">
50+
<el-icon><ChatLineSquare /></el-icon>
51+
<span>弹幕小部件</span>
52+
</el-menu-item>
53+
<el-menu-item index="/subtitle">
54+
<el-icon><ChatDotRound /></el-icon>
55+
<span>字幕小部件</span>
56+
</el-menu-item>
57+
</el-sub-menu>
58+
4359
<el-menu-item index="/devtools">
4460
<el-icon><Tools /></el-icon>
4561
<span>开发工具</span>
@@ -67,11 +83,14 @@ import {
6783
Document,
6884
Tools,
6985
Setting,
70-
Tickets,
7186
Cpu,
7287
TrendCharts,
7388
Clock,
7489
ChatLineRound,
90+
Tickets,
91+
Grid,
92+
ChatLineSquare,
93+
ChatDotRound,
7594
} from '@element-plus/icons-vue';
7695
7796
const route = useRoute();

dashboard/src/views/Dashboard.vue

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,86 @@
258258
<p class="quick-link-desc">配置管理,保存后可重启服务</p>
259259
</div>
260260
</router-link>
261+
<router-link to="/danmaku" target="_blank" class="quick-link-card">
262+
<div class="quick-link-icon">
263+
<el-icon :size="24"><ChatLineSquare /></el-icon>
264+
</div>
265+
<div class="quick-link-content">
266+
<h4 class="quick-link-title">弹幕小部件</h4>
267+
<p class="quick-link-desc">独立的弹幕显示窗口</p>
268+
</div>
269+
</router-link>
270+
<router-link to="/subtitle" target="_blank" class="quick-link-card">
271+
<div class="quick-link-icon">
272+
<el-icon :size="24"><ChatDotRound /></el-icon>
273+
</div>
274+
<div class="quick-link-content">
275+
<h4 class="quick-link-title">字幕小部件</h4>
276+
<p class="quick-link-desc">独立的字幕显示窗口</p>
277+
</div>
278+
</router-link>
261279
</div>
262280
</section>
281+
282+
<!-- 小部件信息 -->
283+
<section class="widget-info-section">
284+
<div class="section-header">
285+
<h2 class="section-title">小部件访问地址</h2>
286+
<el-button
287+
type="primary"
288+
size="small"
289+
text
290+
@click="showWidgetInfo = !showWidgetInfo"
291+
>
292+
{{ showWidgetInfo ? '收起' : '展开' }}
293+
<el-icon :class="{ 'is-rotate': showWidgetInfo }">
294+
<ArrowDown />
295+
</el-icon>
296+
</el-button>
297+
</div>
298+
<el-collapse-transition>
299+
<div v-show="showWidgetInfo" class="widget-urls">
300+
<div class="widget-url-card">
301+
<div class="widget-url-info">
302+
<span class="widget-url-label">弹幕小部件</span>
303+
<code class="widget-url-value">{{ baseUrl }}/danmaku</code>
304+
</div>
305+
<el-button
306+
class="copy-btn"
307+
type="primary"
308+
size="small"
309+
text
310+
@click="copyUrl(`${baseUrl}/danmaku`)"
311+
>
312+
<el-icon><CopyDocument /></el-icon>
313+
复制
314+
</el-button>
315+
</div>
316+
<div class="widget-url-card">
317+
<div class="widget-url-info">
318+
<span class="widget-url-label">字幕小部件</span>
319+
<code class="widget-url-value">{{ baseUrl }}/subtitle</code>
320+
</div>
321+
<el-button
322+
class="copy-btn"
323+
type="primary"
324+
size="small"
325+
text
326+
@click="copyUrl(`${baseUrl}/subtitle`)"
327+
>
328+
<el-icon><CopyDocument /></el-icon>
329+
复制
330+
</el-button>
331+
</div>
332+
</div>
333+
</el-collapse-transition>
334+
</section>
263335
</div>
264336
</template>
265337

266338
<script setup lang="ts">
267-
import { ref, onMounted, onUnmounted } from 'vue';
268-
import { Document, Connection, Tools, Setting } from '@element-plus/icons-vue';
339+
import { ref, computed, onMounted, onUnmounted } from 'vue';
340+
import { Document, Connection, Tools, Setting, ChatLineSquare, ChatDotRound, CopyDocument, ArrowDown } from '@element-plus/icons-vue';
269341
import { ElMessage } from 'element-plus';
270342
import { useSystemStore, useProvidersStore } from '@/stores';
271343
import { storeToRefs } from 'pinia';
@@ -282,6 +354,21 @@ const domainLoading = ref<Record<string, 'start' | 'stop' | null>>({
282354
output: null,
283355
});
284356
357+
// Widget info visibility
358+
const showWidgetInfo = ref(false);
359+
360+
// Base URL for widget links
361+
const baseUrl = computed(() => window.location.origin);
362+
363+
// Copy widget URL to clipboard
364+
function copyUrl(url: string) {
365+
navigator.clipboard.writeText(url).then(() => {
366+
ElMessage.success('URL 已复制到剪贴板');
367+
}).catch(() => {
368+
ElMessage.error('复制失败');
369+
});
370+
}
371+
285372
// Get providers for a specific domain
286373
function getDomainProviders(domain: string) {
287374
if (!providers.value) return [];
@@ -759,6 +846,56 @@ onUnmounted(() => {
759846
line-height: 1.4;
760847
}
761848
849+
/* 小部件信息区域 */
850+
.widget-info-section {
851+
margin-bottom: var(--spacing-lg);
852+
}
853+
854+
.widget-urls {
855+
display: flex;
856+
flex-direction: column;
857+
gap: var(--spacing-md);
858+
}
859+
860+
.widget-url-card {
861+
display: flex;
862+
align-items: center;
863+
justify-content: space-between;
864+
padding: var(--spacing-md);
865+
background: var(--bg-card);
866+
border-radius: var(--radius-md);
867+
border: 1px solid var(--border-color-light);
868+
}
869+
870+
.widget-url-info {
871+
display: flex;
872+
align-items: center;
873+
gap: var(--spacing-md);
874+
}
875+
876+
.widget-url-label {
877+
font-size: 14px;
878+
font-weight: 500;
879+
color: var(--text-primary);
880+
}
881+
882+
.widget-url-value {
883+
font-size: 13px;
884+
font-family: var(--font-mono);
885+
color: var(--text-secondary);
886+
background: var(--bg-hover);
887+
padding: 4px 8px;
888+
border-radius: var(--radius-sm);
889+
}
890+
891+
.copy-btn {
892+
flex-shrink: 0;
893+
}
894+
895+
.is-rotate {
896+
transform: rotate(180deg);
897+
}
898+
762899
/* Utility Classes */
763900
.mono {
764901
font-family: var(--font-mono);

dashboard/src/views/Subtitle.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ const textStyle = computed(() => ({
4141
fontSize: `${fontSize.value}px`,
4242
fontWeight: 'bold',
4343
color: fontColor.value,
44-
textShadow: '-2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 2px 0 #000, 0 0 10px rgba(0,0,0,0.8)',
44+
textShadow:
45+
'-2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 2px 0 #000, 0 0 10px rgba(0,0,0,0.8)',
4546
letterSpacing: '2px',
4647
lineHeight: '1.4',
4748
}));

0 commit comments

Comments
 (0)