514 lines
12 KiB
Vue
514 lines
12 KiB
Vue
<template>
|
||
<view class="verify-detail-page">
|
||
<!-- 自定义导航栏 -->
|
||
<view class="custom-navbar">
|
||
<view class="navbar-content">
|
||
<text class="nav-btn" @click="handleBack">‹</text>
|
||
<text class="nav-title">详情</text>
|
||
<text class="nav-btn" @click="handleBack">×</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 内容区域 -->
|
||
<scroll-view class="content-scroll" scroll-y v-if="!loading">
|
||
<view class="content-wrapper">
|
||
<!-- 详情表格 -->
|
||
<view class="info-card">
|
||
<view class="info-row">
|
||
<text class="info-label">所属项目</text>
|
||
<text class="info-value">{{ detailData.projectName || '--' }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">任务类型</text>
|
||
<view class="info-value">
|
||
<uv-tags
|
||
:text="getTaskTypeLabel(detailData.task?.type)"
|
||
type="success"
|
||
size="mini"
|
||
:plain="false"
|
||
></uv-tags>
|
||
</view>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">优先级</text>
|
||
<view class="info-value">
|
||
<uv-tags
|
||
:text="getPriorityLabel(detailData.task?.level)"
|
||
:type="getPriorityType(detailData.task?.level)"
|
||
size="mini"
|
||
:plain="false"
|
||
></uv-tags>
|
||
</view>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">任务状态</text>
|
||
<view class="info-value">
|
||
<uv-tags
|
||
:text="getTaskStatusLabel(detailData.task?.status)"
|
||
:type="getTaskStatusType(detailData.task?.status)"
|
||
size="mini"
|
||
:plain="false"
|
||
></uv-tags>
|
||
</view>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">审核状态</text>
|
||
<view class="info-value">
|
||
<uv-tags
|
||
:text="getVerifyStatusLabel(detailData.status)"
|
||
:type="getVerifyStatusType(detailData.status)"
|
||
size="mini"
|
||
:plain="false"
|
||
></uv-tags>
|
||
</view>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">创建人</text>
|
||
<text class="info-value">{{ detailData.task?.createName || '--' }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">创建时间</text>
|
||
<text class="info-value">{{ detailData.createTime || '--' }}</text>
|
||
</view>
|
||
<view class="info-row" v-if="detailData.task?.expireTime">
|
||
<text class="info-label">截止时间</text>
|
||
<text class="info-value">{{ detailData.task.expireTime }}</text>
|
||
</view>
|
||
<view class="info-row" v-if="detailData.task?.passTime">
|
||
<text class="info-label">结束时间</text>
|
||
<text class="info-value">{{ detailData.task.passTime }}</text>
|
||
</view>
|
||
<view class="info-row" v-if="detailData.userName">
|
||
<text class="info-label">审核人</text>
|
||
<text class="info-value">{{ detailData.userName }}</text>
|
||
</view>
|
||
<view class="info-row" v-if="detailData.verifyTime">
|
||
<text class="info-label">审核时间</text>
|
||
<text class="info-value">{{ detailData.verifyTime }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 任务描述 -->
|
||
<view class="info-card" v-if="detailData.task?.description">
|
||
<view class="card-title">任务描述</view>
|
||
<view class="content-text">{{ detailData.task.description }}</view>
|
||
</view>
|
||
|
||
<!-- 备注 -->
|
||
<view class="info-card" v-if="detailData.createRemark">
|
||
<view class="card-title">备注</view>
|
||
<view class="content-text">{{ detailData.createRemark }}</view>
|
||
</view>
|
||
|
||
<!-- 改动值 -->
|
||
<view class="info-card" v-if="changeData">
|
||
<view class="card-title">改动值</view>
|
||
<view class="info-row">
|
||
<text class="info-label">字段</text>
|
||
<text class="info-value">{{ changeData.field || '--' }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">值</text>
|
||
<text class="info-value">{{ changeData.value || '--' }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 评论输入框 -->
|
||
<view class="info-card">
|
||
<view class="card-title">审核意见</view>
|
||
<textarea
|
||
v-model="commentText"
|
||
class="comment-textarea"
|
||
placeholder="请输入审核意见"
|
||
:maxlength="500"
|
||
:auto-height="true"
|
||
></textarea>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 加载中 -->
|
||
<view class="loading-wrapper" v-if="loading">
|
||
<text>加载中...</text>
|
||
</view>
|
||
|
||
<!-- 底部操作按钮 -->
|
||
<view class="action-buttons" v-if="!loading && detailData.status === '3'">
|
||
<view class="btn-wrapper">
|
||
<uv-button type="primary" size="normal" @click="handleApprove">通过</uv-button>
|
||
</view>
|
||
<view class="btn-wrapper">
|
||
<uv-button type="error" size="normal" @click="handleReject">驳回</uv-button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { getVerifyDetail, approveVerify, rejectVerify } from '@/api/verify'
|
||
import { getDictLabel } from '@/utils/dict'
|
||
|
||
// 页面参数
|
||
const verifyId = ref('')
|
||
const detailData = ref({})
|
||
const loading = ref(false)
|
||
const commentText = ref('')
|
||
|
||
// 解析改动数据
|
||
const changeData = computed(() => {
|
||
if (!detailData.value.data) return null
|
||
|
||
try {
|
||
const data = typeof detailData.value.data === 'string'
|
||
? JSON.parse(detailData.value.data)
|
||
: detailData.value.data
|
||
|
||
if (data.expireTime) {
|
||
return {
|
||
field: '截止时间',
|
||
value: data.expireTime
|
||
}
|
||
}
|
||
|
||
return null
|
||
} catch (e) {
|
||
console.error('解析改动数据失败:', e)
|
||
return null
|
||
}
|
||
})
|
||
|
||
// 获取任务类型标签
|
||
const getTaskTypeLabel = (type) => {
|
||
if (!type) return '--'
|
||
console.log('getDictLabel', type)
|
||
console.log('getDictLabel',getDictLabel('task_type', type))
|
||
return getDictLabel('task_type', type)
|
||
}
|
||
|
||
// 获取优先级标签
|
||
const getPriorityLabel = (level) => {
|
||
if (!level) return '--'
|
||
return getDictLabel('task_level', level)
|
||
}
|
||
|
||
// 获取优先级类型(用于标签颜色)
|
||
const getPriorityType = (level) => {
|
||
const typeMap = {
|
||
'1': 'error', // 高优先级 - 红色
|
||
'2': 'warning', // 中优先级 - 黄色
|
||
'3': 'success' // 低优先级 - 绿色
|
||
}
|
||
return typeMap[level] || 'primary'
|
||
}
|
||
|
||
// 获取任务状态标签
|
||
const getTaskStatusLabel = (status) => {
|
||
if (!status) return '--'
|
||
return getDictLabel('task_status', status)
|
||
}
|
||
|
||
// 获取任务状态类型(用于标签颜色)
|
||
const getTaskStatusType = (status) => {
|
||
const typeMap = {
|
||
'1': 'primary', // 待接收
|
||
'2': 'warning', // 进行中
|
||
'4': 'success', // 已完成
|
||
'6': 'error' // 已取消
|
||
}
|
||
return typeMap[status] || 'primary'
|
||
}
|
||
|
||
// 获取审核状态标签
|
||
const getVerifyStatusLabel = (status) => {
|
||
if (!status) return '--'
|
||
return getDictLabel('verify_status', status)
|
||
}
|
||
|
||
// 获取审核状态类型(用于标签颜色)
|
||
const getVerifyStatusType = (status) => {
|
||
const typeMap = {
|
||
'1': 'success', // 已通过
|
||
'2': 'error', // 已驳回error
|
||
'3': 'warning' // 待审核
|
||
}
|
||
return typeMap[status] || 'primary'
|
||
}
|
||
|
||
// 加载审核详情
|
||
const loadVerifyDetail = async (id) => {
|
||
if (!id) {
|
||
uni.showToast({
|
||
title: '审核ID不能为空',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
try {
|
||
loading.value = true
|
||
const res = await getVerifyDetail(id)
|
||
console.log('审核详情数据:', res)
|
||
detailData.value = res || {}
|
||
loading.value = false
|
||
} catch (err) {
|
||
console.error('加载审核详情失败:', err)
|
||
loading.value = false
|
||
uni.showToast({
|
||
title: '加载审核详情失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 处理审核通过
|
||
const handleApprove = async () => {
|
||
if (!verifyId.value) {
|
||
uni.showToast({
|
||
title: '审核ID不能为空',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
try {
|
||
uni.showLoading({
|
||
title: '处理中...'
|
||
})
|
||
|
||
await approveVerify(verifyId.value, commentText.value)
|
||
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: '审核通过',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 刷新详情数据
|
||
await loadVerifyDetail(verifyId.value)
|
||
|
||
// 延迟返回上一页
|
||
setTimeout(() => {
|
||
uni.navigateBack()
|
||
}, 1500)
|
||
} catch (err) {
|
||
uni.hideLoading()
|
||
console.error('审核通过失败:', err)
|
||
uni.showToast({
|
||
title: err.message || '审核通过失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 处理审核驳回
|
||
const handleReject = async () => {
|
||
if (!verifyId.value) {
|
||
uni.showToast({
|
||
title: '审核ID不能为空',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 确认对话框
|
||
uni.showModal({
|
||
title: '确认驳回',
|
||
content: '确定要驳回此审核吗?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
uni.showLoading({
|
||
title: '处理中...'
|
||
})
|
||
|
||
await rejectVerify(verifyId.value, commentText.value)
|
||
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: '已驳回',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 刷新详情数据
|
||
await loadVerifyDetail(verifyId.value)
|
||
|
||
// 延迟返回上一页
|
||
setTimeout(() => {
|
||
uni.navigateBack()
|
||
}, 1500)
|
||
} catch (err) {
|
||
uni.hideLoading()
|
||
console.error('审核驳回失败:', err)
|
||
uni.showToast({
|
||
title: err.message || '审核驳回失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 返回上一页
|
||
const handleBack = () => {
|
||
uni.navigateBack()
|
||
}
|
||
|
||
// 页面加载
|
||
onLoad((options) => {
|
||
const id = options.id || options.verifyId
|
||
if (id) {
|
||
verifyId.value = id
|
||
loadVerifyDetail(id)
|
||
} else {
|
||
uni.showToast({
|
||
title: '缺少审核ID',
|
||
icon: 'none'
|
||
})
|
||
setTimeout(() => {
|
||
uni.navigateBack()
|
||
}, 1500)
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.verify-detail-page {
|
||
width: 100%;
|
||
height: 100vh;
|
||
background: #f5f5f5;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.custom-navbar {
|
||
background: #fff;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
}
|
||
|
||
.navbar-content {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 12px 16px;
|
||
height: 44px;
|
||
}
|
||
|
||
.nav-btn {
|
||
font-size: 24px;
|
||
color: #333;
|
||
width: 32px;
|
||
text-align: center;
|
||
line-height: 32px;
|
||
}
|
||
|
||
.nav-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.content-scroll {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.content-wrapper {
|
||
padding: 16px;
|
||
}
|
||
|
||
.info-card {
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
padding: 16px;
|
||
margin-bottom: 16px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 12px 0;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.info-label {
|
||
font-size: 14px;
|
||
color: #666;
|
||
width: 100px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.info-value {
|
||
font-size: 14px;
|
||
color: #333;
|
||
flex: 1;
|
||
text-align: right;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.content-text {
|
||
font-size: 14px;
|
||
color: #333;
|
||
line-height: 1.6;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.comment-textarea {
|
||
width: 100%;
|
||
min-height: 100px;
|
||
padding: 12px;
|
||
font-size: 14px;
|
||
color: #333;
|
||
background: #f5f5f5;
|
||
border-radius: 8px;
|
||
border: 1px solid #e0e0e0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.loading-wrapper {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #999;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
gap: 12px;
|
||
padding: 16px;
|
||
background: #fff;
|
||
border-top: 1px solid #e0e0e0;
|
||
position: sticky;
|
||
bottom: 0;
|
||
z-index: 100;
|
||
}
|
||
|
||
.btn-wrapper {
|
||
flex: 1;
|
||
}
|
||
</style>
|
||
|