Industrial-image-management.../src/views/hr/salary/system-insurance/management/index.vue

659 lines
17 KiB
Vue

<template>
<GiPageLayout>
<div class="insurance-manage-container">
<div class="page-header">
<h2 class="page-title">保险信息管理</h2>
<a-button type="primary" @click="showAddModal">
<template #icon>
<icon-plus />
</template>
新增保险
</a-button>
</div>
<!-- 搜索表单 -->
<a-card class="search-card" :bordered="false">
<a-form :model="searchForm" layout="inline">
<a-form-item label="保险公司" field="insuranceCompanyId">
<a-select
v-model="searchForm.insuranceCompanyId"
placeholder="请选择保险公司"
allow-clear
:loading="loadingCompanies"
style="width: 200px"
>
<a-option
v-for="company in companyList"
:key="company.id"
:value="company.id"
>
{{ company.insuranceCompanyName }}
</a-option>
</a-select>
</a-form-item>
<a-form-item label="保险类型" field="insuranceTypeId">
<a-select
v-model="searchForm.insuranceTypeId"
placeholder="请选择保险类型"
allow-clear
:loading="loadingTypes"
style="width: 200px"
>
<a-option
v-for="type in typeList"
:key="type.id"
:value="type.id"
>
{{ type.insuranceTypeName }}
</a-option>
</a-select>
</a-form-item>
<a-form-item label="用户" field="userId">
<a-input
v-model="searchForm.userId"
placeholder="请输入用户ID"
style="width: 200px"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">
<template #icon>
<icon-search />
</template>
搜索
</a-button>
<a-button @click="handleReset">
<template #icon>
<icon-refresh />
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-form>
</a-card>
<!-- 保险信息表格 -->
<a-card class="table-card" :bordered="false">
<a-table
:columns="columns"
:data="insuranceList"
:pagination="paginationConfig"
:loading="loading"
row-key="id"
@page-change="handlePageChange"
>
<template #insuranceCompany="{ record }">
<span>{{ getCompanyName(record.insuranceCompanyId) }}</span>
</template>
<template #insuranceType="{ record }">
<span>{{ getTypeName(record.insuranceTypeId) }}</span>
</template>
<template #status="{ record }">
<a-tag
:color="record.status === 'active' ? 'green' : 'red'"
>
{{ record.status === 'active' ? '有效' : '失效' }}
</a-tag>
</template>
<template #actions="{ record }">
<a-space>
<a-button type="primary" size="small" @click="editRecord(record)">
编辑
</a-button>
<a-button type="primary" status="danger" size="small" @click="deleteRecord(record)">
删除
</a-button>
</a-space>
</template>
</a-table>
</a-card>
<!-- 新增/编辑保险信息模态框 -->
<a-modal
v-model:visible="modalVisible"
:title="isEdit ? '编辑保险信息' : '新增保险信息'"
width="600px"
@ok="handleSubmit"
@cancel="handleCancel"
>
<a-form
ref="formRef"
:model="formData"
:rules="formRules"
layout="vertical"
>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="保险公司" field="insuranceCompanyId">
<a-select
v-model="formData.insuranceCompanyId"
placeholder="请选择保险公司"
:loading="loadingCompanies"
>
<a-option
v-for="company in companyList"
:key="company.insuranceCompanyId"
:value="company.insuranceCompanyId"
>
{{ company.insuranceCompanyName }}
</a-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="保险类型" field="insuranceTypeId">
<a-select
v-model="formData.insuranceTypeId"
placeholder="请选择保险类型"
:loading="loadingTypes"
>
<a-option
v-for="type in typeList"
:key="type.insuranceTypeId"
:value="type.insuranceTypeId"
>
{{ type.insuranceTypeName }}
</a-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="选择人员" field="userId">
<a-select
v-model="formData.userId"
placeholder="请选择员工"
allow-search
:filter-option="false"
@search="searchEmployees"
>
<a-option
v-for="employee in employeeOptions"
:key="employee.userId"
:value="employee.userId"
>
{{ employee.nickname || employee.name }} ({{ employee.deptName }})
</a-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="保险单号" field="insuranceBillCode">
<a-input v-model="formData.insuranceBillCode" placeholder="请输入保险单号" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="生效日期" field="effectiveDate">
<a-date-picker
v-model="formData.effectiveDate"
placeholder="请选择生效日期"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="到期日期" field="expireDate">
<a-date-picker
v-model="formData.expireDate"
placeholder="请选择到期日期"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="保险金额" field="insuranceAmount">
<a-input-number
v-model="formData.insuranceAmount"
placeholder="请输入保险金额"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="保险费" field="insurancePremium">
<a-input-number
v-model="formData.insurancePremium"
placeholder="请输入保险费"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item label="受益人" field="beneficiary">
<a-input v-model="formData.beneficiary" placeholder="请输入受益人" />
</a-form-item>
<a-col :span="12">
<a-form-item label="上传保单" field="attachInfoId">
<a-upload
:custom-request="uploadInsuranceFile"
>
<a-button type="primary">
<template #icon><icon-upload /></template>
上传保单
</a-button>
</a-upload>
</a-form-item>
</a-col>
<a-form-item label="备注" field="remark">
<a-textarea
v-model="formData.remark"
placeholder="请输入备注"
:auto-size="{ minRows: 3, maxRows: 6 }"
/>
</a-form-item>
</a-form>
</a-modal>
</div>
</GiPageLayout>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { Message, Modal } from '@arco-design/web-vue'
import { IconPlus, IconSearch, IconRefresh } from '@arco-design/web-vue/es/icon'
import * as InsuranceAPI from '@/apis/insurance'
import { listAllUser } from '@/apis/system/user'
import type { InsuranceInfo, InsuranceListParams } from '@/apis/insurance'
import * as InsuranceCompanyAPI from '@/apis/insurance-company'
import * as InsuranceTypeAPI from '@/apis/insurance-type'
import { addAttachInsurance } from '@/apis/attach-info'
// 数据状态
const loading = ref(false)
const loadingCompanies = ref(false)
const loadingTypes = ref(false)
const modalVisible = ref(false)
const isEdit = ref(false)
const formRef = ref()
// 列表数据
const insuranceList = ref<InsuranceInfo[]>([])
const companyList = ref<any[]>([])
const typeList = ref<any[]>([])
// 搜索表单
const searchForm = reactive<InsuranceListParams>({
insuranceCompanyId: '',
insuranceTypeId: '',
userId: ''
})
// 分页配置
const paginationConfig = reactive({
current: 1,
pageSize: 10,
total: 0,
showTotal: true,
showJumper: true
})
// 表单数据
const formData = reactive<InsuranceInfo>({
id: '',
attachInfoId: '',
insuranceCompanyId: '',
insuranceTypeId: '',
userId: '',
insuranceBillCode: '',
effectiveDate: '',
expireDate: '',
insuranceAmount: 0,
insurancePremium: 0,
beneficiary: '',
remark: ''
})
// 表单验证规则
const formRules = {
insuranceCompanyId: [
{ required: true, message: '请选择保险公司' }
],
insuranceTypeId: [
{ required: true, message: '请选择保险类型' }
],
userId: [
{ required: true, message: '请输入用户ID' }
],
insuranceBillCode: [
{ required: true, message: '请输入保险单号' }
],
effectiveDate: [
{ required: true, message: '请选择生效日期' }
],
expireDate: [
{ required: true, message: '请选择到期日期' }
],
insuranceAmount: [
{ required: true, message: '请输入保险金额' }
],
insurancePremium: [
{ required: true, message: '请输入保险费' }
]
}
// 表格列定义
const columns = [
{
title: '用户名称',
dataIndex: 'name',
width: 100
},
{
title: '保险公司',
dataIndex: 'insuranceCompanyName',
slotName: 'insuranceCompanyName',
width: 150
},
{
title: '保险类型',
dataIndex: 'insuranceTypeName',
slotName: 'insuranceTypeName',
width: 120
},
{
title: '保险单号',
dataIndex: 'insuranceBillCode',
width: 150
},
{
title: '生效日期',
dataIndex: 'effectiveDate',
width: 120
},
{
title: '到期日期',
dataIndex: 'expireDate',
width: 120
},
{
title: '保险金额',
dataIndex: 'insuranceAmount',
width: 120
},
{
title: '状态',
dataIndex: 'status',
slotName: 'status',
width: 80
},
{
title: '操作',
slotName: 'actions',
width: 150,
fixed: 'right'
}
]
// 获取保险公司名称
const getCompanyName = (id: string) => {
const company = companyList.value.find(c => c.id === id)
return company ? company.insuranceCompanyName : '-'
}
// 获取保险类型名称
const getTypeName = (id: string) => {
const type = typeList.value.find(t => t.id === id)
return type ? type.insuranceTypeName : '-'
}
// 获取保险公司列表
const getCompanyList = async () => {
try {
loadingCompanies.value = true
const response = await InsuranceCompanyAPI.getInsuranceCompanyList({})
console.log('保险公司列表响应:', response)
if (response.data) {
companyList.value = response.data || []
}
} catch (error) {
console.error('获取保险公司列表失败:', error)
Message.error('获取保险公司列表失败')
} finally {
loadingCompanies.value = false
}
}
// 获取保险类型列表
const getTypeList = async () => {
try {
loadingTypes.value = true
const response = await InsuranceTypeAPI.getInsuranceTypeList()
console.log('保险类型列表响应:', response)
if (response.data) {
typeList.value = response.data || []
}
} catch (error) {
console.error('获取保险类型列表失败:', error)
Message.error('获取保险类型列表失败')
} finally {
loadingTypes.value = false
}
}
// 获取保险信息列表
const getInsuranceList = async () => {
try {
loading.value = true
const params: InsuranceListParams = {
...searchForm,
current: paginationConfig.current,
size: paginationConfig.pageSize
}
const response = await InsuranceAPI.getInsuranceList(params)
console.log('保险信息列表响应:', response)
if (response.data) {
insuranceList.value = response.data || []
paginationConfig.total = response.data.total || 0
}
} catch (error) {
console.error('获取保险信息列表失败:', error)
Message.error('获取保险信息列表失败')
} finally {
loading.value = false
}
}
// 搜索员工
const searchEmployees = (keyword: string) => {
fetchEmployeeOptions(keyword)
}
const employeeOptions = ref<any[]>([])
// 获取员工列表
const fetchEmployeeOptions = async (keyword?: string) => {
try {
const response = await listAllUser({ description: keyword })
employeeOptions.value = response.data || []
} catch (error) {
console.error('获取员工列表失败:', error)
Message.error('获取员工列表失败')
} finally {
}
}
const uploadInsuranceFile = async (options: any) => {
if(!formData.userId || !formData.insuranceBillCode){
Message.error('请先选择员工和输入保险单号')
return
}
const uploadForm = new FormData()
uploadForm.append('file', options.fileItem.file)
uploadForm.append('userDefinedPath', `${formData.userId}/${formData.insuranceBillCode}`)
const response = await addAttachInsurance(uploadForm)
console.log('上传保险文件响应:', response)
formData.attachInfoId = response.data
}
// 搜索
const handleSearch = () => {
paginationConfig.current = 1
getInsuranceList()
}
// 重置搜索
const handleReset = () => {
Object.assign(searchForm, {
insuranceCompanyId: '',
insuranceTypeId: '',
userId: ''
})
paginationConfig.current = 1
getInsuranceList()
}
// 分页变化
const handlePageChange = (page: number) => {
paginationConfig.current = page
getInsuranceList()
}
// 显示新增模态框
const showAddModal = () => {
isEdit.value = false
resetForm()
modalVisible.value = true
}
// 编辑记录
const editRecord = (record: InsuranceInfo) => {
isEdit.value = true
Object.assign(formData, record)
modalVisible.value = true
}
// 删除记录
const deleteRecord = (record: InsuranceInfo) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除这条保险信息吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
try {
await InsuranceAPI.deleteInsurance(record.id!)
Message.success('删除成功')
await getInsuranceList()
} catch (error) {
console.error('删除失败:', error)
Message.error('删除失败')
}
}
})
}
// 表单提交
const handleSubmit = async () => {
try {
await formRef.value?.validate()
if (isEdit.value) {
await InsuranceAPI.updateInsurance(formData.id!, formData)
Message.success('更新成功')
} else {
await InsuranceAPI.createInsurance(formData)
Message.success('创建成功')
}
modalVisible.value = false
resetForm()
await getInsuranceList()
} catch (error) {
console.error('操作失败:', error)
Message.error('操作失败,请重试')
}
}
// 取消操作
const handleCancel = () => {
modalVisible.value = false
resetForm()
}
// 重置表单
const resetForm = () => {
Object.assign(formData, {
id: '',
attachInfoId: '',
insuranceCompanyId: '',
insuranceTypeId: '',
userId: '',
insuranceBillCode: '',
effectiveDate: '',
expireDate: '',
insuranceAmount: 0,
insurancePremium: 0,
beneficiary: '',
remark: ''
})
formRef.value?.resetFields()
}
// 初始化
const init = async () => {
await Promise.all([
getCompanyList(),
getTypeList(),
fetchEmployeeOptions(),
getInsuranceList()
])
}
// 组件挂载
onMounted(() => {
init()
})
</script>
<style scoped>
.insurance-manage-container {
padding: 20px;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.page-title {
margin: 0;
font-size: 18px;
font-weight: 500;
}
.search-card {
margin-bottom: 20px;
}
.table-card {
margin-bottom: 20px;
}
</style>