feat(media): 优化后台媒体预览播放器

重构 data-video-player 事件,阻止默认跳转并按文件扩展名或 data-player-type 自动识别音频与视频类型,避免音频文件误走视频播放器流程。

根据浏览器窗口动态计算播放器弹窗尺寸,补充媒体弹窗样式、原生音视频兜底播放和无法预览时的打开文件入口,提升不同屏幕下的预览稳定性。

在系统文件列表的音频和视频预览入口写入明确的 data-player-type,确保文件管理表格与前端播放器的类型识别保持一致。
This commit is contained in:
邹景立 2026-05-20 23:18:27 +08:00
parent 568fb5d274
commit 0f3d84d4cd
3 changed files with 186 additions and 24 deletions

View File

@ -1409,17 +1409,98 @@ $(function () {
});
/*! 注册 data-video-player 事件行为 */
$.base.onEvent('click', '[data-video-player]', function () {
let idx = $.msg.loading(), url = this.dataset.videoPlayer, name = this.dataset.title || '媒体播放器', payer;
$.module.use(['artplayer'], () => layer.open({
title: name, type: 1, fixed: true, maxmin: false,
content: '<div class="data-play-video" style="width:800px;height:450px"></div>',
end: () => payer.destroy(), success: $ele => payer = new Artplayer({
url: url, container: $ele.selector + ' .data-play-video', controls: [
{html: '全屏播放', position: 'right', click: () => payer.fullscreen = !payer.fullscreen},
]
}, art => art.play(), $.msg.close(idx))
}));
$.base.onEvent('click', '[data-video-player]', function (event) {
event.preventDefault();
let idx = $.msg.loading(), url = this.dataset.videoPlayer, name = this.dataset.title || '媒体播放器', player;
let ext = String(url || '').split(/[?#]/)[0].split('.').pop().toLowerCase();
let type = this.dataset.playerType || (/^(aac|flac|m4a|mp3|oga|ogg|wav|weba|wma)$/.test(ext) ? 'audio' : 'video');
let viewWidth = Math.max(320, $(window).width()), viewHeight = Math.max(320, $(window).height());
let titleHeight = 48, minWidth = type === 'audio' ? Math.min(420, Math.floor(viewWidth * 0.92)) : Math.min(640, Math.floor(viewWidth * 0.92));
let mediaWidth = Math.max(minWidth, Math.min(type === 'audio' ? 640 : 960, Math.floor(viewWidth * 0.86)));
let mediaHeight = type === 'audio' ? 150 : Math.round(mediaWidth * 9 / 16);
let maxMediaHeight = Math.max(type === 'audio' ? 120 : 260, Math.floor(viewHeight * 0.82) - titleHeight);
if (mediaHeight > maxMediaHeight) {
mediaHeight = maxMediaHeight;
mediaWidth = type === 'audio' ? mediaWidth : Math.round(mediaHeight * 16 / 9);
}
function ensurePlayerStyle() {
if (document.getElementById('ta-media-player-style')) return;
let style = document.createElement('style');
style.id = 'ta-media-player-style';
style.innerHTML = [
'.ta-media-layer{border-radius:10px;overflow:hidden;background:#0f141a;box-shadow:0 12px 40px rgba(0,0,0,.28);}',
'.ta-media-layer .layui-layer-title{height:48px;line-height:48px;padding:0 52px 0 18px;border-bottom:1px solid #edf0f5;background:#fff;font-weight:600;}',
'.ta-media-layer .layui-layer-setwin{top:16px;right:16px;}',
'.ta-media-layer .layui-layer-content{overflow:hidden!important;background:#0f141a;}',
'.ta-media-wrap{width:100%;height:100%;background:#0f141a;display:flex;align-items:center;justify-content:center;}',
'.ta-media-wrap .data-play-media{width:100%;height:100%;background:#000;}',
'.ta-media-wrap.is-audio{background:#fff;}',
'.ta-media-wrap.is-audio .data-play-media{background:#fff;display:flex;align-items:center;justify-content:center;}',
'.ta-media-wrap audio{width:88%;}',
'.ta-media-empty{padding:30px;text-align:center;color:#333;}'
].join('');
document.head.appendChild(style);
}
function showMessage($container, message) {
$container.empty().css({background: '#fff', color: '#333', display: 'flex', alignItems: 'center', justifyContent: 'center'});
$container.append($('<div class="ta-media-empty"></div>').append(
$('<p class="color-desc mb10"></p>').text(message),
$('<a class="layui-btn layui-btn-sm layui-btn-primary" target="_blank"></a>').attr('href', url).text('打开文件')
));
}
function nativePlayer($container) {
let $media = $(type === 'audio' ? '<audio controls autoplay></audio>' : '<video controls autoplay playsinline></video>');
$container.empty().css({background: type === 'audio' ? '#fff' : '#000', display: 'flex', alignItems: 'center', justifyContent: 'center'});
$media.attr('src', url).css(type === 'audio' ? {width: '90%'} : {width: '100%', height: '100%', background: '#000'});
$media.one('error', function () {
showMessage($container, '当前媒体无法预览,可尝试打开文件。');
});
$container.append($media);
}
$.module.use(['artplayer'], function (Artplayer) {
ensurePlayerStyle();
layer.open({
title: name, type: 1, fixed: true, maxmin: true, resize: false, skin: 'ta-media-layer',
area: [mediaWidth + 'px', (mediaHeight + titleHeight) + 'px'],
content: '<div class="ta-media-wrap ' + (type === 'audio' ? 'is-audio' : 'is-video') + '" style="height:' + mediaHeight + 'px"><div class="data-play-media"></div></div>',
end: function () {
if (player && typeof player.destroy === 'function') player.destroy();
},
success: function ($ele) {
$.msg.close(idx);
let $wrap = $ele.find('.ta-media-wrap'), $container = $ele.find('.data-play-media'), container = $container.get(0), Player = Artplayer || window.Artplayer;
$wrap.height(mediaHeight);
if (!container) return $.msg.tips('播放器容器初始化失败!');
if (type === 'audio' || typeof Player !== 'function') return nativePlayer($container);
try {
player = new Player({
url: url, container: container, autoplay: true, autoSize: true, volume: 0.7, theme: '#16baaa',
hotkey: true, pip: true, screenshot: true, setting: true, playbackRate: true, aspectRatio: true,
fullscreen: true, fullscreenWeb: true, mutex: true, miniProgressBar: true,
moreVideoAttr: {controls: false, preload: 'metadata', playsInline: true}
}, function (art) {
let ret = art.play();
if (ret && typeof ret.catch === 'function') ret.catch(function () {
});
});
player.on('video:error', function () {
showMessage($container, '当前视频无法预览,可尝试打开文件。');
});
} catch (e) {
console.error(e);
nativePlayer($container);
}
}
});
}).catch(function (error) {
$.msg.close(idx);
console.error(error);
$.msg.tips('播放器组件加载失败!');
});
});
/*! 注册 data-icon 事件行为 */

View File

@ -138,10 +138,10 @@ function (d) {
return '<div><a target="_blank" data-tips-hover data-tips-image="' + fileUrl + '"><i class="layui-icon layui-icon-picture"></i></a></div>';
}
if (typeof d.mime === 'string' && /^video\//.test(d.mime)) {
return '<div><a target="_blank" data-video-player="' + fileUrl + '" data-tips-text="' + %s + '"><i class="layui-icon layui-icon-video"></i></a></div>';
return '<div><a target="_blank" data-player-type="video" data-video-player="' + fileUrl + '" data-tips-text="' + %s + '"><i class="layui-icon layui-icon-video"></i></a></div>';
}
if (typeof d.mime === 'string' && /^audio\//.test(d.mime)) {
return '<div><a target="_blank" data-video-player="' + fileUrl + '" data-tips-text="' + %s + '"><i class="layui-icon layui-icon-headset"></i></a></div>';
return '<div><a target="_blank" data-player-type="audio" data-video-player="' + fileUrl + '" data-tips-text="' + %s + '"><i class="layui-icon layui-icon-headset"></i></a></div>';
}
return '<div><a target="_blank" href="' + fileUrl + '" data-tips-text="' + %s + '"><i class="layui-icon layui-icon-file"></i></a></div>';
}

View File

@ -1409,17 +1409,98 @@ $(function () {
});
/*! 注册 data-video-player 事件行为 */
$.base.onEvent('click', '[data-video-player]', function () {
let idx = $.msg.loading(), url = this.dataset.videoPlayer, name = this.dataset.title || '媒体播放器', payer;
$.module.use(['artplayer'], () => layer.open({
title: name, type: 1, fixed: true, maxmin: false,
content: '<div class="data-play-video" style="width:800px;height:450px"></div>',
end: () => payer.destroy(), success: $ele => payer = new Artplayer({
url: url, container: $ele.selector + ' .data-play-video', controls: [
{html: '全屏播放', position: 'right', click: () => payer.fullscreen = !payer.fullscreen},
]
}, art => art.play(), $.msg.close(idx))
}));
$.base.onEvent('click', '[data-video-player]', function (event) {
event.preventDefault();
let idx = $.msg.loading(), url = this.dataset.videoPlayer, name = this.dataset.title || '媒体播放器', player;
let ext = String(url || '').split(/[?#]/)[0].split('.').pop().toLowerCase();
let type = this.dataset.playerType || (/^(aac|flac|m4a|mp3|oga|ogg|wav|weba|wma)$/.test(ext) ? 'audio' : 'video');
let viewWidth = Math.max(320, $(window).width()), viewHeight = Math.max(320, $(window).height());
let titleHeight = 48, minWidth = type === 'audio' ? Math.min(420, Math.floor(viewWidth * 0.92)) : Math.min(640, Math.floor(viewWidth * 0.92));
let mediaWidth = Math.max(minWidth, Math.min(type === 'audio' ? 640 : 960, Math.floor(viewWidth * 0.86)));
let mediaHeight = type === 'audio' ? 150 : Math.round(mediaWidth * 9 / 16);
let maxMediaHeight = Math.max(type === 'audio' ? 120 : 260, Math.floor(viewHeight * 0.82) - titleHeight);
if (mediaHeight > maxMediaHeight) {
mediaHeight = maxMediaHeight;
mediaWidth = type === 'audio' ? mediaWidth : Math.round(mediaHeight * 16 / 9);
}
function ensurePlayerStyle() {
if (document.getElementById('ta-media-player-style')) return;
let style = document.createElement('style');
style.id = 'ta-media-player-style';
style.innerHTML = [
'.ta-media-layer{border-radius:10px;overflow:hidden;background:#0f141a;box-shadow:0 12px 40px rgba(0,0,0,.28);}',
'.ta-media-layer .layui-layer-title{height:48px;line-height:48px;padding:0 52px 0 18px;border-bottom:1px solid #edf0f5;background:#fff;font-weight:600;}',
'.ta-media-layer .layui-layer-setwin{top:16px;right:16px;}',
'.ta-media-layer .layui-layer-content{overflow:hidden!important;background:#0f141a;}',
'.ta-media-wrap{width:100%;height:100%;background:#0f141a;display:flex;align-items:center;justify-content:center;}',
'.ta-media-wrap .data-play-media{width:100%;height:100%;background:#000;}',
'.ta-media-wrap.is-audio{background:#fff;}',
'.ta-media-wrap.is-audio .data-play-media{background:#fff;display:flex;align-items:center;justify-content:center;}',
'.ta-media-wrap audio{width:88%;}',
'.ta-media-empty{padding:30px;text-align:center;color:#333;}'
].join('');
document.head.appendChild(style);
}
function showMessage($container, message) {
$container.empty().css({background: '#fff', color: '#333', display: 'flex', alignItems: 'center', justifyContent: 'center'});
$container.append($('<div class="ta-media-empty"></div>').append(
$('<p class="color-desc mb10"></p>').text(message),
$('<a class="layui-btn layui-btn-sm layui-btn-primary" target="_blank"></a>').attr('href', url).text('打开文件')
));
}
function nativePlayer($container) {
let $media = $(type === 'audio' ? '<audio controls autoplay></audio>' : '<video controls autoplay playsinline></video>');
$container.empty().css({background: type === 'audio' ? '#fff' : '#000', display: 'flex', alignItems: 'center', justifyContent: 'center'});
$media.attr('src', url).css(type === 'audio' ? {width: '90%'} : {width: '100%', height: '100%', background: '#000'});
$media.one('error', function () {
showMessage($container, '当前媒体无法预览,可尝试打开文件。');
});
$container.append($media);
}
$.module.use(['artplayer'], function (Artplayer) {
ensurePlayerStyle();
layer.open({
title: name, type: 1, fixed: true, maxmin: true, resize: false, skin: 'ta-media-layer',
area: [mediaWidth + 'px', (mediaHeight + titleHeight) + 'px'],
content: '<div class="ta-media-wrap ' + (type === 'audio' ? 'is-audio' : 'is-video') + '" style="height:' + mediaHeight + 'px"><div class="data-play-media"></div></div>',
end: function () {
if (player && typeof player.destroy === 'function') player.destroy();
},
success: function ($ele) {
$.msg.close(idx);
let $wrap = $ele.find('.ta-media-wrap'), $container = $ele.find('.data-play-media'), container = $container.get(0), Player = Artplayer || window.Artplayer;
$wrap.height(mediaHeight);
if (!container) return $.msg.tips('播放器容器初始化失败!');
if (type === 'audio' || typeof Player !== 'function') return nativePlayer($container);
try {
player = new Player({
url: url, container: container, autoplay: true, autoSize: true, volume: 0.7, theme: '#16baaa',
hotkey: true, pip: true, screenshot: true, setting: true, playbackRate: true, aspectRatio: true,
fullscreen: true, fullscreenWeb: true, mutex: true, miniProgressBar: true,
moreVideoAttr: {controls: false, preload: 'metadata', playsInline: true}
}, function (art) {
let ret = art.play();
if (ret && typeof ret.catch === 'function') ret.catch(function () {
});
});
player.on('video:error', function () {
showMessage($container, '当前视频无法预览,可尝试打开文件。');
});
} catch (e) {
console.error(e);
nativePlayer($container);
}
}
});
}).catch(function (error) {
$.msg.close(idx);
console.error(error);
$.msg.tips('播放器组件加载失败!');
});
});
/*! 注册 data-icon 事件行为 */