xinli/xinlidsj/pages/message/send.groovy
2026-02-24 16:49:05 +08:00

479 lines
15 KiB
Groovy
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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">
<view class="panel">
<view class="title"></view>
<view class="subtitle">选择接收人并关联报告,一键发送通知/</view>
</view>
<view class="panel">
<view class="section-title"></view>
<view class="seg" style="margin-bottom: 18rpx;">
<view class="seg-item" :class="sendMode==='role'?'active':''" @tap="setSendMode('role')">按角色群发</view>
<view class="seg-item" :class="sendMode==='single'?'active':''" @tap="setSendMode('single')"></view>
</view>
<view v-if="sendMode==='single'">
<view class="section-title"></view>
<input class="input" v-model="receiverKeyword" placeholder="输入姓名/" />
<button class="btn" type="default" :disabled="receiverLoading" @click="searchReceivers">查询收件人</button>
<view v-if="receiverErrorMsg" class="error">{{ receiverErrorMsg }}</view>
<view v-if="receiverLoading" class="placeholder">加载中...</view>
<view v-else class="list">
<view v-if="receiverRows.length" class="placeholder">请选择收件人</view>
<view v-if="receiverRows.length">
<view class="item" v-for="u in receiverRows" :key="u.userId" @tap="selectReceiver(u)">
<view class="item-title">{{ u.nickName || ('用户#' + u.userId) }}</view>
<view class="item-desc">编号:{{ u.infoNumber || '—' }} userId{{ u.userId }}</view>
</view>
</view>
<view v-if="receiverId" class="hint">已选择收件人:{{ receiverLabel }}</view>
</view>
</view>
<view class="seg">
<view class="seg-item" :class="recipient==='area_manager'?'active':''" @tap="selectRecipient('area_manager')">监区负责人</view>
<view class="seg-item" :class="recipient==='psy_counselor'?'active':''" @tap="selectRecipient('psy_counselor')">心理辅导员</view>
</view>
<view class="section-title">标题(通知必填)</view>
<input class="input" v-model="title" placeholder=" " />
<view class="section-title">内容</view>
<textarea class="textarea" v-model="content" placeholder=""></textarea>
<view class="section-title">选择报告(自动填充)</view>
<input class="input" v-model="reportKeyword" placeholder="/编号,先查询人员" />
<button class="btn" type="default" :disabled="reportLoading" @click="searchPeople"></button>
<view v-if="reportErrorMsg" class="error">{{ reportErrorMsg }}</view>
<view v-if="reportLoading" class="placeholder">...</view>
<view v-else class="list">
<view class="section-title">报告类型</view>
<view class="seg">
<view class="seg-item" :class="reportType==='assessment'?'active':''" @tap="setReportType('assessment')"></view>
<view class="seg-item" :class="reportType==='comprehensive'?'active':''" @tap="setReportType('comprehensive')">综合报告</view>
</view>
<view v-if="peopleRows.length" class="placeholder">请选择人员</view>
<view v-if="peopleRows.length">
<view class="item" v-for="p in peopleRows" :key="p.userId" @tap="selectPerson(p)">
<view class="item-title">{{ p.nickName || ('用户#' + p.userId) }}</view>
<view class="item-desc">编号:{{ p.infoNumber || '—' }} userId{{ p.userId }}</view>
</view>
</view>
<view v-if="reportRows.length === 0" class="placeholder"></view>
<view v-else>
<view class="item" v-for="row in reportRows" :key="row.reportId" @tap="selectReport(row)">
<view class="item-title">{{ row.reportTitle || (reportType === 'assessment' ? `测评报告#${row.reportId}` : `综合报告#${row.reportId}`) }}</view>
<view class="item-desc">{{ formatTime(row.createTime) }}</view>
</view>
</view>
</view>
<view v-if="bizType || linkUrl" class="hint">
{{ bizTypeLabel }}
</view>
<button class="btn" type="primary" :disabled="submitting" @click="submit">发送</button>
</view>
</view>
</template>
<script>
import { getToken } from '../../utils/auth'
import { sendNoticeToRoleKey } from '../../api/app/notice'
import { sendMessageToRoleKey, sendMessageToUser } from '../../api/app/message'
import { searchProfileOptions } from '../../api/app/profile'
import { listAssessmentReportOptionsByUserId } from '../../api/app/report'
import { listComprehensiveReportsByUserId } from '../../api/psychology/comprehensiveReport'
export default {
data() {
return {
sendMode: 'role',
recipient: 'area_manager',
title: '',
content: '',
linkUrl: '',
bizType: '',
bizId: '',
receiverKeyword: '',
receiverLoading: false,
receiverErrorMsg: '',
receiverRows: [],
receiverId: null,
receiverLabel: '',
selectedUserId: null,
reportKeyword: '',
reportType: 'assessment',
reportLoading: false,
reportErrorMsg: '',
peopleRows: [],
reportRows: [],
submitting: false
}
},
onLoad() {
const token = getToken()
if (!token) {
uni.showToast({ title: '', icon: 'none' })
}
this.selectRecipient(this.recipient)
},
computed: {
bizTypeLabel() {
if (this.bizType === 'assessment_report' && this.bizId) {
return `测评报告#${this.bizId}`
}
if (this.bizType === 'report' && this.bizId) {
return `综合报告#${this.bizId}`
}
if (this.bizType === 'warning') {
return ''
}
if (this.linkUrl) {
return this.linkUrl
}
return ''
}
},
methods: {
setSendMode(m) {
if (m !== 'role' && m !== 'single') return
if (this.sendMode === m) return
this.sendMode = m
this.receiverErrorMsg = ''
this.receiverRows = []
this.receiverId = null
this.receiverLabel = ''
this.receiverKeyword = ''
},
async searchReceivers() {
this.receiverErrorMsg = ''
this.receiverRows = []
const kw = (this.receiverKeyword || '').trim()
if (!kw) {
this.receiverErrorMsg = '/编号'
return
}
this.receiverLoading = true
try {
const res = await searchProfileOptions(kw, 10)
const data = res && res.data ? res.data : null
if (!data || data.code !== 200) {
this.receiverErrorMsg = (data && data.msg) ? data.msg : '查询收件人失败'
return
}
this.receiverRows = data.data || []
if (!this.receiverRows.length) {
this.receiverErrorMsg = '未找到匹配收件人'
}
} catch (e) {
this.receiverErrorMsg = e && e.message ? e.message : '网络错误'
} finally {
this.receiverLoading = false
}
},
selectReceiver(u) {
if (!u || !u.userId) return
this.receiverId = u.userId
this.receiverRows = []
this.receiverErrorMsg = ''
this.receiverLabel = `${u.nickName || ('用户#' + u.userId)}${u.infoNumber ? '' + u.infoNumber + '' : ''}`
this.receiverKeyword = this.receiverLabel
},
setReportType(t) {
if (t !== 'assessment' && t !== 'comprehensive') return
if (this.reportType === t) return
this.reportType = t
this.reportErrorMsg = ''
this.reportRows = []
this.peopleRows = []
// 如果已选过人员,切换类型后自动重载报告列表
if (this.selectedUserId) {
this.loadReportsByUserId(this.selectedUserId)
}
},
async loadReportsByUserId(userId) {
if (!userId) return
this.reportErrorMsg = ''
this.reportRows = []
this.reportLoading = true
try {
if (this.reportType === 'assessment') {
const repRes = await listAssessmentReportOptionsByUserId(userId, 50)
const repData = repRes && repRes.data ? repRes.data : null
if (!repData || repData.code !== 200) {
this.reportErrorMsg = (repData && repData.msg) ? repData.msg : '获取测评报告列表失败'
return
}
this.reportRows = repData.data || []
} else {
const repRes = await listComprehensiveReportsByUserId(userId)
const repData = repRes && repRes.data ? repRes.data : null
if (!repData || repData.code !== 200) {
this.reportErrorMsg = (repData && repData.msg) ? repData.msg : '获取综合报告列表失败'
return
}
this.reportRows = repData.data || []
}
if (!this.reportRows.length) {
this.reportErrorMsg = this.reportType === 'assessment' ? '该人员暂无测评报告' : '该人员暂无综合报告'
}
} catch (e) {
this.reportErrorMsg = e && e.message ? e.message : '网络错误'
} finally {
this.reportLoading = false
}
},
selectRecipient(key) {
this.recipient = key
if (key === 'area_manager') {
this.linkUrl = '/pages/warning/index'
this.bizType = 'warning'
this.bizId = ''
if (!this.title) this.title = ''
if (!this.content) this.content = ''
return
}
if (key === 'psy_counselor') {
this.linkUrl = '/pages/warning/index'
this.bizType = 'warning'
this.bizId = ''
if (!this.title) this.title = '异常预警'
if (!this.content) this.content = '某人员数据异常,请协助处理。'
}
},
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 '—'
}
},
async searchPeople() {
this.reportErrorMsg = ''
this.selectedUserId = null
this.peopleRows = []
this.reportRows = []
const kw = (this.reportKeyword || '').trim()
if (!kw) {
this.reportErrorMsg = '请输入姓名/'
return
}
this.reportLoading = true
try {
const res = await searchProfileOptions(kw, 10)
const data = res && res.data ? res.data : null
if (!data || data.code !== 200) {
this.reportErrorMsg = (data && data.msg) ? data.msg : ''
return
}
this.peopleRows = data.data || []
if (!this.peopleRows.length) {
this.reportErrorMsg = ''
}
} catch (e) {
this.reportErrorMsg = e && e.message ? e.message : ''
} finally {
this.reportLoading = false
}
},
async selectPerson(p) {
if (!p || !p.userId) return
this.selectedUserId = p.userId
this.reportErrorMsg = ''
this.peopleRows = []
if (p.nickName || p.infoNumber) {
this.reportKeyword = `${p.nickName || ''}${p.infoNumber ? '' + p.infoNumber + '' : ''}`
}
await this.loadReportsByUserId(p.userId)
},
selectReport(row) {
if (!row || !row.reportId) return
this.bizType = this.reportType === 'assessment' ? 'assessment_report' : 'report'
this.bizId = String(row.reportId)
this.linkUrl = this.reportType === 'assessment'
? `/pages/report/detail?reportId=${encodeURIComponent(row.reportId)}&sourceType=assessment`
: `/pages/comprehensive/detail?reportId=${encodeURIComponent(row.reportId)}`
this.title = row.reportTitle || (this.reportType === 'assessment' ? `测评报告#${row.reportId}` : `综合报告#${row.reportId}`)
const reportLabel = this.reportType === 'assessment' ? '' : ''
this.content = this.recipient === 'area_manager' ? `请查看${reportLabel}并关注风险。` : `请查看${reportLabel}并给出建议。`
uni.showToast({ title: '', icon: 'success' })
},
async submit() {
if (this.submitting) return
if (!this.content) {
uni.showToast({ title: '', icon: 'none' })
return
}
if (this.sendMode === 'role' && this.recipient === 'area_manager' && !this.title) {
uni.showToast({ title: '', icon: 'none' })
return
}
if (this.sendMode === 'single' && !this.receiverId) {
uni.showToast({ title: '', icon: 'none' })
return
}
this.submitting = true
uni.showLoading({ title: '...' })
try {
let res
if (this.sendMode === 'single') {
const payload = {
receiverId: this.receiverId,
title: this.title,
content: this.content,
linkUrl: this.linkUrl,
bizType: this.bizType,
bizId: this.bizId
}
res = await sendMessageToUser(payload)
} else {
const payload = {
roleKey: this.recipient,
title: this.title,
content: this.content,
linkUrl: this.linkUrl,
bizType: this.bizType,
bizId: this.bizId
}
if (this.recipient === 'area_manager') {
res = await sendNoticeToRoleKey(payload)
} else {
res = await sendMessageToRoleKey(payload)
}
}
const data = res && res.data ? res.data : null
if (data && data.code === 200) {
uni.showToast({ title: '', icon: 'success' })
} else {
uni.showToast({ title: (data && data.msg) || '', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '', icon: 'none' })
} finally {
uni.hideLoading()
this.submitting = false
}
}
}
}
</script>
<style>
.page {
min-height: 100vh;
padding: 32rpx;
box-sizing: border-box;
background: #f6f7fb;
}
.panel {
background: #ffffff;
border-radius: 20rpx;
padding: 24rpx;
border: 1px solid rgba(0, 0, 0, 0.05);
margin-bottom: 24rpx;
}
.title {
font-size: 36rpx;
font-weight: 700;
color: #1f2329;
}
.subtitle {
margin-top: 10rpx;
font-size: 24rpx;
color: #646a73;
line-height: 36rpx;
}
.section-title {
font-size: 28rpx;
font-weight: 700;
color: #1f2329;
margin: 14rpx 0 12rpx;
}
.input {
background: #f7f8fa;
border-radius: 16rpx;
padding: 26rpx 22rpx;
font-size: 28rpx;
min-height: 96rpx;
line-height: 44rpx;
box-sizing: border-box;
}
.textarea {
background: #f7f8fa;
border-radius: 16rpx;
padding: 26rpx 22rpx;
font-size: 28rpx;
box-sizing: border-box;
min-height: 360rpx;
line-height: 44rpx;
}
.btn {
width: 100%;
margin-top: 18rpx;
}
.row {
display: flex;
justify-content: space-between;
margin-top: 14rpx;
}
.btn.half {
width: 48%;
}
.seg {
display: flex;
background: #f7f8fa;
border-radius: 16rpx;
overflow: hidden;
}
.seg-item {
flex: 1;
text-align: center;
padding: 18rpx 0;
font-size: 26rpx;
color: #646a73;
}
.seg-item.active {
background: #1677ff;
color: #ffffff;
font-weight: 700;
}
.placeholder {
margin-top: 12rpx;
font-size: 24rpx;
color: #646a73;
}
.error {
margin-top: 12rpx;
font-size: 24rpx;
color: #ef4444;
}
.list {
margin-top: 12rpx;
}
.item {
padding: 18rpx;
border-radius: 16rpx;
background: #f7f8fa;
margin-bottom: 12rpx;
}
.item-title {
font-size: 28rpx;
font-weight: 700;
color: #1f2329;
}
.item-desc {
margin-top: 8rpx;
font-size: 24rpx;
color: #646a73;
}
</style>