Files
school-developer/src/views/professional/outercompanyemployee/indexSecond.vue
guochunsi c6da6e286f a
2026-01-30 16:29:15 +08:00

622 lines
17 KiB
Vue
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-row shadow="hover" v-show="showSearch">
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="handleFilter">
<el-form-item label="单位名称" prop="companyId">
<el-select
v-model="state.queryForm.companyId"
filterable
clearable
placeholder="请选择单位"
style="width: 200px"
>
<el-option
v-for="item in companyList"
:key="item.id"
:label="item.companyName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="职员编号" prop="employeeNo">
<el-input
v-model="state.queryForm.employeeNo"
placeholder="请输入职员编号"
clearable
style="width: 200px"
/>
</el-form-item>
<el-form-item label="姓名" prop="realName">
<el-input
v-model="state.queryForm.realName"
placeholder="请输入姓名"
clearable
style="width: 200px"
/>
</el-form-item>
<el-form-item label="身份证" prop="idCard">
<el-input
v-model="state.queryForm.idCard"
placeholder="请输入身份证"
clearable
style="width: 200px"
/>
</el-form-item>
<el-form-item label="手机" prop="mobile">
<el-input
v-model="state.queryForm.mobile"
placeholder="请输入手机"
clearable
style="width: 200px"
/>
</el-form-item>
<el-form-item label="允许进出" prop="inoutFlag">
<el-select
v-model="state.queryForm.inoutFlag"
clearable
placeholder="请选择"
style="width: 200px"
>
<el-option
v-for="item in yesNoDict"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="handleFilter">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-row>
<!-- 操作按钮 -->
<el-row>
<div class="mb15" style="width: 100%; position: relative;">
<el-button
v-if="hasAuth('professional_outercompanyemployee_add')"
type="primary"
icon="FolderAdd"
@click="handleAdd"
>
</el-button>
<el-button
type="primary"
plain
icon="UploadFilled"
@click="handleExportIn"
v-if="permission.scope == '1'"
class="ml10"
>
</el-button>
<!-- <el-button
type="warning"
plain
icon="Download"
@click="handleExportScore"
:loading="exportLoading"
class="ml10"
>
导出
</el-button>
<el-button
type="danger"
plain
icon="Delete"
@click="batchDelect"
class="ml10"
>
批量删除
</el-button> -->
<!-- <right-toolbar
v-model:showSearch="showSearch"
class="ml10"
style="position: absolute; right: 0; top: 0;"
@queryTable="getDataList"
></right-toolbar> -->
</div>
</el-row>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
row-key="id"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="companyName" label="单位名称" min-width="150" align="center" show-overflow-tooltip />
<el-table-column prop="employeeNo" label="职员编号" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="realName" label="姓名" min-width="100" align="center" show-overflow-tooltip />
<el-table-column prop="idCard" label="身份证" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="mobile" label="手机" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="inoutFlag" label="允许进出" width="100" align="center">
<template #default="scope">
<el-tag
v-if="scope.row.inoutFlag"
:type="scope.row.inoutFlag === '1' ? 'success' : 'info'"
effect="plain"
>
{{ getDictLabel(scope.row.inoutFlag) }}
</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="头像" width="100" align="center">
<template #default="scope">
<el-button
type="primary"
link
icon="Picture"
@click="handlePictureCardPreview(scope.row.employeeNo)"
>
查看
</el-button>
</template>
</el-table-column>
<!-- <el-table-column prop="updateTime" label="更新时间" width="180" align="center" /> -->
<el-table-column label="操作" width="250" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="hasAuth('professional_outercompanyemployee_edit')"
icon="edit-pen"
link
type="primary"
@click="handleEdit(scope.row)">修改
</el-button>
<el-button
v-if="hasAuth('professional_outercompanyemployee_reset_pw')"
icon="RefreshLeft"
link
type="primary"
@click="resetPassword(scope.row)">重置密码
</el-button>
<!-- <el-button
v-if="hasAuth('professional_outercompanyemployee_del')"
icon="delete"
link
type="primary"
@click="handleDel(scope.row)">删除
</el-button> -->
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 新增/编辑弹窗 -->
<form-dialog
v-model="dialogVisible"
:form-data="form"
:company-list="companyList"
:save-api="saveSecond"
@success="handleFormSuccess"
/>
<!-- 头像预览对话框 -->
<el-dialog v-model="dialogUploadVisible" title="头像预览" append-to-body>
<img width="100%" :src="dialogImageUrl" alt="" style="max-height: 600px; object-fit: contain;" />
</el-dialog>
<!-- 导入对话框 -->
<el-dialog v-model="dialogViewVisible" title="导入文件" append-to-body>
<el-upload
class="upload-container"
ref="uploadFormRef"
action="doUpload"
:limit="1"
:file-list="filesList"
:before-upload="fileUpload"
:auto-upload="false"
>
<template #trigger>
<el-button type="primary">选取文件</el-button>
</template>
<a href="outercomanyemployee.xlsx" rel="external nofollow" download="模板" style="margin-left: 20px">
<el-button type="success">下载模板</el-button>
</a>
<template #tip>
<div class="el-upload__tip">只能上传excel文件且不超过5MB</div>
<div class="el-upload__tip">{{ fileName }}</div>
</template>
</el-upload>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogViewVisible = false">取消</el-button>
<el-button type="primary" @click="submitUpload">导入</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useAuth } from '/@/hooks/auth'
import { useMessage } from '/@/hooks/message'
import { useMessageBox } from '/@/hooks/message'
import { useDict } from '/@/hooks/dict'
import { validateNull } from '/@/utils/validate'
import axios from 'axios'
import request from '/@/utils/request'
import { ElMessageBox } from 'element-plus'
import {
fetchList,
getObj,
saveSecond,
delObj,
batchDel,
resetPassWord
} from '/@/api/professional/stayschool/outercompanyemployee'
import { getList as getCompanyList } from '/@/api/professional/stayschool/outercompany'
const FormDialog = defineAsyncComponent(() => import('./form.vue'))
// 无权限即无节点
const { hasAuth } = useAuth()
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 字典数据
const { yes_no_type: yesNoDict } = useDict('yes_no_type')
// 获取字典标签的辅助函数
const getDictLabel = (value: string | number) => {
const item = yesNoDict.value.find((i: any) => i.value === value)
return item ? item.label : ''
}
// 表格引用
const tableRef = ref()
const queryRef = ref()
const uploadFormRef = ref()
// 搜索显示
const showSearch = ref(true)
// 弹窗状态
const dialogVisible = ref(false)
const dialogUploadVisible = ref(false)
const dialogViewVisible = ref(false)
const exportLoading = ref(false)
// 选中的行数据
const selectList = ref<any[]>([])
const permission = reactive({
hasPermission: "0",
scope: "0"
})
// 单位列表
const companyList = ref<any[]>([])
// 表单数据
const form = reactive({
id: '',
companyId: '',
companyName: '',
employeeNo: '',
realName: '',
idCard: '',
mobile: '',
position: '',
address: '',
inoutFlag: '',
remarks: ''
})
// 头像相关
const dialogImageUrl = ref('')
// 导入相关
const fileName = ref('')
const filesList = ref<any[]>([])
let files: File | null = null
// 配置 useTable - 注意这个 API 返回的数据结构特殊
const state: BasicTableProps = reactive<BasicTableProps>({
pageList: async (params: any) => {
const response = await fetchList({
...params,
companyType: '2' // 二期单位
})
// 特殊处理API 返回的是 response.data.data.dataList.records
const dataList = response.data?.data?.dataList || response.data?.dataList || {}
permission.hasPermission = response.data?.data?.permission?.hasPermission || "0"
permission.scope = response.data?.data?.permission?.scope || "0"
return {
data: {
records: dataList.records || [],
total: dataList.total || 0
}
}
},
queryForm: {
companyId: '',
employeeNo: '',
realName: '',
idCard: '',
mobile: '',
inoutFlag: ''
}
})
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 获取单位列表
const loadCompanyList = async () => {
try {
const response = await getCompanyList({ companyType: '2' })
companyList.value = response.data || []
} catch (error) {
// 获取单位列表失败
}
}
// 重置查询
const resetQuery = () => {
queryRef.value?.resetFields()
getDataList()
}
// 处理搜索
const handleFilter = () => {
getDataList()
}
// 多选变化
const handleSelectionChange = (selection: any[]) => {
selectList.value = selection
}
// 打开新增窗口
const handleAdd = () => {
Object.assign(form, {
id: '',
companyId: '',
companyName: '',
employeeNo: '',
realName: '',
idCard: '',
mobile: '',
position: '',
address: '',
inoutFlag: '',
remarks: ''
})
dialogVisible.value = true
}
// 打开编辑窗口
const handleEdit = async (row: any) => {
try {
const response = await getObj(row.id)
const data = response.data
Object.assign(form, {
id: data.id,
companyId: data.companyId || '',
companyName: data.companyName || '',
employeeNo: data.employeeNo || '',
realName: data.realName || '',
idCard: data.idCard || '',
mobile: data.mobile || '',
position: data.position || '',
address: data.address || '',
inoutFlag: data.inoutFlag || '',
remarks: data.remarks || ''
})
dialogVisible.value = true
} catch (error) {
// 获取详情失败
}
}
// 删除
const handleDel = (row: any) => {
messageBox.confirm('是否确认删除该条记录').then(async () => {
await delObj(row.id)
message.success('删除成功')
// 如果当前页只剩一条数据,且不是第一页,则跳转到上一页
if (state.pagination && state.dataList && state.dataList.length === 1 && state.pagination.current && state.pagination.current > 1) {
state.pagination.current = state.pagination.current - 1
}
getDataList()
}).catch(() => {})
}
// 批量删除
const batchDelect = () => {
if (selectList.value.length === 0) {
message.warning('请至少选择一条数据')
return
}
messageBox.confirm('是否确认删除').then(async () => {
await batchDel(selectList.value)
message.success('删除成功')
selectList.value = []
getDataList()
}).catch(() => {})
}
// 重置密码
const resetPassword = (row: any) => {
messageBox.confirm('是否确定重置密码?').then(async () => {
try {
const response = await resetPassWord(row)
const pw = response.data?.data
if (!validateNull(pw)) {
ElMessageBox.alert('重置后密码为: ' + pw, '重置密码')
} else {
ElMessageBox.alert('系统繁忙,请重试', '重置密码')
}
} catch (error) {
// 重置密码失败
}
}).catch(() => {})
}
// 表单提交成功回调
const handleFormSuccess = () => {
getDataList()
}
// 获取图片 URL
const getImageView = (employeeNo: string) => {
const timestamp = Date.parse(new Date().toString())
const baseUrl = import.meta.env.VITE_API_URL || ''
return `${baseUrl}/admin/user/photo/${employeeNo}?${timestamp}`
}
// 预览头像
const handlePictureCardPreview = (employeeNo: string) => {
dialogImageUrl.value = getImageView(employeeNo)
dialogUploadVisible.value = true
}
// 导入
const handleExportIn = () => {
fileName.value = ""
filesList.value = []
files = null
dialogViewVisible.value = true
}
// 文件上传验证
const fileUpload = (file: File) => {
const fileLast = file.name.split('.')
const extension = fileLast[fileLast.length - 1] === 'xls'
const extension2 = fileLast[fileLast.length - 1] === 'xlsx'
const isLt2M = file.size / 1024 / 1024 < 5
if (!extension && !extension2) {
message.warning('上传模板只能是 xls、xlsx格式!')
return false
}
if (!isLt2M) {
message.warning('上传模板大小不能超过 5MB!')
return false
}
fileName.value = file.name
files = file
return false // 返回false不会自动上传
}
// 提交导入
const submitUpload = async () => {
if (!fileName.value || !files) {
message.warning('请选择要上传的文件!')
return
}
const fileFormData = new FormData()
fileFormData.append('file', files, fileName.value)
try {
const response = await request({
url: `/professional/file/exportOuterCompanyEmployee?companyType=2`,
method: 'post',
data: fileFormData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
if (response.code === 0) {
message.success('操作成功')
dialogViewVisible.value = false
getDataList()
} else {
message.error(response.msg || '导入失败')
}
} catch (error: any) {
message.error(error?.msg || '导入失败')
}
}
// 导出
const handleExportScore = async () => {
if (!state.queryForm || Object.keys(state.queryForm).length === 0) {
message.warning('请选择导出条件')
return
}
exportLoading.value = true
try {
const params = {
...state.queryForm,
companyType: "2"
}
const response = await axios({
method: 'post',
url: '/professional/outercompanyemployee/export',
data: params,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
const blob = new Blob([response.data])
const fileName = '二期单位人员导出表.xls'
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
document.body.removeChild(elink)
message.success('导出成功')
} catch (error: any) {
message.error(error?.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 初始化
onMounted(() => {
loadCompanyList()
})
</script>
<style lang="scss" scoped>
.upload-container {
:deep(.el-upload) {
width: 100%;
}
}
</style>