十一、【核心功能篇】测试用例管理:设计用例新增编辑界面

article/2025/8/3 16:31:30

【核心功能篇】测试用例管理:设计用例新增&编辑界面

    • 前言
      • 准备工作
      • 第一步:创建测试用例相关的 API 服务 (`src/api/testcase.ts`)
      • 第二步:创建测试用例编辑页面组件 (`src/views/testcase/TestCaseEditView.vue`)
      • 第三步:配置测试用例编辑页的路由
      • 第四步:测试用例新增&编辑功能
    • 总结

前言

一个好的测试用例编辑界面应该具备以下特点:

  • 清晰直观: 用户能够快速理解各个字段的含义和作用。
  • 高效易用: 能够方便地输入和修改信息,特别是对于重复性的测试步骤。
  • 结构化: 能够清晰地展示和管理测试步骤等复杂结构。
  • 可扩展性: (虽然本篇可能不完全覆盖)未来可以方便地增加对参数化、数据驱动、自定义关键字等高级功能的支持。

在我们的 Django 后端模型 (api/models.py中的 TestCase) 中,我们暂时将 steps_text 定义为一个 TextField,用于存储文本描述的测试步骤。为了实现一个更结构化的步骤编辑界面,前端在提交时需要将这些步骤组织成一种格式(例如 JSON 数组或特定分隔符的文本),而后端在保存或解析时需要能处理这种格式。

这篇文章将带你

  1. 规划测试用例编辑页面的整体布局和交互。
  2. 设计并实现一个能够动态添加、删除和编辑测试步骤的表单区域。
  3. 将测试用例的创建和编辑功能与后端 API 进行联调。

我们将重点放在前端界面的设计与实现,以及与后端 API 的数据交互上。

准备工作

  1. 前端项目就绪: test-platform/frontend 项目可以正常运行 (npm run dev)。
  2. 后端 API 运行中: Django 后端服务运行(python manage.py runserver),测试用例的 API (/api/testcases/) 可用。
  3. Axios 和 API 服务已封装: utils/request.tsapi/project.ts, api/module.ts 已配置好。
  4. 项目和模块管理功能可用: 我们需要先有项目和模块,才能创建测试用例。
  5. Element Plus 集成完毕。

第一步:创建测试用例相关的 API 服务 (src/api/testcase.ts)

与项目和模块类似,我们先为测试用例创建 API 服务文件。
在这里插入图片描述

