| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="indexanalysis"> |
| | | <div class="analysis-top"> |
| | | <div class="title-top">æ¥è¯¢æ¡ä»¶</div> |
| | | <div class="value"> |
| | | <el-form ref="form" :model="queryParams" label-width="120px"> |
| | | <el-form-item label="éæ©é®é¢åç§°"> |
| | | <el-select |
| | | ref="questionSelect" |
| | | remote |
| | | :remote-method="remoteMethod" |
| | | default-first-option |
| | | v-model="selectedTargets" |
| | | @change="handleTargetChange" |
| | | @keyup.enter.native="handleEnterSearch" |
| | | filterable |
| | | multiple |
| | | collapse-tags |
| | | reserve-keyword |
| | | :loading="searchLoading" |
| | | placeholder="请è¾å
¥é®é¢åç§°æç´¢ï¼æå车确认" |
| | | > |
| | | <el-option |
| | | v-for="item in targetList" |
| | | :key="item.id" |
| | | :label="item.scriptContent || item.targetname" |
| | | :value="item.id" |
| | | > |
| | | <span>{{ item.scriptContent || item.targetname }}</span> |
| | | <span style="float: right; color: #8492a6; font-size: 13px"> |
| | | ID: {{ item.id }} |
| | | </span> |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="å·²éé¢ç®"> |
| | | <div class="selected-ids"> |
| | | {{ selectedContentsText }} |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="formindex"> |
| | | <el-table |
| | | v-loading="loading" |
| | | :data="processedTableData" |
| | | :span-method="objectSpanMethod" |
| | | border |
| | | :summary-method="getSummaries" |
| | | show-summary |
| | | style="width: 100%" |
| | | empty-text="è¯·éæ©è¦ç»è®¡çé¢ç®" |
| | | > |
| | | <el-table-column prop="targetname" label="é®é¢åç§°" width="200"> |
| | | <template slot-scope="scope"> |
| | | <div class="target-name-cell"> |
| | | {{ scope.row.targetname }} |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="targetShowCount" label="é®é¢åºç°æ¬¡æ°" width="120"> |
| | | <template slot-scope="scope"> |
| | | {{ scope.row.targetShowCount }}次 |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="completedPercentage" label="é¢ç®å®æåº¦" width="120"> |
| | | <template slot-scope="scope"> |
| | | {{ formatPercentage(scope.row.completedPercentage) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="matchedtext" label="é项å
容" width="150"> |
| | | <template slot-scope="scope"> |
| | | {{ scope.row.matchedtext || '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="count" label="é䏿¬¡æ°" width="100"> |
| | | <template slot-scope="scope"> |
| | | {{ scope.row.count }}次 |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="percentage" label="å æ¯" width="100"> |
| | | <template slot-scope="scope"> |
| | | <span>{{ formatPercentage(scope.row.percentage) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="è¿åº¦æ¡" min-width="200"> |
| | | <template slot-scope="scope"> |
| | | <el-progress |
| | | :percentage="Number(scope.row.percentage) * 100" |
| | | :show-text="false" |
| | | :color="customColors" |
| | | /> |
| | | <span class="progress-text">{{ formatPercentage(scope.row.percentage) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getissuelist, compileissuestatistics } from "@/api/AiCentre/index"; |
| | | |
| | | export default { |
| | | name: "indexanalysis", |
| | | data() { |
| | | return { |
| | | targetList: [], |
| | | selectedTargets: [], // åå¨éä¸çé¢ç®ID |
| | | tableData: [], |
| | | processedTableData: [], |
| | | loading: false, |
| | | searchLoading: false, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 66, |
| | | scriptContent: '', |
| | | }, |
| | | customColors: [ |
| | | { color: '#f56c6c', percentage: 20 }, |
| | | { color: '#e6a23c', percentage: 40 }, |
| | | { color: '#5cb87a', percentage: 60 }, |
| | | { color: '#1989fa', percentage: 80 }, |
| | | { color: '#6f7ad3', percentage: 100 } |
| | | ], |
| | | spanArr: [], |
| | | searchTimer: null, |
| | | currentSearchQuery: '', // å½åæç´¢å
³é®è¯ |
| | | }; |
| | | }, |
| | | |
| | | computed: { |
| | | // 计ç®éä¸çé®é¢å
å®¹ææ¬ |
| | | selectedContentsText() { |
| | | if (this.selectedTargets.length === 0) { |
| | | return 'æªéæ©ä»»ä½é¢ç®'; |
| | | } |
| | | |
| | | // æ ¹æ®éä¸çIDè·å对åºçscriptContent |
| | | const selectedContents = this.selectedTargets.map(id => { |
| | | const target = this.targetList.find(item => item.id === id); |
| | | return target ? (target.scriptContent || target.targetname || `é¢ç®${id}`) : `é¢ç®${id}`; |
| | | }); |
| | | |
| | | return selectedContents.join('; '); |
| | | }, |
| | | |
| | | // è·åéä¸é¡¹çå
容æ°ç»ï¼ç¨äºæ¾ç¤ºï¼ |
| | | selectedContents() { |
| | | return this.selectedTargets.map(id => { |
| | | const target = this.targetList.find(item => item.id === id); |
| | | return target ? (target.scriptContent || target.targetname) : `é¢ç®${id}`; |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | watch: { |
| | | processedTableData: { |
| | | handler(newVal) { |
| | | if (newVal && newVal.length > 0) { |
| | | this.getSpanArr(newVal); |
| | | } else { |
| | | this.spanArr = []; |
| | | } |
| | | }, |
| | | immediate: true, |
| | | deep: true |
| | | } |
| | | }, |
| | | |
| | | created() { |
| | | this.getList(); |
| | | }, |
| | | |
| | | methods: { |
| | | // æ¥è¯¢é®å·å表 |
| | | async getList() { |
| | | this.loading = true; |
| | | try { |
| | | const response = await getissuelist(this.queryParams); |
| | | this.targetList = response.rows || []; |
| | | } catch (error) { |
| | | console.error('è·åé¢ç®å表失败:', error); |
| | | this.$message.error('è·åé¢ç®å表失败'); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // åè½¦é®æç´¢å¤ç[6,8](@ref) |
| | | handleEnterSearch(event) { |
| | | const inputElement = event.target; |
| | | const searchQuery = inputElement.value.trim(); |
| | | |
| | | |
| | | this.currentSearchQuery = searchQuery; |
| | | this.executeSearch(searchQuery); |
| | | |
| | | // 鲿¢é»è®¤è¡ä¸º |
| | | event.preventDefault(); |
| | | event.stopPropagation(); |
| | | |
| | | }, |
| | | |
| | | // è¿ç¨æç´¢æ¹æ³ï¼å¸¦é²æï¼ |
| | | remoteMethod(query) { |
| | | if (this.searchTimer) { |
| | | clearTimeout(this.searchTimer); |
| | | } |
| | | |
| | | this.searchTimer = setTimeout(() => { |
| | | this.currentSearchQuery = query; |
| | | this.executeSearch(query); |
| | | }, 300); |
| | | }, |
| | | |
| | | // æ§è¡æç´¢ |
| | | async executeSearch(query) { |
| | | if (query === '') { |
| | | this.queryParams.scriptContent = ''; |
| | | await this.getList(); |
| | | return; |
| | | } |
| | | |
| | | this.searchLoading = true; |
| | | |
| | | try { |
| | | const searchParams = { |
| | | pageNum: 1, |
| | | pageSize: 50, |
| | | scriptType: "1", |
| | | scriptContent: query |
| | | }; |
| | | |
| | | const response = await getissuelist(searchParams); |
| | | this.targetList = response.rows || []; |
| | | |
| | | if (this.targetList.length === 0) { |
| | | this.$message.info(`æªæ¾å°å
å«"${query}"çé®é¢`); |
| | | } |
| | | } catch (error) { |
| | | console.error('æç´¢é¢ç®å¤±è´¥:', error); |
| | | this.$message.error('æç´¢æå¡å¼å¸¸ï¼è¯·ç¨åéè¯'); |
| | | this.targetList = []; |
| | | } finally { |
| | | this.searchLoading = false; |
| | | } |
| | | }, |
| | | |
| | | // å¤éé¢ç®æ¹åå¤ç |
| | | handleTargetChange(selectedIds) { |
| | | if (selectedIds && selectedIds.length > 0) { |
| | | this.Labelstatistics(selectedIds.join(',')); |
| | | } else { |
| | | this.processedTableData = []; |
| | | this.spanArr = []; |
| | | } |
| | | }, |
| | | |
| | | // è·åç»è®¡ä¿¡æ¯ |
| | | async Labelstatistics(scriptIds) { |
| | | if (!scriptIds) { |
| | | this.processedTableData = []; |
| | | this.spanArr = []; |
| | | return; |
| | | } |
| | | |
| | | this.loading = true; |
| | | try { |
| | | const response = await compileissuestatistics({ scriptids: scriptIds }); |
| | | this.tableData = response.data || []; |
| | | this.processTableData(); |
| | | } catch (error) { |
| | | console.error('è·åç»è®¡ä¿¡æ¯å¤±è´¥:', error); |
| | | this.$message.error('è·åç»è®¡ä¿¡æ¯å¤±è´¥'); |
| | | this.processedTableData = []; |
| | | this.spanArr = []; |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // å¤çè¡¨æ ¼æ°æ® |
| | | processTableData() { |
| | | if (!this.tableData || Object.keys(this.tableData).length === 0) { |
| | | this.processedTableData = []; |
| | | return; |
| | | } |
| | | |
| | | const processedData = []; |
| | | |
| | | Object.keys(this.tableData).forEach(scriptId => { |
| | | const questionData = this.tableData[scriptId]; |
| | | |
| | | if (questionData && questionData.details) { |
| | | const targetName = questionData.scriptContent || `é¢ç®${scriptId}`; |
| | | const targetShowCount = questionData.allQuantity || 0; |
| | | const completedPercentage = questionData.completedPercentage || "0"; |
| | | |
| | | questionData.details.forEach(detail => { |
| | | if (detail.optionText) { |
| | | processedData.push({ |
| | | scriptid: scriptId, |
| | | targetname: targetName, |
| | | targetShowCount: targetShowCount, |
| | | matchedtext: detail.optionText, |
| | | count: detail.chosenQuantity || 0, |
| | | percentage: detail.chosenPercentage || "0", |
| | | completedPercentage: completedPercentage, |
| | | allQuantity: questionData.allQuantity || 0, |
| | | completedQuantity: questionData.completedQuantity || 0 |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | if (questionData.details.length === 0) { |
| | | processedData.push({ |
| | | scriptid: scriptId, |
| | | targetname: targetName, |
| | | targetShowCount: targetShowCount, |
| | | matchedtext: '-', |
| | | count: 0, |
| | | percentage: "0", |
| | | completedPercentage: completedPercentage, |
| | | allQuantity: questionData.allQuantity || 0, |
| | | completedQuantity: questionData.completedQuantity || 0 |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | this.processedTableData = processedData; |
| | | }, |
| | | |
| | | // çæåå¹¶ä¿¡æ¯æ°ç» |
| | | getSpanArr(data) { |
| | | this.spanArr = []; |
| | | |
| | | if (!data || data.length === 0) return; |
| | | |
| | | for (let i = 0; i < data.length; i++) { |
| | | if (i === 0) { |
| | | this.spanArr.push(1); |
| | | this.pos = 0; |
| | | } else { |
| | | if (data[i].scriptid === data[i - 1].scriptid) { |
| | | this.spanArr[this.pos] += 1; |
| | | this.spanArr.push(0); |
| | | } else { |
| | | this.spanArr.push(1); |
| | | this.pos = i; |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // åå
æ ¼åå¹¶æ¹æ³ |
| | | objectSpanMethod({ row, column, rowIndex, columnIndex }) { |
| | | if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) { |
| | | if (this.spanArr.length > rowIndex) { |
| | | const rowspan = this.spanArr[rowIndex]; |
| | | const colspan = rowspan > 0 ? 1 : 0; |
| | | |
| | | return { |
| | | rowspan: rowspan, |
| | | colspan: colspan |
| | | }; |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // æ ¼å¼åç¾åæ¯æ¾ç¤º |
| | | formatPercentage(value) { |
| | | const numValue = Number(value); |
| | | return isNaN(numValue) ? '0%' : `${(numValue * 100).toFixed(2)}%`; |
| | | }, |
| | | |
| | | // è¡¨æ ¼å计è¡è®¡ç® |
| | | getSummaries(param) { |
| | | const { columns, data } = param; |
| | | const sums = []; |
| | | |
| | | columns.forEach((column, index) => { |
| | | if (index === 0) { |
| | | sums[index] = 'å计'; |
| | | return; |
| | | } |
| | | |
| | | if (data.length === 0) { |
| | | sums[index] = '-'; |
| | | return; |
| | | } |
| | | |
| | | switch (column.property) { |
| | | case 'targetShowCount': |
| | | const totalQuestions = new Set(data.map(item => item.scriptid)).size; |
| | | sums[index] = `${totalQuestions}个é¢ç®`; |
| | | break; |
| | | |
| | | case 'count': |
| | | const values = data.map(item => Number(item.count)); |
| | | const totalCount = values.reduce((prev, curr) => prev + curr, 0); |
| | | sums[index] = `${totalCount}次`; |
| | | break; |
| | | |
| | | case 'percentage': |
| | | const percentages = data.map(item => Number(item.percentage)); |
| | | const validPercentages = percentages.filter(p => !isNaN(p)); |
| | | if (validPercentages.length > 0) { |
| | | const avgPercentage = validPercentages.reduce((a, b) => a + b, 0) / validPercentages.length; |
| | | sums[index] = `${(avgPercentage * 100).toFixed(2)}%`; |
| | | } else { |
| | | sums[index] = '0%'; |
| | | } |
| | | break; |
| | | |
| | | case 'completedPercentage': |
| | | const completedPercentages = data.map(item => Number(item.completedPercentage)); |
| | | const validCompleted = completedPercentages.filter(p => !isNaN(p)); |
| | | if (validCompleted.length > 0) { |
| | | const avgCompleted = validCompleted.reduce((a, b) => a + b, 0) / validCompleted.length; |
| | | sums[index] = `${(avgCompleted * 100).toFixed(2)}%`; |
| | | } else { |
| | | sums[index] = '0%'; |
| | | } |
| | | break; |
| | | |
| | | default: |
| | | sums[index] = '-'; |
| | | break; |
| | | } |
| | | }); |
| | | |
| | | return sums; |
| | | } |
| | | }, |
| | | |
| | | beforeDestroy() { |
| | | if (this.searchTimer) { |
| | | clearTimeout(this.searchTimer); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .analysis-top { |
| | | border: 1px solid #dcdfe6; |
| | | -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04); |
| | | margin: 15px; |
| | | |
| | | .title-top { |
| | | background-color: #6784f2; |
| | | color: #fff; |
| | | padding: 10px 20px; |
| | | font-size: 20px; |
| | | font-weight: 500; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .value { |
| | | padding: 0 20px 20px; |
| | | } |
| | | } |
| | | |
| | | .formindex { |
| | | margin: 0 15px; |
| | | border: 1px solid #dcdfe6; |
| | | -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04); |
| | | padding: 20px; |
| | | } |
| | | |
| | | .selected-ids { |
| | | padding: 8px 12px; |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | border: 1px solid #e4e7ed; |
| | | min-height: 36px; |
| | | word-break: break-all; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .target-name-cell { |
| | | font-weight: 600; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .progress-text { |
| | | margin-left: 10px; |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | ::v-deep .el-progress-bar { |
| | | padding-right: 0; |
| | | margin-right: 0; |
| | | } |
| | | |
| | | ::v-deep .el-select { |
| | | width: 100%; |
| | | } |
| | | |
| | | ::v-deep .el-table { |
| | | .cell { |
| | | word-break: break-word; |
| | | } |
| | | |
| | | .el-table__body tr:hover > td.el-table__cell { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .el-table__body .el-table__cell { |
| | | vertical-align: top; |
| | | } |
| | | } |
| | | |
| | | .merged-cell { |
| | | background-color: #f0f9ff; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | ::v-deep .el-select__tags { |
| | | .el-tag { |
| | | max-width: 200px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | |
| | | .el-tag__close { |
| | | margin-left: 4px; |
| | | } |
| | | } |
| | | } |
| | | </style> |