2025-05-29 14:04:05 +08:00
|
|
|
|
import QtQuick 2.15
|
|
|
|
|
|
import QtQuick.Window 2.15
|
|
|
|
|
|
import QtQuick.Controls 2.15
|
|
|
|
|
|
import QtMultimedia 5.15
|
2025-09-15 09:46:04 +08:00
|
|
|
|
import HuskarUI.Basic 1.0
|
2025-05-29 14:04:05 +08:00
|
|
|
|
import QmlTool 1.0
|
|
|
|
|
|
import FileTransfer 1.0
|
|
|
|
|
|
import "../MyGlobals" 1.0
|
|
|
|
|
|
import "../Component" 1.0
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusWindow {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id:plugininfo_goods
|
|
|
|
|
|
width: 1110
|
|
|
|
|
|
height: 630
|
|
|
|
|
|
visible: true
|
|
|
|
|
|
title: qsTr("插件详情页")
|
|
|
|
|
|
captionBar.topButtonVisible: true
|
|
|
|
|
|
captionBar.winIconDelegate: Image {
|
|
|
|
|
|
id: name
|
|
|
|
|
|
width: 20
|
|
|
|
|
|
height: 20
|
|
|
|
|
|
source: "qrc:/image/logo.png"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//原始数据
|
|
|
|
|
|
property var p_basedata: null
|
|
|
|
|
|
//插件名
|
|
|
|
|
|
property string p_name : "未定名插件"
|
|
|
|
|
|
//作者名
|
|
|
|
|
|
property string p_author : "未定名作者"
|
|
|
|
|
|
//版本号
|
|
|
|
|
|
property string p_version: "0.0.1"
|
|
|
|
|
|
//描述
|
|
|
|
|
|
property string p_description: "暂无描述"
|
|
|
|
|
|
//售价
|
|
|
|
|
|
property int p_price: 0
|
|
|
|
|
|
//插件文件数组
|
|
|
|
|
|
property var p_filelist : []
|
|
|
|
|
|
//是否是凌众插件
|
|
|
|
|
|
property bool p_isrindro : false
|
|
|
|
|
|
//图像
|
|
|
|
|
|
property string p_image:"qrc:/image/logo2.png"
|
|
|
|
|
|
|
|
|
|
|
|
Component.onCompleted: {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Shortcut {
|
|
|
|
|
|
sequences: ["Esc"]
|
|
|
|
|
|
onActivated: close()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function init(index){
|
|
|
|
|
|
//全局数据插件列表存在
|
|
|
|
|
|
if(!GlobalVars.serverPluginexMap)return;
|
|
|
|
|
|
var Data = GlobalVars.serverPluginexMap[index]
|
|
|
|
|
|
p_basedata = Data;
|
|
|
|
|
|
p_name = Data.ProjectName
|
|
|
|
|
|
p_author = Data.ProjectAuthor
|
|
|
|
|
|
p_version = Data.ProjectVersion
|
|
|
|
|
|
p_description = Data.ProjectDescribe
|
|
|
|
|
|
//如果有插件文件数组
|
|
|
|
|
|
if(Data.ProjectFiles)p_filelist = Data.ProjectFiles
|
|
|
|
|
|
//如果有插件的详细描述
|
|
|
|
|
|
if(Data.ProjectDetails)details.model = Data.ProjectDetails
|
|
|
|
|
|
//如果有售价才设置售价
|
|
|
|
|
|
if(Data.ProjectPrice)p_price = Data.ProjectPrice
|
|
|
|
|
|
else p_price = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function isLocalIP(ip) {
|
|
|
|
|
|
// 检查是否为空或无效IP
|
|
|
|
|
|
if (!ip || typeof ip !== 'string') return false;
|
|
|
|
|
|
|
|
|
|
|
|
// 常见本地IP模式
|
|
|
|
|
|
const localIPPatterns = [
|
|
|
|
|
|
/^127\./, // 127.0.0.0-127.255.255.255
|
|
|
|
|
|
/^10\./, // 10.0.0.0-10.255.255.255
|
|
|
|
|
|
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0-172.31.255.255
|
|
|
|
|
|
/^192\.168\./ // 192.168.0.0-192.168.255.255
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否匹配任何本地IP模式
|
|
|
|
|
|
return localIPPatterns.some(pattern => pattern.test(ip));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function buyPlugin(){
|
|
|
|
|
|
var RealBuyIp = GlobalVars.accServerList[GlobalVars.selectServer].serverIp;
|
|
|
|
|
|
if(isLocalIP(RealBuyIp)){
|
|
|
|
|
|
GlobalVars.msg_control.error("暂不支持单机服务器使用双端插件!");
|
|
|
|
|
|
close()
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GlobalVars.buyExPlugin(p_name,RealBuyIp)
|
|
|
|
|
|
close()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rectangle{
|
|
|
|
|
|
id:title
|
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
|
anchors.leftMargin: 10
|
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
|
anchors.rightMargin: 15
|
|
|
|
|
|
anchors.top: parent.top
|
|
|
|
|
|
anchors.topMargin: 45
|
|
|
|
|
|
height:78 + headerdiv.height + description.height
|
|
|
|
|
|
radius:8
|
2025-09-15 09:46:04 +08:00
|
|
|
|
border.color: HusTheme.isDark ? "#23272e" : "#f0f4f7"
|
2025-05-29 14:04:05 +08:00
|
|
|
|
border.width: 2
|
|
|
|
|
|
color:"transparent"
|
|
|
|
|
|
|
|
|
|
|
|
Image {
|
|
|
|
|
|
id: logo
|
|
|
|
|
|
source: "qrc:/image/logo.png"
|
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
|
anchors.leftMargin: 10
|
|
|
|
|
|
anchors.top: parent.top
|
|
|
|
|
|
anchors.topMargin: 15
|
|
|
|
|
|
width: 48
|
|
|
|
|
|
height: 48
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusDivider {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id:headerdiv
|
|
|
|
|
|
anchors.top: logo.bottom
|
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
|
anchors.leftMargin: 1
|
|
|
|
|
|
width: parent.width - 1
|
|
|
|
|
|
height: 30
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Text {
|
|
|
|
|
|
id:description
|
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
|
anchors.leftMargin: 10
|
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
|
anchors.rightMargin: 10
|
|
|
|
|
|
anchors.top: headerdiv.bottom
|
|
|
|
|
|
text: p_description
|
|
|
|
|
|
|
|
|
|
|
|
wrapMode: Text.WordWrap
|
|
|
|
|
|
font {
|
|
|
|
|
|
pixelSize: 14
|
2025-09-15 09:46:04 +08:00
|
|
|
|
family: HusTheme.Primary.fontPrimaryFamily
|
2025-05-29 14:04:05 +08:00
|
|
|
|
}
|
2025-09-15 09:46:04 +08:00
|
|
|
|
color: HusTheme.Primary.colorTextBase
|
2025-05-29 14:04:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Text {
|
|
|
|
|
|
id:pluginname
|
|
|
|
|
|
anchors.left: logo.right
|
|
|
|
|
|
anchors.leftMargin: 10
|
|
|
|
|
|
anchors.top: parent.top
|
|
|
|
|
|
anchors.topMargin: 14
|
|
|
|
|
|
text: p_name
|
|
|
|
|
|
font {
|
|
|
|
|
|
pixelSize: 20
|
2025-09-15 09:46:04 +08:00
|
|
|
|
family: HusTheme.Primary.fontPrimaryFamily
|
2025-05-29 14:04:05 +08:00
|
|
|
|
}
|
2025-09-15 09:46:04 +08:00
|
|
|
|
color: HusTheme.Primary.colorTextBase
|
2025-05-29 14:04:05 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Text {
|
|
|
|
|
|
anchors.left: logo.right
|
|
|
|
|
|
anchors.leftMargin: 10
|
|
|
|
|
|
anchors.top: pluginname.bottom
|
|
|
|
|
|
anchors.topMargin: 2
|
|
|
|
|
|
text: "作者: " + p_author
|
|
|
|
|
|
font {
|
|
|
|
|
|
pixelSize: 14
|
2025-09-15 09:46:04 +08:00
|
|
|
|
family: HusTheme.Primary.fontPrimaryFamily
|
2025-05-29 14:04:05 +08:00
|
|
|
|
}
|
2025-09-15 09:46:04 +08:00
|
|
|
|
color: HusTheme.Primary.colorTextBase
|
2025-05-29 14:04:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusTag {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id:version_tag
|
|
|
|
|
|
anchors.left: pluginname.right
|
|
|
|
|
|
anchors.leftMargin: 15
|
|
|
|
|
|
anchors.top: pluginname.top
|
|
|
|
|
|
anchors.topMargin: 2
|
|
|
|
|
|
text:"Ver:" + p_version
|
|
|
|
|
|
presetColor:"green"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusTag {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id:price_tag
|
|
|
|
|
|
anchors.top: parent.top
|
|
|
|
|
|
anchors.topMargin: 15
|
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
|
anchors.rightMargin: 10
|
|
|
|
|
|
text:"所需贡献点:" + p_price
|
|
|
|
|
|
presetColor:"green"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusButton {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id:buy_button
|
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
|
anchors.rightMargin: 10
|
|
|
|
|
|
anchors.top: price_tag.bottom
|
|
|
|
|
|
anchors.topMargin: 2
|
|
|
|
|
|
height: 26
|
|
|
|
|
|
text: "购买"
|
|
|
|
|
|
onClicked: {
|
|
|
|
|
|
//我这里临时先写免费服务端插件的安装
|
|
|
|
|
|
buyPlugin();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rectangle{
|
|
|
|
|
|
id:content
|
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
|
anchors.leftMargin: 10
|
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
|
anchors.rightMargin: 15
|
|
|
|
|
|
anchors.top: title.bottom
|
|
|
|
|
|
anchors.topMargin: 10
|
|
|
|
|
|
anchors.bottom:parent.bottom
|
|
|
|
|
|
anchors.bottomMargin: 10
|
|
|
|
|
|
radius:8
|
2025-09-15 09:46:04 +08:00
|
|
|
|
border.color: HusTheme.isDark ? "#23272e" : "#f0f4f7"
|
2025-05-29 14:04:05 +08:00
|
|
|
|
border.width: 2
|
|
|
|
|
|
color:"transparent"
|
|
|
|
|
|
clip: true
|
|
|
|
|
|
|
|
|
|
|
|
ScrollView {
|
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
|
anchors.margins: 10
|
|
|
|
|
|
Column {
|
|
|
|
|
|
id: contentColumn
|
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
|
spacing: 10
|
|
|
|
|
|
|
|
|
|
|
|
Repeater {
|
|
|
|
|
|
id:details
|
|
|
|
|
|
delegate: Column { // 直接使用 Column 作为根元素
|
|
|
|
|
|
width: parent.width
|
|
|
|
|
|
spacing: 0
|
|
|
|
|
|
|
|
|
|
|
|
Loader {
|
|
|
|
|
|
width: parent.width
|
|
|
|
|
|
sourceComponent: {
|
|
|
|
|
|
switch(modelData.type) {
|
|
|
|
|
|
case "str": return textComponent;
|
|
|
|
|
|
case "img": return imageComponent;
|
|
|
|
|
|
case "mov": return videoComponent;
|
|
|
|
|
|
default: return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 动态绑定组件属性
|
|
|
|
|
|
property var itemData: modelData
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 定义组件映射
|
|
|
|
|
|
Component {
|
|
|
|
|
|
id: textComponent;
|
|
|
|
|
|
Text {
|
|
|
|
|
|
width: parent.width - 20
|
|
|
|
|
|
text: itemData.content
|
|
|
|
|
|
wrapMode: Text.Wrap
|
|
|
|
|
|
font {
|
|
|
|
|
|
pixelSize: 14
|
2025-09-15 09:46:04 +08:00
|
|
|
|
family: HusTheme.Primary.fontPrimaryFamily
|
2025-05-29 14:04:05 +08:00
|
|
|
|
}
|
2025-09-15 09:46:04 +08:00
|
|
|
|
color: HusTheme.Primary.colorTextBase
|
2025-05-29 14:04:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Component {
|
|
|
|
|
|
id: imageComponent;
|
|
|
|
|
|
Image {
|
|
|
|
|
|
source: GlobalVars.server_url + "/rindro/getimg/" + p_name + "/" + itemData.content
|
|
|
|
|
|
fillMode: Image.PreserveAspectFit
|
|
|
|
|
|
asynchronous: true
|
|
|
|
|
|
cache: true
|
|
|
|
|
|
// 动态计算宽度
|
|
|
|
|
|
width: Math.min(implicitWidth, parent.width)
|
|
|
|
|
|
// 让图像靠左边显示
|
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
|
// 确保父级有明确宽度传递
|
|
|
|
|
|
property real maxWidth: parent ? parent.width : 0
|
|
|
|
|
|
// 异步加载完成后更新尺寸
|
|
|
|
|
|
onStatusChanged: {
|
|
|
|
|
|
if (status === Image.Ready) {
|
|
|
|
|
|
width = Math.min(implicitWidth, maxWidth)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Component {
|
|
|
|
|
|
// id: videoComponent
|
|
|
|
|
|
|
|
|
|
|
|
// Item {
|
|
|
|
|
|
// id: videoContainer
|
|
|
|
|
|
// width: parent.width
|
|
|
|
|
|
// height: 400
|
|
|
|
|
|
|
|
|
|
|
|
// // 视频播放器
|
|
|
|
|
|
// Video {
|
|
|
|
|
|
// id: videoPlayer
|
|
|
|
|
|
// anchors.fill: parent
|
|
|
|
|
|
// anchors.bottomMargin: 15
|
|
|
|
|
|
// source: itemData.content
|
|
|
|
|
|
// loops: MediaPlayer.Infinite
|
|
|
|
|
|
// autoPlay: false
|
|
|
|
|
|
|
|
|
|
|
|
// // 错误处理
|
|
|
|
|
|
// onErrorChanged: {
|
|
|
|
|
|
// if (error !== MediaPlayer.NoError) {
|
|
|
|
|
|
// GlobalVars.msg_control.error("播放错误:", errorString);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// // 播放控制按钮(可选)
|
|
|
|
|
|
// Row {
|
|
|
|
|
|
// anchors.top: videoPlayer.bottom
|
|
|
|
|
|
// anchors.topMargin: 4
|
|
|
|
|
|
// anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
|
|
// spacing: 10
|
|
|
|
|
|
|
|
|
|
|
|
// DelButton {
|
|
|
|
|
|
// text: videoPlayer.playbackState === MediaPlayer.PlayingState ? "暂停" : "播放"
|
|
|
|
|
|
// onClicked: videoPlayer.playbackState === MediaPlayer.PlayingState ? videoPlayer.pause() : videoPlayer.play()
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// DelButton {
|
|
|
|
|
|
// text: "静音"
|
|
|
|
|
|
// onClicked: videoPlayer.muted = !videoPlayer.muted
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
Component {
|
|
|
|
|
|
id: videoComponent
|
|
|
|
|
|
|
|
|
|
|
|
Item {
|
|
|
|
|
|
id: videoContainer
|
|
|
|
|
|
width: itemData.width
|
|
|
|
|
|
height: itemData.height + 40
|
|
|
|
|
|
|
|
|
|
|
|
// 视频播放器
|
|
|
|
|
|
Video {
|
|
|
|
|
|
id: videoPlayer
|
|
|
|
|
|
anchors {
|
|
|
|
|
|
left: parent.left
|
|
|
|
|
|
right: parent.right
|
|
|
|
|
|
top: parent.top
|
|
|
|
|
|
}
|
|
|
|
|
|
height: itemData.height
|
|
|
|
|
|
anchors.margins: 2
|
|
|
|
|
|
// fillMode: MediaPlayer.PreserveAspectFit // 保持视频比例,不拉伸
|
|
|
|
|
|
// source: itemData.content
|
|
|
|
|
|
source: itemData.content
|
|
|
|
|
|
loops: MediaPlayer.Infinite
|
|
|
|
|
|
autoPlay: false
|
|
|
|
|
|
focus: false // 确保视频播放器不捕获焦点
|
|
|
|
|
|
|
|
|
|
|
|
// 错误处理
|
|
|
|
|
|
onErrorChanged: {
|
|
|
|
|
|
if (error !== MediaPlayer.NoError) {
|
|
|
|
|
|
GlobalVars.msg_control.error("播放错误:", errorString);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 外边框
|
|
|
|
|
|
Rectangle {
|
|
|
|
|
|
id: border
|
|
|
|
|
|
anchors {
|
|
|
|
|
|
left: videoPlayer.left
|
|
|
|
|
|
right: videoPlayer.right
|
|
|
|
|
|
top: videoPlayer.top
|
|
|
|
|
|
bottom: videoPlayer.bottom
|
|
|
|
|
|
}
|
|
|
|
|
|
border.color: "#cccccc"
|
|
|
|
|
|
border.width: 2
|
|
|
|
|
|
radius: 4
|
|
|
|
|
|
color: "transparent"
|
|
|
|
|
|
z: 1 // 确保边框在视频上方
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 视频加载状态指示器
|
|
|
|
|
|
Rectangle {
|
|
|
|
|
|
id: loadingIndicator
|
|
|
|
|
|
anchors.centerIn: videoPlayer
|
|
|
|
|
|
width: 60
|
|
|
|
|
|
height: 60
|
|
|
|
|
|
radius: 30
|
|
|
|
|
|
color: "#00000048"
|
|
|
|
|
|
z: 2 // 确保加载指示器在最上层
|
|
|
|
|
|
|
|
|
|
|
|
Text {
|
|
|
|
|
|
id: loadingText
|
|
|
|
|
|
anchors.centerIn: parent
|
|
|
|
|
|
text: "加载中..."
|
|
|
|
|
|
color: "white"
|
|
|
|
|
|
font.pixelSize: 12
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
visible: videoPlayer.status === MediaPlayer.LoadingStatus
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 错误提示文本
|
|
|
|
|
|
Text {
|
|
|
|
|
|
id: errorText
|
|
|
|
|
|
anchors.centerIn: videoPlayer
|
|
|
|
|
|
text: "视频加载失败,请检查链接或网络"
|
|
|
|
|
|
color: "red"
|
|
|
|
|
|
font.pixelSize: 14
|
|
|
|
|
|
visible: videoPlayer.error !== MediaPlayer.NoError
|
|
|
|
|
|
z: 2 // 确保错误文本在最上层
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 进度条容器,移到视频下方
|
|
|
|
|
|
Rectangle {
|
|
|
|
|
|
id: progressBarContainer
|
|
|
|
|
|
anchors {
|
|
|
|
|
|
left: parent.left
|
|
|
|
|
|
right: parent.right
|
|
|
|
|
|
bottom: videoPlayer.bottom
|
|
|
|
|
|
bottomMargin: 2
|
|
|
|
|
|
}
|
|
|
|
|
|
height: 10
|
|
|
|
|
|
color: "#00000048"
|
|
|
|
|
|
radius: 2
|
|
|
|
|
|
z: 2 // 确保进度条在最上层
|
|
|
|
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
|
|
id: progressBar
|
|
|
|
|
|
anchors {
|
|
|
|
|
|
left: parent.left
|
|
|
|
|
|
top: parent.top
|
|
|
|
|
|
bottom: parent.bottom
|
|
|
|
|
|
}
|
|
|
|
|
|
width: parent.width * (videoPlayer.position / Math.max(1, videoPlayer.duration))
|
|
|
|
|
|
color: "#0078d7"
|
|
|
|
|
|
radius: 2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
|
|
id: progressBarMouseArea
|
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
|
hoverEnabled: true
|
|
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
|
|
acceptedButtons: Qt.LeftButton
|
|
|
|
|
|
propagateComposedEvents: true // 允许事件传播
|
|
|
|
|
|
|
|
|
|
|
|
onPressed: {
|
|
|
|
|
|
if (videoPlayer.duration > 0)
|
|
|
|
|
|
videoPlayer.seek((mouse.x / width) * videoPlayer.duration)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onPositionChanged: {
|
|
|
|
|
|
if (mouse.pressedButtons & Qt.LeftButton && videoPlayer.duration > 0) {
|
|
|
|
|
|
videoPlayer.seek((mouse.x / width) * videoPlayer.duration)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 播放控制按钮,移到视频下方
|
|
|
|
|
|
Row {
|
|
|
|
|
|
id: controlButtons
|
|
|
|
|
|
anchors {
|
|
|
|
|
|
top: videoPlayer.bottom
|
|
|
|
|
|
topMargin: 5
|
|
|
|
|
|
horizontalCenter: parent.horizontalCenter
|
|
|
|
|
|
}
|
|
|
|
|
|
spacing: 10
|
|
|
|
|
|
visible: true
|
|
|
|
|
|
z: 2 // 确保控制按钮在最上层
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusButton {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id: playPauseButton
|
|
|
|
|
|
text: videoPlayer.playbackState === MediaPlayer.PlayingState ? "暂停" : "播放"
|
|
|
|
|
|
onClicked: {
|
|
|
|
|
|
if (videoPlayer.playbackState === MediaPlayer.PlayingState)
|
|
|
|
|
|
videoPlayer.pause()
|
|
|
|
|
|
else
|
|
|
|
|
|
videoPlayer.play()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusButton {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id: muteButton
|
|
|
|
|
|
text: videoPlayer.muted ? "取消静音" : "静音"
|
|
|
|
|
|
onClicked: videoPlayer.muted = !videoPlayer.muted
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusButton {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
id: replayButton
|
|
|
|
|
|
text: "重播"
|
|
|
|
|
|
onClicked: {
|
|
|
|
|
|
videoPlayer.seek(0)
|
|
|
|
|
|
videoPlayer.play()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 09:46:04 +08:00
|
|
|
|
HusButton {
|
2025-05-29 14:04:05 +08:00
|
|
|
|
text: "外部浏览器打开"
|
|
|
|
|
|
onClicked: {
|
|
|
|
|
|
Qt.openUrlExternally(GlobalVars.server_url + "/api/videos/" + p_name + "/" + itemData.index)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标悬停显示控制按钮
|
|
|
|
|
|
MouseArea {
|
|
|
|
|
|
id: containerMouseArea
|
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
|
hoverEnabled: true
|
|
|
|
|
|
propagateComposedEvents: true // 允许事件传播
|
|
|
|
|
|
z: 1 // 确保鼠标区域在适当层级
|
|
|
|
|
|
|
|
|
|
|
|
// onEntered: {
|
|
|
|
|
|
// controlButtons.visible = true
|
|
|
|
|
|
// progressBarContainer.visible = true
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// onExited: {
|
|
|
|
|
|
// controlButtons.visible = false
|
|
|
|
|
|
// progressBarContainer.visible = false
|
|
|
|
|
|
// }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DelButton {
|
|
|
|
|
|
text: "Open XLSX File"
|
|
|
|
|
|
anchors.centerIn: parent
|
|
|
|
|
|
onClicked: {
|
|
|
|
|
|
var filePath = "./基础配置.xlsx"; // 请替换为实际的文件路径
|
|
|
|
|
|
QmlTool.openFile(filePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
}
|