Skip to content

Conversation

@aice030
Copy link
Collaborator

@aice030 aice030 commented Oct 10, 2025

变更背景和解决方案

关联issue: #

文档更新(架构文档、API文档、升级文档)

Checklist

  • 确认是否有文档更新
  • 确认是否自测
  • 确认是否考虑兼容升级,不兼容升级需要有对应的解决方案
  • 确认是否考虑添加监控指标
  • API 设计是否符合 API 设计规范, 如果没有 API 变更,请忽略
  • 我已经添加了相关人员到 Reviewers 列表中
  • 我已经设置了 Development 关联的 Issue

# Conflicts:
#	client/README.md
#	client/package.json
#	client/src/api/index.ts
#	client/src/mock/api.ts
#	client/src/mock/services.ts
#	client/src/router/index.ts
#	client/src/stores/app.ts
#	client/src/views/ChangeLogView.vue
#	client/src/views/HomeView.vue
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @aice030, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求旨在将前端应用程序从使用模拟数据接口全面迁移到使用后端提供的真实API接口。这一变更确保了应用程序能够获取和展示实时、准确的数据,并支持实际的部署操作,从而使前端功能与后端服务完全集成,提升了系统的整体功能性和可靠性。

Highlights

  • API 调用切换: 将前端所有对模拟API的调用全面切换为对后端真实API的调用,确保数据实时性和操作的有效性。
  • 数据获取逻辑更新: 更新了 ChangeLogView.vueHomeView.vue 中多个数据加载函数(如服务数据、服务详情、指标、可用版本、部署计划等),使其使用 apiService 获取数据,并正确处理 response.data 结构。
  • 部署操作重构: 重构了 HomeView.vue 中创建发布、取消部署、暂停/继续部署、回滚发布以及版本级别的暂停/继续和回滚功能,使其通过 apiService 与后端交互,并移除了所有模拟数据操作及相关逻辑。
  • 依赖清理: 移除了 go.mod 中对 github.com/gin-gonic/gin 的间接依赖。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@Erickw87 Erickw87 merged commit 98bac4e into qiniu:develop Oct 10, 2025
1 check passed
@github-actions
Copy link

🚀 Frontend deployed successfully!

📱 Preview URL: https://zeroops-6t0e4gvvx-liuscrafts-projects.vercel.app

✅ Build completed successfully

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

本次 PR 主要将前端的 mock API 调用切换为真实的后端 API 调用,整体实现正确。这是一个很好的进步!为了进一步提升代码质量和性能,我提出了一些建议。主要集中在 HomeView.vue 文件中,我发现多处在执行操作后重新加载数据的逻辑,这些网络请求是串行执行的,可以通过 Promise.all 并行化来提升性能。此外,部分函数参数使用了 any 类型,建议定义明确的接口以增强类型安全。代码中还存在一些用于调试的 console.log 语句,建议在最终合并前移除。具体的修改建议请见评论。

