Kaynağa Gözat

feat(questionnaire): add report details page

Developer 1 hafta önce
ebeveyn
işleme
5995f07505

BIN
dist.zip


+ 9 - 3
src/api/agent/index.js

@@ -414,13 +414,19 @@ export function updateReportPdfUrl(data) {
     data
   })
 }
-export function getTeamReportWjList(relationId) {
+export function getTeamReportWjList(relationId) {
   return request({
     url: `/core/report/team/member/reportList/team/${relationId}`,
     method: 'get'
   })
-}
-export function getPersonReportWjList(relationId) {
+}
+export function getQuestionnaireReportList(teamQuestionnaireId) {
+  return request({
+    url: `/core/report/team/member/questionnaireReportList/${teamQuestionnaireId}`,
+    method: 'get'
+  })
+}
+export function getPersonReportWjList(relationId) {
   return request({
     url: `/core/report/team/member/reportList/member/${relationId}`,
     method: 'get'

+ 1 - 0
src/router/index.js

@@ -63,6 +63,7 @@ export const moduleRoutes = {
     { path: '/agentKnowledgeFile', component: () => import('@/views/modules/agent/knowledge/file'), name: 'agentKnowledgeFile', meta: { title: '知识库文件', isTab: false } },
     { path: '/agentQuestionnaireSchedule', component: () => import('@/views/modules/agent/questionnaire/schedule'), name: 'agentQuestionnaireSchedule', meta: { title: '问卷作答进度', isTab: false } },
     { path: '/agentQuestionnaireReport', component: () => import('@/views/modules/agent/questionnaire/report'), name: 'agentQuestionnaireReport', meta: { title: '问卷报告', isTab: false } },
+    { path: '/agentQuestionnaireReports', component: () => import('@/views/modules/agent/questionnaire/reports'), name: 'agentQuestionnaireReports', meta: { title: '问卷报告列表', isTab: false } },
     { path: '/agentQuestionnaireDetail', component: () => import('@/views/modules/agent/questionnaire/detail'), name: 'agentQuestionnaireDetail', meta: { title: '问卷详情', isTab: false } },
     { path: '/agentQuestionnairePublish', component: () => import('@/views/modules/agent/questionnaire/publish'), name: 'agentQuestionnairePublish', meta: { title: '发布问卷', isTab: false } },
     { path: '/agentUserInfo', component: () => import('@/views/modules/agent/userInfo'), name: 'agentUserInfo', meta: { title: '个人信息', isTab: false } },

+ 20 - 50
src/views/modules/agent/questionnaire.vue

@@ -43,11 +43,15 @@
                             <img src="@/assets/images/agent/send_mini.png">
                             <span>查看进度</span>
                         </div>
-                        <div class="lr_pre adfac" v-hasPermi="['core:questionnaire:info']" @click="handleSchedule(item)">
-                            <img src="@/assets/images/agent/report_mini.png">
-                            <span>生成报告</span>
-                        </div>
-                        <div class="lr_pre adfac" @click="handleDelete(item)">
+                        <div class="lr_pre adfac" v-hasPermi="['core:questionnaire:info']" @click="handleSchedule(item)">
+                            <img src="@/assets/images/agent/report_mini.png">
+                            <span>生成报告</span>
+                        </div>
+                        <div class="lr_pre adfac" @click="handleReportList(item)">
+                            <img src="@/assets/images/agent/report_mini.png">
+                            <span>报告列表</span>
+                        </div>
+                        <div class="lr_pre adfac" @click="handleDelete(item)">
                             <img src="@/assets/images/agent/report_mini.png">
                             <span>删除问卷</span>
                         </div>
@@ -70,18 +74,6 @@
                     <span>完成情况</span>
                     <span>{{ item.userNum?((item.finishNum/item.userNum)*100).toFixed(0):0 }}%</span>
                 </div>
-                <div class="li_report_action">
-                    <el-button link type="text" size="mini" @click="toggleReportList(item)">报告列表</el-button>
-                </div>
-                <div v-if="item.reportExpanded" v-loading="item.reportLoading">
-                    <reportList
-                        :item="item"
-                        :reportList="item.reportList"
-                        :showMore="true"
-                        @toggleReport="toggleReportList"
-                        @refreshReportList="refreshReportList">
-                    </reportList>
-                </div>
             </div>
             <el-row style="display: flex;justify-content: center;">
                 <el-pagination
@@ -189,10 +181,8 @@
 <script setup name="">
     import { ref, getCurrentInstance, onMounted } from 'vue'
     import {useAgentStore} from "@/store_v3/modules/agent";
-    import reportList from '@/components/reportList/index.vue'
     import {
         getTeamQuestionnaireList,
-        getTeamReportWjList,
         deleteQuestionnaireOne,
         getQuestionnairePublishInfo,
         getProgramList,
@@ -371,7 +361,7 @@
         getList()
     }
 
-    const handleSchedule = (item) => {
+    const handleSchedule = (item) => {
         proxy.$router.push({
             path: '/agentQuestionnaireSchedule',
             query:{
@@ -385,42 +375,22 @@
                 userNum: item.userNum,
                 finishNum: item.finishNum
             }
-        })
-    }
-
-    const getList = () => {
-        let query = {...queryParams.value};
-        getTeamQuestionnaireList(query).then(res=>{
-            if(res.code!==0) return proxy.$message.error(res.msg)
-            dataList.value = res.data.list.map(item => ({
-                ...item,
-                reportExpanded: false,
-                reportLoading: false,
-                reportList: []
-            }));
-            total.value = res.data.total;
         })
     }
 
-    const toggleReportList = async row => {
-        row.reportExpanded = !row.reportExpanded
-        if (!row.reportExpanded || row.reportList.length > 0) return
-        row.reportLoading = true
-        try {
-            const res = await getTeamReportWjList(row.id)
-            if(res.code!==0) return proxy.$message.error(res.msg)
-            row.reportList = res.data || []
-        } finally {
-            row.reportLoading = false
-        }
+    const handleReportList = item => {
+        proxy.$router.push({
+            path: '/agentQuestionnaireReports',
+            query: { id: item.id, title: item.title, teamName: item.teamName }
+        })
     }
 
-    const refreshReportList = relationId => {
-        const row = dataList.value.find(item => item.id === relationId)
-        if (!row) return
-        getTeamReportWjList(row.id).then(res => {
+    const getList = () => {
+        let query = {...queryParams.value};
+        getTeamQuestionnaireList(query).then(res=>{
             if(res.code!==0) return proxy.$message.error(res.msg)
-            row.reportList = res.data || []
+            dataList.value = res.data.list;
+            total.value = res.data.total;
         })
     }
 

+ 86 - 0
src/views/modules/agent/questionnaire/reports.vue

@@ -0,0 +1,86 @@
+<template>
+  <div class="page">
+    <div class="top adfacjb">
+      <div>
+        <p>问卷报告</p>
+        <p class="tip">{{ title }}<span v-if="teamName"> · {{ teamName }}</span></p>
+      </div>
+      <el-button @click="$router.back()">返回问卷</el-button>
+    </div>
+    <el-table :data="dataList" border v-loading="loading" empty-text="暂无报告" style="margin-top: 18px;">
+      <el-table-column label="序号" width="60">
+        <template #default="scope">{{ scope.$index + 1 }}</template>
+      </el-table-column>
+      <el-table-column label="报告名称" prop="reportName" min-width="220" />
+      <el-table-column label="报告类型" width="130">
+        <template #default="scope">{{ reportTypeDict[scope.row.reportType] || '报告' }}</template>
+      </el-table-column>
+      <el-table-column label="报告状态" width="110">
+        <template #default="scope">{{ stateDict[scope.row.state] || '未知' }}</template>
+      </el-table-column>
+      <el-table-column label="团队名称" prop="teamName" min-width="150" />
+      <el-table-column label="创建时间" prop="createDate" min-width="160" />
+      <el-table-column label="操作" width="390">
+        <template #default="scope">
+          <template v-if="isGenerated(scope.row)">
+            <el-button link type="text" size="mini" @click="handleReview(scope.row, 'personal')">个人报告</el-button>
+            <el-button link type="text" size="mini" @click="handleReview(scope.row, 'background')">背景报告</el-button>
+            <el-button link type="text" size="mini" @click="handleReview(scope.row, 'professional')">教练报告</el-button>
+            <el-button link type="text" size="mini" @click="handleReview(scope.row, 'public')">团队报告</el-button>
+            <el-button link type="text" size="mini" @click="handleDownload(scope.row)">下载报告</el-button>
+          </template>
+          <span v-else-if="scope.row.state === -1" class="failed">生成失败</span>
+          <span v-else class="pending">生成中</span>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+
+<script setup name="QuestionnaireReports">
+  import { ref, getCurrentInstance, onMounted } from 'vue'
+  import { getQuestionnaireReportList } from '@/api/agent/index.js'
+  import { reportArtifactUrl } from '@/utils/reportArtifactLinks.js'
+
+  const { proxy } = getCurrentInstance()
+  const id = proxy.$route.query.id
+  const title = proxy.$route.query.title || '问卷报告'
+  const teamName = proxy.$route.query.teamName || ''
+  const dataList = ref([])
+  const loading = ref(false)
+  const reportTypeDict = { 1: '团队报告', 2: '个人报告' }
+  const stateDict = { '-1': '生成失败', 0: '生成中', 1: '未发送', 2: '已发送' }
+
+  const isGenerated = row => [1, 2].includes(Number(row.state))
+  const handleReview = (row, kind) => {
+    const url = reportArtifactUrl(row, kind)
+    if (!url) return proxy.$message.error('该报告尚未生成,请生成后再查看!')
+    window.open(url, '_blank', 'noopener,noreferrer')
+  }
+  const handleDownload = row => {
+    if (!row.fileUrl) return proxy.$message.error('该报告尚未生成,请生成后再下载!')
+    window.open(row.fileUrl, '_blank', 'noopener,noreferrer')
+  }
+  const getList = async () => {
+    if (!id) return
+    loading.value = true
+    try {
+      const res = await getQuestionnaireReportList(id)
+      if (res.code !== 0) return proxy.$message.error(res.msg)
+      dataList.value = res.data || []
+    } finally {
+      loading.value = false
+    }
+  }
+
+  onMounted(getList)
+</script>
+
+<style scoped lang="scss">
+.page { padding: 28px 20px; background: #FAFAFA; }
+.top { padding: 16px 20px; background: #FFF; border-radius: 6px; }
+.top p { margin: 0; font-weight: bold; }
+.top .tip { margin-top: 10px; color: #6B7280; font-size: 14px; font-weight: normal; }
+.failed { color: #F31616; }
+.pending { color: #FEA400; }
+</style>

+ 18 - 2
tests/unit/questionnaireReportMerge.spec.js

@@ -31,8 +31,24 @@ test('questionnaire survey page exposes reports from each questionnaire row', ()
   )
 
   expect(questionnaireSource).toContain('报告列表')
-  expect(questionnaireSource).toContain('getTeamReportWjList')
-  expect(questionnaireSource).toContain('reportList')
+  expect(questionnaireSource).toContain('@click="handleReportList(item)"')
+  expect(questionnaireSource).toContain("path: '/agentQuestionnaireReports'")
+  expect(questionnaireSource).not.toContain('reportExpanded')
+})
+
+test('questionnaire report page lists report types like mini-program report records', () => {
+  const reportPageSource = fs.readFileSync(
+    path.resolve(__dirname, '../../src/views/modules/agent/questionnaire/reports.vue'),
+    'utf8'
+  )
+
+  expect(reportPageSource).toContain('getQuestionnaireReportList')
+  expect(reportPageSource).toContain('报告类型')
+  expect(reportPageSource).toContain('个人报告')
+  expect(reportPageSource).toContain('背景报告')
+  expect(reportPageSource).toContain('教练报告')
+  expect(reportPageSource).toContain('团队报告')
+  expect(reportPageSource).toContain('reportArtifactUrl')
 })
 
 test('questionnaire management wires inline report mutation events to report APIs', () => {