批量推送代码

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
郭庆泰
2026-08-29 17:52:05 +08:00
co-authored by Claude
parent 36528b6e0c
commit e47f76478b
130 changed files with 3972 additions and 2546 deletions
+58 -9
View File
@@ -41,7 +41,7 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="load"></el-button>
<el-button type="primary" @click="load"></el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
@@ -62,7 +62,11 @@
<el-table-column prop="projectNo" label="项目编号" min-width="170" fixed>
<template #default="{ row }">
<el-link type="primary" :underline="false" @click="openDetail(row)">{{ row.projectNo }}</el-link></template></el-table-column>
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip>
<template #default="{ row }">
<el-link type="primary" :underline="false" @click="openDetail(row)">{{ row.projectName }}</el-link>
</template>
</el-table-column>
<el-table-column prop="totalSessions" label="总场次/总期数" width="120" align="center" />
<el-table-column prop="doneSessions" label="已执行" width="80" align="center" />
<el-table-column prop="todoSessions" label="未执行" width="80" align="center" />
@@ -72,13 +76,13 @@
<el-table-column label="已支付会务费" width="120" align="right"><template #default="{ row }">¥{{ formatMoney(row.paidMeetingAmount) }}</template></el-table-column>
<el-table-column prop="managerScore" label="执行单位得分(合规)" width="150" align="center">
<template #default="{ row }">
<span v-if="row.managerScore != null">{{ row.managerScore }}</span>
<el-link v-if="row.managerScore != null" :underline="false" type="primary" @click="openScoreDetail(row, 'manager')">{{ row.managerScore }}</el-link>
<span v-else style="color:#c0c4cc">-</span>
</template>
</el-table-column>
<el-table-column prop="sponsorScore" label="执行单位评价(支持方)" width="160" align="center">
<template #default="{ row }">
<span v-if="row.sponsorScore != null">{{ row.sponsorScore }}</span>
<el-link v-if="row.sponsorScore != null" :underline="false" type="primary" @click="openScoreDetail(row, 'sponsor')">{{ row.sponsorScore }}</el-link>
<span v-else style="color:#c0c4cc">-</span>
</template>
</el-table-column>
@@ -196,7 +200,6 @@
<el-descriptions-item label="可用金额">¥{{ formatMoney(detail.availableAmount) }}</el-descriptions-item>
<el-descriptions-item label="已支付劳务费">¥{{ formatMoney(detail.paidLaborAmount) }}</el-descriptions-item>
<el-descriptions-item label="已支付会务费">¥{{ formatMoney(detail.paidMeetingAmount) }}</el-descriptions-item>
<el-descriptions-item label="执行单位得分">{{ detail.managerScore || '-' }}</el-descriptions-item>
<el-descriptions-item label="是否结题">
<el-tag :type="detail.isFinished === '1' ? 'success' : 'info'" disable-transitions>
{{ detail.isFinished === '1' ? '已结题' : '未结题' }}
@@ -207,6 +210,29 @@
</el-descriptions>
<template #footer><el-button @click="detailOpen = false">关闭</el-button></template>
</el-dialog>
<!-- ============= 评分详情 modal只读 4 维度明细, 点列表列查看 ============= -->
<el-dialog v-model="scoreDetailOpen" :title="scoreDetailTitle" width="520px" :show-close="false">
<table style="width:100%;border-collapse:collapse;font-size:13px">
<thead><tr style="background:#fafafa">
<th style="width:110px;padding:10px 12px;text-align:left">评价维度</th>
<th style="padding:10px 12px;text-align:left">评价内容(简洁版)</th>
<th style="width:110px;padding:10px 12px;text-align:center">平均得分</th>
</tr></thead>
<tbody>
<tr><td style="padding:10px 12px;border-top:1px solid #f5f5f5">履约质量</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5">服务/活动效果达标度</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5;text-align:center">{{ scoreDetail.qualityScore ?? '-' }}</td></tr>
<tr><td style="padding:10px 12px;border-top:1px solid #f5f5f5">时效响应</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5">执行 & 售后响应速度</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5;text-align:center">{{ scoreDetail.responseScore ?? '-' }}</td></tr>
<tr><td style="padding:10px 12px;border-top:1px solid #f5f5f5">配合度</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5">沟通配合 & 问题处理</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5;text-align:center">{{ scoreDetail.cooperationScore ?? '-' }}</td></tr>
<tr><td style="padding:10px 12px;border-top:1px solid #f5f5f5">合规安全</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5">流程合规 & 无安全事故</td><td style="padding:10px 12px;border-top:1px solid #f5f5f5;text-align:center">{{ scoreDetail.complianceScore ?? '-' }}</td></tr>
</tbody>
</table>
<div style="margin-top:12px;text-align:right;font-size:13px;color:#303133">
平均分: <b>{{ scoreDetailTotal }}</b>
</div>
<template #footer>
<el-button @click="scoreDetailOpen=false">关闭</el-button>
</template>
</el-dialog>
</div>
</template>
@@ -234,6 +260,12 @@ const form = reactive({
const rateOpen = ref(false)
const rateForm = reactive({ projectId: null, projectNo: '', projectName: '', q1: 0, q2: 0, q3: 0, q4: 0, remark: '' })
// ========== 评分详情 (只读 4 维度明细, 点列表 score 列查看) ==========
const scoreDetailOpen = ref(false)
const scoreDetailTitle = ref('评分详情')
const scoreDetail = reactive({ qualityScore: null, responseScore: null, cooperationScore: null, complianceScore: null })
const scoreDetailTotal = ref('—')
const assignOpen = ref(false)
const assignForm = reactive({ projectId: '', projectNo: '', projectName: '', supervisor: '', supervisionPoint: '' })
const personList = ref([])
@@ -335,6 +367,26 @@ function openRate(row) {
Object.assign(rateForm, { projectId: row.projectId, projectNo: row.projectNo, projectName: row.projectName, q1: 0, q2: 0, q3: 0, q4: 0, remark: '' })
rateOpen.value = true
}
// 点击列表「执行单位得分(合规)/评价(支持方)」列 → 只读显示该角色 4 维度评分明细
async function openScoreDetail(row, role) {
scoreDetailTitle.value = role === 'sponsor' ? '执行单位评分详情(支持方)' : '执行单位评分详情(合规)'
Object.assign(scoreDetail, { qualityScore: null, responseScore: null, cooperationScore: null, complianceScore: null })
scoreDetailTotal.value = role === 'sponsor' ? (row.sponsorScore ?? '—') : (row.managerScore ?? '—')
scoreDetailOpen.value = true
try {
const r = await request({ url: '/business/project/ratings', method: 'get', params: { projectId: row.projectId } })
const list = (r.data && (Array.isArray(r.data) ? r.data : r.data.rows)) || r.rows || []
const items = list.filter(x => String(x.projectId) === String(row.projectId) && x.raterRole === role)
if (items.length) {
const n = items.length
const dimAvg = (key) => (items.reduce((s, x) => s + (Number(x[key]) || 0), 0) / n).toFixed(1)
scoreDetail.qualityScore = dimAvg('qualityScore')
scoreDetail.responseScore = dimAvg('responseScore')
scoreDetail.cooperationScore = dimAvg('cooperationScore')
scoreDetail.complianceScore = dimAvg('complianceScore')
}
} catch (e) { /* 拉取失败保持空, 弹窗显示 - */ }
}
async function submitRate() {
if (!rateForm.q1 && !rateForm.q2 && !rateForm.q3 && !rateForm.q4) {
ElMessage.warning('请至少完成一项评分'); return
@@ -356,10 +408,7 @@ async function submitRate() {
complianceScore: rateForm.q4,
remark: rateForm.remark
})
// 2. 写聚合分到 biz_project.sponsor_score
if (avg != null) {
await bizUpdate('project', { projectId: rateForm.projectId, sponsorScore: Number(avg) })
}
// 聚合分由后端 /rate 重算, 前端不再单独写 sponsor_score
ElMessage.success(`评分已提交, 平均分:${avg ?? '-'}`)
rateOpen.value = false
load()