Comment on lines +1153 to 1179
// 重新加载服务详情数据(饼状图会自动更新
const serviceDetailResult = await loadServiceDetail(selectedNode.value.name)
console.log('重新加载的服务详情数据:', serviceDetailResult)
if (serviceDetailResult) {
selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
console.log('更新后的selectedNode.value:', selectedNode.value)
}
// 3. 重新加载可发布版本数据(这样下拉框会自动更新
// 重新加载可发布版本数据(下拉框会自动更新
const availableVersionsResult = await loadServiceAvailableVersions(selectedNode.value.name)
if (availableVersionsResult) {
currentServiceAvailableVersions.value = availableVersionsResult
}
// 4. 生成合理的黄金指标数值并更新表格
const generateMetrics = () => {
return {
latency: (Math.random() * 50 + 10).toFixed(1), // 10-60ms
traffic: (Math.random() * 1000 + 100).toFixed(0), // 100-1100 req/s
errorRatio: (Math.random() * 2).toFixed(1), // 0-2%
saturation: (Math.random() * 20 + 60).toFixed(0) // 60-80%
}
// 重新加载服务指标数据
const metricsDataResult = await loadServiceMetrics(selectedNode.value.name)
if (metricsDataResult) {
currentServiceMetrics.value = metricsDataResult
}
const newMetrics = generateMetrics()
// 直接更新当前服务的指标数据
if (currentServiceMetrics.value) {
// 添加新版本的指标数据
const newVersionMetrics = {
version: selectedVersion.value,
metrics: [
{ name: 'latency', value: parseFloat(newMetrics.latency) },
{ name: 'traffic', value: parseFloat(newMetrics.traffic) },
{ name: 'errorRatio', value: parseFloat(newMetrics.errorRatio) },
{ name: 'saturation', value: parseFloat(newMetrics.saturation) }
]
}
// 检查是否已存在该版本,如果存在则更新,否则添加
const existingIndex = currentServiceMetrics.value.items.findIndex(item => item.version === selectedVersion.value)
if (existingIndex >= 0) {
currentServiceMetrics.value.items[existingIndex] = newVersionMetrics
} else {
currentServiceMetrics.value.items.push(newVersionMetrics)
}
// 更新summary数据(使用所有版本的平均值)
const allVersions = currentServiceMetrics.value.items
const avgLatency = allVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'latency')?.value || 0), 0) / allVersions.length
const avgTraffic = allVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'traffic')?.value || 0), 0) / allVersions.length
const avgErrorRatio = allVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'errorRatio')?.value || 0), 0) / allVersions.length
const avgSaturation = allVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'saturation')?.value || 0), 0) / allVersions.length
currentServiceMetrics.value.summary.metrics = [
{ name: 'latency', value: avgLatency },
{ name: 'traffic', value: avgTraffic },
{ name: 'errorRatio', value: avgErrorRatio },
{ name: 'saturation', value: avgSaturation }
]
// 重新加载发布计划列表
const deploymentPlansDataResult = await loadServiceDeploymentPlans(selectedNode.value.name)
if (deploymentPlansDataResult) {
currentServiceDeploymentPlans.value = deploymentPlansDataResult
}
// 5. 重新加载服务数据以更新拓扑图
// 重新加载服务数据以更新拓扑图
await loadServicesData()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这里的多个 await 会导致数据串行加载,影响性能。建议使用 Promise.all 来并行加载这些数据,可以有效减少等待时间。

    // 并行重新加载数据以提升性能
    const serviceName = selectedNode.value.name;
    const [
        serviceDetailResult,
        availableVersionsResult,
        metricsDataResult,
        deploymentPlansDataResult
    ] = await Promise.all([
        loadServiceDetail(serviceName),
        loadServiceAvailableVersions(serviceName),
        loadServiceMetrics(serviceName),
        loadServiceDeploymentPlans(serviceName)
    ]);

    if (serviceDetailResult) {
      selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
    }
    if (availableVersionsResult) {
      currentServiceAvailableVersions.value = availableVersionsResult
    }
    if (metricsDataResult) {
      currentServiceMetrics.value = metricsDataResult
    }
    if (deploymentPlansDataResult) {
      currentServiceDeploymentPlans.value = deploymentPlansDataResult
    }
    
    // 重新加载服务数据以更新拓扑图
    await loadServicesData()

editForm.value.scheduleTime = ''
}
const confirmCancel = async (plan: any) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

参数 plan 的类型被定义为 any,这会降低代码的可读性和类型安全性。建议为 deploymentPlansForDisplay 计算属性返回的计划对象定义一个明确的 interface,并在使用它的函数(如 confirmCancel, togglePauseResume, rollbackRelease)中应用该类型。

例如:

interface DisplayDeploymentPlan {
  id: string;
  service: string;
  version: string;
  status: string;
  time: string;
  originalStatus: 'Schedule' | 'InDeployment' | 'Finished';
  isPaused: boolean;
  scheduleTime?: string;
}

const confirmCancel = async (plan: DisplayDeploymentPlan) => {
  // ...
}

