HistoryTab.qml 12.5 KB
import QtQuick
import QtQuick.Controls.Basic
import QtQuick.Layouts
import "components"
import "." as App

Item {
    id: tab

    property string selectedTimestamp: ""
    property var selectedItem: ({})

    function selectTimestamp(ts) {
        if (!ts) {
            tab.selectedTimestamp = ""
            tab.selectedItem = ({})
            return
        }
        tab.selectedTimestamp = ts
        tab.selectedItem = history.getItem(ts) || ({})
    }

    // 列表数据变化时校正选中项
    Connections {
        target: history
        function onItemRemoved(ts) {
            if (tab.selectedTimestamp === ts) tab.selectTimestamp("")
        }
        function onCountChanged() {
            // 自动选中第一条(首次加载 / 新增时)
            if (tab.selectedTimestamp === "" && historyList.count > 0) {
                var idx = historyList.model.index(0, 0)
                var ts = historyList.model.data(idx, Qt.UserRole)
                if (ts) tab.selectTimestamp(ts)
            }
        }
    }

    Component.onCompleted: {
        if (historyList.count > 0) {
            var idx = historyList.model.index(0, 0)
            var ts = historyList.model.data(idx, Qt.UserRole)
            if (ts) tab.selectTimestamp(ts)
        }
    }

    RowLayout {
        anchors.fill: parent
        anchors.margins: App.Theme.space5
        spacing: App.Theme.space4

        // ===== 左侧:列表 =====
        Card {
            Layout.preferredWidth: 340
            Layout.fillHeight: true

            ColumnLayout {
                anchors.fill: parent
                anchors.margins: App.Theme.space4
                spacing: App.Theme.space3

                RowLayout {
                    spacing: App.Theme.space3
                    CaptionLabel {
                        text: "历史记录"
                        font.pointSize: App.Theme.fontLg
                    }
                    Label {
                        text: history.count + " 条"
                        font.family: App.Theme.fontFamily
                        font.pointSize: App.Theme.fontSm
                        color: App.Theme.textSecondary
                    }
                    Item { Layout.fillWidth: true }
                    SecondaryButton {
                        text: "刷新"
                        onClicked: history.refresh()
                    }
                }

                // 空态
                Label {
                    visible: historyList.count === 0
                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                    text: "暂无历史记录\n生成图片后会自动出现在这里"
                    font.family: App.Theme.fontFamily
                    font.pointSize: App.Theme.fontSm
                    color: App.Theme.textTertiary
                }

                ListView {
                    id: historyList
                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    visible: count > 0
                    spacing: 4
                    clip: true
                    model: history.model

                    delegate: Rectangle {
                        required property int index
                        required property string display
                        required property string toolTip
                        required property string timestamp

                        width: ListView.view.width
                        height: 76
                        radius: App.Theme.radiusSm
                        color: tab.selectedTimestamp === timestamp ? App.Theme.accentSubtle
                             : itemMouse.containsMouse                ? App.Theme.bgHover
                             : "transparent"
                        border.width: tab.selectedTimestamp === timestamp ? 1 : 0
                        border.color: App.Theme.accent

                        RowLayout {
                            anchors.fill: parent
                            anchors.margins: App.Theme.space2
                            spacing: App.Theme.space3

                            // 缩略图
                            Rectangle {
                                Layout.preferredWidth: 60
                                Layout.preferredHeight: 60
                                radius: App.Theme.radiusSm
                                color: App.Theme.bgSubtle

                                Image {
                                    id: thumb
                                    anchors.fill: parent
                                    anchors.margins: 1
                                    source: {
                                        var p = history.thumbnailPath(timestamp)
                                        return p ? "file:///" + p : ""
                                    }
                                    fillMode: Image.PreserveAspectCrop
                                    smooth: true
                                    asynchronous: true
                                }
                            }

                            // 文字
                            ColumnLayout {
                                Layout.fillWidth: true
                                Layout.fillHeight: true
                                spacing: 2

                                Text {
                                    Layout.fillWidth: true
                                    text: timestamp
                                    color: App.Theme.textPrimary
                                    font.family: App.Theme.fontFamily
                                    font.pointSize: App.Theme.fontXs
                                    font.weight: Font.DemiBold
                                }
                                Text {
                                    Layout.fillWidth: true
                                    text: display.split("\n").slice(1).join(" ")
                                    color: App.Theme.textSecondary
                                    font.family: App.Theme.fontFamily
                                    font.pointSize: App.Theme.fontXs
                                    elide: Text.ElideRight
                                    maximumLineCount: 2
                                    wrapMode: Text.Wrap
                                }
                            }
                        }

                        MouseArea {
                            id: itemMouse
                            anchors.fill: parent
                            hoverEnabled: true
                            cursorShape: Qt.PointingHandCursor
                            onClicked: tab.selectTimestamp(timestamp)
                        }

                        ToolTip.text: toolTip
                        ToolTip.visible: itemMouse.containsMouse && toolTip.length > 0
                        ToolTip.delay: 600
                    }
                }
            }
        }

        // ===== 右侧:详情 =====
        Card {
            Layout.fillWidth: true
            Layout.fillHeight: true

            // 空态
            Label {
                anchors.centerIn: parent
                visible: tab.selectedTimestamp === ""
                text: "选择左侧记录查看详情"
                font.family: App.Theme.fontFamily
                font.pointSize: App.Theme.fontSm
                color: App.Theme.textTertiary
            }

            ColumnLayout {
                visible: tab.selectedTimestamp !== ""
                anchors.fill: parent
                anchors.margins: App.Theme.space4
                spacing: App.Theme.space3

                // header: 时间 + 操作按钮
                RowLayout {
                    Layout.fillWidth: true
                    spacing: App.Theme.space3

                    CaptionLabel {
                        text: tab.selectedItem.timestamp || ""
                        font.pointSize: App.Theme.fontLg
                    }
                    Label {
                        text: tab.selectedItem.createdAt || ""
                        font.family: App.Theme.fontFamily
                        font.pointSize: App.Theme.fontSm
                        color: App.Theme.textSecondary
                    }
                    Item { Layout.fillWidth: true }
                    SecondaryButton {
                        text: "在文件管理器中打开"
                        onClicked: {
                            if (tab.selectedItem.generatedImagePath) {
                                Qt.openUrlExternally("file:///" + tab.selectedItem.generatedImagePath)
                            }
                        }
                    }
                    SecondaryButton {
                        text: "删除"
                        onClicked: {
                            if (tab.selectedTimestamp) {
                                history.deleteItem(tab.selectedTimestamp)
                            }
                        }
                    }
                }

                // 大图
                Rectangle {
                    Layout.fillWidth: true
                    Layout.preferredHeight: 360
                    color: App.Theme.bgSubtle
                    radius: App.Theme.radiusMd

                    Image {
                        anchors.fill: parent
                        anchors.margins: App.Theme.space3
                        source: tab.selectedItem.generatedImagePath
                            ? "file:///" + tab.selectedItem.generatedImagePath
                            : ""
                        fillMode: Image.PreserveAspectFit
                        smooth: true
                        asynchronous: true

                        MouseArea {
                            anchors.fill: parent
                            cursorShape: Qt.PointingHandCursor
                            onDoubleClicked: {
                                if (tab.selectedItem.generatedImagePath) {
                                    Qt.openUrlExternally("file:///" + tab.selectedItem.generatedImagePath)
                                }
                            }
                        }
                    }
                }

                // 元信息
                GridLayout {
                    Layout.fillWidth: true
                    columns: 4
                    columnSpacing: App.Theme.space4
                    rowSpacing: App.Theme.space2

                    CaptionLabel { text: "宽高比" }
                    Label {
                        text: tab.selectedItem.aspectRatio || "—"
                        font.family: App.Theme.fontFamily
                        font.pointSize: App.Theme.fontSm
                        color: App.Theme.textPrimary
                    }
                    CaptionLabel { text: "尺寸" }
                    Label {
                        text: tab.selectedItem.imageSize || "—"
                        font.family: App.Theme.fontFamily
                        font.pointSize: App.Theme.fontSm
                        color: App.Theme.textPrimary
                    }

                    CaptionLabel { text: "模型" }
                    Label {
                        Layout.columnSpan: 3
                        text: tab.selectedItem.model || "—"
                        font.family: App.Theme.fontFamily
                        font.pointSize: App.Theme.fontSm
                        color: App.Theme.textPrimary
                        elide: Text.ElideRight
                        Layout.fillWidth: true
                    }
                }

                // prompt
                CaptionLabel { text: "提示词" }
                ScrollView {
                    Layout.fillWidth: true
                    Layout.preferredHeight: 80
                    Rectangle {
                        anchors.fill: parent
                        color: App.Theme.bgSubtle
                        radius: App.Theme.radiusMd
                        Text {
                            anchors.fill: parent
                            anchors.margins: App.Theme.space3
                            text: tab.selectedItem.prompt || ""
                            color: App.Theme.textPrimary
                            font.family: App.Theme.fontFamily
                            font.pointSize: App.Theme.fontSm
                            wrapMode: Text.Wrap
                        }
                    }
                }

                Item { Layout.fillHeight: true }
            }
        }
    }
}