7cf6c18e by 柴进

feat(qml): task #17 任务队列 sidebar 接 taskQueue.model

MainWindow.qml sidebar 改造:
- header: 加 "N 进行中" 计数(绑定 taskQueue.runningCount + pendingCount,0 时隐藏)
- ListView model: 硬编码 ListModel → taskQueue.model(_TaskListModel QAbstractListModel)
- 空态占位: "暂无任务"(visible: count === 0)
- delegate 改造,56px 高 ColumnLayout 三行:
  1. prompt 摘要(>14 字省略)
  2. 状态彩色文字(pending=橙 / running=蓝 / completed=绿 / failed=红) + 耗时
  3. 进行中任务的细进度条(高 2px,绑 progress 0-1)
- delegate 用 required property 声明 6 个 role:taskId / prompt / status / progress / statusText / elapsed
- 右键点击 pending/running 任务 → taskQueue.cancelTask(taskId)

至此 生成 → sidebar → 历史 闭环完整:
- 用户在图片生成 tab 点 "生成图片" → ImageGenBridge.submitTask
- TaskQueueManager 信号 → TaskQueueBridge._on_task_added → upsert 进 model
- sidebar ListView 自动渲染新行,状态文字 + 进度条同步
- 完成后 ImageGenBridge → HistoryBridge.addNew,历史 tab 也会增量

视觉验证:QML_AUTO_LOGIN=1 启动主窗口,空态正确显示"暂无任务",UI 无回归。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5d893c50
...@@ -146,15 +146,29 @@ Rectangle { ...@@ -146,15 +146,29 @@ Rectangle {
146 implicitHeight: 48 146 implicitHeight: 48
147 color: App.Theme.bgSurface 147 color: App.Theme.bgSurface
148 148
149 Label { 149 RowLayout {
150 anchors.left: parent.left 150 anchors.left: parent.left
151 anchors.right: parent.right
151 anchors.leftMargin: App.Theme.space4 152 anchors.leftMargin: App.Theme.space4
153 anchors.rightMargin: App.Theme.space4
152 anchors.verticalCenter: parent.verticalCenter 154 anchors.verticalCenter: parent.verticalCenter
153 text: "任务队列" 155 spacing: App.Theme.space2
154 font.family: App.Theme.fontFamily 156
155 font.pointSize: App.Theme.fontBase 157 Label {
156 font.weight: Font.DemiBold 158 text: "任务队列"
157 color: App.Theme.textPrimary 159 font.family: App.Theme.fontFamily
160 font.pointSize: App.Theme.fontBase
161 font.weight: Font.DemiBold
162 color: App.Theme.textPrimary
163 }
164 Item { Layout.fillWidth: true }
165 Label {
166 visible: taskQueue.runningCount + taskQueue.pendingCount > 0
167 text: taskQueue.runningCount + taskQueue.pendingCount + " 进行中"
168 font.family: App.Theme.fontFamily
169 font.pointSize: App.Theme.fontXs
170 color: App.Theme.textSecondary
171 }
158 } 172 }
159 173
160 // 底部分隔线 174 // 底部分隔线
...@@ -169,32 +183,95 @@ Rectangle { ...@@ -169,32 +183,95 @@ Rectangle {
169 183
170 // 列表 184 // 列表
171 ListView { 185 ListView {
186 id: taskList
172 Layout.fillWidth: true 187 Layout.fillWidth: true
173 Layout.fillHeight: true 188 Layout.fillHeight: true
174 Layout.margins: App.Theme.space2 189 Layout.margins: App.Theme.space2
175 spacing: 4 190 spacing: 6
176 clip: true 191 clip: true
177 192
178 model: ListModel { 193 model: taskQueue.model
179 ListElement { status: "执行中"; color: "#ff9500" } 194
180 ListElement { status: "等待中"; color: "#0071e3" } 195 // 空状态占位
181 ListElement { status: "已完成"; color: "#34c759" } 196 Label {
197 anchors.centerIn: parent
198 text: "暂无任务"
199 font.family: App.Theme.fontFamily
200 font.pointSize: App.Theme.fontSm
201 color: App.Theme.textTertiary
202 visible: taskList.count === 0
182 } 203 }
183 204
184 delegate: Rectangle { 205 delegate: Rectangle {
206 required property string taskId
207 required property string prompt
208 required property string status
209 required property real progress
210 required property string statusText
211 required property string elapsed
212
185 width: ListView.view.width 213 width: ListView.view.width
186 height: 36 214 height: 56
187 radius: App.Theme.radiusSm 215 radius: App.Theme.radiusSm
188 color: itemMouse.containsMouse ? App.Theme.bgHover : "transparent" 216 color: itemMouse.containsMouse ? App.Theme.bgHover : "transparent"
217 border.width: 1
218 border.color: App.Theme.divider
189 219
190 Text { 220 ColumnLayout {
191 anchors.left: parent.left 221 anchors.fill: parent
192 anchors.leftMargin: App.Theme.space3 222 anchors.margins: App.Theme.space2
193 anchors.verticalCenter: parent.verticalCenter 223 spacing: 2
194 text: status 224
195 color: model.color 225 // 第一行: prompt 摘要(最多约 14 字)
196 font.family: App.Theme.fontFamily 226 Text {
197 font.pointSize: App.Theme.fontSm 227 text: prompt.length > 14 ? prompt.substring(0, 14) + "…" : prompt
228 color: App.Theme.textPrimary
229 font.family: App.Theme.fontFamily
230 font.pointSize: App.Theme.fontXs
231 Layout.fillWidth: true
232 elide: Text.ElideRight
233 }
234
235 // 第二行: 状态彩色 + elapsed
236 RowLayout {
237 Layout.fillWidth: true
238 spacing: 4
239
240 Text {
241 text: statusText
242 color: status === "completed" ? App.Theme.success
243 : status === "failed" ? App.Theme.danger
244 : status === "running" ? App.Theme.accent
245 : App.Theme.warning // pending
246 font.family: App.Theme.fontFamily
247 font.pointSize: App.Theme.fontXs
248 Layout.fillWidth: true
249 elide: Text.ElideRight
250 }
251 Text {
252 visible: elapsed.length > 0
253 text: elapsed
254 color: App.Theme.textTertiary
255 font.family: App.Theme.fontFamily
256 font.pointSize: App.Theme.fontXs
257 }
258 }
259
260 // 第三行: running 时显示细进度条
261 Rectangle {
262 visible: status === "running"
263 Layout.fillWidth: true
264 Layout.preferredHeight: 2
265 color: App.Theme.bgSubtle
266 radius: 1
267
268 Rectangle {
269 width: parent.width * Math.max(0.05, Math.min(progress, 1.0))
270 height: parent.height
271 color: App.Theme.accent
272 radius: 1
273 }
274 }
198 } 275 }
199 276
200 MouseArea { 277 MouseArea {
...@@ -202,6 +279,13 @@ Rectangle { ...@@ -202,6 +279,13 @@ Rectangle {
202 anchors.fill: parent 279 anchors.fill: parent
203 hoverEnabled: true 280 hoverEnabled: true
204 cursorShape: Qt.PointingHandCursor 281 cursorShape: Qt.PointingHandCursor
282 acceptedButtons: Qt.LeftButton | Qt.RightButton
283 onClicked: function(mouse) {
284 if (mouse.button === Qt.RightButton
285 && (status === "pending" || status === "running")) {
286 taskQueue.cancelTask(taskId)
287 }
288 }
205 } 289 }
206 } 290 }
207 } 291 }
......