Skip to content

Commit def75c1

Browse files
author
Taois
committed
feat: 修复大量bug
1 parent 270c03b commit def75c1

File tree

7 files changed

+449
-36
lines changed

7 files changed

+449
-36
lines changed

dashboard/src/components/players/ArtVideoPlayer.vue

Lines changed: 249 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,29 @@
7272
</div>
7373
</div>
7474
</div>
75+
76+
<!-- 选集列表弹窗 -->
77+
<div v-if="showEpisodeDialog" class="episode-dialog">
78+
<div class="episode-dialog-overlay" @click="closeEpisodeDialog"></div>
79+
<div class="episode-dialog-content">
80+
<div class="episode-dialog-header">
81+
<h3>选择集数</h3>
82+
<button @click="closeEpisodeDialog" class="episode-close-btn">×</button>
83+
</div>
84+
<div ref="episodeListRef" class="episode-list">
85+
<button
86+
v-for="(episode, index) in props.episodes"
87+
:key="index"
88+
:ref="el => { if (index === props.currentEpisodeIndex) currentEpisodeRef = el }"
89+
@click="selectEpisode(episode)"
90+
:class="['episode-item', { 'current': index === props.currentEpisodeIndex }]"
91+
>
92+
<span class="episode-number">{{ index + 1 }}</span>
93+
<span class="episode-name">{{ episode.name || `第${index + 1}集` }}</span>
94+
</button>
95+
</div>
96+
</div>
97+
</div>
7598
</div>
7699
</a-card>
77100
</template>
@@ -121,7 +144,7 @@ const props = defineProps({
121144
})
122145
123146
// Emits
124-
const emit = defineEmits(['close', 'error', 'player-change', 'next-episode'])
147+
const emit = defineEmits(['close', 'error', 'player-change', 'next-episode', 'episode-selected'])
125148
126149
// 响应式数据
127150
const artPlayerContainer = ref(null)
@@ -138,6 +161,11 @@ const autoNextTimer = ref(null) // 自动下一集定时器
138161
const showAutoNextDialog = ref(false) // 显示自动下一集对话框
139162
const countdownEnabled = ref(false) // 倒计时开关,默认关闭
140163
164+
// 选集弹窗相关数据
165+
const showEpisodeDialog = ref(false) // 显示选集弹窗
166+
const episodeListRef = ref(null) // 选集列表容器引用
167+
const currentEpisodeRef = ref(null) // 当前选集按钮引用
168+
141169
// 链接类型判断函数
142170
const isDirectVideoLink = (url) => {
143171
if (!url) return false
@@ -322,6 +350,15 @@ const initArtPlayer = async (url) => {
322350
playNextEpisode()
323351
},
324352
},
353+
{
354+
position: 'right',
355+
html: props.episodes.length > 1 ? '选集' : '',
356+
tooltip: props.episodes.length > 1 ? '选择集数' : '',
357+
style: props.episodes.length > 1 ? {} : { display: 'none' },
358+
click: function () {
359+
toggleEpisodeDialog()
360+
},
361+
},
325362
{
326363
position: 'right',
327364
html: '关闭',
@@ -603,6 +640,79 @@ const toggleCountdown = () => {
603640
}
604641
}
605642
643+
// 滚动到当前选集位置
644+
const scrollToCurrentEpisode = async () => {
645+
// 等待DOM更新
646+
await nextTick()
647+
648+
if (!episodeListRef.value || props.currentEpisodeIndex < 0) {
649+
return
650+
}
651+
652+
// 查找当前选集按钮
653+
const currentButton = episodeListRef.value.querySelector('.episode-item.current')
654+
if (!currentButton) {
655+
return
656+
}
657+
658+
const container = episodeListRef.value
659+
const containerHeight = container.clientHeight
660+
const containerScrollHeight = container.scrollHeight
661+
const buttonTop = currentButton.offsetTop
662+
const buttonHeight = currentButton.offsetHeight
663+
664+
// 计算滚动位置,让当前选集出现在容器的中间偏上位置(约30%处)
665+
const targetPosition = buttonTop + (buttonHeight / 2) - (containerHeight * 0.3)
666+
667+
// 确保滚动位置在有效范围内
668+
const maxScrollTop = containerScrollHeight - containerHeight
669+
const targetScrollTop = Math.max(0, Math.min(targetPosition, maxScrollTop))
670+
671+
// 只有当需要滚动的距离超过一定阈值时才执行滚动
672+
const currentScrollTop = container.scrollTop
673+
const scrollDistance = Math.abs(targetScrollTop - currentScrollTop)
674+
675+
if (scrollDistance > 50) { // 滚动距离超过50px才执行
676+
container.scrollTo({
677+
top: targetScrollTop,
678+
behavior: 'smooth'
679+
})
680+
console.log(`自动滚动到当前选集: 第${props.currentEpisodeIndex + 1}集,滚动距离: ${scrollDistance}px`)
681+
} else {
682+
console.log(`当前选集已在可视区域中心,无需滚动: 第${props.currentEpisodeIndex + 1}`)
683+
}
684+
}
685+
686+
// 切换选集弹窗显示状态
687+
const toggleEpisodeDialog = async () => {
688+
showEpisodeDialog.value = !showEpisodeDialog.value
689+
console.log('选集弹窗:', showEpisodeDialog.value ? '显示' : '隐藏')
690+
691+
// 如果弹窗打开,等待弹窗动画完成后再滚动
692+
if (showEpisodeDialog.value) {
693+
// 延迟350ms,等待弹窗动画完成(CSS动画时长为300ms)
694+
setTimeout(async () => {
695+
await scrollToCurrentEpisode()
696+
}, 350)
697+
}
698+
}
699+
700+
// 关闭选集弹窗
701+
const closeEpisodeDialog = () => {
702+
showEpisodeDialog.value = false
703+
}
704+
705+
// 选择剧集
706+
const selectEpisode = (episode) => {
707+
console.log('选择剧集:', episode)
708+
709+
// 关闭弹窗
710+
closeEpisodeDialog()
711+
712+
// 发送选集事件给父组件
713+
emit('episode-selected', episode)
714+
}
715+
606716
// 监听视频URL变化
607717
watch(() => props.videoUrl, async (newUrl) => {
608718
if (newUrl && props.visible) {
@@ -929,4 +1039,142 @@ onUnmounted(() => {
9291039
.btn-cancel:hover {
9301040
background: #555;
9311041
}
1042+
1043+
/* 选集弹窗样式 */
1044+
.episode-dialog {
1045+
position: fixed;
1046+
top: 0;
1047+
left: 0;
1048+
width: 100%;
1049+
height: 100%;
1050+
z-index: 10000;
1051+
display: flex;
1052+
align-items: center;
1053+
justify-content: center;
1054+
}
1055+
1056+
.episode-dialog-overlay {
1057+
position: absolute;
1058+
top: 0;
1059+
left: 0;
1060+
width: 100%;
1061+
height: 100%;
1062+
background: rgba(0, 0, 0, 0.7);
1063+
backdrop-filter: blur(4px);
1064+
}
1065+
1066+
.episode-dialog-content {
1067+
position: relative;
1068+
background: white;
1069+
border-radius: 12px;
1070+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
1071+
max-width: 600px;
1072+
max-height: 80vh;
1073+
width: 90%;
1074+
overflow: hidden;
1075+
animation: episodeDialogShow 0.3s ease-out;
1076+
}
1077+
1078+
@keyframes episodeDialogShow {
1079+
from {
1080+
opacity: 0;
1081+
transform: scale(0.9) translateY(-20px);
1082+
}
1083+
to {
1084+
opacity: 1;
1085+
transform: scale(1) translateY(0);
1086+
}
1087+
}
1088+
1089+
.episode-dialog-header {
1090+
display: flex;
1091+
justify-content: space-between;
1092+
align-items: center;
1093+
padding: 20px 24px;
1094+
border-bottom: 1px solid #e8e8e8;
1095+
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
1096+
}
1097+
1098+
.episode-dialog-header h3 {
1099+
margin: 0;
1100+
font-size: 18px;
1101+
font-weight: 600;
1102+
color: #2c3e50;
1103+
}
1104+
1105+
.episode-close-btn {
1106+
background: none;
1107+
border: none;
1108+
font-size: 24px;
1109+
cursor: pointer;
1110+
color: #666;
1111+
width: 32px;
1112+
height: 32px;
1113+
display: flex;
1114+
align-items: center;
1115+
justify-content: center;
1116+
border-radius: 50%;
1117+
transition: all 0.2s ease;
1118+
}
1119+
1120+
.episode-close-btn:hover {
1121+
background: rgba(0, 0, 0, 0.1);
1122+
color: #333;
1123+
}
1124+
1125+
.episode-list {
1126+
padding: 16px;
1127+
max-height: 60vh;
1128+
overflow-y: auto;
1129+
display: grid;
1130+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
1131+
gap: 12px;
1132+
}
1133+
1134+
.episode-item {
1135+
display: flex;
1136+
align-items: center;
1137+
padding: 12px 16px;
1138+
border: 2px solid #e8e8e8;
1139+
border-radius: 8px;
1140+
background: white;
1141+
cursor: pointer;
1142+
transition: all 0.2s ease;
1143+
text-align: left;
1144+
min-height: 60px;
1145+
}
1146+
1147+
.episode-item:hover {
1148+
border-color: #23ade5;
1149+
background: #f8fcff;
1150+
transform: translateY(-2px);
1151+
box-shadow: 0 4px 12px rgba(35, 173, 229, 0.2);
1152+
}
1153+
1154+
.episode-item.current {
1155+
border-color: #23ade5;
1156+
background: linear-gradient(135deg, #23ade5 0%, #1e90ff 100%);
1157+
color: white;
1158+
box-shadow: 0 4px 12px rgba(35, 173, 229, 0.3);
1159+
}
1160+
1161+
.episode-item.current:hover {
1162+
background: linear-gradient(135deg, #1e90ff 0%, #23ade5 100%);
1163+
}
1164+
1165+
.episode-number {
1166+
font-size: 16px;
1167+
font-weight: bold;
1168+
margin-right: 12px;
1169+
min-width: 24px;
1170+
text-align: center;
1171+
}
1172+
1173+
.episode-name {
1174+
font-size: 14px;
1175+
flex: 1;
1176+
overflow: hidden;
1177+
text-overflow: ellipsis;
1178+
white-space: nowrap;
1179+
}
9321180
</style>

dashboard/src/stores/favoriteStore.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ export const useFavoriteStore = defineStore('favorite', () => {
4343
api_info: {
4444
module: videoData.module || '',
4545
api_url: videoData.api_url || '',
46-
site_name: videoData.site_name || ''
46+
site_name: videoData.site_name || '',
47+
ext: videoData.ext || null // 添加站源扩展配置
4748
},
4849
created_at: new Date().toISOString(),
4950
updated_at: new Date().toISOString()

dashboard/src/stores/historyStore.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ export const useHistoryStore = defineStore('history', () => {
6363
const addToHistory = (videoInfo, routeInfo, episodeInfo) => {
6464
const now = new Date().toISOString()
6565

66+
// 调试:检查传入的videoInfo
67+
console.log('=== historyStore.addToHistory 调试 ===')
68+
console.log('传入的videoInfo.api_info:', videoInfo.api_info)
69+
console.log('传入的videoInfo.api_info.ext:', videoInfo.api_info.ext)
70+
6671
// 检查是否已存在相同的视频
6772
const existingIndex = histories.value.findIndex(
6873
item => item.id === videoInfo.id && item.api_info.api_url === videoInfo.api_info.api_url
@@ -84,23 +89,36 @@ export const useHistoryStore = defineStore('history', () => {
8489
...histories.value[existingIndex],
8590
...historyItem
8691
}
92+
console.log('更新后的历史记录api_info:', histories.value[existingIndex].api_info)
8793
} else {
8894
// 添加新记录
8995
historyItem.created_at = now
9096
histories.value.push(historyItem)
97+
console.log('新添加的历史记录api_info:', historyItem.api_info)
9198
}
92-
99+
100+
console.log('=== historyStore.addToHistory 调试结束 ===')
93101
saveHistories()
94102
}
95103

96104
const removeFromHistory = (item) => {
105+
if (!item || !item.id || !item.api_info || !item.api_info.api_url) {
106+
console.error('删除历史记录失败:参数无效', item)
107+
return false
108+
}
109+
97110
const index = histories.value.findIndex(
98111
h => h.id === item.id && h.api_info.api_url === item.api_info.api_url
99112
)
100113

101114
if (index !== -1) {
102115
histories.value.splice(index, 1)
103116
saveHistories()
117+
console.log('删除历史记录成功:', item.name)
118+
return true
119+
} else {
120+
console.warn('未找到要删除的历史记录:', item)
121+
return false
104122
}
105123
}
106124

dashboard/src/views/BookGallery.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,11 @@ const goToDetail = async (item) => {
399399
const siteInfo = {
400400
name: item.api_info.site_name,
401401
api: item.api_info.api_url,
402-
key: item.api_info.module
402+
key: item.api_info.module,
403+
ext: item.api_info.ext || null // 从收藏数据中获取extend参数
403404
}
404405
405-
console.log('从书画柜进入详情页,使用临时站源:', siteInfo.name)
406+
console.log('从书画柜进入详情页,使用临时站源:', siteInfo.name, '扩展参数:', siteInfo.ext)
406407
407408
// 跳转到详情页,传递站源信息
408409
router.push({
@@ -424,6 +425,7 @@ const goToDetail = async (item) => {
424425
tempSiteName: siteInfo.name,
425426
tempSiteApi: siteInfo.api,
426427
tempSiteKey: siteInfo.key,
428+
tempSiteExt: siteInfo.ext, // 添加extend参数传递
427429
// 添加来源页面信息
428430
sourceRouteName: 'BookGallery',
429431
sourceRouteParams: JSON.stringify({}),

0 commit comments

Comments
 (0)