<!-- ProjectManagement.vue -->
<template>
<div class="project-management">
<el-button @click="openEditDialog">新建项目</el-button>
<el-table :data="projects">
<el-table-column prop="name" label="项目名称" />
<el-table-column prop="description" label="描述" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button @click="openEditDialog(row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<EditProjectDialog
v-model:visible="editDialogVisible"
:project="currentProject"
@update="handleProjectUpdate"
/>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import EditProjectDialog from './EditProjectDialog.vue'
import { Project } from '../types'
import { getProjects, updateProject, createProject } from '../api/projectApi'
const projects = ref<Project[]>([])
const editDialogVisible = ref(false)
const currentProject = reactive<Project>({
id: '',
name: '',
description: '',
softwarePackage: null
})
const fetchProjects = async () => {
try {
projects.value = await getProjects()
} catch (error) {
ElMessage.error('获取项目列表失败')
}
}
const openEditDialog = (project?: Project) => {
if (project) {
Object.assign(currentProject, project)
} else {
Object.assign(currentProject, { id: '', name: '', description: '', softwarePackage: null })
}
editDialogVisible.value = true
}
const handleProjectUpdate = async (updatedProject: Project) => {
try {
if (updatedProject.id) {
await updateProject(updatedProject)
ElMessage.success('项目更新成功')
} else {
await createProject(updatedProject)
ElMessage.success('项目创建成功')
}
fetchProjects()
editDialogVisible.value = false
} catch (error) {
ElMessage.error('操作失败')
}
}
fetchProjects()
</script>
接下来是编辑弹框组件:
<!-- EditProjectDialog.vue -->
<template>
<el-dialog
v-model="dialogVisible"
title="编辑项目"
@close="handleClose"
>
<el-form :model="form" label-width="120px">
<el-form-item label="项目名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" type="textarea" />
</el-form-item>
<el-form-item label="软件包">
<el-input v-model="form.softwarePackage?.name" readonly>
<template #append>
<el-button @click="openSoftwarePackageDialog">选择</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</span>
</template>
<SoftwarePackageDialog
v-model:visible="softwarePackageDialogVisible"
@select="handleSoftwarePackageSelect"
/>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue'
import SoftwarePackageDialog from './SoftwarePackageDialog.vue'
import { Project, SoftwarePackage } from '../types'
const props = defineProps<{
visible: boolean
project: Project
}>()
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void
(e: 'update', project: Project): void
}>()
const dialogVisible = ref(props.visible)
const softwarePackageDialogVisible = ref(false)
const form = reactive<Project>({ ...props.project })
watch(() => props.visible, (newValue) => {
dialogVisible.value = newValue
})
watch(dialogVisible, (newValue) => {
emit('update:visible', newValue)
})
const handleClose = () => {
dialogVisible.value = false
}
const handleSubmit = () => {
emit('update', { ...form })
}
const openSoftwarePackageDialog = () => {
softwarePackageDialogVisible.value = true
}
const handleSoftwarePackageSelect = (softwarePackage: SoftwarePackage) => {
form.softwarePackage = softwarePackage
}
</script>
软件包选择弹框组件:
<!-- SoftwarePackageDialog.vue -->
<template>
<el-dialog
v-model="dialogVisible"
title="选择软件包"
@close="handleClose"
>
<el-table :data="softwarePackages" @row-click="handleRowClick">
<el-table-column width="55">
<template #default="{ row }">
<el-radio v-model="selectedPackageId" :label="row.id" />
</template>
</el-table-column>
<el-table-columntype="radio"width="55"></el-table-column>
<el-table-column prop="name" label="软件包名称" />
<el-table-column prop="version" label="版本" />
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { SoftwarePackage } from '../types'
import { getSoftwarePackages } from '../api/softwarePackageApi'
const props = defineProps<{
visible: boolean
}>()
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void
(e: 'select', softwarePackage: SoftwarePackage): void
}>()
const dialogVisible = ref(props.visible)
const softwarePackages = ref<SoftwarePackage[]>([])
const selectedPackageId = ref('')
watch(() => props.visible, (newValue) => {
dialogVisible.value = newValue
if (newValue) {
fetchSoftwarePackages()
}
})
watch(dialogVisible, (newValue) => {
emit('update:visible', newValue)
})
const fetchSoftwarePackages = async () => {
try {
softwarePackages.value = await getSoftwarePackages()
} catch (error) {
ElMessage.error('获取软件包列表失败')
}
}
const handleClose = () => {
dialogVisible.value = false
selectedPackageId.value = ''
}
const handleConfirm = () => {
const selectedPackage = softwarePackages.value.find(pkg => pkg.id === selectedPackageId.value)
if (selectedPackage) {
emit('select', selectedPackage)
handleClose()
} else {
ElMessage.warning('请选择一个软件包')
}
}
const handleRowClick = (row: SoftwarePackage) => {
selectedPackageId.value = row.id
}
</script>
类型定义:
// types.ts
export interface Project {
id: string
name: string
description: string
softwarePackage: SoftwarePackage | null
}
export interface SoftwarePackage {
id: string
name: string
version: string
}
API服务:
// api/projectApi.ts
import axios from 'axios'
import { Project } from '../types'
const API_URL = '/api/projects'
export const getProjects = async (): Promise<Project[]> => {
const response = await axios.get(API_URL)
return response.data
}
export const createProject = async (project: Project): Promise<Project> => {
const response = await axios.post(API_URL, project)
return response.data
}
export const updateProject = async (project: Project): Promise<Project> => {
const response = await axios.put(`${API_URL}/${project.id}`, project)
return response.data
}
// api/softwarePackageApi.ts
import axios from 'axios'
import { SoftwarePackage } from '../types'
const API_URL = '/api/software-packages'
export const getSoftwarePackages = async (): Promise<SoftwarePackage[]> => {
const response = await axios.get(API_URL)
return response.data
}
关注微信公众号温暖前端,不定期分享前端知识点和前端资料↓↓↓