|
|
@@ -94,6 +94,27 @@ const todayStats = computed(() => {
|
|
|
}))
|
|
|
})
|
|
|
|
|
|
+const activeStatusCodes: StatusCode[] = ['busy', 'reasoning', 'using_tool', 'running', 'pending', 'retry']
|
|
|
+
|
|
|
+const workDuration = computed(() => {
|
|
|
+ const items = eventLog.value.slice().reverse()
|
|
|
+ if (items.length === 0) return '0m'
|
|
|
+
|
|
|
+ let totalMs = 0
|
|
|
+ for (let i = 0; i < items.length; i++) {
|
|
|
+ if (activeStatusCodes.includes(items[i].code)) {
|
|
|
+ const end = i + 1 < items.length ? items[i + 1].ts : Date.now()
|
|
|
+ totalMs += end - items[i].ts
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const totalMin = Math.floor(totalMs / 60000)
|
|
|
+ if (totalMin < 60) return `${totalMin}m`
|
|
|
+ const hr = Math.floor(totalMin / 60)
|
|
|
+ const min = totalMin % 60
|
|
|
+ return `${hr}h ${min}m`
|
|
|
+})
|
|
|
+
|
|
|
function getOrCreatePieChart(): echarts.ECharts {
|
|
|
if (!pieChart && pieChartRef.value) {
|
|
|
pieChart = echarts.init(pieChartRef.value)
|
|
|
@@ -342,6 +363,10 @@ async function sendCode(code: string) {
|
|
|
</div>
|
|
|
|
|
|
<div class="stats-row">
|
|
|
+ <div class="work-section">
|
|
|
+ <div class="section-title">今日工作时长</div>
|
|
|
+ <div class="work-duration">{{ workDuration }}</div>
|
|
|
+ </div>
|
|
|
<div class="stats-section">
|
|
|
<div class="section-title">今日统计</div>
|
|
|
<div v-if="todayStats.length === 0" class="stats-empty">暂无数据</div>
|
|
|
@@ -563,6 +588,28 @@ async function sendCode(code: string) {
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
+.work-section {
|
|
|
+ width: 180px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 16px 20px;
|
|
|
+ background: var(--card-bg);
|
|
|
+ border: 1px solid var(--border-color);
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.work-duration {
|
|
|
+ font-size: 36px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #1890ff;
|
|
|
+ font-variant-numeric: tabular-nums;
|
|
|
+ line-height: 1;
|
|
|
+ margin-top: 4px;
|
|
|
+}
|
|
|
+
|
|
|
.stats-section {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
@@ -688,6 +735,14 @@ async function sendCode(code: string) {
|
|
|
flex-direction: column;
|
|
|
}
|
|
|
|
|
|
+ .stats-row {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .work-section {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
.log-section {
|
|
|
padding: 16px;
|
|
|
max-height: 240px;
|