增加hooks配置

This commit is contained in:
BianLzhaoMin 2025-12-18 13:48:23 +08:00
parent 6e54c974a4
commit 4d2b6a245c
14 changed files with 526 additions and 5 deletions

View File

@ -29,6 +29,7 @@
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
"nprogress": "0.2.0",
"pinia": "3.0.2",
"splitpanes": "4.0.4",

27
src/api/common.js Normal file
View File

@ -0,0 +1,27 @@
import request from '@/utils/request'
// 公共下拉选数据 - 获取人员所属
export function getInspectionStationSelectAPI(query = { category: 0 }) {
return request({
url: '/personnel/getInspectionStationSelect',
method: 'GET',
params: query,
})
}
// 公共下拉选数据 - 获取岗位
export function getPositionSelectAPI(query = { category: 0 }) {
return request({
url: '/personnel/getInspectionStationSelect',
method: 'GET',
params: query,
})
}
// 公共下拉选数据 - 获取人员性质和人员分类
export function getPersonNatureAndCategorySelectAPI(data) {
return request({
url: '/personnel/getPersonnelClassificationSelect',
method: 'GET',
params: data,
})
}

View File

@ -0,0 +1,37 @@
import request from '@/utils/request'
// 人员管理- 查询列表
export function listPersonAPI(query) {
return request({
url: '/personnel/getPersonnelList',
method: 'GET',
params: query,
})
}
// 人员管理- 新增
export function addPersonAPI(data) {
return request({
url: '/personnel/addPersonnel',
method: 'POST',
data,
})
}
// 人员管理- 修改
export function updatePersonAPI(data) {
return request({
url: '/personnel/updatePersonnel',
method: 'POST',
data,
})
}
// 人员管理- 删除
export function delPersonAPI(data) {
return request({
url: `/personnel/delPersonnel`,
method: 'POST',
data,
})
}

View File

