479 lines
15 KiB
Groovy
479 lines
15 KiB
Groovy
<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>
|