Files
hzdyjs/mobile/src/pages/visit/detail.vue
T
2025-10-25 17:19:54 +08:00

467 lines
16 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="visit-detail-container">
<!-- 顶部导航 -->
<u-navbar title="走访详情" :border-bottom="false" bg-color="#3c9cff" title-color="#fff">
<view slot="left" @click="goBack">
<u-icon name="arrow-left" color="#fff" size="22"></u-icon>
</view>
</u-navbar>
<!-- 加载状态 -->
<u-loading-page :loading="pageLoading" loading-text="加载中..."></u-loading-page>
<!-- 内容区域 -->
<view v-if="!pageLoading" class="content-wrapper">
<!-- 学生信息 -->
<view class="info-section">
<view class="section-title">学生信息</view>
<view class="section-content">
<view class="info-item">
<text class="info-label">学生姓名:</text>
<text class="info-value">{{ visitInfo.studentName || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">学号:</text>
<text class="info-value">{{ visitInfo.studentNo || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">班级:</text>
<text class="info-value">{{ visitInfo.className || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">专业:</text>
<text class="info-value">{{ visitInfo.majorName || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">学院:</text>
<text class="info-value">{{ visitInfo.collegeName || '-' }}</text>
</view>
</view>
</view>
<!-- 企业信息 -->
<view class="info-section">
<view class="section-title">企业信息</view>
<view class="section-content">
<view class="info-item">
<text class="info-label">企业名称:</text>
<text class="info-value">{{ visitInfo.companyName || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">企业地址:</text>
<text class="info-value">{{ visitInfo.companyAddress || '-' }}</text>
</view>
</view>
</view>
<!-- 走访基本信息 -->
<view class="info-section">
<view class="section-title">走访基本信息</view>
<view class="section-content">
<view class="info-item">
<text class="info-label">走访日期:</text>
<text class="info-value">{{ visitInfo.visitDate || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">走访人员:</text>
<text class="info-value">{{ visitInfo.visitorName || '-' }}</text>
</view>
<view class="info-item" v-if="visitInfo.visitorPosition">
<text class="info-label">走访人职务:</text>
<text class="info-value">{{ visitInfo.visitorPosition }}</text>
</view>
<view class="info-item">
<text class="info-label">走访状态:</text>
<u-tag
:text="getStatusText(visitInfo.status)"
:type="getStatusType(visitInfo.status)"
size="mini"
/>
</view>
<view class="info-item info-item-full" v-if="visitInfo.visitPurpose">
<text class="info-label">走访目的:</text>
<text class="info-value info-value-multiline">
{{ visitInfo.visitPurpose }}
</text>
</view>
</view>
</view>
<!-- 走访内容 -->
<view class="info-section">
<view class="section-title">走访内容</view>
<view class="section-content">
<view class="info-item info-item-full" v-if="visitInfo.companySituation">
<text class="info-label">企业情况:</text>
<text class="info-value info-value-multiline">
{{ visitInfo.companySituation }}
</text>
</view>
<view class="info-item info-item-full" v-if="visitInfo.studentPerformance">
<text class="info-label">学生表现:</text>
<text class="info-value info-value-multiline">
{{ visitInfo.studentPerformance }}
</text>
</view>
<view class="info-item info-item-full" v-if="visitInfo.problemsFound">
<text class="info-label">发现问题:</text>
<text class="info-value info-value-multiline">
{{ visitInfo.problemsFound }}
</text>
</view>
<view class="info-item info-item-full" v-if="visitInfo.suggestions">
<text class="info-label">改进建议:</text>
<text class="info-value info-value-multiline">
{{ visitInfo.suggestions }}
</text>
</view>
<view class="info-item info-item-full" v-if="visitInfo.visitSummary">
<text class="info-label">走访总结:</text>
<text class="info-value info-value-multiline">
{{ visitInfo.visitSummary }}
</text>
</view>
</view>
</view>
<!-- 现场照片 -->
<view class="info-section" v-if="imageList.length > 0">
<view class="section-title">现场照片</view>
<view class="section-content">
<view class="image-grid">
<view
class="image-item"
v-for="(image, index) in imageList"
:key="index"
@click="previewImage(index)"
>
<image :src="image.url" mode="aspectFill" />
</view>
</view>
</view>
</view>
<!-- 备注信息 -->
<view class="info-section" v-if="visitInfo.remark">
<view class="section-title">备注信息</view>
<view class="section-content">
<view class="info-item info-item-full">
<text class="info-value info-value-multiline">{{ visitInfo.remark }}</text>
</view>
</view>
</view>
<!-- 系统信息 -->
<view class="info-section">
<view class="section-title">系统信息</view>
<view class="section-content">
<view class="info-item">
<text class="info-label">创建时间:</text>
<text class="info-value">{{ visitInfo.createTime || '-' }}</text>
</view>
<view class="info-item" v-if="visitInfo.updateTime">
<text class="info-label">更新时间:</text>
<text class="info-value">{{ visitInfo.updateTime }}</text>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="action-section" v-if="canEdit">
<u-button
type="primary"
shape="round"
@click="handleEdit"
:loading="loading"
style="flex: 1; margin-right: 20rpx"
>
<u-icon name="edit-pen" size="16" style="margin-right: 4rpx"></u-icon>
编辑走访记录
</u-button>
<u-button
type="error"
shape="round"
@click="handleDelete"
:loading="loading"
plain
style="flex: 1"
>
<u-icon name="trash" size="16" style="margin-right: 4rpx"></u-icon>
删除记录
</u-button>
</view>
</view>
</view>
</template>
<script>
import { getVisit, delVisit } from '@/api/visit.js';
export default {
name: 'VisitDetail',
data() {
return {
// 页面参数
visitId: '',
// 页面状态
pageLoading: true,
loading: false,
// 走访信息
visitInfo: {},
// 图片数据
imageList: [],
};
},
computed: {
// 是否可以编辑
canEdit() {
// 只有计划中或草稿状态的记录可以编辑
return (
this.visitInfo.status === 'planned' ||
this.visitInfo.status === '0' ||
this.visitInfo.status === 'draft'
);
},
},
onLoad(options) {
if (options.id) {
this.visitId = options.id;
this.loadVisitDetail();
} else {
uni.showToast({ title: '参数错误', icon: 'none' });
uni.navigateBack();
}
},
methods: {
// 返回上一页
goBack() {
uni.navigateBack();
},
// 加载走访记录详情
async loadVisitDetail() {
this.pageLoading = true;
try {
const response = await getVisit(this.visitId);
if (response.code === 200 && response.data) {
this.visitInfo = response.data;
// 处理图片数据
if (response.data.visitImages) {
try {
this.imageList = JSON.parse(response.data.visitImages) || [];
} catch (e) {
console.warn('解析图片数据失败:', e);
this.imageList = [];
}
}
} else {
uni.showToast({ title: response.msg || '获取数据失败', icon: 'none' });
uni.navigateBack();
}
} catch (error) {
console.error('加载走访记录详情失败:', error);
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
uni.navigateBack();
} finally {
this.pageLoading = false;
}
},
// 获取状态文本
getStatusText(status) {
switch (status) {
case 'planned':
case '0':
return '计划中';
case 'completed':
case '1':
return '已完成';
case 'cancelled':
case '2':
return '已取消';
default:
return status || '未知';
}
},
// 获取状态类型
getStatusType(status) {
switch (status) {
case 'planned':
case '0':
return 'primary';
case 'completed':
case '1':
return 'success';
case 'cancelled':
case '2':
return 'error';
default:
return 'default';
}
},
// 预览图片
previewImage(index) {
const urls = this.imageList.map((item) => item.url);
uni.previewImage({
urls,
current: index,
});
},
// 编辑走访记录
handleEdit() {
uni.navigateTo({
url: `/pages/visit/edit?id=${this.visitId}`,
});
},
// 删除走访记录
handleDelete() {
uni.showModal({
title: '确认删除',
content: '确定要删除这条走访记录吗?删除后无法恢复。',
success: async (res) => {
if (res.confirm) {
await this.deleteVisit();
}
},
});
},
// 执行删除
async deleteVisit() {
this.loading = true;
try {
const response = await delVisit(this.visitId);
if (response.code === 200) {
uni.showToast({ title: '删除成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({ title: response.msg || '删除失败', icon: 'none' });
}
} catch (error) {
console.error('删除走访记录失败:', error);
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
} finally {
this.loading = false;
}
},
},
};
</script>
<style lang="scss" scoped>
.visit-detail-container {
min-height: 100vh;
background-color: #f8f8f8;
}
.content-wrapper {
padding: 20rpx;
padding-bottom: 40rpx;
}
.info-section {
background: #ffffff;
border-radius: 12rpx;
margin-bottom: 20rpx;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
.section-title {
padding: 24rpx 20rpx 16rpx;
font-size: 32rpx;
font-weight: 600;
color: #303133;
border-bottom: 1rpx solid #ebeef5;
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
}
.section-content {
padding: 20rpx;
}
}
.info-item {
display: flex;
align-items: flex-start;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
&.info-item-full {
flex-direction: column;
align-items: stretch;
}
.info-label {
font-size: 28rpx;
color: #606266;
width: 160rpx;
flex-shrink: 0;
margin-bottom: 8rpx;
}
.info-value {
font-size: 28rpx;
color: #303133;
flex: 1;
&.info-value-multiline {
line-height: 1.8;
word-break: break-all;
color: #606266;
}
}
}
.image-grid {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
.image-item {
width: 200rpx;
height: 200rpx;
border-radius: 8rpx;
overflow: hidden;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
}
image {
width: 100%;
height: 100%;
}
}
}
.action-section {
display: flex;
gap: 20rpx;
padding: 20rpx;
background: #ffffff;
border-radius: 12rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
}
</style>