Files
klp-oa/klp-ui/src/views/wms/hrm/todo/index.vue

475 lines
15 KiB
Vue
Raw Normal View History

<template>
<div class="app-container">
<el-row :gutter="20">
<!-- 左侧筛选区域 - 自定义样式替代el-tabs -->
<el-col :span="4">
<div class="filter-container">
<!-- <h4>筛选条件</h4> -->
<!-- 申请类型自定义选项卡替代el-tabs -->
<div class="custom-tabs">
<div class="custom-tabs-header">申请类型</div>
<div class="custom-tabs-nav">
<div
class="custom-tabs-item"
:class="{ active: queryParams.applyType === undefined || queryParams.applyType === '' }"
@click="handleTabClick('applyType', '')"
>
全部
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.applyType === 'leave' }"
@click="handleTabClick('applyType', 'leave')"
>
请假
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.applyType === 'out' }"
@click="handleTabClick('applyType', 'out')"
>
外出
</div>
</div>
</div>
<!-- 审批状态自定义选项卡替代el-tabs -->
<div class="custom-tabs">
<div class="custom-tabs-header">审批状态</div>
<div class="custom-tabs-nav">
<div
class="custom-tabs-item"
:class="{ active: queryParams.approveStatus === undefined || queryParams.approveStatus === '' }"
@click="handleTabClick('approveStatus', '')"
>
全部
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.approveStatus === 'pending' }"
@click="handleTabClick('approveStatus', 'pending')"
>
待审批
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.approveStatus === 'approved' }"
@click="handleTabClick('approveStatus', 'approved')"
>
已审批
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.approveStatus === 'rejected' }"
@click="handleTabClick('approveStatus', 'rejected')"
>
已驳回
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.approveStatus === 'withdrawn' }"
@click="handleTabClick('approveStatus', 'withdrawn')"
>
已撤回
</div>
</div>
</div>
<!-- 重置按钮 -->
<!-- <el-button type="text" @click="resetQuery" style="width: 100%">重置筛选</el-button> -->
</div>
</el-col>
<!-- 右侧表格区域修复el-table多余的total属性 -->
<el-col :span="20">
<el-table
v-loading="loading"
:data="todoList"
border
stripe
style="width: 100%"
@selection-change="handleSelectionChange"
>
<!-- 通用列 -->
<el-table-column prop="applicantName" label="申请人" align="center" />
<el-table-column prop="createBy" label="发起人" align="center" />
<el-table-column prop="applyType" label="申请类型" align="center">
<template slot-scope="scope">
{{ getApplyTypeText(scope.row.applyType) }}
</template>
</el-table-column>
<el-table-column prop="applicantDeptName" label="审批部门" align="center" show-overflow-tooltip/>
<el-table-column prop="startTime" label="开始时间" align="center">
<template slot-scope="scope">
{{ scope.row.startTime ? formatTime(scope.row.startTime) : '-' }}
</template>
</el-table-column>
<el-table-column prop="endTime" label="结束时间" align="center">
<template slot-scope="scope">
{{ scope.row.endTime ? formatTime(scope.row.endTime) : '-' }}
</template>
</el-table-column>
<el-table-column prop="approvalStatus" label="审批状态" align="center">
<template slot-scope="scope">
<el-tag :type="getStatusTagType(scope.row.approvalStatus)">
{{ getStatusText(scope.row.approvalStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="240">
<template slot-scope="scope">
<el-button
size="small"
icon="el-icon-view"
@click="handleDetail(scope.row)"
>
详情
</el-button>
<el-button
v-if="scope.row.approvalStatus === '待审批'"
size="small"
icon="el-icon-check"
@click="handleApprove(scope.row)"
:loading="buttonLoading"
>
同意
</el-button>
<el-button
v-if="scope.row.approvalStatus === '待审批'"
size="small"
icon="el-icon-close"
@click="handleReject(scope.row)"
:loading="buttonLoading"
>
驳回
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryParams.pageNum"
:page-sizes="[10, 20, 50, 100]"
:page-size="queryParams.pageSize"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top: 20px; text-align: right"
>
</el-pagination>
</el-col>
</el-row>
<!-- 详情弹窗无变化 -->
<el-dialog
title="申请详情"
:visible.sync="detailDialogVisible"
width="600px"
destroy-on-close
>
<div v-if="currentDetail.applyType === 'leave'" class="detail-content">
<el-descriptions :column="1" border>
<el-descriptions-item label="请假标题">{{ currentDetail.leaveTitle || '-' }}</el-descriptions-item>
<el-descriptions-item label="请假类型">{{ currentDetail.leaveType || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请人">{{ currentDetail.applicantName || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请部门">{{ currentDetail.applicantDeptName || '-' }}</el-descriptions-item>
<el-descriptions-item label="请假开始时间">{{ formatTime(currentDetail.startTime) || '-' }}</el-descriptions-item>
<el-descriptions-item label="请假结束时间">{{ formatTime(currentDetail.endTime) || '-' }}</el-descriptions-item>
<el-descriptions-item label="请假班次">{{ currentDetail.leaveShift || '-' }}</el-descriptions-item>
<el-descriptions-item label="请假天数">{{ currentDetail.leaveDays || '-' }}</el-descriptions-item>
<el-descriptions-item label="请假原因">{{ currentDetail.leaveReason || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ currentDetail.remark || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<div v-if="currentDetail.applyType === 'out'" class="detail-content">
<el-descriptions :column="1" border>
<el-descriptions-item label="外出类型">{{ currentDetail.outType || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请人">{{ currentDetail.applicantName || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请部门">{{ currentDetail.applicantDeptName || '-' }}</el-descriptions-item>
<el-descriptions-item label="外出开始时间">{{ formatTime(currentDetail.startTime) || '-' }}</el-descriptions-item>
<el-descriptions-item label="外出结束时间">{{ formatTime(currentDetail.endTime) || '-' }}</el-descriptions-item>
<el-descriptions-item label="外出时长(小时)">{{ currentDetail.outHours || '-' }}</el-descriptions-item>
<el-descriptions-item label="外出地点">{{ currentDetail.outPlace || '-' }}</el-descriptions-item>
<el-descriptions-item label="外出原因">{{ currentDetail.outReason || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ currentDetail.remark || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<template v-slot:footer>
<el-button @click="detailDialogVisible = false">关闭</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import { listApproval, updateApproval } from '@/api/wms/approval'
export default {
name: 'TodoList',
data() {
return {
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
approveStatus: '', // 审批状态pending(待审批)、approved(已审批)、rejected(已驳回)、withdrawn(已撤回)
applyType: '', // 申请类型leave(请假)、out(外出),空为全部
},
// 列表数据
todoList: [],
total: 0,
loading: false,
buttonLoading: false,
// 详情弹窗相关
detailDialogVisible: false,
currentDetail: {},
}
},
// 新增从Vuex获取nickName
computed: {
nickName() {
return this.$store.getters.nickName
}
},
created() {
// 页面加载时查询列表
this.getTodoList()
},
methods: {
// 查询待办列表 - 核心修改新增approveName参数
getTodoList() {
this.loading = true
// 拼接请求参数新增approveName
const requestParams = {
...this.queryParams,
approveName: this.nickName
}
listApproval(requestParams)
.then((res) => {
this.todoList = res.rows.map((item) => {
return {
approvalStatus: item.approval.approvalStatus,
applyId: item.approval.applyId,
approvalId: item.approval.approvalId,
applyType: item.approval.applyType,
approverName: item.approval.approverName,
...item.detail, // 合并请假/外出的详情字段
}
})
this.total = res.total
this.loading = false
})
.catch((err) => {
this.loading = false
this.$message.error('查询待办列表失败:' + err.message)
})
},
// 自定义tab点击事件替代原el-tabs的tab-click
handleTabClick(field, value) {
this.queryParams[field] = value
this.handleQuery()
},
// 处理筛选查询
handleQuery() {
this.queryParams.pageNum = 1 // 筛选时重置页码
this.getTodoList()
},
// 重置筛选条件
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 20,
approveStatus: '',
applyType: '',
}
this.getTodoList()
},
// 分页-每页条数变更
handleSizeChange(val) {
this.queryParams.pageSize = val
this.getTodoList()
},
// 分页-当前页变更
handleCurrentChange(val) {
this.queryParams.pageNum = val
this.getTodoList()
},
// 查看详情
handleDetail(row) {
this.currentDetail = { ...row } // 深拷贝避免原数据被修改
this.detailDialogVisible = true
},
// 审批通过
handleApprove(row) {
this.$confirm('确定要审批通过该申请吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
this.buttonLoading = true
try {
// 这里替换为你的审批接口调用
await updateApproval({
approvalId: row.approvalId,
approvalStatus: '已同意',
})
this.$message.success('审批通过成功!')
this.getTodoList() // 重新查询列表
} catch (err) {
this.$message.error('审批通过失败:' + err.message)
} finally {
this.buttonLoading = false
}
})
},
// 驳回申请
handleReject(row) {
this.$confirm('确定要驳回该申请吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
required: true,
}).then(async ({ value }) => {
this.buttonLoading = true
try {
// 这里替换为你的驳回接口调用
await updateApproval({
approvalId: row.approvalId,
approvalStatus: '已驳回'
})
this.$message.success('驳回成功!')
this.getTodoList() // 重新查询列表
} catch (err) {
this.$message.error('驳回失败:' + err.message)
} finally {
this.buttonLoading = false
}
})
},
// 格式化时间(如果项目没有内置工具,可使用此方法)
formatTime(time) {
if (!time) return '-'
return this.parseTime(time, '{y}-{m}-{d} {h}')
},
// 获取审批状态对应的标签类型
getStatusTagType(status) {
const typeMap = {
'待审批': 'warning',
'已同意': 'success',
'已驳回': 'danger',
'已撤消': 'info',
}
return typeMap[status] || 'default'
},
// 获取审批状态的中文文本
getStatusText(status) {
const textMap = {
'待审批': '待审批',
'已同意': '已同意',
'已驳回': '已驳回',
'已撤消': '已撤消',
}
return textMap[status] || '未知状态'
},
getApplyTypeText(type) {
const textMap = {
'leave': '请假',
'out': '外出',
}
return textMap[type] || '未知类型'
},
// 表格多选事件(可选,根据需求使用)
handleSelectionChange(val) {
// 可用于批量操作
console.log('选中的数据:', val)
},
},
}
</script>
<style scoped>
.app-container {
padding: 20px;
}
.filter-container {
background: #f5f7fa;
padding: 20px;
border-radius: 4px;
height: fit-content;
}
.filter-container h4 {
margin: 0 0 20px 0;
font-size: 16px;
color: #333;
}
/* 自定义tabs样式 */
.custom-tabs {
margin-bottom: 20px;
width: 100%;
}
.custom-tabs-header {
font-size: 14px;
color: #606266;
margin-bottom: 10px;
font-weight: 500;
}
.custom-tabs-nav {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.custom-tabs-item {
padding: 10px 15px;
text-align: center;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
background: #ffffff;
border: 1px solid #e4e7ed;
}
.custom-tabs-item:hover {
background: #ecf5ff;
border-color: #c6e2ff;
}
.custom-tabs-item.active {
background: #409eff;
color: #ffffff;
border-color: #409eff;
}
.detail-content {
margin-top: 10px;
}
.el-descriptions {
--el-descriptions-item-label-color: #606266;
--el-descriptions-item-content-color: #303133;
}
</style>