21
This commit is contained in:
parent
e1dc8c37ee
commit
e85cd41a2d
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* AssessmentRecord API - 测评记录管理 API
|
||||
* @module api/business/assessmentRecord
|
||||
* @description 提供测评记录相关接口,包括记录列表、详情、报告和导出功能
|
||||
*/
|
||||
import { request, type ApiResponse } from '@/utils/request'
|
||||
import type { PagedRequest, PagedResult } from '@/types/common'
|
||||
|
||||
// ==================== 类型定义 ====================
|
||||
|
||||
/** 测评记录列表项 */
|
||||
export interface AssessmentRecordItem {
|
||||
id: number
|
||||
userId: number
|
||||
userNickname: string | null
|
||||
orderId: number
|
||||
orderNo: string | null
|
||||
assessmentTypeId: number
|
||||
assessmentTypeName: string | null
|
||||
name: string
|
||||
phone: string
|
||||
gender: number
|
||||
genderName: string
|
||||
age: number
|
||||
educationStage: number
|
||||
educationStageName: string
|
||||
province: string
|
||||
city: string
|
||||
district: string
|
||||
status: number
|
||||
statusName: string
|
||||
startTime: string | null
|
||||
submitTime: string | null
|
||||
completeTime: string | null
|
||||
createTime: string
|
||||
}
|
||||
|
||||
/** 答案详情 */
|
||||
export interface AnswerDetail {
|
||||
id: number
|
||||
questionId: number
|
||||
questionNo: number
|
||||
questionContent: string
|
||||
answerValue: number
|
||||
createTime: string
|
||||
}
|
||||
|
||||
/** 结果详情 */
|
||||
export interface ResultDetail {
|
||||
id: number
|
||||
categoryId: number
|
||||
categoryName: string
|
||||
categoryTypeName: string
|
||||
score: number
|
||||
maxScore: number
|
||||
percentage: number
|
||||
rank: number
|
||||
starLevel: number
|
||||
createTime: string
|
||||
}
|
||||
|
||||
/** 测评记录详情(含答案和结果) */
|
||||
export interface AssessmentRecordDetail extends AssessmentRecordItem {
|
||||
answers: AnswerDetail[]
|
||||
results: ResultDetail[]
|
||||
}
|
||||
|
||||
/** 报告分类项 */
|
||||
export interface ReportCategoryItem {
|
||||
categoryId: number
|
||||
categoryName: string
|
||||
score: number
|
||||
maxScore: number
|
||||
percentage: number
|
||||
starLevel: number
|
||||
conclusionContent: string | null
|
||||
}
|
||||
|
||||
/** 报告分类组 */
|
||||
export interface ReportCategoryGroup {
|
||||
categoryTypeId: number
|
||||
categoryTypeName: string
|
||||
items: ReportCategoryItem[]
|
||||
}
|
||||
|
||||
/** 测评报告 */
|
||||
export interface AssessmentReport extends AssessmentRecordItem {
|
||||
resultGroups: ReportCategoryGroup[]
|
||||
}
|
||||
|
||||
/** 测评记录查询参数 */
|
||||
export interface AssessmentRecordQuery extends PagedRequest {
|
||||
userId?: number
|
||||
assessmentTypeId?: number
|
||||
status?: number
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}
|
||||
|
||||
// ==================== API ====================
|
||||
|
||||
/** 获取测评记录列表 */
|
||||
export function getRecordList(params: AssessmentRecordQuery): Promise<ApiResponse<PagedResult<AssessmentRecordItem>>> {
|
||||
return request<PagedResult<AssessmentRecordItem>>({
|
||||
url: '/admin/assessmentRecord/getList',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
/** 获取测评记录详情 */
|
||||
export function getRecordDetail(id: number): Promise<ApiResponse<AssessmentRecordDetail>> {
|
||||
return request<AssessmentRecordDetail>({
|
||||
url: '/admin/assessmentRecord/getDetail',
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/** 获取测评报告 */
|
||||
export function getRecordReport(id: number): Promise<ApiResponse<AssessmentReport>> {
|
||||
return request<AssessmentReport>({
|
||||
url: '/admin/assessmentRecord/getReport',
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/** 导出测评记录 */
|
||||
export function exportRecords(params: AssessmentRecordQuery): Promise<ApiResponse<Blob>> {
|
||||
return request<Blob>({
|
||||
url: '/admin/assessmentRecord/export',
|
||||
method: 'get',
|
||||
params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
|
@ -118,6 +118,12 @@ export const businessRoutes: RouteRecordRaw[] = [
|
|||
name: 'ScoreOption',
|
||||
component: () => import('@/views/business/assessment/scoreOption/index.vue'),
|
||||
meta: { title: '评分标准', permission: 'assessment:view', keepAlive: true }
|
||||
},
|
||||
{
|
||||
path: 'record',
|
||||
name: 'AssessmentRecord',
|
||||
component: () => import('@/views/business/assessment/record/index.vue'),
|
||||
meta: { title: '测评记录', permission: 'assessmentRecord:view', keepAlive: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,638 @@
|
|||
<template>
|
||||
<div class="record-container">
|
||||
<!-- 页面标题和操作栏 -->
|
||||
<el-card class="page-header">
|
||||
<div class="header-content">
|
||||
<div class="header-left">
|
||||
<h2 class="page-title">测评记录</h2>
|
||||
<span class="page-description">查看用户测评记录、答案详情和测评报告</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-button type="success" @click="handleExport" :loading="state.exportLoading">
|
||||
<el-icon><Download /></el-icon>
|
||||
导出Excel
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-card class="search-card">
|
||||
<el-form :model="queryParams" inline>
|
||||
<el-form-item label="用户ID">
|
||||
<el-input
|
||||
v-model="queryParams.userId"
|
||||
placeholder="请输入用户ID"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="待测评" :value="1" />
|
||||
<el-option label="测评中" :value="2" />
|
||||
<el-option label="生成中" :value="3" />
|
||||
<el-option label="已完成" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
:shortcuts="dateShortcuts"
|
||||
@change="handleDateRangeChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card v-loading="state.loading" class="table-card">
|
||||
<el-table :data="state.tableData" row-key="id" stripe>
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column label="用户" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.userNickname || '-' }}</div>
|
||||
<div class="sub-text">ID: {{ row.userId }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="被测评人" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.name }}</div>
|
||||
<div class="sub-text">{{ row.phone }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="assessmentTypeName" label="测评类型" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="性别/年龄" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.genderName }} / {{ row.age }}岁
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="educationStageName" label="学历阶段" width="110" align="center" />
|
||||
<el-table-column label="地区" min-width="130" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.province }}{{ row.city }}{{ row.district }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusTagType(row.status)" size="small">
|
||||
{{ row.statusName }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orderNo" label="订单号" width="170" show-overflow-tooltip />
|
||||
<el-table-column prop="submitTime" label="提交时间" width="170" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.submitTime || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="170" align="center" />
|
||||
<el-table-column label="操作" width="160" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link size="small" @click="handleViewDetail(row)">
|
||||
<el-icon><View /></el-icon>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 4"
|
||||
type="success"
|
||||
link
|
||||
size="small"
|
||||
@click="handleViewReport(row)"
|
||||
>
|
||||
<el-icon><Document /></el-icon>
|
||||
报告
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.page"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="state.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 详情抽屉 -->
|
||||
<el-drawer
|
||||
v-model="state.detailVisible"
|
||||
title="测评记录详情"
|
||||
size="650px"
|
||||
:close-on-click-modal="true"
|
||||
>
|
||||
<div v-loading="state.detailLoading" class="record-detail">
|
||||
<template v-if="state.detail">
|
||||
<!-- 基本信息 -->
|
||||
<div class="detail-section">
|
||||
<h4 class="section-title">基本信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="被测评人">{{ state.detail.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="手机号">{{ state.detail.phone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">{{ state.detail.genderName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="年龄">{{ state.detail.age }}岁</el-descriptions-item>
|
||||
<el-descriptions-item label="学历阶段">{{ state.detail.educationStageName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="地区">{{ state.detail.province }}{{ state.detail.city }}{{ state.detail.district }}</el-descriptions-item>
|
||||
<el-descriptions-item label="测评类型">{{ state.detail.assessmentTypeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="getStatusTagType(state.detail.status)" size="small">
|
||||
{{ state.detail.statusName }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="订单号" :span="2">{{ state.detail.orderNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开始时间">{{ state.detail.startTime || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="提交时间">{{ state.detail.submitTime || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="完成时间">{{ state.detail.completeTime || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ state.detail.createTime }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 答案列表 -->
|
||||
<div v-if="state.detail.answers && state.detail.answers.length > 0" class="detail-section">
|
||||
<h4 class="section-title">答案列表(共{{ state.detail.answers.length }}题)</h4>
|
||||
<el-table :data="state.detail.answers" stripe size="small" max-height="400">
|
||||
<el-table-column prop="questionNo" label="题号" width="60" align="center" />
|
||||
<el-table-column prop="questionContent" label="题目内容" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="answerValue" label="答案" width="70" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small" type="primary">{{ row.answerValue }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 结果列表 -->
|
||||
<div v-if="state.detail.results && state.detail.results.length > 0" class="detail-section">
|
||||
<h4 class="section-title">测评结果</h4>
|
||||
<el-table :data="state.detail.results" stripe size="small" max-height="400">
|
||||
<el-table-column prop="categoryTypeName" label="分类类型" width="120" />
|
||||
<el-table-column prop="categoryName" label="分类名称" min-width="120" />
|
||||
<el-table-column label="得分" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.score }} / {{ row.maxScore }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="百分比" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.percentage }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="星级" width="130" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-rate v-model="row.starLevel" disabled />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 报告抽屉 -->
|
||||
<el-drawer
|
||||
v-model="state.reportVisible"
|
||||
title="测评报告"
|
||||
size="700px"
|
||||
:close-on-click-modal="true"
|
||||
>
|
||||
<div v-loading="state.reportLoading" class="record-detail">
|
||||
<template v-if="state.report">
|
||||
<!-- 被测评人信息 -->
|
||||
<div class="detail-section">
|
||||
<h4 class="section-title">被测评人信息</h4>
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item label="姓名">{{ state.report.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">{{ state.report.genderName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="年龄">{{ state.report.age }}岁</el-descriptions-item>
|
||||
<el-descriptions-item label="学历阶段">{{ state.report.educationStageName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="地区" :span="2">{{ state.report.province }}{{ state.report.city }}{{ state.report.district }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 按分类分组展示结果 -->
|
||||
<div
|
||||
v-for="group in state.report.resultGroups"
|
||||
:key="group.categoryTypeId"
|
||||
class="detail-section"
|
||||
>
|
||||
<h4 class="section-title">{{ group.categoryTypeName }}</h4>
|
||||
<el-table :data="group.items" stripe size="small">
|
||||
<el-table-column prop="categoryName" label="分类" min-width="120" />
|
||||
<el-table-column label="得分" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.score }} / {{ row.maxScore }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="百分比" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.percentage }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="星级" width="130" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-rate v-model="row.starLevel" disabled />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="conclusionContent" label="结论" min-width="200" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 测评记录管理页面
|
||||
* @description 查看用户测评记录、答案详情和测评报告,支持搜索、导出
|
||||
*/
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { Search, Refresh, View, Download, Document } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
getRecordList,
|
||||
getRecordDetail,
|
||||
getRecordReport,
|
||||
exportRecords,
|
||||
type AssessmentRecordItem,
|
||||
type AssessmentRecordDetail,
|
||||
type AssessmentReport,
|
||||
type AssessmentRecordQuery
|
||||
} from '@/api/business/assessmentRecord'
|
||||
|
||||
// ============ Constants ============
|
||||
|
||||
/** 日期快捷选项 */
|
||||
const dateShortcuts = [
|
||||
{
|
||||
text: '最近一周',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return [start, end]
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '最近一个月',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
return [start, end]
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '最近三个月',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
return [start, end]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// ============ Types ============
|
||||
|
||||
interface RecordPageState {
|
||||
loading: boolean
|
||||
tableData: AssessmentRecordItem[]
|
||||
total: number
|
||||
detailVisible: boolean
|
||||
detailLoading: boolean
|
||||
detail: AssessmentRecordDetail | null
|
||||
reportVisible: boolean
|
||||
reportLoading: boolean
|
||||
report: AssessmentReport | null
|
||||
exportLoading: boolean
|
||||
}
|
||||
|
||||
// ============ Refs ============
|
||||
|
||||
const dateRange = ref<[string, string] | null>(null)
|
||||
|
||||
// ============ State ============
|
||||
|
||||
const queryParams = reactive({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
userId: '',
|
||||
status: undefined as number | undefined,
|
||||
startDate: undefined as string | undefined,
|
||||
endDate: undefined as string | undefined
|
||||
})
|
||||
|
||||
const state = reactive<RecordPageState>({
|
||||
loading: false,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
detailVisible: false,
|
||||
detailLoading: false,
|
||||
detail: null,
|
||||
reportVisible: false,
|
||||
reportLoading: false,
|
||||
report: null,
|
||||
exportLoading: false
|
||||
})
|
||||
|
||||
// ============ Helper Functions ============
|
||||
|
||||
/**
|
||||
* 获取状态标签类型
|
||||
* 待测评=info, 测评中=primary, 生成中=warning, 已完成=success
|
||||
*/
|
||||
function getStatusTagType(status: number): 'info' | 'primary' | 'warning' | 'success' {
|
||||
switch (status) {
|
||||
case 1: return 'info'
|
||||
case 2: return 'primary'
|
||||
case 3: return 'warning'
|
||||
case 4: return 'success'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// ============ API Functions ============
|
||||
|
||||
/** 加载测评记录列表 */
|
||||
async function loadRecordList() {
|
||||
state.loading = true
|
||||
try {
|
||||
const params: AssessmentRecordQuery = {
|
||||
page: queryParams.page,
|
||||
pageSize: queryParams.pageSize
|
||||
}
|
||||
if (queryParams.userId) {
|
||||
params.userId = Number(queryParams.userId)
|
||||
}
|
||||
if (queryParams.status !== undefined) {
|
||||
params.status = queryParams.status
|
||||
}
|
||||
if (queryParams.startDate) {
|
||||
params.startDate = queryParams.startDate
|
||||
}
|
||||
if (queryParams.endDate) {
|
||||
params.endDate = queryParams.endDate
|
||||
}
|
||||
|
||||
const res = await getRecordList(params)
|
||||
if (res.code === 0) {
|
||||
state.tableData = res.data?.list || []
|
||||
state.total = res.data?.total || 0
|
||||
} else {
|
||||
throw new Error(res.message || '获取测评记录列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : '获取测评记录列表失败'
|
||||
ElMessage.error(message)
|
||||
} finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 加载测评记录详情 */
|
||||
async function loadRecordDetail(id: number) {
|
||||
state.detailLoading = true
|
||||
try {
|
||||
const res = await getRecordDetail(id)
|
||||
if (res.code === 0) {
|
||||
state.detail = res.data
|
||||
} else {
|
||||
throw new Error(res.message || '获取测评记录详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : '获取测评记录详情失败'
|
||||
ElMessage.error(message)
|
||||
} finally {
|
||||
state.detailLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 加载测评报告 */
|
||||
async function loadRecordReport(id: number) {
|
||||
state.reportLoading = true
|
||||
try {
|
||||
const res = await getRecordReport(id)
|
||||
if (res.code === 0) {
|
||||
state.report = res.data
|
||||
} else {
|
||||
throw new Error(res.message || '获取测评报告失败')
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : '获取测评报告失败'
|
||||
ElMessage.error(message)
|
||||
} finally {
|
||||
state.reportLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Event Handlers ============
|
||||
|
||||
function handleSearch() {
|
||||
queryParams.page = 1
|
||||
loadRecordList()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
queryParams.userId = ''
|
||||
queryParams.status = undefined
|
||||
queryParams.startDate = undefined
|
||||
queryParams.endDate = undefined
|
||||
dateRange.value = null
|
||||
queryParams.page = 1
|
||||
loadRecordList()
|
||||
}
|
||||
|
||||
function handleDateRangeChange(val: [string, string] | null) {
|
||||
if (val) {
|
||||
queryParams.startDate = val[0]
|
||||
queryParams.endDate = val[1]
|
||||
} else {
|
||||
queryParams.startDate = undefined
|
||||
queryParams.endDate = undefined
|
||||
}
|
||||
}
|
||||
|
||||
function handleSizeChange(size: number) {
|
||||
queryParams.pageSize = size
|
||||
queryParams.page = 1
|
||||
loadRecordList()
|
||||
}
|
||||
|
||||
function handleCurrentChange(page: number) {
|
||||
queryParams.page = page
|
||||
loadRecordList()
|
||||
}
|
||||
|
||||
function handleViewDetail(row: AssessmentRecordItem) {
|
||||
state.detailVisible = true
|
||||
state.detail = null
|
||||
loadRecordDetail(row.id)
|
||||
}
|
||||
|
||||
function handleViewReport(row: AssessmentRecordItem) {
|
||||
state.reportVisible = true
|
||||
state.report = null
|
||||
loadRecordReport(row.id)
|
||||
}
|
||||
|
||||
async function handleExport() {
|
||||
state.exportLoading = true
|
||||
try {
|
||||
const params: AssessmentRecordQuery = {
|
||||
page: 1,
|
||||
pageSize: 10000
|
||||
}
|
||||
if (queryParams.userId) {
|
||||
params.userId = Number(queryParams.userId)
|
||||
}
|
||||
if (queryParams.status !== undefined) {
|
||||
params.status = queryParams.status
|
||||
}
|
||||
if (queryParams.startDate) {
|
||||
params.startDate = queryParams.startDate
|
||||
}
|
||||
if (queryParams.endDate) {
|
||||
params.endDate = queryParams.endDate
|
||||
}
|
||||
|
||||
const res = await exportRecords(params)
|
||||
|
||||
// 创建下载链接
|
||||
const blob = res.data instanceof Blob ? res.data : new Blob([res.data as BlobPart])
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = `测评记录_${new Date().toISOString().slice(0, 10)}.xlsx`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(url)
|
||||
|
||||
ElMessage.success('导出成功')
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : '导出失败'
|
||||
ElMessage.error(message)
|
||||
} finally {
|
||||
state.exportLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Lifecycle ============
|
||||
|
||||
onMounted(() => {
|
||||
loadRecordList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.record-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary, #303133);
|
||||
}
|
||||
|
||||
.page-description {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary, #909399);
|
||||
}
|
||||
|
||||
.search-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.search-card :deep(.el-card__body) {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.table-card {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.sub-text {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary, #909399);
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
/* 详情/报告抽屉样式 */
|
||||
.record-detail {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary, #303133);
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--border-lighter, #ebeef5);
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
:deep(.el-table) {
|
||||
--el-table-border-color: var(--border-lighter, #ebeef5);
|
||||
}
|
||||
|
||||
:deep(.el-table th.el-table__cell) {
|
||||
background-color: var(--bg-light, #f5f7fa);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions) {
|
||||
--el-descriptions-item-bordered-label-background: var(--bg-light, #f5f7fa);
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user