@ -73,9 +73,9 @@ const handleCloseInner = () => {
flex-direction: column;
margin: 0;
position: absolute;
top: 50%;
top: 25%;
left: 50%;
transform: translate(-50%, -75%);
transform: translate(-50%, -25%);
min-height: var(--com-dialog-min-height);
max-height: var(--com-dialog-max-height);
border-radius: 16px;

48
src/hooks/useOptions.js Normal file
View File

@ -0,0 +1,48 @@
import { ref, onMounted, onUnmounted } from 'vue'
import { bus, BUS_EVENTS } from '@/utils/bus'
import useOptionsStore from '@/store/modules/options'
export function useOptions(type, apiFn, params = {}) {
const options = ref([])
const optionStore = useOptionsStore()
const fetchOptions = async (force = false) => {
// 1. 如果不是强制刷新,且 Store 中已有值,直接取 Store
if (!force && optionStore[type] && optionStore[type].length > 0) {
options.value = optionStore[type]
return
}
// 2. 否则调接口
try {
const res = await apiFn(params)
const data = res.rows || res.data || []
options.value = data
// 3. 更新 Store 缓存
optionStore.setOptions(type, data)
} catch (error) {
console.error(`获取${type}下拉失败:`, error)
}
}
// 监听刷新信号
const handleRefresh = (refreshType) => {
if (refreshType === type || refreshType === 'all') {
fetchOptions(true) // 强制刷新
}
}
onMounted(() => {
fetchOptions()
bus.on(BUS_EVENTS.REFRESH_OPTIONS, handleRefresh)
})
onUnmounted(() => {
bus.off(BUS_EVENTS.REFRESH_OPTIONS, handleRefresh)
})
return {
options,
}
}

View File

@ -0,0 +1,22 @@
import { defineStore } from 'pinia'
const useOptionsStore = defineStore('options', {
state: () => ({
positionOptions: [], // 人员岗位
personNatureOptions: [], // 人员性质
personCategoryOptions: [], // 人员分类
inspectionStationOptions: [], // 运检站
}),
actions: {
// 通用的设置方法,方便 Hook 调用
setOptions(type, options) {
this[type] = options
},
// 清空特定缓存
clearOptions(type) {
this[type] = []
},
},
})
export default useOptionsStore

7
src/utils/bus.js Normal file
View File

@ -0,0 +1,7 @@
import mitt from 'mitt'
export const bus = mitt()
// 定义事件名称常量
export const BUS_EVENTS = {
REFRESH_OPTIONS: 'REFRESH_OPTIONS', // 刷新下拉选项信号
}

View File

@ -66,6 +66,7 @@ import {
delInspectionStationAPI,
updateInspectionStationAPI,
} from '@/api/basicManage/inspectionStation'
import { bus, BUS_EVENTS } from '@/utils/bus'
import config from './config'
import ComTable from '@/components/ComTable/index.vue'
import ComButton from '@/components/ComButton/index.vue'
@ -120,6 +121,7 @@ const actionColumns = [
})
if (result.code === 200) {
proxy.$modal.msgSuccess('删除成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'inspectionStationOptions') //
comTableRef.value?.refresh() //
}
})
@ -157,6 +159,7 @@ const onHandleSave = async () => {
const result = await API(params)
if (result.code === 200) {
proxy.$modal.msgSuccess(editId.value ? '编辑成功' : '新增成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'inspectionStationOptions') //
addAndEditFormRef.value.resetFields() //
dialogConfig.outerVisible = false
comTableRef.value?.refresh() //

View File

@ -66,6 +66,7 @@ import {
delPersonCategoryAPI,
updatePersonCategoryAPI,
} from '@/api/basicManage/personCategory'
import { bus, BUS_EVENTS } from '@/utils/bus'
import config from './config'
import ComTable from '@/components/ComTable/index.vue'
import ComButton from '@/components/ComButton/index.vue'
@ -121,6 +122,7 @@ const actionColumns = [
})
if (result.code === 200) {
proxy.$modal.msgSuccess('删除成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'personCategoryOptions') //
comTableRef.value?.refresh() //
}
})
@ -158,6 +160,7 @@ const onHandleSave = async () => {
const result = await API(params)
if (result.code === 200) {
proxy.$modal.msgSuccess(editId.value ? '编辑成功' : '新增成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'personCategoryOptions') //
addAndEditFormRef.value.resetFields() //
dialogConfig.outerVisible = false
comTableRef.value?.refresh() //

View File

@ -66,6 +66,7 @@ import {
delPersonNatureAPI,
updatePersonNatureAPI,
} from '@/api/basicManage/personNature'
import { bus, BUS_EVENTS } from '@/utils/bus'
import config from './config'
import ComTable from '@/components/ComTable/index.vue'
import ComButton from '@/components/ComButton/index.vue'
@ -121,6 +122,7 @@ const actionColumns = [
})
if (result.code === 200) {
proxy.$modal.msgSuccess('删除成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'personNatureOptions') //
comTableRef.value?.refresh() //
}
})
@ -158,6 +160,7 @@ const onHandleSave = async () => {
const result = await API(params)
if (result.code === 200) {
proxy.$modal.msgSuccess(editId.value ? '编辑成功' : '新增成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'personNatureOptions') //
addAndEditFormRef.value.resetFields() //
dialogConfig.outerVisible = false
comTableRef.value?.refresh() //

View File

@ -66,6 +66,7 @@ import {
delPositionAPI,
updatePositionAPI,
} from '@/api/basicManage/position'
import { bus, BUS_EVENTS } from '@/utils/bus'
import config from './config'
import ComTable from '@/components/ComTable/index.vue'
import ComButton from '@/components/ComButton/index.vue'
@ -119,6 +120,7 @@ const actionColumns = [
})
if (result.code === 200) {
proxy.$modal.msgSuccess('删除成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'positionOptions')
comTableRef.value?.refresh() //
}
})
@ -156,6 +158,7 @@ const onHandleSave = async () => {
const result = await API(params)
if (result.code === 200) {
proxy.$modal.msgSuccess(editId.value ? '编辑成功' : '新增成功')
bus.emit(BUS_EVENTS.REFRESH_OPTIONS, 'positionOptions') //
addAndEditFormRef.value.resetFields() //
dialogConfig.outerVisible = false
comTableRef.value?.refresh() //

View File

@ -0,0 +1,181 @@
<template>
<el-form
size="large"
label-width="100px"
:model="formData"
ref="formRef"
:rules="rules"
class="add-and-edit-form"
>
<el-form-item label="人员所属" prop="orgId">
<el-select
v-model="formData.orgId"
placeholder="请选择人员所属"
clearable
style="width: 100%"
>
<el-option
v-for="item in orgOptions"
:key="item.inspectionStationId"
:label="item.inspectionStationName"
:value="item.inspectionStationId"
/>
</el-select>
</el-form-item>
<el-form-item label="姓名" prop="personName">
<el-input
v-model.trim="formData.personName"
placeholder="请输入姓名"
clearable
maxlength="20"
/>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="formData.gender">
<el-radio-button :label="0">男性 </el-radio-button>
<el-radio-button :label="1">女性 </el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input
v-model.trim="formData.phone"
placeholder="请输入电话"
clearable
maxlength="11"
/>
</el-form-item>
<el-form-item label="岗位" prop="positionId">
<el-select
v-model="formData.positionId"
placeholder="请选择岗位"
clearable
style="width: 100%"
>
<el-option
v-for="item in positionOptions"
:key="item.personnelClassificationId"
:label="item.personnelClassificationName"
:value="item.personnelClassificationId"
/>
</el-select>
</el-form-item>
<el-form-item label="人员性质" prop="natureId">
<el-select
v-model="formData.natureId"
placeholder="请选择人员性质"
clearable
style="width: 100%"
>
<el-option
v-for="item in natureOptions"
:key="item.personnelClassificationId"
:label="item.personnelClassificationName"
:value="item.personnelClassificationId"
/>
</el-select>
</el-form-item>
<el-form-item label="人员分类" prop="categoryId">
<el-select
v-model="formData.categoryId"
placeholder="请选择人员分类"
clearable
style="width: 100%"
>
<el-option
v-for="item in categoryOptions"
:key="item.personnelClassificationId"
:label="item.personnelClassificationName"
:value="item.personnelClassificationId"
/>
</el-select>
</el-form-item>
</el-form>
</template>
<script setup name="AddAndEditForm">
import { ref } from 'vue'
import { useOptions } from '@/hooks/useOptions'
import {
getInspectionStationSelectAPI,
getPositionSelectAPI,
getPersonNatureAndCategorySelectAPI,
} from '@/api/common.js'
const props = defineProps({
formData: {
type: Object,
default: () => ({}),
},
})
const formRef = ref(null)
// 使 Hook
//
const { options: inspectionStationOptions } = useOptions(
'inspectionStationOptions',
getInspectionStationSelectAPI,
)
//
// const { options: positionOptions } = useOptions('positionOptions', getPositionSelectAPI, {
// category: 2,
// })
//
const { options: natureOptions } = useOptions(
'personNatureOptions',
getPersonNatureAndCategorySelectAPI,
{
category: 1,
},
)
//
const { options: categoryOptions } = useOptions(
'personCategoryOptions',
getPersonNatureAndCategorySelectAPI,
{
category: 0,
},
)
const rules = {
orgId: [{ required: true, message: '请选择人员所属', trigger: 'change' }],
personName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
positionId: [{ required: true, message: '请选择岗位', trigger: 'change' }],
natureId: [{ required: true, message: '请选择人员性质', trigger: 'change' }],
categoryId: [{ required: true, message: '请选择人员分类', trigger: 'change' }],
}
//
defineExpose({
validate: () => formRef.value.validate(),
resetFields: () => formRef.value.resetFields(),
clearValidate: () => formRef.value.clearValidate(),
})
</script>
<style lang="scss" scoped>
.add-and-edit-form {
padding: 10px 20px;
:deep(.el-radio-button__inner) {
border-radius: 20px;
margin-right: 10px;
border: 1px solid #dcdfe6 !important;
box-shadow: none !important;
}
:deep(.el-radio-button:first-child .el-radio-button__inner) {
border-left: 1px solid #dcdfe6 !important;
}
:deep(.el-radio-button.is-active .el-radio-button__inner) {
background-color: var(--el-color-primary-light-9);
color: var(--el-color-primary);
border-color: var(--el-color-primary) !important;
}
}
</style>

View File

@ -0,0 +1,53 @@
import { reactive } from 'vue'
export default {
formColumns: [
{
type: 'input',
prop: 'personName',
placeholder: '请输入姓名',
},
],
tableColumns: [
{
prop: 'orgName',
label: '人员所属',
},
{
prop: 'personName',
label: '姓名',
},
{
prop: 'gender',
label: '性别',
type: 'dict', // 假设有字典处理
dictData: [
{ label: '男', value: 0 },
{ label: '女', value: 1 },
],
},
{
prop: 'phone',
label: '电话',
},
{
prop: 'positionName',
label: '岗位',
},
{
prop: 'natureName',
label: '人员性质',
},
{
prop: 'categoryName',
label: '人员分类',
},
],
dialogConfig: reactive({
outerVisible: false,
outerTitle: '新增人员',
outerWidth: '640px', // 根据图片缩小宽度更美观
minHeight: '400px',
maxHeight: '80vh',
}),
}

View File

@ -1,7 +1,140 @@
<template>
<div class="app-container">人员管理</div>
<div class="app-container">
<!-- 人员管理 -->
<ComTable
ref="comTableRef"
:form-columns="formColumns"
:table-columns="tableColumns"
:load-data="listPersonAPI"
:show-toolbar="true"
:show-action="true"
:action-columns="actionColumns"
>
<template #toolbar>
<ComButton type="primary" icon="Plus" @click="onHandleAdd">新建人员</ComButton>
</template>
</ComTable>
<ComDialog :dialog-config="dialogConfig" @closeDialogOuter="onCloseDialogOuter">
<template #outerContent>
<!-- 将表单抽离到独立组件中保持 index.vue 简洁 -->
<AddAndEditForm ref="formRef" :form-data="addAndEditForm" />
<el-row class="common-btn-row">
<ComButton plain type="info" @click="onHandleCancel">取消</ComButton>
<ComButton @click="onHandleSave">保存</ComButton>
</el-row>
</template>
</ComDialog>
</div>
</template>
<script setup name="Person"></script>
<script setup name="Person">
import { ref, nextTick, getCurrentInstance } from 'vue'
// TODO: API
// import { listPersonAPI, addPersonAPI, updatePersonAPI, delPersonAPI } from '@/api/personManage'
import config from './config'
import ComTable from '@/components/ComTable/index.vue'
import ComButton from '@/components/ComButton/index.vue'
import ComDialog from '@/components/ComDialog/index.vue'
import AddAndEditForm from './addAndEditForm.vue'
<style scoped lang="scss"></style>
// API
const listPersonAPI = () => Promise.resolve({ rows: [], total: 0 })
const addPersonAPI = () => Promise.resolve({ code: 200 })
const updatePersonAPI = () => Promise.resolve({ code: 200 })
const delPersonAPI = () => Promise.resolve({ code: 200 })
const { formColumns, tableColumns, dialogConfig } = config
const { proxy } = getCurrentInstance()
const formRef = ref(null)
const comTableRef = ref(null)
const editId = ref(null)
// 1.
const getInitFormData = () => ({
orgId: null,
personName: '',
gender: 0,
phone: '',
positionId: null,
natureId: null,
categoryId: null,
})
const addAndEditForm = ref(getInitFormData())
const actionColumns = [
{
label: '编辑',
type: 'primary',
link: true,
handler: (row) => {
editId.value = row.personId
dialogConfig.outerTitle = '编辑人员'
dialogConfig.outerVisible = true
// 2. 使 nextTick
nextTick(() => {
Object.assign(addAndEditForm.value, row)
})
},
},
{
label: '删除',
type: 'danger',
link: true,
handler: (row) => {
proxy.$modal.confirm('是否确认删除该人员?').then(async () => {
const result = await delPersonAPI(row.personId)
if (result.code === 200) {
proxy.$modal.msgSuccess('删除成功')
comTableRef.value?.refresh()
}
})
},
},
]
//
const onHandleAdd = () => {
editId.value = null
dialogConfig.outerTitle = '新增人员'
dialogConfig.outerVisible = true
addAndEditForm.value = getInitFormData()
nextTick(() => {
formRef.value?.clearValidate()
})
}
//
const onHandleCancel = () => {
dialogConfig.outerVisible = false
}
//
const onHandleSave = async () => {
try {
// 3. validate
await formRef.value.validate()
const API = editId.value ? updatePersonAPI : addPersonAPI
const result = await API(addAndEditForm.value)
if (result.code === 200) {
proxy.$modal.msgSuccess(editId.value ? '编辑成功' : '新增成功')
dialogConfig.outerVisible = false
comTableRef.value?.refresh()
}
} catch (error) {
return Promise.reject(error)
}
}
//
const onCloseDialogOuter = (visible) => {
dialogConfig.outerVisible = visible
if (!visible) {
formRef.value?.resetFields()
}
}
</script>