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

254 lines
9.4 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="card">
<view class="card-title">查询</view>
<view class="field">
<input class="input" v-model="keyword" placeholder="请输入姓名 / 编号" />
</view>
<button class="btn primary" :disabled="loading" @click="onSearch">查询</button>
<view class="btn-row">
<button class="btn ghost" :disabled="!selectedUserId" @click="goUserTags">标签管理</button>
<button class="btn ghost" :disabled="!selectedUserId" @click="goCompare">历史对比</button>
</view>
<view v-if="errorMsg" class="error">{{ errorMsg }}</view>
</view>
<view class="card">
<view class="card-title">概览</view>
<view class="kv">
<view class="kv-item"><text class="k">姓名</text><text class="v">{{ summary.userName || summary.nickName || '—' }}</text></view>
<view class="kv-item"><text class="k">部门</text><text class="v">{{ summary.deptName || '—' }}</text></view>
<view class="kv-item"><text class="k">监区</text><text class="v">{{ summary.prisonAreaName || '—' }}</text></view>
<view class="kv-item"><text class="k">测评数</text><text class="v">{{ summary.totalAssessments || 0 }}</text></view>
</view>
</view>
<view class="card">
<view class="card-title">量表记录</view>
<view v-if="loading" class="empty">加载中...</view>
<view v-else>
<view v-if="(summary.scales || []).length === 0" class="empty">暂无数据</view>
<view v-else class="list">
<view class="item" v-for="(s, idx) in summary.scales" :key="idx" @click="openScaleReport(s)">
<view class="item-head">
<view class="item-title">{{ s.scaleName || ('量表#' + s.scaleId) }}</view>
<view class="pill">{{ s.latestReportStatus || '—' }}</view>
</view>
<view class="item-grid">
<view class="item-desc">次数:{{ (s.attempts || []).length }}</view>
<view class="item-desc">最近:{{ formatTime(s.latestSubmitTime) }}</view>
<view class="item-desc">分数{{ s.latestTotalScore == null ? '' : s.latestTotalScore }}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { getStudentOptions, getUserAssessmentSummary } from '../../api/psychology/assessment'
export default {
data() {
return {
isH5: false,
keyword: '',
loading: false,
errorMsg: '',
selectedUserId: null,
summary: {
scales: []
}
}
},
onLoad(query) {
try {
const info = uni.getSystemInfoSync()
this.isH5 = info && info.uniPlatform === 'web'
} catch (e) {
this.isH5 = false
}
const keyword = query && query.keyword ? String(query.keyword) : ''
if (keyword) {
this.keyword = keyword
}
const userId = query && query.userId ? query.userId : null
if (userId) {
this.selectedUserId = userId
this.fetchSummary(userId)
return
}
if (keyword) {
this.onSearch()
}
},
methods: {
openScaleReport(scale) {
if (!scale) return
const attempts = Array.isArray(scale.attempts) ? scale.attempts.slice() : []
attempts.sort((a, b) => {
const ta = a && (a.submitTime || a.startTime) ? new Date(a.submitTime || a.startTime).getTime() : 0
const tb = b && (b.submitTime || b.startTime) ? new Date(b.submitTime || b.startTime).getTime() : 0
return tb - ta
})
const withReport = attempts.find((a) => a && a.reportId)
if (!withReport || !withReport.reportId) {
uni.showToast({ title: '暂无可用报告', icon: 'none' })
return
}
uni.navigateTo({
url: `/pages/report/detail?reportId=${encodeURIComponent(withReport.reportId)}&sourceType=assessment`
})
},
fetchSummary(userId) {
if (!userId) return
this.errorMsg = ''
this.loading = true
this.summary = { scales: [] }
return getUserAssessmentSummary(userId)
.then((res) => {
this.loading = false
const data = res && res.data ? res.data : null
if (!data || data.code !== 200) {
this.errorMsg = (data && data.msg) ? data.msg : '获取画像失败'
return
}
this.summary = data.data || { scales: [] }
})
.catch((e) => {
this.loading = false
this.errorMsg = e && e.message ? e.message : '网络错误'
})
},
goUserTags() {
if (!this.selectedUserId) return
uni.navigateTo({ url: `/pages/profile/tags?userId=${encodeURIComponent(this.selectedUserId)}` })
},
goCompare() {
if (!this.selectedUserId) return
uni.navigateTo({ url: `/pages/profile/compare?userId=${encodeURIComponent(this.selectedUserId)}` })
},
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 '—'
}
},
onSearch() {
this.errorMsg = ''
this.loading = true
this.summary = { scales: [] }
this.selectedUserId = null
getStudentOptions({ keyword: this.keyword || '', limit: 1 }).then((res) => {
const data = res && res.data ? res.data : null
if (!data || data.code !== 200) {
this.loading = false
this.errorMsg = (data && data.msg) ? data.msg : '查询失败'
return
}
const list = data.data || []
if (list.length === 0) {
this.loading = false
this.errorMsg = '未找到匹配人员'
return
}
this.selectedUserId = list[0].userId
this.fetchSummary(this.selectedUserId)
}).catch((e) => {
this.loading = false
this.errorMsg = e && e.message ? e.message : '网络错误'
})
}
}
}
</script>
<style scoped>
.page { min-height: 100vh; padding: 24rpx 24rpx 120rpx; box-sizing: border-box; background: #F4F6FB; }
.card { background: rgba(255, 255, 255, 0.95); border-radius: 18rpx; padding: 24rpx; border: 1px solid rgba(15, 23, 42, 0.06); margin-bottom: 18rpx; box-shadow: 0 10rpx 22rpx rgba(15, 23, 42, 0.05); }
.card-title { font-size: 28rpx; font-weight: 700; color: #111827; margin-bottom: 14rpx; }
.field { margin-bottom: 12rpx; }
.input { width: 100%; background: rgba(15, 23, 42, 0.04); border-radius: 16rpx; padding: 22rpx 20rpx; font-size: 28rpx; box-sizing: border-box; border: 1px solid rgba(15,23,42,0.06); min-height: 92rpx; line-height: 92rpx; }
.btn { width: 100%; height: 84rpx; line-height: 84rpx; border-radius: 18rpx; font-size: 28rpx; }
.btn.primary { background: #1677ff; color: #FFFFFF; }
.btn.ghost { background: #FFFFFF; color: #1F2937; border: 1px solid rgba(17,24,39,0.12); }
.btn-row { display: flex; justify-content: space-between; margin-top: 14rpx; }
.btn-row .btn { width: 48%; height: 78rpx; line-height: 78rpx; }
.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: #6B7280; font-size: 24rpx; }
.v { color: #111827; font-size: 24rpx; font-weight: 700; }
.list { margin-top: 8rpx; }
.item { background: #FFFFFF; border-radius: 20rpx; padding: 22rpx; border: 1px solid rgba(15, 23, 42, 0.06); margin-bottom: 18rpx; }
.item-head { display: flex; justify-content: space-between; align-items: center; }
.item-title { font-size: 28rpx; font-weight: 700; color: #111827; }
.pill { padding: 8rpx 14rpx; border-radius: 999rpx; font-size: 22rpx; color: #2B6BFF; background: rgba(43, 107, 255, 0.12); }
.item-grid { margin-top: 10rpx; display: flex; flex-wrap: wrap; justify-content: space-between; }
.item-desc { width: 48%; margin-top: 8rpx; font-size: 24rpx; color: #4B5563; }
.empty { height: 200rpx; border-radius: 20rpx; background: rgba(255, 255, 255, 0.85); border: 1px solid rgba(15, 23, 42, 0.06); display: flex; align-items: center; justify-content: center; color: #94A3B8; font-size: 24rpx; }
.error { margin-top: 14rpx; font-size: 24rpx; color: #EF4444; line-height: 36rpx; }
.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 .card,
.page.big .item,
.page.big .empty {
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 .card-title,
.page.big .item-title,
.page.big .v {
color: rgba(235, 248, 255, 0.92);
}
.page.big .k,
.page.big .item-desc {
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.primary {
background: linear-gradient(90deg, rgba(116, 216, 255, 0.95) 0%, rgba(43, 107, 255, 0.92) 100%);
color: #0b1226;
}
.page.big .btn.ghost {
background: rgba(7, 13, 28, 0.35);
border-color: rgba(116, 216, 255, 0.18);
color: rgba(201, 242, 255, 0.86);
}
.page.big .pill {
color: rgba(201, 242, 255, 0.90);
background: rgba(116, 216, 255, 0.10);
border: 1px solid rgba(116, 216, 255, 0.18);
}
</style>