xinli/xinlidsj/pages/comprehensive/index.vue
2026-02-24 16:49:05 +08:00

297 lines
9.8 KiB
Vue
Raw Permalink 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="page" :class="{ big: isH5 }">
<view class="panel">
<view class="section-title">查询</view>
<input class="input" v-model="keyword" placeholder="请输入姓名/编号" />
<button class="btn" type="primary" :disabled="loading" @click="onSearch">查询</button>
<button class="btn" :disabled="loading" @click="goHistory">查看历史综合报告</button>
<view v-if="errorMsg" class="error">{{ errorMsg }}</view>
</view>
<view v-if="loading" class="state">
<uni-icons type="spinner-cycle" size="28" color="#94AB38"></uni-icons>
<view class="state-text">加载中...</view>
</view>
<view v-else>
<view v-if="hasData" class="panel">
<view class="kv">
<view class="kv-item"><text class="k">用户ID</text><text class="v">{{ selectedUserId || '—' }}</text></view>
</view>
</view>
<view v-if="assessments.length" class="panel">
<view class="section-title">量表(测评)</view>
<view class="list">
<view class="item" v-for="row in assessments" :key="row.assessmentId" @click="openAssessmentDetail(row)">
<view class="item-title">{{ row.scaleName || ('量表#' + row.scaleId) }}</view>
<view class="item-desc">测评ID{{ row.assessmentId }} · 状态:{{ statusText(row.status) }}</view>
<view class="item-foot">开始:{{ formatTime(row.startTime) }} · 提交:{{ formatTime(row.submitTime) }}</view>
</view>
</view>
</view>
<view v-if="reports.length" class="panel">
<view class="section-title">报告</view>
<view class="list">
<view class="item" v-for="row in reports" :key="row.reportId" @click="openReportDetail(row)">
<view class="item-title">{{ row.reportTitle || ('报告#' + row.reportId) }}</view>
<view class="item-desc">类型:{{ row.reportType || '-' }} · 来源:{{ row.sourceType === 'questionnaire' ? '问卷' : '测评' }}</view>
<view class="item-foot">生成:{{ formatTime(row.generateTime) }} · 创建:{{ formatTime(row.createTime) }}</view>
</view>
</view>
</view>
<view v-if="comprehensiveReports.length" class="panel">
<view class="section-title">综合报告</view>
<view class="list">
<view class="item" v-for="row in comprehensiveReports" :key="row.reportId" @click="openComprehensiveDetail(row)">
<view class="item-title">{{ row.reportTitle || ('综合报告#' + row.reportId) }}</view>
<view class="item-desc">创建:{{ formatTime(row.createTime) }}</view>
</view>
</view>
</view>
<view v-if="!hasData" class="state">
<uni-icons type="paperplane" size="34" color="#CBD5E1"></uni-icons>
<view class="state-text">暂无报告</view>
</view>
</view>
</view>
</template>
<script>
import { request } from '../../utils/request'
import { listAssessment } from '../../api/psychology/assessment'
import { listReport } from '../../api/psychology/report'
import { listComprehensiveReportsByUserId } from '../../api/psychology/comprehensiveReport'
import UniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
export default {
components: {
UniIcons
},
data() {
return {
isH5: false,
keyword: '',
loading: false,
errorMsg: '',
selectedUserId: null,
assessments: [],
reports: [],
comprehensiveReports: []
}
},
onLoad() {
try {
const info = uni.getSystemInfoSync()
this.isH5 = info && info.uniPlatform === 'web'
} catch (e) {
this.isH5 = false
}
},
computed: {
hasData() {
return !!(this.selectedUserId && (this.assessments.length || this.reports.length || this.comprehensiveReports.length))
}
},
methods: {
goHistory() {
uni.navigateTo({ url: '/pages/comprehensive/history' })
},
formatTime(val) {
if (!val) return '—'
try {
const d = new Date(val)
if (isNaN(d.getTime())) return '—'
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const hh = String(d.getHours()).padStart(2, '0')
const mm = String(d.getMinutes()).padStart(2, '0')
return `${y}-${m}-${day} ${hh}:${mm}`
} catch (e) {
return '—'
}
},
statusText(status) {
const map = { '0': '进行中', '1': '已完成', '2': '已作废', '3': '已暂停' }
return map[String(status)] || '未知'
},
openAssessmentDetail(row) {
if (!row || !row.assessmentId) return
uni.navigateTo({ url: `/pages/assessment/detail?assessmentId=${encodeURIComponent(row.assessmentId)}` })
},
openReportDetail(row) {
if (!row || !row.reportId) return
const url = `/pages/report/detail?reportId=${encodeURIComponent(row.reportId)}&sourceType=${encodeURIComponent(row.sourceType || '')}`
uni.navigateTo({ url })
},
openComprehensiveDetail(row) {
if (!row || !row.reportId) return
uni.navigateTo({ url: `/pages/comprehensive/detail?reportId=${encodeURIComponent(row.reportId)}` })
},
async onSearch() {
this.errorMsg = ''
this.loading = true
this.selectedUserId = null
this.assessments = []
this.reports = []
this.comprehensiveReports = []
try {
// 先通过学员选项接口把关键词解析成 userId
const userRes = await request({
url: `/psychology/assessment/student/options?keyword=${encodeURIComponent(this.keyword || '')}&limit=1`,
method: 'GET'
})
const userData = userRes && userRes.data ? userRes.data : null
if (!userData || userData.code !== 200) {
this.errorMsg = (userData && userData.msg) ? userData.msg : '查询失败'
this.loading = false
return
}
const list = userData.data || []
if (!list.length) {
this.errorMsg = '未找到匹配人员'
this.loading = false
return
}
this.selectedUserId = list[0].userId
const uid = this.selectedUserId
const [assRes, repRes, compRes] = await Promise.all([
listAssessment({ pageNum: 1, pageSize: 1000, userId: uid }),
listReport({ pageNum: 1, pageSize: 1000, userId: uid }),
listComprehensiveReportsByUserId(uid)
])
const assData = assRes && assRes.data ? assRes.data : null
if (assData && assData.code === 200) {
this.assessments = assData.rows || []
}
const repData = repRes && repRes.data ? repRes.data : null
if (repData && repData.code === 200) {
this.reports = repData.rows || []
}
const compData = compRes && compRes.data ? compRes.data : null
if (compData && compData.code === 200) {
this.comprehensiveReports = compData.data || []
}
this.loading = false
} catch (e) {
this.loading = false
this.errorMsg = e && e.message ? e.message : '网络错误'
}
}
}
}
</script>
<style>
.page {
min-height: 100vh;
padding: 24rpx 24rpx 120rpx;
box-sizing: border-box;
background: #F4F6FB;
}
.panel {
background: rgba(255, 255, 255, 0.95);
border-radius: 18rpx;
padding: 24rpx;
border: 1px solid rgba(15, 23, 42, 0.06);
box-shadow: 0 10rpx 22rpx rgba(15, 23, 42, 0.05);
margin-bottom: 18rpx;
}
.section-title {
margin-top: 8rpx;
font-size: 28rpx;
font-weight: 700;
color: #111827;
margin-bottom: 16rpx;
}
.input {
width: 100%;
background: rgba(15, 23, 42, 0.04);
border-radius: 16rpx;
padding: 26rpx 22rpx;
font-size: 32rpx;
line-height: 44rpx;
min-height: 92rpx;
box-sizing: border-box;
margin-bottom: 16rpx;
border: 1px solid rgba(15, 23, 42, 0.06);
}
.btn {
width: 100%;
margin-top: 12rpx;
border-radius: 16rpx;
}
.kv-item { display: flex; justify-content: space-between; padding: 12rpx 0; border-bottom: 1px solid rgba(15, 23, 42, 0.06); }
.kv-item:last-child { border-bottom: 0; }
.k { color: #94A3B8; font-size: 24rpx; }
.v { color: #111827; font-size: 24rpx; font-weight: 700; }
.list { margin-top: 8rpx; }
.item { background: rgba(255, 255, 255, 0.95); border-radius: 18rpx; padding: 18rpx; border: 1px solid rgba(15, 23, 42, 0.06); margin-bottom: 14rpx; }
.item-title { font-size: 28rpx; font-weight: 700; color: #111827; }
.item-desc { margin-top: 10rpx; font-size: 24rpx; color: #64748B; }
.item-foot { margin-top: 10rpx; font-size: 22rpx; color: #94A3B8; }
.state {
height: 360rpx;
border-radius: 20rpx;
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(15, 23, 42, 0.06);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12rpx;
}
.state-text {
font-size: 24rpx;
color: #94A3B8;
font-weight: 700;
}
.error { margin-top: 14rpx; font-size: 24rpx; color: #ff4d4f; line-height: 36rpx; }
.hint { margin-top: 10rpx; font-size: 22rpx; color: #8f959e; }
.page.big {
padding: 14rpx 14rpx 120rpx;
background-image:
radial-gradient(1100rpx 520rpx at 50% 14%, rgba(43, 107, 255, 0.30) 0%, rgba(6, 16, 40, 0.0) 65%),
linear-gradient(180deg, rgba(5, 11, 24, 0.90) 0%, rgba(8, 20, 45, 0.85) 42%, rgba(6, 16, 40, 0.92) 100%),
url('/static/bg.png');
background-size: auto, auto, cover;
background-position: center, center, center;
background-repeat: no-repeat, no-repeat, no-repeat;
}
.page.big .panel,
.page.big .item,
.page.big .state {
border: 1px solid rgba(116, 216, 255, 0.22);
background: linear-gradient(180deg, rgba(10, 18, 38, 0.75) 0%, rgba(5, 10, 22, 0.55) 100%);
box-shadow: 0 12rpx 24rpx rgba(0, 0, 0, 0.35);
}
.page.big .section-title,
.page.big .item-title,
.page.big .v {
color: rgba(235, 248, 255, 0.92);
}
.page.big .k,
.page.big .item-desc,
.page.big .item-foot,
.page.big .state-text {
color: rgba(201, 242, 255, 0.65);
}
.page.big .input {
background: rgba(7, 13, 28, 0.35);
border-color: rgba(116, 216, 255, 0.18);
color: rgba(235, 248, 255, 0.92);
}
.page.big .btn[type="primary"] {
background: linear-gradient(90deg, rgba(116, 216, 255, 0.95) 0%, rgba(43, 107, 255, 0.92) 100%);
color: #0b1226;
}
</style>