feat: 岗位管理模块前端实现
前端实现:
- post.js: API接口封装(86行,8个接口)
- getPostList(): 分页查询
- getPostListByDept(): 按部门查询
- getPostListEnabled(): 获取启用的岗位
- getPostById(): 查询详情
- createPost(): 创建岗位
- updatePost(): 更新岗位
- deletePost(): 删除岗位
- updatePostStatus(): 更新状态
- post.vue: 岗位管理页面(416行)
- 搜索功能:岗位编码、名称、所属部门(树选择)、状态
- 表格展示:编码、名称、部门、职责、排序、状态、时间
- 状态开关:el-switch直接切换状态
- 新增/编辑对话框:
* 岗位编码、名称(必填)
* 所属部门(树选择器)
* 岗位职责、岗位要求(多行文本)
* 排序号、状态、备注
技术特点:
- 部门树选择器(el-tree-select)
- 状态开关(el-switch)
- 表单验证(必填项)
- 删除确认
模块状态:✅ 完整(前端+后端)
This commit is contained in:
parent
2b7c43366b
commit
84adda022e
85
fund-admin/src/api/post.js
Normal file
85
fund-admin/src/api/post.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import request from '../utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取岗位列表(分页)
|
||||||
|
*/
|
||||||
|
export const getPostList = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/sys/api/v1/post/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据部门ID获取岗位列表
|
||||||
|
*/
|
||||||
|
export const getPostListByDept = (deptId) => {
|
||||||
|
return request({
|
||||||
|
url: `/sys/api/v1/post/list/dept/${deptId}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有启用的岗位列表
|
||||||
|
*/
|
||||||
|
export const getPostListEnabled = () => {
|
||||||
|
return request({
|
||||||
|
url: '/sys/api/v1/post/list/enabled',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取岗位详情
|
||||||
|
*/
|
||||||
|
export const getPostById = (postId) => {
|
||||||
|
return request({
|
||||||
|
url: `/sys/api/v1/post/${postId}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建岗位
|
||||||
|
*/
|
||||||
|
export const createPost = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/sys/api/v1/post',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新岗位
|
||||||
|
*/
|
||||||
|
export const updatePost = (postId, data) => {
|
||||||
|
return request({
|
||||||
|
url: `/sys/api/v1/post/${postId}`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除岗位
|
||||||
|
*/
|
||||||
|
export const deletePost = (postId) => {
|
||||||
|
return request({
|
||||||
|
url: `/sys/api/v1/post/${postId}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新岗位状态
|
||||||
|
*/
|
||||||
|
export const updatePostStatus = (postId, status) => {
|
||||||
|
return request({
|
||||||
|
url: `/sys/api/v1/post/${postId}/status`,
|
||||||
|
method: 'put',
|
||||||
|
params: { status }
|
||||||
|
})
|
||||||
|
}
|
||||||
415
fund-admin/src/views/system/post.vue
Normal file
415
fund-admin/src/views/system/post.vue
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
<template>
|
||||||
|
<div class="post-container">
|
||||||
|
<el-card>
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<el-form :inline="true" :model="searchForm">
|
||||||
|
<el-form-item label="岗位编码">
|
||||||
|
<el-input v-model="searchForm.postCode" placeholder="请输入岗位编码" clearable style="width: 150px;" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="岗位名称">
|
||||||
|
<el-input v-model="searchForm.postName" placeholder="请输入岗位名称" clearable style="width: 150px;" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属部门">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="searchForm.deptId"
|
||||||
|
:data="deptTreeOptions"
|
||||||
|
placeholder="请选择部门"
|
||||||
|
clearable
|
||||||
|
check-strictly
|
||||||
|
:render-after-expand="false"
|
||||||
|
style="width: 200px;"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-select v-model="searchForm.status" placeholder="请选择状态" clearable style="width: 120px;">
|
||||||
|
<el-option label="启用" :value="1" />
|
||||||
|
<el-option label="禁用" :value="0" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||||
|
<el-button @click="handleReset">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 操作栏 -->
|
||||||
|
<el-row style="margin-bottom: 15px;">
|
||||||
|
<el-button type="primary" @click="handleAdd">新增岗位</el-button>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 表格 -->
|
||||||
|
<el-table :data="tableData" border v-loading="loading" stripe>
|
||||||
|
<el-table-column prop="postId" label="岗位ID" width="80" />
|
||||||
|
<el-table-column prop="postCode" label="岗位编码" width="120" />
|
||||||
|
<el-table-column prop="postName" label="岗位名称" width="150" />
|
||||||
|
<el-table-column prop="deptId" label="所属部门" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ getDeptName(row.deptId) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="postDuty" label="岗位职责" width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="sortOrder" label="排序" width="80" align="center" />
|
||||||
|
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-switch
|
||||||
|
v-model="row.status"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
@change="handleStatusChange(row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="createdTime" label="创建时间" width="180" />
|
||||||
|
<el-table-column label="操作" width="150" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
|
||||||
|
<el-button type="danger" size="small" @click="handleDelete(row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="page.current"
|
||||||
|
v-model:page-size="page.size"
|
||||||
|
:total="page.total"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="fetchData"
|
||||||
|
@current-change="fetchData"
|
||||||
|
style="margin-top: 20px; justify-content: flex-end;"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 新增/编辑对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="form.postId ? '编辑岗位' : '新增岗位'"
|
||||||
|
width="600px"
|
||||||
|
>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="岗位编码" prop="postCode">
|
||||||
|
<el-input v-model="form.postCode" placeholder="请输入岗位编码" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="岗位名称" prop="postName">
|
||||||
|
<el-input v-model="form.postName" placeholder="请输入岗位名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="所属部门" prop="deptId">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="form.deptId"
|
||||||
|
:data="deptTreeOptions"
|
||||||
|
placeholder="请选择部门"
|
||||||
|
clearable
|
||||||
|
check-strictly
|
||||||
|
:render-after-expand="false"
|
||||||
|
style="width: 100%;"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="岗位职责">
|
||||||
|
<el-input
|
||||||
|
v-model="form.postDuty"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="请输入岗位职责描述"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="岗位要求">
|
||||||
|
<el-input
|
||||||
|
v-model="form.postRequirement"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="请输入岗位要求"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="排序号">
|
||||||
|
<el-input-number v-model="form.sortOrder" :min="0" style="width: 100%;" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<el-radio-group v-model="form.status">
|
||||||
|
<el-radio :value="1">启用</el-radio>
|
||||||
|
<el-radio :value="0">禁用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input
|
||||||
|
v-model="form.remark"
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
placeholder="请输入备注"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getPostList,
|
||||||
|
createPost,
|
||||||
|
updatePost,
|
||||||
|
deletePost,
|
||||||
|
updatePostStatus
|
||||||
|
} from '../../api/post'
|
||||||
|
import { getDeptTree } from '../../api/dept'
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const searchForm = reactive({
|
||||||
|
postCode: '',
|
||||||
|
postName: '',
|
||||||
|
deptId: null,
|
||||||
|
status: null
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表格数据
|
||||||
|
const tableData = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
const page = reactive({
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// 对话框
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const formRef = ref(null)
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const form = reactive({
|
||||||
|
postId: null,
|
||||||
|
postCode: '',
|
||||||
|
postName: '',
|
||||||
|
postDuty: '',
|
||||||
|
postRequirement: '',
|
||||||
|
deptId: null,
|
||||||
|
sortOrder: 0,
|
||||||
|
status: 1,
|
||||||
|
remark: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const rules = {
|
||||||
|
postCode: [
|
||||||
|
{ required: true, message: '请输入岗位编码', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
postName: [
|
||||||
|
{ required: true, message: '请输入岗位名称', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 部门树选项
|
||||||
|
const deptTreeOptions = ref([])
|
||||||
|
|
||||||
|
// 部门映射(用于显示部门名称)
|
||||||
|
const deptMap = ref({})
|
||||||
|
|
||||||
|
// 加载部门树
|
||||||
|
const loadDeptTree = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getDeptTree()
|
||||||
|
deptTreeOptions.value = convertToTreeSelect(data)
|
||||||
|
buildDeptMap(data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载部门树失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为TreeSelect格式
|
||||||
|
const convertToTreeSelect = (data) => {
|
||||||
|
return data.map(item => ({
|
||||||
|
value: item.deptId,
|
||||||
|
label: item.deptName,
|
||||||
|
children: item.children ? convertToTreeSelect(item.children) : []
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建部门映射
|
||||||
|
const buildDeptMap = (data) => {
|
||||||
|
data.forEach(item => {
|
||||||
|
deptMap.value[item.deptId] = item.deptName
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
buildDeptMap(item.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取部门名称
|
||||||
|
const getDeptName = (deptId) => {
|
||||||
|
return deptMap.value[deptId] || '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载数据
|
||||||
|
const fetchData = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
current: page.current,
|
||||||
|
size: page.size,
|
||||||
|
postCode: searchForm.postCode || undefined,
|
||||||
|
postName: searchForm.postName || undefined,
|
||||||
|
deptId: searchForm.deptId || undefined,
|
||||||
|
status: searchForm.status !== null && searchForm.status !== '' ? searchForm.status : undefined
|
||||||
|
}
|
||||||
|
const res = await getPostList(params)
|
||||||
|
tableData.value = res.records
|
||||||
|
page.total = res.total
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载数据失败:', error)
|
||||||
|
ElMessage.error(error.message || '加载数据失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
const handleSearch = () => {
|
||||||
|
page.current = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const handleReset = () => {
|
||||||
|
searchForm.postCode = ''
|
||||||
|
searchForm.postName = ''
|
||||||
|
searchForm.deptId = null
|
||||||
|
searchForm.status = null
|
||||||
|
page.current = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const handleAdd = () => {
|
||||||
|
Object.assign(form, {
|
||||||
|
postId: null,
|
||||||
|
postCode: '',
|
||||||
|
postName: '',
|
||||||
|
postDuty: '',
|
||||||
|
postRequirement: '',
|
||||||
|
deptId: null,
|
||||||
|
sortOrder: 0,
|
||||||
|
status: 1,
|
||||||
|
remark: ''
|
||||||
|
})
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
Object.assign(form, {
|
||||||
|
postId: row.postId,
|
||||||
|
postCode: row.postCode,
|
||||||
|
postName: row.postName,
|
||||||
|
postDuty: row.postDuty,
|
||||||
|
postRequirement: row.postRequirement,
|
||||||
|
deptId: row.deptId,
|
||||||
|
sortOrder: row.sortOrder,
|
||||||
|
status: row.status,
|
||||||
|
remark: row.remark
|
||||||
|
})
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await formRef.value.validate()
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.warning('请检查表单填写是否完整')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (form.postId) {
|
||||||
|
await updatePost(form.postId, form)
|
||||||
|
ElMessage.success('更新成功')
|
||||||
|
} else {
|
||||||
|
await createPost(form)
|
||||||
|
ElMessage.success('创建成功')
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
await fetchData()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
ElMessage.error(error.message || '操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态变更
|
||||||
|
const handleStatusChange = async (row) => {
|
||||||
|
try {
|
||||||
|
await updatePostStatus(row.postId, row.status)
|
||||||
|
ElMessage.success('状态更新成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('状态更新失败:', error)
|
||||||
|
ElMessage.error(error.message || '状态更新失败')
|
||||||
|
// 回滚状态
|
||||||
|
row.status = row.status === 1 ? 0 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
const handleDelete = async (row) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('确定要删除该岗位吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
|
||||||
|
await deletePost(row.postId)
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
|
||||||
|
// 如果是最后一条且不是第一页,返回上一页
|
||||||
|
if (tableData.value.length === 1 && page.current > 1) {
|
||||||
|
page.current--
|
||||||
|
}
|
||||||
|
|
||||||
|
await fetchData()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('删除失败:', error)
|
||||||
|
ElMessage.error(error.message || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
onMounted(() => {
|
||||||
|
loadDeptTree()
|
||||||
|
fetchData()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.post-container {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user