Files
code-utils/frontend/src/components/RefreshIntervalPicker.vue
李琦 c430a0f6da 1. 后台图表多样化 API 的 /admin/overview 新增了按 AI 提供商聚合的用量(providerSeries)和云端数据构成(dataDist)。Admin.vue 概览页改用 ECharts:日活折线图、Token 堆叠柱状图(叠加调用次数折线)、AI 提供商用量饼图、云端数据构成饼图。
2. 端口监控与刷新间隔 「存为应用」不再跳转启动台,而是在本页弹出复用的 LaunchAppFormModal 表单,保存成功后弹确认框询问「留在本页 / 前往启动台」。启动台和端口监控页头都加了 RefreshIntervalPicker(仅手动 / 5 / 10 / 30 / 60 秒,默认 30 秒),选择记忆在 localStorage。

3. 团队所有者与用户详情 团队列表的所有者、用户列表的用户名都改为「头像 + 昵称 + ID」的可点击单元格,点击弹出用户详情:头像、昵称、头衔、待办/工单/笔记/团队数量、注册时间、最近活跃、拥有团队数。API 新增 GET /admin/users/:id,团队列表关联查询出 ownerNickname/ownerAvatar。

4. 项目专属排除规则 SQLite exclusion_rules 加了 project_id 列(唯一约束改为 (project_id, pattern),旧库自动重建迁移)。项目详情页「代码」标签下新增专属规则面板,可增删;扫描时全局规则 + 项目规则叠加生效。规则随项目身份上云,其它机器认领项目后自动带回。

5. 一句话 AI 生成待办/工单 待办页和工单页工具栏各嵌入一个 AI 生成输入条:一句话回车后由后端 AIGenerateTasks 调用 AI 拆解成多条草稿,弹预览框逐条勾选、可改标题/类型/优先级/日期,选归属项目后批量保存。

6. 项目云同步与认领

全局挂载了 CloudClaimModal:登录同步后发现云端有本机未落地的项目时自动弹出(同一批只打扰一次),每个项目可「选目录认领」或「忽略」;工作台横幅和个人主页可随时再打开。
统计数据按机器码推送到 stats:<机器码> 文档,只推不拉,不同电脑的扫描历史互不覆盖。
个人主页 · 云同步新增「项目云同步」区块:自动/手动模式切换(手动模式下常规同步跳过项目文档,仅点「立即同步项目」时推拉)、待认领入口、已忽略项目的恢复列表。
途中补齐了约 60 个中英双语 i18n 键,并修掉了 PortMonitor 引用但缺失的 pmSavedToast 键。
2026-08-17 09:04:53 +08:00

43 lines
1.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
// 自动刷新间隔选择0=不自动刷新(仅手动),其余为秒数。父组件负责持久化与定时器。
import { useI18n } from 'vue-i18n'
import { Timer } from 'lucide-vue-next'
defineProps({ modelValue: { type: Number, default: 30 } })
const emit = defineEmits(['update:modelValue'])
const { t } = useI18n()
const OPTIONS = [0, 5, 10, 30, 60, 120]
</script>
<template>
<label class="refresh-pick" :title="t('autoRefreshEvery')">
<Timer />
<select :value="modelValue" @change="emit('update:modelValue', Number($event.target.value))">
<option v-for="o in OPTIONS" :key="o" :value="o">{{ o === 0 ? t('refreshManualOnly') : t('refreshEveryN', { n: o }) }}</option>
</select>
</label>
</template>
<style scoped>
.refresh-pick {
display: inline-flex;
align-items: center;
gap: .35rem;
padding: 0 .55rem;
border: 1px solid var(--border);
border-radius: 10px;
background: var(--panel, transparent);
color: var(--muted);
}
.refresh-pick svg { width: 15px; height: 15px; }
.refresh-pick select {
border: 0;
background: transparent;
color: var(--text);
font-size: .85rem;
padding: .45rem 0;
outline: none;
cursor: pointer;
}
</style>