// test-platform/frontend/src/api/testcase.ts
import request from '@/utils/request'
import type { AxiosPromise } from 'axios'// 与后端 TestCase model 和 TestCaseSerializer 对应
export interface TestCase {id: number;name: string;description: string | null;module: number; // 所属模块 IDmodule_name?: string; // 可选,如果 API 返回project_id?: number; // 可选,如果 API 返回project_name?: string; // 可选,如果 API 返回priority: 'P0' | 'P1' | 'P2' | 'P3';priority_display?: string;precondition: string | null;steps_text: string; // 后端存储的是合并后的文本expected_result: string;case_type: 'functional' | 'api' | 'ui';case_type_display?: string;maintainer: string | null;create_time: string;update_time: string;
}export type TestCaseListResponse = TestCase[] // 假设列表直接返回数组// 创建或更新测试用例时发送的数据类型
export interface UpsertTestCaseData {name: string;description?: string | null;module: number; // 必须priority?: 'P0' | 'P1' | 'P2' | 'P3';precondition?: string | null;steps_text: string; // 前端会将步骤数组合并为这个文本expected_result?: string;case_type?: 'functional' | 'api' | 'ui';maintainer?: string | null;
}// 1. 获取测试用例列表 (支持按模块或项目过滤)
export function getTestCaseList(params?: { module_id?: number, project_id?: number, search?: string }): AxiosPromise<TestCaseListResponse> {return request({url: '/testcases/',method: 'get',params})
}// 2. 创建测试用例
export function createTestCase(data: UpsertTestCaseData): AxiosPromise<TestCase> {return request({url: '/testcases/',method: 'post',data})
}// 3. 获取单个测试用例详情
export function getTestCaseDetail(testCaseId: number): AxiosPromise<TestCase> {return request({url: `/testcases/${testCaseId}/`,method: 'get'})
}// 4. 更新测试用例
export function updateTestCase(testCaseId: number, data: Partial<UpsertTestCaseData>): AxiosPromise<TestCase> {return request({url: `/testcases/${testCaseId}/`,method: 'put', // 或者 patchdata})
}// 5. 删除测试用例
export function deleteTestCase(testCaseId: number): AxiosPromise<void> {return request({url: `/testcases/${testCaseId}/`,method: 'delete'})
}

关键点:

  • UpsertTestCaseData 中的 steps_text 字段,前端会将动态编辑的多个步骤描述合并成一个字符串传递给它。
  • 类型定义应尽量与后端 DRF Serializer 的输入输出保持一致。

第二步:创建测试用例编辑页面组件 (src/views/testcase/TestCaseEditView.vue)

我们将创建一个新的路由页面专门用于新建和编辑测试用例。

a. 创建文件:
src/views/ 目录下创建 testcase 文件夹,并在其中创建 TestCaseEditView.vue
在这里插入图片描述

b. 编写 TestCaseEditView.vue 的基本结构和表单:
在这里插入图片描述

<!-- test-platform/frontend/src/views/testcase/TestCaseEditView.vue -->
<template><div class="testcase-edit-view" v-loading="pageLoading"><el-page-header @back="goBack" :content="pageTitle" class="page-header-custom" /><el-card class="form-card"><el-formref="testCaseFormRef":model="formData":rules="formRules"label-width="120px"label-position="right"><el-row :gutter="20"><el-col :span="12"><el-form-item label="用例名称" prop="name"><el-input v-model="formData.name" placeholder="请输入用例名称" /></el-form-item></el-col><el-col :span="12"><el-form-item label="所属模块" prop="module"><!-- 这里需要一个模块选择器,先用 Input 占位,后续改进 --><el-select v-model="formData.module" placeholder="请选择所属模块" filterablestyle="width: 100%;"@focus="fetchModulesForSelect" :loading="moduleSelectLoading"><el-optionv-for="item in moduleOptions":key="item.id":label="`${item.project_name} - ${item.name}`":value="item.id"/></el-select></el-form-item></el-col></el-row><el-form-item label="用例描述" prop="description"><el-input v-model="formData.description" type="textarea" placeholder="请输入用例描述" /></el-form-item><el-row :gutter="20"><el-col :span="12"><el-form-item label="优先级" prop="priority"><el-select v-model="formData.priority" placeholder="请选择优先级" style="width: 100%;"><el-option label="P0 - 最高" value="P0" /><el-option label="P1 - 高" value="P1" /><el-option label="P2 - 中" value="P2" /><el-option label="P3 - 低" value="P3" /></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="用例类型" prop="case_type"><el-select v-model="formData.case_type" placeholder="请选择用例类型" style="width: 100%;"><el-option label="功能测试" value="functional" /><el-option label="接口测试" value="api" /><el-option label="UI测试" value="ui" /></el-select></el-form-item></el-col></el-row><el-form-item label="维护人" prop="maintainer"><el-input v-model="formData.maintainer" placeholder="请输入维护人名称" /></el-form-item><el-form-item label="前置条件" prop="precondition"><el-input v-model="formData.precondition" type="textarea" :rows="2" placeholder="请输入前置条件" /></el-form-item><!-- 测试步骤区域 --><el-form-item label="测试步骤" prop="steps_text_ignored"> <!-- steps_text_ignored 仅用于触发表单项样式 --><div class="steps-editor"><div v-for="(step, index) in formData.steps" :key="index" class="step-item"><el-inputv-model="step.description"type="textarea":autosize="{ minRows: 1, maxRows: 4 }"placeholder="请输入步骤描述"class="step-input"/><el-buttontype="danger":icon="Delete"circlesize="small"@click="removeStep(index)"class="step-action-btn"v-if="formData.steps.length > 1"/></div><el-button type="primary" :icon="Plus" @click="addStep" plain size="small">添加步骤</el-button></div><!-- 隐藏的表单项,用于实际提交 steps_text,由 steps 数组生成 --><el-input v-model="computedStepsText" style="display: none;"></el-input></el-form-item><el-form-item label="预期结果" prop="expected_result"><el-input v-model="formData.expected_result" type="textarea" :rows="3" placeholder="请输入预期结果" /></el-form-item><el-form-item><el-button type="primary" @click="handleSubmit" :loading="submitLoading">{{ isEditMode ? '更新用例' : '创建用例' }}</el-button><el-button @click="goBack">取消</el-button></el-form-item></el-form></el-card></div>
</template><script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElPageHeader } from 'element-plus' // 确保导入 ElPageHeader
import type { FormInstance, FormRules } from 'element-plus'
import { Plus, Delete } from '@element-plus/icons-vue'
import { createTestCase, getTestCaseDetail, updateTestCase, type UpsertTestCaseData,type TestCase
} from '@/api/testcase'
import { getModuleList, type Module as ApiModule } from '@/api/module' // 获取所有模块用于选择器interface FormStep {description: string;
}interface TestCaseFormData extends Omit<UpsertTestCaseData, 'steps_text'> {steps: FormStep[]; // 前端用步骤数组来编辑
}const route = useRoute()
const router = useRouter()const pageLoading = ref(false)
const submitLoading = ref(false)
const testCaseFormRef = ref<FormInstance>()const testCaseId = computed(() => route.params.id ? Number(route.params.id) : null)
const isEditMode = computed(() => !!testCaseId.value)
const pageTitle = computed(() => (isEditMode.value ? '编辑测试用例' : '新建测试用例'))// 所属模块选择器的数据
const moduleOptions = ref<ApiModule[]>([])
const moduleSelectLoading = ref(false)const initialFormData: TestCaseFormData = {name: '',description: null,module: undefined as number | undefined, // 确保初始为 undefined 以便 placeholder 显示priority: 'P1',precondition: null,steps: [{ description: '' }], // 至少有一个空步骤expected_result: '',case_type: 'functional',maintainer: null,
}
const formData = reactive<TestCaseFormData>({ ...initialFormData })const formRules = reactive<FormRules>({name: [{ required: true, message: '用例名称不能为空', trigger: 'blur' }],module: [{ required: true, message: '请选择所属模块', trigger: 'change' }],priority: [{ required: true, message: '请选择优先级', trigger: 'change' }],steps: [{ // 对 steps 数组的校验 (虽然我们主要校验合并后的 steps_text)type: 'array', required: true, validator: (rule, value, callback) => {if (!value || value.length === 0 || value.every((step: FormStep) => !step.description.trim())) {callback(new Error('测试步骤不能为空'));} else {callback();}}, trigger: 'change' }],expected_result: [{ required: true, message: '预期结果不能为空', trigger: 'blur' }],
})// 将步骤数组转换为提交给后端的 steps_text 字符串
const computedStepsText = computed(() => {return formData.steps.map(step => step.description.trim()).filter(desc => desc).join('\n');
})// 加载模块列表给选择器
const fetchModulesForSelect = async () => {if (moduleOptions.value.length > 0 && !isEditMode.value) return; // 避免重复加载 (新建时如果已有数据则不重载)// 编辑时可能需要强制重载,或当模块列表不常变时缓存moduleSelectLoading.value = true;try {// 这里获取所有模块,实际项目中可能需要分页或搜索// 如果模块非常多,这里需要优化,例如使用远程搜索的 Selectconst response = await getModuleList(); // 这个 getModuleList 需要支持不传 projectId 获取所有moduleOptions.value = response.data;} catch (error) {console.error('获取模块列表失败:', error);ElMessage.error('获取模块列表失败');} finally {moduleSelectLoading.value = false;}
}// 加载用例详情 (编辑模式)
const loadTestCaseDetail = async () => {if (!isEditMode.value || !testCaseId.value) returnpageLoading.value = truetry {const response = await getTestCaseDetail(testCaseId.value)const dataFromServer = response.data// 回填表单数据formData.name = dataFromServer.nameformData.description = dataFromServer.descriptionformData.module = dataFromServer.moduleformData.priority = dataFromServer.priorityformData.precondition = dataFromServer.preconditionformData.expected_result = dataFromServer.expected_resultformData.case_type = dataFromServer.case_typeformData.maintainer = dataFromServer.maintainer// 将 steps_text 解析回步骤数组if (dataFromServer.steps_text) {formData.steps = dataFromServer.steps_text.split('\n').map(desc => ({ description: desc }))if (formData.steps.length === 0) { // 保证至少有一个空步骤输入框formData.steps.push({ description: '' });}} else {formData.steps = [{ description: '' }]}// 确保模块选择器中有当前模块的选项,如果没有,需要手动获取一次模块列表(或者在 fetchModulesForSelect 中处理)if (formData.module && !moduleOptions.value.find(m => m.id === formData.module)) {await fetchModulesForSelect(); // 重新获取模块列表以确保包含当前模块}} catch (error) {ElMessage.error('获取用例详情失败')console.error(error)} finally {pageLoading.value = false}
}onMounted(async () => {await fetchModulesForSelect(); // 先加载模块选项if (isEditMode.value) {await loadTestCaseDetail()}
})// 动态步骤管理
const addStep = () => {formData.steps.push({ description: '' })
}
const removeStep = (index: number) => {if (formData.steps.length > 1) {formData.steps.splice(index, 1)} else {ElMessage.warning('至少需要一个测试步骤')}
}const handleSubmit = async () => {if (!testCaseFormRef.value) returnawait testCaseFormRef.value.validate(async (valid) => {if (valid) {// 再次校验 steps 是否真的有内容(因为 formRules 对数组的校验可能不够精细)if (!computedStepsText.value.trim()) {ElMessage.error('测试步骤描述不能为空');return;}submitLoading.value = trueconst dataToSubmit: UpsertTestCaseData = {name: formData.name,description: formData.description,module: formData.module!, // module 是必填的,这里可以用 ! 断言priority: formData.priority,precondition: formData.precondition,steps_text: computedStepsText.value, // 使用合并后的文本expected_result: formData.expected_result,case_type: formData.case_type,maintainer: formData.maintainer,}try {if (isEditMode.value && testCaseId.value) {await updateTestCase(testCaseId.value, dataToSubmit)ElMessage.success('测试用例更新成功!')} else {await createTestCase(dataToSubmit)ElMessage.success('测试用例创建成功!')}// 成功后可以跳转到用例列表页或详情页// router.push(`/testcases/list?moduleId=${formData.module}`) // 假设有列表页router.push({ name: 'testcases', query: { moduleId: formData.module } }) // 假设列表页路由名为 'testcases'} catch (error) {console.error('用例操作失败:', error)// 全局错误提示已处理} finally {submitLoading.value = false}} else {ElMessage.error('请检查表单填写是否正确!')return false}})
}const goBack = () => {router.back()
}
</script><style scoped lang="scss">
.testcase-edit-view {padding: 20px;
}
.page-header-custom {margin-bottom: 20px;background-color: #fff;padding: 16px 24px;border-radius: 4px;box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.form-card {padding: 20px;
}.steps-editor {width: 100%;.step-item {display: flex;align-items: center;margin-bottom: 10px;.step-input {flex-grow: 1;margin-right: 10px;}.step-action-btn {// flex-shrink: 0; // 防止按钮被压缩}}
}
</style>

代码解释与关键点:

  • 整体布局: 使用 ElPageHeader 提供返回和标题,ElCard 包裹表单。
  • 表单字段: 根据 TestCase 模型定义了各个输入项。
    • 所属模块 (formData.module):
      • 使用 el-select
      • moduleOptions 通过调用 getModuleList() API (在 api/module.ts 中) 来获取所有模块(这里暂时获取所有,实际项目可能需要优化为按项目筛选或远程搜索)。
      • fetchModulesForSelect 在组件挂载时以及 Select 获得焦点时(如果选项为空)被调用。
      • 重要: api/module.ts 中的 getModuleList 函数需要能够不传 projectId 时返回所有模块,或者你需要一个新的 API 来获取所有模块。这里假设 getModuleList() 可以无参数调用以获取所有模块。
  • 动态测试步骤 (formData.steps):
    • formData.steps 是一个响应式数组,每个元素是 { description: string } 对象。
    • 使用 v-for 渲染每个步骤的输入框和删除按钮。
    • addStep() 方法向数组中添加一个新的空步骤。
    • removeStep(index) 方法从数组中删除指定索引的步骤(至少保留一个)。
    • computedStepsText 这是一个计算属性,它将 formData.steps 数组中的 description 合并成一个用换行符 \n 分隔的字符串。这个计算属性的值将用于赋值给提交给后端的 steps_text 字段。我们在模板中添加了一个隐藏的 el-input 绑定到它,主要是为了方便调试时查看,实际提交时我们直接用这个计算属性的值。
    • 表单校验 (formRules.steps): 我们为 steps 数组添加了一个自定义校验器,确保至少有一个步骤并且步骤描述不全为空。
  • 编辑模式 (isEditMode):
    • 通过 route.params.id 判断当前是新建还是编辑模式。
    • pageTitle 动态显示。
    • onMounted 中,如果是编辑模式,则调用 loadTestCaseDetail()
  • loadTestCaseDetail()
    • 调用 getTestCaseDetail API 获取用例数据。
    • 回填表单各个字段。
    • 解析 steps_text 将从后端获取的 steps_text 字符串按换行符分割,转换回 formData.steps 数组。
    • 模块选择器回显: 确保在编辑时,如果 formData.module 有值,moduleOptions 中包含该选项,否则 Select 可能无法正确显示已选模块。如果 moduleOptions 中没有,则重新调用 fetchModulesForSelect
  • handleSubmit()
    • 表单校验。
    • 特别校验 computedStepsText 确保合并后的步骤文本不为空。
    • 构造提交给后端的数据 dataToSubmit,其中 steps_text 使用 computedStepsText.value
    • 根据 isEditMode 调用 createTestCaseupdateTestCase API。
    • 成功后跳转到用例列表页 (我们暂时假设用例列表页的路由名为 testcases,并且可以通过 moduleId 查询参数筛选)。

修改 frontend/src/api/module.ts 中的 getModuleList

为了让模块选择器能获取所有模块,我们需要修改 api/module.ts 中的 getModuleList 函数,使其在不传递 projectId 时能获取所有模块。

假设后端 /api/modules/ 在没有 project_id 参数时返回所有模块,那么前端 getModuleList 可以这样:
在这里插入图片描述

// test-platform/frontend/src/api/module.ts
// ...
// 1. 获取模块列表 (支持按项目ID过滤,不传则获取所有)
export function getModuleList(projectId?: number): AxiosPromise<ModuleListResponse> {const params: { project_id?: number } = {};if (projectId) {params.project_id = projectId;}return request({url: '/modules/',method: 'get',params // 如果 projectId 未定义,则 params 为空对象,不传 project_id 参数})
}
// ...

后端 DRF ModuleViewSet 的相应调整:

确保 ModuleViewSetget_queryset 方法在 project_id 未提供时返回所有模块。目前的实现(在上一篇文章中修改的)已经是这样了,如果 project_idNone,则不过滤。
在这里插入图片描述

# api/views.py -> ModuleViewSet
class ModuleViewSet(viewsets.ModelViewSet):# ...def get_queryset(self):queryset = super().get_queryset()project_id = self.request.query_params.get('project_id', None) # 修改这里,如果没传,project_id 为 Noneif project_id is not None: # 只有当 project_id 实际传递了才过滤try:queryset = queryset.filter(project_id=int(project_id))except ValueError:pass return queryset.order_by('-create_time')

第三步:配置测试用例编辑页的路由

打开 frontend/src/router/index.ts,添加新建和编辑测试用例的路由。
在这里插入图片描述

// test-platform/frontend/src/router/index.ts
// ... (在 Layout 的 children 中添加){path: '/testcases', // 用例列表页 (我们将在下一篇创建)name: 'testcases',component: () => import('../views/project/TestCaseListView.vue'),meta: { title: '用例管理', requiresAuth: true }},{path: '/testcase/create', // 新建用例name: 'testcaseCreate',component: () => import('../views/testcase/TestCaseEditView.vue'),meta: { title: '新建测试用例', requiresAuth: true }},{path: '/testcase/edit/:id', // 编辑用例,:id 是用例IDname: 'testcaseEdit',component: () => import('../views/testcase/TestCaseEditView.vue'),meta: { title: '编辑测试用例', requiresAuth: true },props: true // 将路由参数 id 作为 props 传递给组件 (虽然我们组件内主要用 route.params)},
// ...

说明:

  • 我们为新建 (/testcase/create) 和编辑 (/testcase/edit/:id) 都指向了同一个 TestCaseEditView.vue 组件。组件内部通过 route.params.id 是否存在来区分模式。
  • 为编辑路由启用了 props: true,虽然我们当前组件实现主要依赖 useRoute(),但这是一个好习惯。

第四步:测试用例新增&编辑功能

  1. 确保前后端服务运行,CORS 和 API 正常。
  2. 测试新建用例:
    • 访问 http://127.0.0.1:5173/testcase/create

    • 填写表单,包括选择所属模块,添加几个测试步骤。

    • 点击“创建用例”。
      在这里插入图片描述

    • 观察 Network 面板的 API 请求 (POST /api/testcases/),查看请求体中的 steps_text 是否是合并后的字符串。
      在这里插入图片描述

    • 看是否成功创建并跳转 (跳转目标页 TestCaseListView.vue 尚不存在,会显示空白,但 API 调用是会成功的)。
      在这里插入图片描述

    • 去 Django Admin 或通过 API 确认用例已创建,steps_text 已保存。

  3. 测试编辑用例 (需要先通过 API 或 Django Admin 创建一个用例):
    • 在上面我创建了一个 ID 为 3 的用例。

    • 访问 http://127.0.0.1:5173/testcase/edit/3

    • 页面应加载该用例的数据,表单应被回填,测试步骤应被正确解析并显示。
      在这里插入图片描述

    • 修改数据,例如增删步骤,修改其他字段。

    • 点击“更新用例”。

    • 观察 Network 面板的 API 请求 (PUT /api/testcases/3/)。

    • 确认更新成功。
      在这里插入图片描述

总结

在这篇文章中,我们攻克了测试用例管理中复杂的编辑界面设计与实现:

  • 为测试用例创建了相应的 API 服务函数 (api/testcase.ts) 和 TypeScript 类型。
  • 设计并实现了 TestCaseEditView.vue 组件,用于新建和编辑测试用例,其核心特性包括:
    • 一个包含用例名称、描述、所属模块选择器、优先级、类型、前置条件、预期结果等字段的综合表单。
    • 一个动态的测试步骤编辑区域,用户可以方便地添加、删除和编辑多个步骤描述。
    • 将前端编辑的步骤数组通过计算属性 computedStepsText 合并为后端 steps_text 字段所需的单一字符串。
    • 在编辑模式下,能够从后端 API 获取用例详情,并将 steps_text 解析回步骤数组以供编辑。
  • 配置了新建和编辑测试用例的路由。
  • 指导了如何测试新建和编辑用例的完整流程,并与后端 API 进行了联调。
  • 解决了模块选择器的数据加载和编辑时选项回显的问题。

测试用例的创建和编辑是测试平台的核心功能,一个良好设计的界面能极大地提升测试人员的效率。

在下一篇文章中,我们将实现测试用例的列表展示与搜索功能 (TestCaseListView.vue),让用户能够方便地查看、筛选和查找已创建的测试用例,并从列表跳转到编辑页面。


http://www.hkcw.cn/article/qDcfMTaQjY.shtml

相关文章

YC-8002型综合变配电监控自动化系统

一 .系统概述 YC-8002型综合变配电监控自动化系统是西安亚川电力科技有限公司为适应广大客户要求&#xff0c;总结多项低 压配电网络自动化工程实例的经验&#xff0c;基于先进的电子技术、计算机和网络通讯等技术自主研发的--套结合本公司网络配电产品的应用于低压配电领域的…

DeviceNET转EtherCAT网关:医院药房自动化的智能升级神经中枢

在现代医院药房自动化系统中&#xff0c;高效、精准、可靠的设备通信是保障患者用药安全与效率的核心。当面临既有支持DeviceNET协议的传感器、执行器&#xff08;如药盒状态传感器、机械臂限位开关&#xff09;需接入先进EtherCAT高速实时网络时&#xff0c;JH-DVN-ECT疆鸿智能…

股指期货出现大幅贴水时,为什么不适合套期保值?

先简单说下股指期货贴水。股指期货有个理论价格&#xff0c;正常情况下&#xff0c;期货价格和理论价格应该是差不多的。但要是期货价格比理论价格低了不少&#xff0c;这就叫贴水。就好比一件衣服&#xff0c;本来标价100元&#xff0c;现在市场上只卖80元&#xff0c;这就是贴…

脱发因素机器学习数据分析

脱发因素机器学习数据分析 一、背景描述 随着年龄增长&#xff0c;脱发成为影响外貌与健康的重要问题。 本数据集包含遗传、荷尔蒙变化、医疗状况、药物治疗、营养缺乏、心理压力等12个可能导致脱发的因素&#xff0c; 旨在通过数据分析挖掘各因素与脱发的潜在关联&#xf…

Transformer架构技术学习笔记:从理论到实战的完整解析

引言&#xff1a;重新定义序列建模的里程碑 2017年&#xff0c;Vaswani等人在论文《Attention Is All You Need》中提出的Transformer架构&#xff0c;彻底改变了自然语言处理领域的游戏规则。与传统RNN/LSTM相比&#xff0c;Transformer具有三大革命性特征&#xff1a; 全注意…

从0开始学习R语言--Day12--泊松分布

今天我们来看一个很经典的回归模型&#xff1a;泊松分布。 泊松分布 我们一般会把泊松分布用于预测问题&#xff0c;比如想知道成年人每天接到的骚扰电话次数&#xff0c;医院每天的急诊病人等。但在一些方面&#xff0c;跟我们想的会有出入。例如你不能将其应用在预测下周你的…

机器学习无监督学习sklearn实战一:K-Means 算法聚类对葡萄酒数据集进行聚类分析和可视化( 主成分分析PCA特征降维)

本项目代码在个人github链接&#xff1a;https://github.com/KLWU07/Machine-learning-Project-practice/tree/main/1-Wine%20cluster%20analysis 如果对于聚类算法理论不理解可参考这篇之前文章机器学习中无监督学习方法的聚类&#xff1a;划分式聚类、层次聚类、密度聚类&…

接口的概念及特性

目录 1、接口的概念2、语法规则2.1 接口的定义2.2、接口的使用 3、特性4、实现多个接口5、接口中的继承6、接口使用实例 1、接口的概念 在现实生活中&#xff0c;接口的例子有很多&#xff0c;比如&#xff1a;笔记本的 USB 接口&#xff0c;电源插座等。在电脑的 USB 口上&am…

品牌控价维护渠道生态与品牌价值的关键

在品牌发展的征程中&#xff0c;随着经销商队伍不断壮大&#xff0c;价格管控已成为关乎品牌存亡的核心命题。价格体系一旦失控&#xff0c;渠道乱象便如潮水般涌来。低价倾销不仅挤压正规经销商的生存空间&#xff0c;削弱其市场竞争力&#xff0c;更会引发消费者对产品价值的…

2011肠衣问题

1 D类竞赛题目---具体题目 D题 天然肠衣搭配问题 天然肠衣&#xff08;以下简称肠衣&#xff09;制作加工是我国的一个传统产业&#xff0c;出口量占世界首位。肠衣经过清洗整理后被分割成长度不等的小段&#xff08;原料&#xff09;&#xff0c;进入组装工序。 传统的生产…

Express教程【001】:Express创建基本的Web服务器

文章目录 1、初识express1.1 什么是Express1.2 主要特点1.3 Express的基本使用1.3.1 安装1.3.2 创建基本的Web服务器 1、初识express 目标&#xff1a; 能够使用express.static()快速托管静态资源能够使用express路由精简项目结构能够使用常见的express中间件能够使用express创…

CentOS 7 环境中部署 LNMP(Linux + Nginx + MySQL 5.7 + PHP)

在 CentOS 7 环境中部署 LNMP&#xff08;Linux Nginx MySQL 5.7 PHP&#xff09; 环境的详细步骤如下。此方案确保各组件版本兼容&#xff0c;并提供完整的配置验证流程。 1. 更新系统 sudo yum update -y 2. 安装 MySQL 5.7 2.1 添加 MySQL 官方 YUM 仓库 由于MySQL并不…

从零打造算法题刷题助手:Agent搭建保姆级攻略

我用Trae 做了一个有意思的Agent 「大厂机试助手」。 点击 https://s.trae.com.cn/a/d2a596 立即复刻&#xff0c;一起来玩吧&#xff01; Agent 简介 Agent名称为大厂机试助手&#xff0c;主要功能有以下三点。 解题&#xff1a; 根据用户给出的题目给出具体的解题思路引导做…

华院计算出席信创论坛,分享AI教育创新实践并与燧原科技共同推出教育一体机

5月21日&#xff0c;信创论坛于上海漕河泾会议中心举办。本次论坛以“聚力融合&#xff0c;繁荣生态”为主题&#xff0c;话题聚焦工业制造、交通运输、金融、教育、医疗等领域。华院计算技术&#xff08;上海&#xff09;股份有限公司&#xff08;以下简称“华院计算”&#x…

MyBatis操作数据库

1.MyBatis:MyBatis是一款优秀的持久层框架,用于简化JDBC的开发.(持久层通常指数据访问层,用来操作数据库). 创建userInfo表,并插入如下数据: 在model中建立userinfo实体类,属性与之一一对应. 配置数据库连接字符串,Mybatis中要连接数据库,需要数据库相关参数配置. 接下来就可…

OCC笔记:BRepMesh_IncrementalMesh的使用

1. 函数接口 2. 线性偏转与角度偏转 2.1. theLineDeflection&#xff1a;线性偏转 根据文档推导下 isRelative传入Standard_True时&#xff0c;theLineDeflection为相对值。 参看isRelative说明 //! param isRelative if TRUE deflection used for discretization of //! ea…

调试技巧总结

目录 一.调试1.什么是调试2.调试语义的分类2.1 静态语义2.2 动态语义 二.实用的调试技巧1.屏蔽代码2.借助打印3.查看汇编代码4.调试技巧总结 一.调试 1.什么是调试 调试&#xff0c;通俗易懂地说就是不断排查代码的错误&#xff0c;进行修正的过程&#xff0c;在写代码的时候…

通过实时动作捕捉加速人形机器人训练

通过实时动作捕捉加速人形机器人训练 用于训练、控制和性能优化的精确实时运动学——受到全球机器人创新者的信赖&#xff01; 为什么选择 Xsens 进行人形机器人训练&#xff1f; 无与伦比的运动数据精度-经过科学验证的运动数据&#xff0c;用于简化AI/ML训练。 轻松集成到…

【UE5 C++】绘制地表贴合线

目录 原理 效果 步骤 源码 原理 先设置绘制线段的起点和终点&#xff0c;然后我们将起点和终点的高度升高&#xff0c;然后通过插值&#xff0c;在起点和终点之间添加多个点&#xff0c;再由这些点向地心发出射线&#xff0c;这样我们就可以获取到这些点在地表的投影点&…

01 redis 的环境搭建

前言 这一系列文章主要包含的内容主要是 各种常用软件的调试环境的搭建 主要的目的是 搭建一个可打断点的一个调试环境 c 系列 主要是基于 clion 调试, java 系列主要是基于 idea 调试, js 系列主要是基于 webstorm 调试 需要有一定的 c, c, java, js 相关基础 基于的…