Comment on lines +1301 to 1313
// 刷新发布计划列表和服务详情
if (selectedNode.value) {
const deploymentPlansDataResult = await loadServiceDeploymentPlans(selectedNode.value.name)
if (deploymentPlansDataResult) {
currentServiceDeploymentPlans.value = deploymentPlansDataResult
}
// 刷新服务详情数据(饼图会自动更新)
const serviceDetailResult = await loadServiceDetail(selectedNode.value.name)
if (serviceDetailResult) {
selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这里的两个 await 会导致数据串行加载。建议使用 Promise.all 来并行加载,以提升性能。

    // 并行刷新发布计划列表和服务详情以提升性能
    if (selectedNode.value) {
      const [deploymentPlansDataResult, serviceDetailResult] = await Promise.all([
        loadServiceDeploymentPlans(selectedNode.value.name),
        loadServiceDetail(selectedNode.value.name)
      ])
      
      if (deploymentPlansDataResult) {
        currentServiceDeploymentPlans.value = deploymentPlansDataResult
      }
      
      if (serviceDetailResult) {
        selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
      }
    }

}
// 版本表格中的操作
const togglePauseResumeForVersion = async (version: any) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

参数 version 的类型被定义为 any。为了提高代码质量,建议为 getVersionTableData 返回的版本对象定义一个明确的 interface,并在 togglePauseResumeForVersionrollbackVersion 函数中使用它。

例如:

interface VersionTableItem {
  version: string;
  latency: number;
  traffic: number;
  errors: string;
  saturation: number;
  status: string;
  isPaused: boolean;
  deployId: string;
}

const togglePauseResumeForVersion = async (version: VersionTableItem) => {
  // ...
}

Comment on lines +1335 to 1347
// 重新加载服务详情数据以更新UI
if (selectedNode.value) {
await loadServiceDetail(selectedNode.value.name)
const serviceDetailResult = await loadServiceDetail(selectedNode.value.name)
if (serviceDetailResult) {
selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
}
// 重新加载发布计划列表
const deploymentPlansDataResult = await loadServiceDeploymentPlans(selectedNode.value.name)
if (deploymentPlansDataResult) {
currentServiceDeploymentPlans.value = deploymentPlansDataResult
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

与其它地方类似,这里的数据加载也是串行的。建议使用 Promise.all 并行加载以优化性能。

    // 并行重新加载服务详情和发布计划以更新UI和提升性能
    if (selectedNode.value) {
      const [serviceDetailResult, deploymentPlansDataResult] = await Promise.all([
        loadServiceDetail(selectedNode.value.name),
        loadServiceDeploymentPlans(selectedNode.value.name)
      ])

      if (serviceDetailResult) {
        selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
      }
      
      if (deploymentPlansDataResult) {
        currentServiceDeploymentPlans.value = deploymentPlansDataResult
      }
    }

Comment on lines +1361 to 1383
// 重新加载服务详情数据(饼状图会自动更新
if (selectedNode.value) {
const serviceDetailResult = await loadServiceDetail(selectedNode.value.name)
if (serviceDetailResult) {
selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
}
}
// 3. 重新加载可发布版本数据(这样下拉框会自动更新
// 重新加载可发布版本数据(下拉框会自动更新
if (selectedNode.value) {
const availableVersionsResult = await loadServiceAvailableVersions(selectedNode.value.name)
if (availableVersionsResult) {
currentServiceAvailableVersions.value = availableVersionsResult
}
}
// 4. 从指标数据中移除该版本
if (currentServiceMetrics.value) {
const versionIndex = currentServiceMetrics.value.items.findIndex(item => item.version === version.version)
if (versionIndex >= 0) {
currentServiceMetrics.value.items.splice(versionIndex, 1)
// 更新summary数据(使用剩余版本的平均值)
const remainingVersions = currentServiceMetrics.value.items
if (remainingVersions.length > 0) {
const avgLatency = remainingVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'latency')?.value || 0), 0) / remainingVersions.length
const avgTraffic = remainingVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'traffic')?.value || 0), 0) / remainingVersions.length
const avgErrorRatio = remainingVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'errorRatio')?.value || 0), 0) / remainingVersions.length
const avgSaturation = remainingVersions.reduce((sum, v) => sum + (v.metrics.find(m => m.name === 'saturation')?.value || 0), 0) / remainingVersions.length
currentServiceMetrics.value.summary.metrics = [
{ name: 'latency', value: avgLatency },
{ name: 'traffic', value: avgTraffic },
{ name: 'errorRatio', value: avgErrorRatio },
{ name: 'saturation', value: avgSaturation }
]
} else {
// 如果没有剩余版本,清空summary数据
currentServiceMetrics.value.summary.metrics = [
{ name: 'latency', value: 0 },
{ name: 'traffic', value: 0 },
{ name: 'errorRatio', value: 0 },
{ name: 'saturation', value: 0 }
]
}
// 重新加载服务指标数据
if (selectedNode.value) {
const metricsDataResult = await loadServiceMetrics(selectedNode.value.name)
if (metricsDataResult) {
currentServiceMetrics.value = metricsDataResult
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这里的多个 if 判断和串行 await 可以合并优化。使用 Promise.all 并行加载数据,并整合 if (selectedNode.value) 判断,可以使代码更简洁高效。

    // 并行重新加载数据以提升性能
    if (selectedNode.value) {
      const serviceName = selectedNode.value.name
      const [serviceDetailResult, availableVersionsResult, metricsDataResult] = await Promise.all([
        loadServiceDetail(serviceName),
        loadServiceAvailableVersions(serviceName),
        loadServiceMetrics(serviceName)
      ])

      if (serviceDetailResult) {
        selectedNode.value = { ...serviceDetailResult, status: getNodeStatus(serviceDetailResult) }
      }
      if (availableVersionsResult) {
        currentServiceAvailableVersions.value = availableVersionsResult
      }
      if (metricsDataResult) {
        currentServiceMetrics.value = metricsDataResult
      }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants