vue3+ts表格表单代码示例

<!-- 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
}

关注微信公众号温暖前端,不定期分享前端知识点和前端资料↓↓↓

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温暖前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值