OfficeSystem/pages/verify/detail/index.vue

514 lines
12 KiB
Vue
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>
<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', // 进行中
'3': 'success', // 已完成
'4': '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', // 已驳回
'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>