wuzhen update 1.0

This commit is contained in:
wuzhen committed 2025-08-21 08:42:05 +08:00
1 parent 64a0c9e81a
commit cf5eb97553
40 files changed
+1011 -1276

No files matched your search

+1
View File
@@ -414,6 +414,7 @@
<version>${revision}</version>
</dependency>
<!-- 社团管理模块 -->
<!-- <dependency>
<groupId>org.dromara</groupId>
+1
View File
@@ -112,6 +112,7 @@
<groupId>org.dromara</groupId>
<artifactId>ruoyi-xg</artifactId>
</dependency>
<!-- 学工管理-学生信息管理模块 -->
<!-- <dependency>
<groupId>org.dromara</groupId>
@@ -4,7 +4,7 @@ import { AssessmentIndicatorVO, AssessmentIndicatorQuery, AssessmentIndicatorFor
/**
* 查询班主任考核指标体系列表
* @param query 查询条件
* @returns
* @returns
*/
export function listBmzrAssessmentIndicator(query?: AssessmentIndicatorQuery) {
return request({
@@ -17,7 +17,7 @@ export function listBmzrAssessmentIndicator(query?: AssessmentIndicatorQuery) {
/**
* 查询班主任考核指标体系详细
* @param id 主键
* @returns
* @returns
*/
export function getBmzrAssessmentIndicator(id: string | number) {
return request({
@@ -29,7 +29,7 @@ export function getBmzrAssessmentIndicator(id: string | number) {
/**
* 新增班主任考核指标体系
* @param data 表单数据
* @returns
* @returns
*/
export function addBmzrAssessmentIndicator(data: AssessmentIndicatorForm) {
return request({
@@ -42,7 +42,7 @@ export function addBmzrAssessmentIndicator(data: AssessmentIndicatorForm) {
/**
* 修改班主任考核指标体系
* @param data 表单数据
* @returns
* @returns
*/
export function updateBmzrAssessmentIndicator(data: AssessmentIndicatorForm) {
return request({
@@ -55,7 +55,7 @@ export function updateBmzrAssessmentIndicator(data: AssessmentIndicatorForm) {
/**
* 删除班主任考核指标体系
* @param ids 主键串
* @returns
* @returns
*/
export function delBmzrAssessmentIndicator(ids: string | number | Array<string | number>) {
return request({
@@ -66,7 +66,7 @@ export function delBmzrAssessmentIndicator(ids: string | number | Array<string |
/**
* 获取指标类型选项
* @returns
* @returns
*/
export function getIndicatorTypeOptions() {
return request({
@@ -77,11 +77,11 @@ export function getIndicatorTypeOptions() {
/**
* 获取父级指标选项
* @returns
* @returns
*/
export function getParentIndicatorOptions() {
return request({
url: '/bzrkh/assessmentIndicator/treeselect',
method: 'get'
});
}
}
@@ -234,4 +234,4 @@ export interface AssessmentIndicatorTypeOption {
* 状态(0正常 1停用)
*/
status?: string;
}
}
@@ -72,4 +72,4 @@ export const delAssessmentIndicatorType = (id: string | number | Array<string |
url: '/bzrkh/assessmentIndicatorType/' + id,
method: 'delete'
});
};
};
@@ -107,4 +107,4 @@ export interface AssessmentIndicatorTypeQuery extends PageQuery {
* 日期范围参数
*/
params?: any;
}
}
+1 -1
View File
@@ -97,4 +97,4 @@ export const changeAssessmentPlanStatus = (id: string | number, status: string)
planStatus: status
}
});
};
};
+1 -1
View File
@@ -237,4 +237,4 @@ export interface AssessmentSchemeOption {
* 状态
*/
status?: string;
}
}
+1 -1
View File
@@ -71,4 +71,4 @@ export const exportBmzrAssessmentScheme = (query?: BmzrAssessmentSchemeQuery): A
method: 'post',
data: query
});
};
};
+1 -1
View File
@@ -182,4 +182,4 @@ export interface BmzrAssessmentSchemeQuery extends PageQuery {
* 参数
*/
params?: any;
}
}
@@ -4,7 +4,7 @@ import { BmzrAssessmentSchemeIndicatorVO, BmzrAssessmentSchemeIndicatorQuery, Bm
/**
* 查询班主任考核方案指标关联列表
* @param query 查询条件
* @returns
* @returns
*/
export function listBmzrAssessmentSchemeIndicator(query?: BmzrAssessmentSchemeIndicatorQuery) {
return request({
@@ -17,7 +17,7 @@ export function listBmzrAssessmentSchemeIndicator(query?: BmzrAssessmentSchemeIn
/**
* 根据方案ID查询指标关联列表
* @param schemeId 方案ID
* @returns
* @returns
*/
export function listBySchemeId(schemeId: string | number) {
return request({
@@ -29,7 +29,7 @@ export function listBySchemeId(schemeId: string | number) {
/**
* 查询班主任考核方案指标关联详细
* @param id 主键
* @returns
* @returns
*/
export function getBmzrAssessmentSchemeIndicator(id: string | number) {
return request({
@@ -41,7 +41,7 @@ export function getBmzrAssessmentSchemeIndicator(id: string | number) {
/**
* 新增班主任考核方案指标关联
* @param data 表单数据
* @returns
* @returns
*/
export function addBmzrAssessmentSchemeIndicator(data: BmzrAssessmentSchemeIndicatorForm) {
return request({
@@ -54,7 +54,7 @@ export function addBmzrAssessmentSchemeIndicator(data: BmzrAssessmentSchemeIndic
/**
* 修改班主任考核方案指标关联
* @param data 表单数据
* @returns
* @returns
*/
export function updateBmzrAssessmentSchemeIndicator(data: BmzrAssessmentSchemeIndicatorForm) {
return request({
@@ -67,7 +67,7 @@ export function updateBmzrAssessmentSchemeIndicator(data: BmzrAssessmentSchemeIn
/**
* 删除班主任考核方案指标关联
* @param ids 主键串
* @returns
* @returns
*/
export function delBmzrAssessmentSchemeIndicator(ids: string | number | Array<string | number>) {
return request({
@@ -80,7 +80,7 @@ export function delBmzrAssessmentSchemeIndicator(ids: string | number | Array<st
* 批量保存方案指标关联
* @param schemeId 方案ID
* @param indicatorList 指标列表
* @returns
* @returns
*/
export function batchSaveSchemeIndicators(schemeId: string | number, indicatorList: BmzrAssessmentSchemeIndicatorForm[]) {
return request({
@@ -88,4 +88,4 @@ export function batchSaveSchemeIndicators(schemeId: string | number, indicatorLi
method: 'post',
data: indicatorList
});
}
}
@@ -147,4 +147,4 @@ export interface BmzrAssessmentSchemeIndicatorQuery extends PageQuery {
* 参数
*/
params?: any;
}
}
@@ -113,7 +113,6 @@ export interface DormHygieneCheckVO {
* 检查备注
*/
checkRemarks: string;
}
export interface DormHygieneCheckForm extends BaseEntity {
@@ -231,11 +230,9 @@ export interface DormHygieneCheckForm extends BaseEntity {
* 检查备注
*/
checkRemarks?: string;
}
export interface DormHygieneCheckQuery extends PageQuery {
/**
* 删除标志(0代表存在 1代表删除)
*/
@@ -346,10 +343,10 @@ export interface DormHygieneCheckQuery extends PageQuery {
*/
checkRemarks?: string;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
// 宿舍级联选择相关类型
@@ -643,6 +640,3 @@ export interface DormHygieneCheckCompleteForm extends DormHygieneCheckForm {
*/
studentScores?: DormHygieneStudentScoreForm[];
}
@@ -98,7 +98,6 @@ export interface DormHygieneStudentScoreVO {
* 改进意见
*/
improvementNotes: string;
}
export interface DormHygieneStudentScoreForm extends BaseEntity {
@@ -201,11 +200,9 @@ export interface DormHygieneStudentScoreForm extends BaseEntity {
* 改进意见
*/
improvementNotes?: string;
}
export interface DormHygieneStudentScoreQuery extends PageQuery {
/**
* 删除标志(0代表存在 1代表删除)
*/
@@ -301,11 +298,8 @@ export interface DormHygieneStudentScoreQuery extends PageQuery {
*/
improvementNotes?: string;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
@@ -138,7 +138,6 @@ export interface DormViolationVO {
* 备注
*/
remark: string;
}
export interface DormViolationForm extends BaseEntity {
@@ -281,11 +280,9 @@ export interface DormViolationForm extends BaseEntity {
* 备注
*/
remark?: string;
}
export interface DormViolationQuery extends PageQuery {
/**
* 学生ID
*/
@@ -416,10 +413,10 @@ export interface DormViolationQuery extends PageQuery {
*/
deleted?: string;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
// 学生选择相关类型
@@ -478,6 +475,3 @@ export interface BedOptionVO {
id: string | number;
bedName: string;
}
@@ -67,7 +67,9 @@ export const delHolidayStay = (id: string | number | Array<string | number>) =>
* @param query 查询参数
* @returns 学生选项列表
*/
export const getStudentOptions = (query?: StudentOptionQuery): AxiosPromise<{
export const getStudentOptions = (
query?: StudentOptionQuery
): AxiosPromise<{
total: number;
rows: StudentOptionVO[];
}> => {
@@ -173,7 +173,6 @@ export interface HolidayStayVO {
* 备注信息
*/
remark: string;
}
export interface HolidayStayForm extends BaseEntity {
@@ -351,11 +350,9 @@ export interface HolidayStayForm extends BaseEntity {
* 备注信息
*/
remark?: string;
}
export interface HolidayStayQuery extends PageQuery {
/**
* 删除标志(0代表存在 1代表删除)
*/
@@ -526,10 +523,10 @@ export interface HolidayStayQuery extends PageQuery {
*/
status?: string;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
/**
@@ -752,6 +749,3 @@ export interface BedOptionVO {
*/
bedStatus?: string;
}
@@ -245,7 +245,6 @@ export interface DisciplineRecordForm {
}
export interface DisciplineRecordQuery extends PageQuery {
/**
* 学生ID
*/
@@ -346,10 +345,10 @@ export interface DisciplineRecordQuery extends PageQuery {
*/
approvalRemark?: string;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
/**
@@ -38,7 +38,6 @@ export interface DisciplineTypeVO {
* 删除标志(0-未删除 1-已删除)
*/
deleted: number;
}
export interface DisciplineTypeForm extends BaseEntity {
@@ -81,11 +80,9 @@ export interface DisciplineTypeForm extends BaseEntity {
* 删除标志(0-未删除 1-已删除)
*/
deleted?: number;
}
export interface DisciplineTypeQuery extends PageQuery {
/**
* 类型编码
*/
@@ -116,11 +113,8 @@ export interface DisciplineTypeQuery extends PageQuery {
*/
deleted?: number;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
@@ -33,7 +33,6 @@ export interface RewardTypeVO {
* 删除标志(0-未删除 1-已删除)
*/
deleted: number;
}
export interface RewardTypeForm extends BaseEntity {
@@ -71,11 +70,9 @@ export interface RewardTypeForm extends BaseEntity {
* 删除标志(0-未删除 1-已删除)
*/
deleted?: number;
}
export interface RewardTypeQuery extends PageQuery {
/**
* 类型编码
*/
@@ -106,11 +103,8 @@ export interface RewardTypeQuery extends PageQuery {
*/
deleted?: number;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
@@ -245,7 +245,6 @@ export interface DisciplineRecordForm {
}
export interface DisciplineRecordQuery extends PageQuery {
/**
* 学生ID
*/
@@ -346,10 +345,10 @@ export interface DisciplineRecordQuery extends PageQuery {
*/
approvalRemark?: string;
/**
* 日期范围参数
*/
params?: any;
/**
* 日期范围参数
*/
params?: any;
}
/**
+13 -14
View File
@@ -1,4 +1,4 @@
import request from '@/utils/request'
import request from '@/utils/request';
// 查询学生月度总结列表
export function listInternshipMonthly(query: any) {
@@ -6,7 +6,7 @@ export function listInternshipMonthly(query: any) {
url: '/zsjy/internship/monthly/list',
method: 'get',
params: query
})
});
}
// 获取学生月度总结详细信息
@@ -14,7 +14,7 @@ export function getInternshipMonthly(monthlyId: string | number) {
return request({
url: '/zsjy/internship/monthly/' + monthlyId,
method: 'get'
})
});
}
// 新增学生月度总结
@@ -23,7 +23,7 @@ export function addInternshipMonthly(data: any) {
url: '/zsjy/internship/monthly',
method: 'post',
data: data
})
});
}
// 修改学生月度总结
@@ -32,7 +32,7 @@ export function updateInternshipMonthly(data: any) {
url: '/zsjy/internship/monthly',
method: 'put',
data: data
})
});
}
// 删除学生月度总结
@@ -40,7 +40,7 @@ export function delInternshipMonthly(monthlyIds: string | number | Array<string
return request({
url: '/zsjy/internship/monthly/' + monthlyIds,
method: 'delete'
})
});
}
// 提交月度总结审批
@@ -48,7 +48,7 @@ export function submitInternshipMonthly(monthlyId: string | number) {
return request({
url: '/zsjy/internship/monthly/submit/' + monthlyId,
method: 'put'
})
});
}
// 自动保存草稿
@@ -57,7 +57,7 @@ export function autosaveInternshipMonthly(data: any) {
url: '/zsjy/internship/monthly/autosave',
method: 'post',
data: data
})
});
}
// 检查月份重复
@@ -65,7 +65,7 @@ export function checkSummaryMonth(summaryMonth: string) {
return request({
url: '/zsjy/internship/monthly/check/' + summaryMonth,
method: 'get'
})
});
}
// 获取月度总结模板
@@ -73,7 +73,7 @@ export function getMonthlyTemplate(summaryMonth: string) {
return request({
url: '/zsjy/internship/monthly/template/' + summaryMonth,
method: 'get'
})
});
}
// 获取状态统计
@@ -81,7 +81,7 @@ export function getMonthlyStatistics() {
return request({
url: '/zsjy/internship/monthly/statistics',
method: 'get'
})
});
}
// 导出月度总结数据
@@ -90,7 +90,7 @@ export function exportInternshipMonthly(query: any) {
url: '/zsjy/internship/monthly/export',
method: 'post',
params: query
})
});
}
// 获取学生当前实习信息
@@ -98,6 +98,5 @@ export function getCurrentInternshipInfo() {
return request({
url: '/zsjy/internship/monthly/current-internship',
method: 'get'
})
});
}
+13 -13
View File
@@ -1,4 +1,4 @@
import request from '@/utils/request'
import request from '@/utils/request';
/**
* 二维码管理 VO
@@ -156,7 +156,7 @@ export function listQrCode(query?: QrCodeQuery) {
url: '/zsjy/qrcode/list',
method: 'get',
params: query
})
});
}
/**
@@ -166,7 +166,7 @@ export function getQrCode(id: string | number) {
return request({
url: '/zsjy/qrcode/' + id,
method: 'get'
})
});
}
/**
@@ -177,7 +177,7 @@ export function addQrCode(data: QrCodeBO) {
url: '/zsjy/qrcode',
method: 'post',
data: data
})
});
}
/**
@@ -188,7 +188,7 @@ export function updateQrCode(data: QrCodeBO) {
url: '/zsjy/qrcode',
method: 'put',
data: data
})
});
}
/**
@@ -198,7 +198,7 @@ export function delQrCode(ids: string | number | Array<string | number>) {
return request({
url: '/zsjy/qrcode/' + ids,
method: 'delete'
})
});
}
/**
@@ -210,7 +210,7 @@ export function exportQrCode(query?: QrCodeQuery) {
method: 'post',
data: query,
responseType: 'blob'
})
});
}
/**
@@ -220,7 +220,7 @@ export function validateToken(token: string) {
return request({
url: '/zsjy/qrcode/validate/' + token,
method: 'get'
})
});
}
/**
@@ -230,7 +230,7 @@ export function getQrCodeByToken(token: string) {
return request({
url: '/zsjy/qrcode/token/' + token,
method: 'get'
})
});
}
/**
@@ -240,7 +240,7 @@ export function incrementUsage(id: string | number) {
return request({
url: '/zsjy/qrcode/increment/' + id,
method: 'post'
})
});
}
/**
@@ -250,7 +250,7 @@ export function generateToken() {
return request({
url: '/zsjy/qrcode/generate-token',
method: 'post'
})
});
}
/**
@@ -261,7 +261,7 @@ export const qrCodeTypeOptions = [
label: '招生报名',
value: 1
}
]
];
/**
* 状态选项
@@ -275,4 +275,4 @@ export const statusOptions = [
label: '启用',
value: 1
}
]
];
+8 -9
View File
@@ -140,13 +140,12 @@ service.interceptors.response.use(
code === 0 ||
code === 'SUCCESS' ||
resData.success === true ||
(res.status === 200 && (
resData.rows !== undefined ||
resData.total !== undefined ||
(resData.data && (resData.data.rows !== undefined || resData.data.total !== undefined || resData.data.list !== undefined)) ||
resData.list !== undefined
)) ||
(res.status === 200 && (res.config?.method === 'get'))
(res.status === 200 &&
(resData.rows !== undefined ||
resData.total !== undefined ||
(resData.data && (resData.data.rows !== undefined || resData.data.total !== undefined || resData.data.list !== undefined)) ||
resData.list !== undefined)) ||
(res.status === 200 && res.config?.method === 'get')
) {
return Promise.resolve(resData);
}
@@ -179,8 +178,8 @@ service.interceptors.response.use(
} else if (code === 403) {
// 特殊处理403权限错误,提供更明确的错误提示
const permissionMsg = '无访问权限,可能原因:\n1. 用户权限不足\n2. 权限配置问题\n请联系管理员检查权限配置';
ElMessage({
message: permissionMsg,
ElMessage({
message: permissionMsg,
type: 'warning',
duration: 8000,
showClose: true
@@ -41,24 +41,10 @@
<el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['bzrkh:assessmentIndicator:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
icon="Edit"
:disabled="single"
@click="handleUpdate()"
v-hasPermi="['bzrkh:assessmentIndicator:edit']"
>
修改
</el-button>
<el-button icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['bzrkh:assessmentIndicator:edit']"> 修改 </el-button>
</el-col>
<el-col :span="1.5">
<el-button
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['bzrkh:assessmentIndicator:remove']"
>
删除
</el-button>
<el-button icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['bzrkh:assessmentIndicator:remove']"> 删除 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
@@ -66,12 +52,7 @@
</template>
<div class="table-container">
<el-table
v-loading="loading"
border
:data="assessmentIndicatorList"
@selection-change="handleSelectionChange"
>
<el-table v-loading="loading" border :data="assessmentIndicatorList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="指标编码" align="center" prop="indicatorCode" width="140" show-overflow-tooltip />
<el-table-column label="指标名称" align="center" prop="indicatorName" min-width="180" show-overflow-tooltip />
@@ -91,10 +72,22 @@
<el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['bzrkh:assessmentIndicator:edit']"></el-button>
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['bzrkh:assessmentIndicator:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['bzrkh:assessmentIndicator:remove']"></el-button>
<el-button
link
type="danger"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['bzrkh:assessmentIndicator:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
@@ -170,8 +163,21 @@
</template>
<script setup name="AssessmentIndicator" lang="ts">
import { listBmzrAssessmentIndicator, getBmzrAssessmentIndicator, delBmzrAssessmentIndicator, addBmzrAssessmentIndicator, updateBmzrAssessmentIndicator, getIndicatorTypeOptions, getParentIndicatorOptions } from '@/api/bzrkh/assessmentIndicator';
import { AssessmentIndicatorVO, AssessmentIndicatorQuery, AssessmentIndicatorForm, AssessmentIndicatorTypeOption } from '@/api/bzrkh/assessmentIndicator/types';
import {
listBmzrAssessmentIndicator,
getBmzrAssessmentIndicator,
delBmzrAssessmentIndicator,
addBmzrAssessmentIndicator,
updateBmzrAssessmentIndicator,
getIndicatorTypeOptions,
getParentIndicatorOptions
} from '@/api/bzrkh/assessmentIndicator';
import {
AssessmentIndicatorVO,
AssessmentIndicatorQuery,
AssessmentIndicatorForm,
AssessmentIndicatorTypeOption
} from '@/api/bzrkh/assessmentIndicator/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_item_enable, sys_yes_no } = toRefs<any>(proxy?.useDict('sys_item_enable', 'sys_yes_no'));
@@ -234,7 +240,7 @@ const { queryParams, form, rules } = toRefs(data);
/** 获取指标类型名称 */
const getIndicatorTypeName = (code: string) => {
const option = indicatorTypeOptions.value.find(item => item.indicatorTypeCode === code);
const option = indicatorTypeOptions.value.find((item) => item.indicatorTypeCode === code);
return option ? option.indicatorTypeName : code;
};
@@ -359,8 +365,6 @@ const handleDelete = async (row?: AssessmentIndicatorVO) => {
await getList();
};
onMounted(() => {
getList();
getIndicatorTypeOptionsList();
@@ -400,4 +404,4 @@ onMounted(() => {
background-color: #fff;
margin-top: 0px !important;
}
</style>
</style>
@@ -44,7 +44,9 @@
<el-button icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['bzrkh:assessmentIndicatorType:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['bzrkh:assessmentIndicatorType:remove']">删除</el-button>
<el-button icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['bzrkh:assessmentIndicatorType:remove']"
>删除</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@@ -69,10 +71,22 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['bzrkh:assessmentIndicatorType:edit']"></el-button>
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['bzrkh:assessmentIndicatorType:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['bzrkh:assessmentIndicatorType:remove']"></el-button>
<el-button
link
type="danger"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['bzrkh:assessmentIndicatorType:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
@@ -112,7 +126,13 @@
</template>
<script setup name="AssessmentIndicatorType" lang="ts">
import { listAssessmentIndicatorType, getAssessmentIndicatorType, delAssessmentIndicatorType, addAssessmentIndicatorType, updateAssessmentIndicatorType } from '@/api/bzrkh/assessmentIndicatorType';
import {
listAssessmentIndicatorType,
getAssessmentIndicatorType,
delAssessmentIndicatorType,
addAssessmentIndicatorType,
updateAssessmentIndicatorType
} from '@/api/bzrkh/assessmentIndicatorType';
import { AssessmentIndicatorTypeVO, AssessmentIndicatorTypeQuery, AssessmentIndicatorTypeForm } from '@/api/bzrkh/assessmentIndicatorType/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -300,4 +320,4 @@ onMounted(() => {
background-color: #fff;
margin-top: 0px !important;
}
</style>
</style>
+19 -17
View File
@@ -91,7 +91,7 @@
<el-table-column label="计划编码" align="center" prop="planCode" :show-overflow-tooltip="true" />
<el-table-column label="考核方案" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<span>{{ schemeOptions.find(item => item.id === scope.row.schemeId)?.schemeName || '' }}</span>
<span>{{ schemeOptions.find((item) => item.id === scope.row.schemeId)?.schemeName || '' }}</span>
</template>
</el-table-column>
<el-table-column label="学年学期" align="center" width="120">
@@ -165,7 +165,12 @@
<el-col :span="24">
<el-form-item label="考核方案" prop="schemeId">
<el-select v-model="form.schemeId" placeholder="请选择考核方案" style="width: 100%">
<el-option v-for="item in schemeOptions" :key="item.id" :label="`${item.schemeName}(${item.academicYear}${item.semester === '1' ? '上' : '下'}学期)`" :value="item.id" />
<el-option
v-for="item in schemeOptions"
:key="item.id"
:label="`${item.schemeName}(${item.academicYear}${item.semester === '1' ? '上' : '下'}学期)`"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
@@ -277,11 +282,7 @@ import {
changeAssessmentPlanStatus
} from '@/api/bzrkh/assessmentPlan';
import { listBmzrAssessmentScheme } from '@/api/bzrkh/assessmentScheme';
import {
AssessmentPlanVO,
AssessmentPlanQuery,
AssessmentPlanForm
} from '@/api/bzrkh/assessmentPlan/types';
import { AssessmentPlanVO, AssessmentPlanQuery, AssessmentPlanForm } from '@/api/bzrkh/assessmentPlan/types';
import { BmzrAssessmentSchemeVO } from '@/api/bzrkh/assessmentScheme/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -371,7 +372,7 @@ const getList = async () => {
/** 获取考核方案选项 */
const getSchemeOptions = async () => {
const res = await listBmzrAssessmentScheme({
const res = await listBmzrAssessmentScheme({
status: '0', // 只获取正常状态的方案
pageNum: 1,
pageSize: 1000 // 设置较大的pageSize以获取所有可用方案
@@ -479,18 +480,19 @@ const handleDelete = async (row?: AssessmentPlanVO) => {
});
};
/** 状态修改 */
const handleStatusChange = async (row: AssessmentPlanVO) => {
const text = row.planStatus === '1' ? '启用' : '禁用';
await proxy?.$modal.confirm('确认要"' + text + '""' + row.planName + '"考核计划吗?').then(async () => {
await changeAssessmentPlanStatus(row.id!, row.planStatus!).then(() => {
proxy?.$modal.msgSuccess(text + '成功');
await proxy?.$modal
.confirm('确认要"' + text + '""' + row.planName + '"考核计划吗?')
.then(async () => {
await changeAssessmentPlanStatus(row.id!, row.planStatus!).then(() => {
proxy?.$modal.msgSuccess(text + '成功');
});
})
.catch(() => {
row.planStatus = row.planStatus === '1' ? '0' : '1';
});
}).catch(() => {
row.planStatus = row.planStatus === '1' ? '0' : '1';
});
};
onMounted(() => {
@@ -532,4 +534,4 @@ onMounted(() => {
background-color: #fff;
margin-top: 0px !important;
}
</style>
</style>
@@ -1,12 +1,5 @@
<template>
<el-dialog
title="指标体系管理"
v-model="dialogVisible"
width="1200px"
append-to-body
:close-on-click-modal="false"
@close="handleClose"
>
<el-dialog title="指标体系管理" v-model="dialogVisible" width="1200px" append-to-body :close-on-click-modal="false" @close="handleClose">
<div class="indicator-management-container">
<!-- 检索区域 -->
<div class="search-container">
@@ -15,12 +8,7 @@
<el-row :gutter="20">
<el-col :lg="8" :md="12" :sm="24">
<el-form-item label="指标名称" prop="indicatorName">
<el-input
v-model="searchParams.indicatorName"
placeholder="请输入指标名称"
clearable
@keyup.enter="handleSearchIndicators"
/>
<el-input v-model="searchParams.indicatorName" placeholder="请输入指标名称" clearable @keyup.enter="handleSearchIndicators" />
</el-form-item>
</el-col>
<el-col :lg="16" :md="12" :sm="24">
@@ -31,15 +19,10 @@
</el-col>
</el-row>
</el-form>
<!-- 搜索结果提示 -->
<div v-if="searchResultInfo" class="search-result-info">
<el-alert
:title="searchResultInfo"
type="info"
:closable="false"
show-icon
/>
<el-alert :title="searchResultInfo" type="info" :closable="false" show-icon />
</div>
</el-card>
</div>
@@ -54,8 +37,8 @@
<!-- 没有搜索结果时显示提示 -->
<div v-else-if="filteredIndicatorList.length === 0" class="empty-state">
<div style="text-align: center; color: #909399;">
<el-icon size="48" style="margin-bottom: 16px;"><Search /></el-icon>
<div style="text-align: center; color: #909399">
<el-icon size="48" style="margin-bottom: 16px"><Search /></el-icon>
<p>未找到匹配"{{ searchParams.indicatorName }}"的指标</p>
<el-button type="text" @click="resetSearch">清除搜索条件</el-button>
</div>
@@ -71,19 +54,14 @@
</div>
<div class="row-item">
<span class="label">指标名称:</span>
<el-select
v-model="item.indicatorId"
placeholder="请选择指标名称"
<el-select
v-model="item.indicatorId"
placeholder="请选择指标名称"
style="width: 250px"
@change="handleIndicatorChange(item, getOriginalIndex(item))"
filterable
>
<el-option
v-for="indicator in availableIndicators"
:key="indicator.id"
:label="indicator.indicatorName"
:value="indicator.id"
/>
<el-option v-for="indicator in availableIndicators" :key="indicator.id" :label="indicator.indicatorName" :value="indicator.id" />
</el-select>
</div>
<div class="row-item">
@@ -153,13 +131,13 @@ const filteredIndicatorList = computed(() => {
// 没有搜索条件时,显示所有指标
return indicatorList.value;
}
// 有搜索条件时,只显示匹配的指标
return indicatorList.value.filter(item => {
return indicatorList.value.filter((item) => {
// 根据indicatorId查找对应的指标名称
const indicator = availableIndicators.value.find(ind => ind.id == item.indicatorId);
const indicator = availableIndicators.value.find((ind) => ind.id == item.indicatorId);
const indicatorName = indicator?.indicatorName || '';
// 检查指标名称是否包含搜索关键词(不区分大小写)
return indicatorName.toLowerCase().includes(keyword.toLowerCase());
});
@@ -167,10 +145,11 @@ const filteredIndicatorList = computed(() => {
// 获取指标在原始列表中的索引
const getOriginalIndex = (item: BmzrAssessmentSchemeIndicatorForm) => {
return indicatorList.value.findIndex(originalItem =>
originalItem === item ||
(originalItem.id && originalItem.id === item.id) ||
(originalItem.indicatorId && originalItem.indicatorId === item.indicatorId && originalItem.sortOrder === item.sortOrder)
return indicatorList.value.findIndex(
(originalItem) =>
originalItem === item ||
(originalItem.id && originalItem.id === item.id) ||
(originalItem.indicatorId && originalItem.indicatorId === item.indicatorId && originalItem.sortOrder === item.sortOrder)
);
};
@@ -178,10 +157,10 @@ const getOriginalIndex = (item: BmzrAssessmentSchemeIndicatorForm) => {
const open = async (id: string | number) => {
schemeId.value = id;
dialogVisible.value = true;
// 加载可选指标
await loadAvailableIndicators();
// 加载当前方案的指标
await loadSchemeIndicators();
};
@@ -194,24 +173,24 @@ const loadAvailableIndicators = async () => {
pageNum: 1,
pageSize: 1000 // 加载所有指标
};
// 如果有搜索条件,添加到查询参数中
const hasSearchCondition = !!(searchParams.value.indicatorName && searchParams.value.indicatorName.trim());
if (hasSearchCondition) {
queryParams.indicatorName = searchParams.value.indicatorName.trim();
}
const res = await listBmzrAssessmentIndicator(queryParams);
availableIndicators.value = res.rows || [];
// 调试日志
console.log('loadAvailableIndicators完成:', {
queryParams,
hasSearchCondition,
resultCount: availableIndicators.value.length,
indicatorNames: availableIndicators.value.map(i => i.indicatorName)
indicatorNames: availableIndicators.value.map((i) => i.indicatorName)
});
// 更新搜索结果信息
updateSearchResultInfo(hasSearchCondition, availableIndicators.value.length);
} catch (error) {
@@ -225,15 +204,16 @@ const loadAvailableIndicators = async () => {
const loadSchemeIndicators = async () => {
try {
const res = await listBySchemeId(schemeId.value);
indicatorList.value = res.data?.map((item: any) => ({
id: item.id,
schemeId: item.schemeId,
indicatorId: item.indicatorId,
// 优先使用score字段,如果为空则使用customMaxScore字段(兜底方案)
score: item.score || item.customMaxScore,
remark: item.remark || getIndicatorRemark(item.indicatorId),
sortOrder: item.sortOrder
})) || [];
indicatorList.value =
res.data?.map((item: any) => ({
id: item.id,
schemeId: item.schemeId,
indicatorId: item.indicatorId,
// 优先使用score字段,如果为空则使用customMaxScore字段(兜底方案)
score: item.score || item.customMaxScore,
remark: item.remark || getIndicatorRemark(item.indicatorId),
sortOrder: item.sortOrder
})) || [];
} catch (error) {
console.error('加载方案指标失败:', error);
proxy?.$modal.msgError('加载方案指标失败');
@@ -242,7 +222,7 @@ const loadSchemeIndicators = async () => {
// 根据指标ID获取指标描述
const getIndicatorRemark = (indicatorId: string | number) => {
const indicator = availableIndicators.value.find(item => item.id == indicatorId);
const indicator = availableIndicators.value.find((item) => item.id == indicatorId);
return indicator?.remark || '';
};
@@ -261,23 +241,23 @@ const updateSearchResultInfo = (hasSearchCondition: boolean, resultCount: number
const getAvailableIndicators = (currentIndex: number) => {
// 搜索功能:直接返回后端搜索结果,允许重复选择同一指标
// 这样用户可以在不同位置选择相同的指标
// 调试日志
console.log('getAvailableIndicators调用:', {
currentIndex,
totalAvailable: availableIndicators.value.length,
searchKeyword: searchParams.value.indicatorName,
availableIndicatorIds: availableIndicators.value.map(i => i.id),
availableIndicatorNames: availableIndicators.value.map(i => i.indicatorName),
availableIndicatorIds: availableIndicators.value.map((i) => i.id),
availableIndicatorNames: availableIndicators.value.map((i) => i.indicatorName),
currentSelectedIndicatorId: indicatorList.value[currentIndex]?.indicatorId
});
return availableIndicators.value;
};
// 指标选择变化
const handleIndicatorChange = (item: BmzrAssessmentSchemeIndicatorForm, index: number) => {
const selectedIndicator = availableIndicators.value.find(indicator => indicator.id == item.indicatorId);
const selectedIndicator = availableIndicators.value.find((indicator) => indicator.id == item.indicatorId);
if (selectedIndicator) {
item.score = selectedIndicator.score;
item.remark = selectedIndicator.remark;
@@ -311,7 +291,7 @@ const handleSearchIndicators = async () => {
proxy?.$modal.msgWarning('请输入搜索关键词');
return;
}
try {
await loadAvailableIndicators();
proxy?.$modal.msgSuccess('搜索完成');
@@ -337,7 +317,7 @@ const resetSearch = async () => {
// 保存
const handleSave = async () => {
// 验证必填项
const invalidItems = indicatorList.value.filter(item => !item.indicatorId);
const invalidItems = indicatorList.value.filter((item) => !item.indicatorId);
if (invalidItems.length > 0) {
proxy?.$modal.msgError('请选择所有指标名称');
return;
@@ -469,10 +449,10 @@ defineExpose({
align-items: flex-start;
gap: 12px;
}
.row-item {
width: 100%;
justify-content: space-between;
}
}
</style>
</style>
+22 -18
View File
@@ -112,14 +112,26 @@
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['bzrkh:assessmentScheme:edit']"></el-button>
</el-tooltip>
<el-tooltip content="指标体系管理" placement="top">
<el-button link type="success" icon="Management" @click="handleIndicatorManagement(scope.row)" v-hasPermi="['bzrkh:assessmentSchemeIndicator:list']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['bzrkh:assessmentScheme:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
<el-tooltip content="指标体系管理" placement="top">
<el-button
link
type="success"
icon="Management"
@click="handleIndicatorManagement(scope.row)"
v-hasPermi="['bzrkh:assessmentSchemeIndicator:list']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="danger"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['bzrkh:assessmentScheme:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
@@ -222,9 +234,7 @@ import { BmzrAssessmentSchemeVO, BmzrAssessmentSchemeQuery, BmzrAssessmentScheme
import IndicatorManagement from './IndicatorManagement.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable, sys_yesno } = toRefs<any>(
proxy?.useDict('sys_normal_disable', 'sys_yesno')
);
const { sys_normal_disable, sys_yesno } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_yesno'));
const schemeList = ref<BmzrAssessmentSchemeVO[]>([]);
const buttonLoading = ref(false);
@@ -385,8 +395,6 @@ const handleDelete = async (row?: BmzrAssessmentSchemeVO) => {
}
};
/** 指标体系管理按钮操作 */
const handleIndicatorManagement = (row: BmzrAssessmentSchemeVO) => {
indicatorManagementRef.value?.open(row.id);
@@ -485,10 +493,6 @@ onMounted(() => {
border-bottom: none !important;
}
/* 表单样式 */
.scheme-form {
padding: 20px;
@@ -513,4 +517,4 @@ onMounted(() => {
justify-content: flex-end;
gap: 12px;
}
</style>
</style>
+1 -7
View File
@@ -353,13 +353,7 @@
</template>
<script setup name="OverseasApproval">
import {
listOverseasApproval,
getOverseasApproval,
delOverseasApproval,
addOverseasApproval,
updateOverseasApproval
} from '@/api/rs/overseas';
import { listOverseasApproval, getOverseasApproval, delOverseasApproval, addOverseasApproval, updateOverseasApproval } from '@/api/rs/overseas';
import { ref, reactive, toRefs, onMounted, getCurrentInstance, nextTick } from 'vue';
import { parseTime } from '@/utils/ruoyi';
@@ -29,9 +29,7 @@
<el-tag v-if="detail.learningAbility" :type="getScoreTagType(detail.learningAbility)">
学习能力: {{ detail.learningAbility }}分
</el-tag>
<el-tag v-if="detail.workAttitude" :type="getScoreTagType(detail.workAttitude)">
工作态度: {{ detail.workAttitude }}分
</el-tag>
<el-tag v-if="detail.workAttitude" :type="getScoreTagType(detail.workAttitude)"> 工作态度: {{ detail.workAttitude }}分 </el-tag>
</div>
</el-descriptions-item>
<el-descriptions-item label="总字数">
@@ -205,93 +203,81 @@
<el-row class="mt-6">
<el-col :span="24" class="text-center">
<el-button @click="handleClose">关闭</el-button>
<el-button
v-if="detail.reviewStatus === 3"
type="primary"
@click="handleEdit"
>
编辑
</el-button>
<el-button
v-if="detail.reviewStatus === 3"
type="success"
@click="handleSubmit"
>
提交审核
</el-button>
<el-button v-if="detail.reviewStatus === 3" type="primary" @click="handleEdit"> 编辑 </el-button>
<el-button v-if="detail.reviewStatus === 3" type="success" @click="handleSubmit"> 提交审核 </el-button>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { getInternshipMonthly, submitInternshipMonthly } from '@/api/zsjy/internshipMonthly'
import { getInternshipMonthly, submitInternshipMonthly } from '@/api/zsjy/internshipMonthly';
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'))
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'));
const emit = defineEmits(['edit', 'close'])
const emit = defineEmits(['edit', 'close']);
// 详情数据
const detail = ref<any>({})
const loading = ref(false)
const detail = ref<any>({});
const loading = ref(false);
/** 重置表单 */
const resetForm = async (monthlyId: string | number) => {
loading.value = true
loading.value = true;
try {
const res = await getInternshipMonthly(monthlyId)
detail.value = res.data || {}
const res = await getInternshipMonthly(monthlyId);
detail.value = res.data || {};
} catch (error) {
console.error('获取月度总结详情失败:', error)
proxy?.$modal.msgError('获取详情失败')
console.error('获取月度总结详情失败:', error);
proxy?.$modal.msgError('获取详情失败');
} finally {
loading.value = false
loading.value = false;
}
}
};
/** 根据分数获取标签类型 */
const getScoreTagType = (score: number) => {
if (!score) return 'info'
if (score >= 9) return 'success'
if (score >= 7) return 'warning'
if (score >= 5) return ''
return 'danger'
}
if (!score) return 'info';
if (score >= 9) return 'success';
if (score >= 7) return 'warning';
if (score >= 5) return '';
return 'danger';
};
/** 获取字数标签类型 */
const getWordCountTagType = (count: number) => {
if (!count) return 'info'
if (count < 100) return 'info'
if (count < 500) return 'warning'
if (count < 1000) return 'success'
return 'danger'
}
if (!count) return 'info';
if (count < 100) return 'info';
if (count < 500) return 'warning';
if (count < 1000) return 'success';
return 'danger';
};
/** 编辑操作 */
const handleEdit = () => {
emit('edit', detail.value.monthlyId)
}
emit('edit', detail.value.monthlyId);
};
/** 提交审核操作 */
const handleSubmit = async () => {
try {
await proxy?.$modal.confirm('确认提交该月度总结?提交后将无法再次编辑')
await submitInternshipMonthly(detail.value.monthlyId)
proxy?.$modal.msgSuccess('提交成功')
await proxy?.$modal.confirm('确认提交该月度总结?提交后将无法再次编辑');
await submitInternshipMonthly(detail.value.monthlyId);
proxy?.$modal.msgSuccess('提交成功');
// 重新加载详情
await resetForm(detail.value.monthlyId)
await resetForm(detail.value.monthlyId);
} catch {}
}
};
/** 关闭操作 */
const handleClose = () => {
emit('close')
}
emit('close');
};
defineExpose({
resetForm
})
});
</script>
<style scoped>
@@ -316,4 +302,3 @@ defineExpose({
white-space: pre-wrap;
}
</style>
+84 -101
View File
@@ -7,13 +7,7 @@
<template #header>
<div class="flex justify-between items-center">
<span class="font-medium">基本信息</span>
<el-button
v-if="form.monthlyId && form.reviewStatus === 3"
type="primary"
size="small"
@click="handleAutoSave"
:loading="autoSaving"
>
<el-button v-if="form.monthlyId && form.reviewStatus === 3" type="primary" size="small" @click="handleAutoSave" :loading="autoSaving">
{{ autoSaving ? '保存中...' : '保存草稿' }}
</el-button>
</div>
@@ -262,12 +256,7 @@
<span class="font-medium">月份检查</span>
</template>
<el-alert
:type="monthDuplicateCheck.type"
:title="monthDuplicateCheck.message"
show-icon
:closable="false"
/>
<el-alert :type="monthDuplicateCheck.type" :title="monthDuplicateCheck.message" show-icon :closable="false" />
</el-card>
</el-col>
</el-row>
@@ -305,16 +294,16 @@ import {
checkSummaryMonth,
getMonthlyTemplate,
getCurrentInternshipInfo
} from '@/api/zsjy/internshipMonthly'
} from '@/api/zsjy/internshipMonthly';
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'))
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'));
const emit = defineEmits(['success'])
const emit = defineEmits(['success']);
const monthlyFormRef = ref<ElFormInstance>()
const submitting = ref(false)
const autoSaving = ref(false)
const monthlyFormRef = ref<ElFormInstance>();
const submitting = ref(false);
const autoSaving = ref(false);
// 表单数据
const initFormData = {
@@ -337,15 +326,13 @@ const initFormData = {
reviewStatus: undefined,
submitTime: undefined,
createTime: undefined
}
};
const form = ref({ ...initFormData })
const form = ref({ ...initFormData });
// 表单验证规则
const rules = ref({
summaryMonth: [
{ required: true, message: '总结月份不能为空', trigger: 'change' }
],
summaryMonth: [{ required: true, message: '总结月份不能为空', trigger: 'change' }],
workContent: [
{ required: true, message: '工作内容不能为空', trigger: 'blur' },
{ min: 10, message: '工作内容至少需要10个字符', trigger: 'blur' },
@@ -380,107 +367,103 @@ const rules = ref({
{ required: true, message: '自我评价不能为空', trigger: 'blur' },
{ max: 300, message: '自我评价不能超过300个字符', trigger: 'blur' }
],
nextMonthPlan: [
{ max: 300, message: '下月计划不能超过300个字符', trigger: 'blur' }
],
remark: [
{ max: 200, message: '备注说明不能超过200个字符', trigger: 'blur' }
]
})
nextMonthPlan: [{ max: 300, message: '下月计划不能超过300个字符', trigger: 'blur' }],
remark: [{ max: 200, message: '备注说明不能超过200个字符', trigger: 'blur' }]
});
// 月份重复检查
const monthDuplicateCheck = ref({
show: false,
type: 'info',
message: ''
})
});
// 自动保存定时器
let autoSaveTimer: NodeJS.Timeout | null = null
let autoSaveTimer: NodeJS.Timeout | null = null;
/** 重置表单 */
const resetForm = async (monthlyId?: string | number) => {
form.value = { ...initFormData }
monthDuplicateCheck.value.show = false
form.value = { ...initFormData };
monthDuplicateCheck.value.show = false;
if (monthlyId) {
try {
const res = await getInternshipMonthly(monthlyId)
form.value = { ...res.data }
updateWordCount()
const res = await getInternshipMonthly(monthlyId);
form.value = { ...res.data };
updateWordCount();
} catch (error) {
console.error('获取月度总结详情失败:', error)
console.error('获取月度总结详情失败:', error);
}
} else {
// 新增时获取当前月份模板和学生实习信息
const currentMonth = new Date().toISOString().substring(0, 7)
form.value.summaryMonth = currentMonth
await loadMonthlyTemplate(currentMonth)
const currentMonth = new Date().toISOString().substring(0, 7);
form.value.summaryMonth = currentMonth;
await loadMonthlyTemplate(currentMonth);
// 获取学生当前实习信息
try {
const internshipRes = await getCurrentInternshipInfo()
const internshipRes = await getCurrentInternshipInfo();
if (internshipRes.code === 200 && internshipRes.data) {
form.value.internshipId = internshipRes.data.internshipId
form.value.internshipId = internshipRes.data.internshipId;
} else {
// 如果没有进行中的实习记录,提示用户
proxy?.$modal.msgError('您当前没有进行中的实习记录,无法创建月度总结')
emit('success') // 关闭对话框
return
proxy?.$modal.msgError('您当前没有进行中的实习记录,无法创建月度总结');
emit('success'); // 关闭对话框
return;
}
} catch (error) {
console.error('获取学生实习信息失败:', error)
proxy?.$modal.msgError('获取实习信息失败,请稍后重试')
emit('success') // 关闭对话框
return
console.error('获取学生实习信息失败:', error);
proxy?.$modal.msgError('获取实习信息失败,请稍后重试');
emit('success'); // 关闭对话框
return;
}
}
nextTick(() => {
monthlyFormRef.value?.clearValidate()
})
}
monthlyFormRef.value?.clearValidate();
});
};
/** 加载月份模板 */
const loadMonthlyTemplate = async (month: string) => {
try {
const res = await getMonthlyTemplate(month)
const res = await getMonthlyTemplate(month);
if (res.data) {
// 如果有模板数据,可以预填充一些内容
// form.value.nextMonthPlan = res.data.suggestedPlan || ''
}
} catch (error) {
console.log('获取月份模板失败,将使用空模板')
console.log('获取月份模板失败,将使用空模板');
}
}
};
/** 检查月份重复 */
const checkMonthDuplicate = async () => {
if (!form.value.summaryMonth) return
if (!form.value.summaryMonth) return;
try {
const res = await checkSummaryMonth(form.value.summaryMonth)
const res = await checkSummaryMonth(form.value.summaryMonth);
if (res.data.exists && (!form.value.monthlyId || res.data.monthlyId !== form.value.monthlyId)) {
monthDuplicateCheck.value = {
show: true,
type: 'warning',
message: '该月份已存在总结记录,请选择其他月份'
}
};
} else {
monthDuplicateCheck.value = {
show: true,
type: 'success',
message: '该月份可以创建总结'
}
};
}
} catch (error) {
monthDuplicateCheck.value = {
show: true,
type: 'error',
message: '检查月份失败,请重试'
}
};
}
}
};
/** 更新字数统计 */
const updateWordCount = () => {
@@ -492,91 +475,91 @@ const updateWordCount = () => {
form.value.selfEvaluation,
form.value.nextMonthPlan,
form.value.remark
].join('')
].join('');
form.value.wordCount = content.length
form.value.wordCount = content.length;
// 设置自动保存定时器
if (form.value.monthlyId && form.value.reviewStatus === 3) {
if (autoSaveTimer) {
clearTimeout(autoSaveTimer)
clearTimeout(autoSaveTimer);
}
autoSaveTimer = setTimeout(() => {
handleAutoSave()
}, 5000) // 5秒后自动保存
handleAutoSave();
}, 5000); // 5秒后自动保存
}
}
};
/** 获取字数标签类型 */
const getWordCountTagType = (count: number) => {
if (count < 100) return 'info'
if (count < 500) return 'warning'
if (count < 1000) return 'success'
return 'danger'
}
if (count < 100) return 'info';
if (count < 500) return 'warning';
if (count < 1000) return 'success';
return 'danger';
};
/** 自动保存草稿 */
const handleAutoSave = async () => {
if (!form.value.monthlyId || form.value.reviewStatus !== 3) return
if (!form.value.monthlyId || form.value.reviewStatus !== 3) return;
autoSaving.value = true
autoSaving.value = true;
try {
await autosaveInternshipMonthly(form.value)
proxy?.$message.success('草稿已自动保存')
await autosaveInternshipMonthly(form.value);
proxy?.$message.success('草稿已自动保存');
} catch (error) {
console.error('自动保存失败:', error)
console.error('自动保存失败:', error);
} finally {
autoSaving.value = false
autoSaving.value = false;
}
}
};
/** 提交表单 */
const handleSubmit = async (type: 'draft' | 'submit') => {
if (!monthlyFormRef.value) return
if (!monthlyFormRef.value) return;
const valid = await monthlyFormRef.value.validate().catch(() => false)
if (!valid) return
const valid = await monthlyFormRef.value.validate().catch(() => false);
if (!valid) return;
submitting.value = true
submitting.value = true;
try {
updateWordCount()
updateWordCount();
const formData = {
...form.value,
reviewStatus: type === 'draft' ? 3 : 0, // 草稿=3,待审核=0
submitTime: type === 'submit' ? new Date() : undefined
}
};
if (form.value.monthlyId) {
await updateInternshipMonthly(formData)
await updateInternshipMonthly(formData);
} else {
await addInternshipMonthly(formData)
await addInternshipMonthly(formData);
}
proxy?.$modal.msgSuccess(type === 'draft' ? '保存成功' : '提交成功')
emit('success')
proxy?.$modal.msgSuccess(type === 'draft' ? '保存成功' : '提交成功');
emit('success');
} catch (error) {
console.error('提交失败:', error)
console.error('提交失败:', error);
} finally {
submitting.value = false
submitting.value = false;
}
}
};
/** 取消操作 */
const handleCancel = () => {
emit('success')
}
emit('success');
};
// 清理定时器
onUnmounted(() => {
if (autoSaveTimer) {
clearTimeout(autoSaveTimer)
clearTimeout(autoSaveTimer);
}
})
});
defineExpose({
resetForm
})
});
</script>
<style scoped>
+97 -129
View File
@@ -31,13 +31,7 @@
</el-col>
<el-col :span="6">
<el-form-item label="专业技能" prop="professionalSkills">
<el-input-number
v-model="queryParams.professionalSkills"
:min="1"
:max="10"
placeholder="请输入专业技能评分"
style="width: 100%"
/>
<el-input-number v-model="queryParams.professionalSkills" :min="1" :max="10" placeholder="请输入专业技能评分" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
@@ -60,10 +54,14 @@
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:internshipmonthly:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['zsjy:internshipmonthly:edit']">修改</el-button>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['zsjy:internshipmonthly:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['zsjy:internshipmonthly:remove']">删除</el-button>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['zsjy:internshipmonthly:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internshipmonthly:export']">导出</el-button>
@@ -80,20 +78,16 @@
<el-table-column label="综合评分" align="center" width="120">
<template #default="scope">
<el-tooltip content="专业/沟通/团队/学习/态度" placement="top">
<el-tag :type="getScoreTagType(getAverageScore(scope.row))">
{{ getAverageScore(scope.row).toFixed(1) }}分
</el-tag>
<el-tag :type="getScoreTagType(getAverageScore(scope.row))"> {{ getAverageScore(scope.row).toFixed(1) }}分 </el-tag>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="字数统计" align="center" width="100">
<template #default="scope">
{{ scope.row.wordCount || 0 }}字
</template>
<template #default="scope"> {{ scope.row.wordCount || 0 }}字 </template>
</el-table-column>
<el-table-column label="审核状态" align="center" prop="reviewStatus" width="100">
<template #default="scope">
<dict-tag :options="internship_monthly_status" :value="scope.row.reviewStatus" />
<dict-tag :options="internship_monthly_status" :value="scope.row.reviewStatus" />
</template>
</el-table-column>
<el-table-column label="是否逾期" align="center" prop="isOverdue" width="100">
@@ -116,59 +110,29 @@
<template #default="scope">
<!-- 查看详情 -->
<el-tooltip content="查看详情" placement="top">
<el-button
link
type="primary"
icon="View"
@click="handleDetail(scope.row)"
v-hasPermi="['zsjy:internshipmonthly:list']"
></el-button>
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['zsjy:internshipmonthly:list']"></el-button>
</el-tooltip>
<!-- 编辑(只有草稿状态才能编辑) -->
<el-tooltip content="编辑" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['zsjy:internshipmonthly:edit']"
></el-button>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['zsjy:internshipmonthly:edit']"></el-button>
</el-tooltip>
<!-- 提交(只有草稿状态才能提交) -->
<el-tooltip content="提交" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button
link
type="success"
icon="Check"
@click="handleSubmit(scope.row)"
v-hasPermi="['zsjy:internshipmonthly:submit']"
></el-button>
<el-button link type="success" icon="Check" @click="handleSubmit(scope.row)" v-hasPermi="['zsjy:internshipmonthly:submit']"></el-button>
</el-tooltip>
<!-- 删除(只有草稿状态才能删除) -->
<el-tooltip content="删除" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button
link
type="danger"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['zsjy:internshipmonthly:remove']"
></el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['zsjy:internshipmonthly:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改月度总结对话框 -->
@@ -190,30 +154,30 @@ import {
delInternshipMonthly,
submitInternshipMonthly,
exportInternshipMonthly
} from '@/api/zsjy/internshipMonthly'
import MonthlyForm from './form.vue'
import MonthlyDetail from './detail.vue'
} from '@/api/zsjy/internshipMonthly';
import MonthlyForm from './form.vue';
import MonthlyDetail from './detail.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'))
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'));
const monthlyList = ref<any[]>([])
const loading = ref(true)
const showSearch = ref(true)
const ids = ref<Array<string | number>>([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const monthlyList = ref<any[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
})
});
const detailDialog = reactive<DialogOption>({
visible: false,
title: ''
})
});
const initFormData: any = {
pageNum: 1,
@@ -221,101 +185,105 @@ const initFormData: any = {
summaryMonth: undefined,
reviewStatus: undefined,
professionalSkills: undefined
}
};
const data = reactive<PageData<any, any>>({
form: {},
queryParams: { ...initFormData },
rules: {}
})
});
const { queryParams, form, rules } = toRefs(data)
const { queryParams, form, rules } = toRefs(data);
const queryFormRef = ref<ElFormInstance>()
const monthlyFormRef = ref<ComponentRef<typeof MonthlyForm>>()
const monthlyDetailRef = ref<ComponentRef<typeof MonthlyDetail>>()
const queryFormRef = ref<ElFormInstance>();
const monthlyFormRef = ref<ComponentRef<typeof MonthlyForm>>();
const monthlyDetailRef = ref<ComponentRef<typeof MonthlyDetail>>();
/** 查询月度总结列表 */
const getList = async () => {
loading.value = true
const res = await listInternshipMonthly(queryParams.value)
monthlyList.value = res.rows
total.value = res.total
loading.value = false
}
loading.value = true;
const res = await listInternshipMonthly(queryParams.value);
monthlyList.value = res.rows;
total.value = res.total;
loading.value = false;
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1
getList()
}
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields()
handleQuery()
}
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: any) => {
ids.value = selection.map((item: any) => item.monthlyId)
single.value = selection.length !== 1
multiple.value = !selection.length
}
ids.value = selection.map((item: any) => item.monthlyId);
single.value = selection.length !== 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
dialog.visible = true
dialog.title = '添加月度总结'
dialog.visible = true;
dialog.title = '添加月度总结';
nextTick(() => {
monthlyFormRef.value?.resetForm()
})
}
monthlyFormRef.value?.resetForm();
});
};
/** 修改按钮操作 */
const handleUpdate = async (row?: any) => {
dialog.visible = true
dialog.title = '修改月度总结'
dialog.visible = true;
dialog.title = '修改月度总结';
nextTick(() => {
const monthlyId = row?.monthlyId || ids.value[0]
monthlyFormRef.value?.resetForm(monthlyId)
})
}
const monthlyId = row?.monthlyId || ids.value[0];
monthlyFormRef.value?.resetForm(monthlyId);
});
};
/** 查看详情操作 */
const handleDetail = async (row: any) => {
detailDialog.visible = true
detailDialog.visible = true;
nextTick(() => {
monthlyDetailRef.value?.resetForm(row.monthlyId)
})
}
monthlyDetailRef.value?.resetForm(row.monthlyId);
});
};
/** 提交审批操作 */
const handleSubmit = async (row: any) => {
try {
await proxy?.$modal.confirm('确认提交该月度总结?提交后将无法再次编辑')
await submitInternshipMonthly(row.monthlyId)
await getList()
proxy?.$modal.msgSuccess('提交成功')
await proxy?.$modal.confirm('确认提交该月度总结?提交后将无法再次编辑');
await submitInternshipMonthly(row.monthlyId);
await getList();
proxy?.$modal.msgSuccess('提交成功');
} catch {}
}
};
/** 删除按钮操作 */
const handleDelete = async (row?: any) => {
const monthlyIds = row?.monthlyId || ids.value
const monthlyIds = row?.monthlyId || ids.value;
try {
await proxy?.$modal.confirm('是否确认删除月度总结编号为"' + monthlyIds + '"的数据项?')
await delInternshipMonthly(monthlyIds)
await getList()
proxy?.$modal.msgSuccess('删除成功')
await proxy?.$modal.confirm('是否确认删除月度总结编号为"' + monthlyIds + '"的数据项?');
await delInternshipMonthly(monthlyIds);
await getList();
proxy?.$modal.msgSuccess('删除成功');
} catch {}
}
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.$download('zsjy/internship/monthly/export', {
...queryParams.value
}, `月度总结_${new Date().getTime()}.xlsx`)
}
proxy?.$download(
'zsjy/internship/monthly/export',
{
...queryParams.value
},
`月度总结_${new Date().getTime()}.xlsx`
);
};
/** 计算五项技能的平均分 */
const getAverageScore = (row: any) => {
@@ -325,23 +293,23 @@ const getAverageScore = (row: any) => {
row.teamworkAbility || 0,
row.learningAbility || 0,
row.workAttitude || 0
].filter(score => score > 0)
if (scores.length === 0) return 0
return scores.reduce((sum, score) => sum + score, 0) / scores.length
}
].filter((score) => score > 0);
if (scores.length === 0) return 0;
return scores.reduce((sum, score) => sum + score, 0) / scores.length;
};
/** 根据分数获取标签类型 */
const getScoreTagType = (score: number) => {
if (score >= 9) return 'success'
if (score >= 7) return 'warning'
if (score >= 5) return ''
return 'danger'
}
if (score >= 9) return 'success';
if (score >= 7) return 'warning';
if (score >= 5) return '';
return 'danger';
};
onMounted(() => {
getList()
})
getList();
});
</script>
<style scoped>
+156 -219
View File
@@ -14,20 +14,10 @@
/>
</el-form-item>
<el-form-item label="学生姓名" prop="studentName">
<el-input
v-model="queryParams.studentName"
placeholder="请输入学生姓名"
clearable
style="width: 150px"
/>
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable style="width: 150px" />
</el-form-item>
<el-form-item label="学号" prop="studentNumber">
<el-input
v-model="queryParams.studentNumber"
placeholder="请输入学号"
clearable
style="width: 150px"
/>
<el-input v-model="queryParams.studentNumber" placeholder="请输入学号" clearable style="width: 150px" />
</el-form-item>
<el-form-item label="审核状态" prop="reviewStatus">
<el-select v-model="queryParams.reviewStatus" placeholder="请选择状态" clearable style="width: 150px">
@@ -84,34 +74,14 @@
<div class="table-header">
<div class="table-title">月度总结审核</div>
<div class="table-actions">
<el-button
type="success"
icon="Check"
:disabled="!selections.length"
@click="handleBatchApprove"
>
批量通过
</el-button>
<el-button
type="warning"
icon="Close"
:disabled="!selections.length"
@click="handleBatchReject"
>
批量拒绝
</el-button>
<el-button type="success" icon="Check" :disabled="!selections.length" @click="handleBatchApprove"> 批量通过 </el-button>
<el-button type="warning" icon="Close" :disabled="!selections.length" @click="handleBatchReject"> 批量拒绝 </el-button>
<el-button type="info" icon="Download" @click="handleExport">导出</el-button>
</div>
</div>
<!-- 数据表格 -->
<el-table
v-loading="loading"
:data="reviewList"
@selection-change="handleSelectionChange"
border
stripe
>
<el-table v-loading="loading" :data="reviewList" @selection-change="handleSelectionChange" border stripe>
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="学生信息" width="200" fixed="left">
<template #default="scope">
@@ -125,10 +95,7 @@
<el-table-column prop="monthNumber" label="第几个月" width="100" align="center" />
<el-table-column label="状态" width="100" align="center">
<template #default="scope">
<el-tag
:type="getStatusType(scope.row.reviewStatus)"
size="small"
>
<el-tag :type="getStatusType(scope.row.reviewStatus)" size="small">
{{ getStatusText(scope.row.reviewStatus) }}
</el-tag>
</template>
@@ -146,48 +113,19 @@
</el-table-column>
<el-table-column label="操作" width="200" align="center" fixed="right">
<template #default="scope">
<el-button type="primary" link size="small" @click="handleDetail(scope.row)">
查看详情
</el-button>
<el-button
v-if="scope.row.reviewStatus === 0"
type="success"
link
size="small"
@click="handleApprove(scope.row)"
>
审核
</el-button>
<el-button
v-if="scope.row.reviewStatus !== 0"
type="warning"
link
size="small"
@click="handleReReview(scope.row)"
>
重新审核
</el-button>
<el-button type="primary" link size="small" @click="handleDetail(scope.row)"> 查看详情 </el-button>
<el-button v-if="scope.row.reviewStatus === 0" type="success" link size="small" @click="handleApprove(scope.row)"> 审核 </el-button>
<el-button v-if="scope.row.reviewStatus !== 0" type="warning" link size="small" @click="handleReReview(scope.row)"> 重新审核 </el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 审核对话框 -->
<el-dialog
:title="reviewForm.monthlyId ? '审核月度总结' : '批量审核'"
v-model="reviewVisible"
width="600px"
:close-on-click-modal="false"
>
<el-dialog :title="reviewForm.monthlyId ? '审核月度总结' : '批量审核'" v-model="reviewVisible" width="600px" :close-on-click-modal="false">
<el-form :model="reviewForm" :rules="reviewRules" ref="reviewFormRef" label-width="100px">
<el-form-item label="审核结果" prop="reviewStatus">
<el-radio-group v-model="reviewForm.reviewStatus">
@@ -202,25 +140,11 @@
</el-radio-group>
</el-form-item>
<el-form-item label="评分" prop="reviewScore">
<el-input-number
v-model="reviewForm.reviewScore"
:min="0"
:max="100"
:precision="1"
placeholder="请输入评分(0-100)"
style="width: 200px"
/>
<el-input-number v-model="reviewForm.reviewScore" :min="0" :max="100" :precision="1" placeholder="请输入评分(0-100)" style="width: 200px" />
<span class="ml-2 text-gray-500">分</span>
</el-form-item>
<el-form-item label="审核意见" prop="reviewComment">
<el-input
v-model="reviewForm.reviewComment"
type="textarea"
:rows="4"
placeholder="请输入审核意见"
maxlength="500"
show-word-limit
/>
<el-input v-model="reviewForm.reviewComment" type="textarea" :rows="4" placeholder="请输入审核意见" maxlength="500" show-word-limit />
</el-form-item>
<el-form-item label="改进建议" prop="reviewSuggestions">
<el-input
@@ -240,19 +164,14 @@
</el-dialog>
<!-- 详情对话框 -->
<monthly-detail
v-if="detailVisible"
:monthly-id="currentMonthlyId"
:visible="detailVisible"
@close="detailVisible = false"
/>
<monthly-detail v-if="detailVisible" :monthly-id="currentMonthlyId" :visible="detailVisible" @close="detailVisible = false" />
</div>
</template>
<script setup lang="ts" name="MonthlyReview">
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Check, Close, Search, Refresh, Download } from '@element-plus/icons-vue'
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Check, Close, Search, Refresh, Download } from '@element-plus/icons-vue';
import {
getPendingReviewList,
getReviewList,
@@ -264,18 +183,18 @@ import {
type MonthlyReviewParams,
type BatchReviewParams,
type ReviewStatistics
} from '@/api/zsjy/internshipMonthlyReview'
import MonthlyDetail from './detail.vue'
} from '@/api/zsjy/internshipMonthlyReview';
import MonthlyDetail from './detail.vue';
// 响应式数据
const loading = ref(false)
const reviewLoading = ref(false)
const reviewVisible = ref(false)
const detailVisible = ref(false)
const currentMonthlyId = ref<number | null>(null)
const selections = ref<any[]>([])
const total = ref(0)
const reviewList = ref<any[]>([])
const loading = ref(false);
const reviewLoading = ref(false);
const reviewVisible = ref(false);
const detailVisible = ref(false);
const currentMonthlyId = ref<number | null>(null);
const selections = ref<any[]>([]);
const total = ref(0);
const reviewList = ref<any[]>([]);
// 查询参数
const queryParams = reactive<MonthlyReviewQueryParams & { pageNum: number; pageSize: number }>({
@@ -285,7 +204,7 @@ const queryParams = reactive<MonthlyReviewQueryParams & { pageNum: number; pageS
studentName: '',
studentNumber: '',
reviewStatus: undefined
})
});
// 统计数据
const statistics = ref<ReviewStatistics>({
@@ -295,7 +214,7 @@ const statistics = ref<ReviewStatistics>({
rejectedCount: 0,
averageScore: 0,
completionRate: 0
})
});
// 审核表单
const reviewForm = reactive<MonthlyReviewParams & { isBatch?: boolean; monthlyIds?: number[] }>({
@@ -306,143 +225,143 @@ const reviewForm = reactive<MonthlyReviewParams & { isBatch?: boolean; monthlyId
reviewSuggestions: '',
isBatch: false,
monthlyIds: []
})
});
// 表单校验规则
const reviewRules = {
reviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
reviewComment: [{ required: true, message: '请输入审核意见', trigger: 'blur' }]
}
};
// ref引用
const queryFormRef = ref()
const reviewFormRef = ref()
const queryFormRef = ref();
const reviewFormRef = ref();
// 获取列表数据
const getList = async () => {
loading.value = true
loading.value = true;
try {
const response = await getReviewList(queryParams)
reviewList.value = response.rows
total.value = response.total
const response = await getReviewList(queryParams);
reviewList.value = response.rows;
total.value = response.total;
} catch (error) {
console.error('获取审核列表失败:', error)
console.error('获取审核列表失败:', error);
} finally {
loading.value = false
loading.value = false;
}
}
};
// 获取统计数据
const getStatistics = async () => {
try {
const response = await getReviewStatistics(queryParams)
statistics.value = response.data
const response = await getReviewStatistics(queryParams);
statistics.value = response.data;
} catch (error) {
console.error('获取统计数据失败:', error)
console.error('获取统计数据失败:', error);
}
}
};
// 搜索
const handleQuery = () => {
queryParams.pageNum = 1
getList()
getStatistics()
}
queryParams.pageNum = 1;
getList();
getStatistics();
};
// 重置搜索
const resetQuery = () => {
queryFormRef.value?.resetFields()
queryParams.pageNum = 1
getList()
getStatistics()
}
queryFormRef.value?.resetFields();
queryParams.pageNum = 1;
getList();
getStatistics();
};
// 选择变化
const handleSelectionChange = (selection: any[]) => {
selections.value = selection
}
selections.value = selection;
};
// 查看详情
const handleDetail = (row: any) => {
currentMonthlyId.value = row.monthlyId
detailVisible.value = true
}
currentMonthlyId.value = row.monthlyId;
detailVisible.value = true;
};
// 单个审核
const handleApprove = (row: any) => {
reviewForm.monthlyId = row.monthlyId
reviewForm.isBatch = false
reviewForm.reviewStatus = 1
reviewForm.reviewScore = undefined
reviewForm.reviewComment = ''
reviewForm.reviewSuggestions = ''
reviewVisible.value = true
}
reviewForm.monthlyId = row.monthlyId;
reviewForm.isBatch = false;
reviewForm.reviewStatus = 1;
reviewForm.reviewScore = undefined;
reviewForm.reviewComment = '';
reviewForm.reviewSuggestions = '';
reviewVisible.value = true;
};
// 重新审核
const handleReReview = (row: any) => {
reviewForm.monthlyId = row.monthlyId
reviewForm.isBatch = false
reviewForm.reviewStatus = row.reviewStatus
reviewForm.reviewScore = row.reviewScore
reviewForm.reviewComment = row.reviewComment || ''
reviewForm.reviewSuggestions = row.reviewSuggestions || ''
reviewVisible.value = true
}
reviewForm.monthlyId = row.monthlyId;
reviewForm.isBatch = false;
reviewForm.reviewStatus = row.reviewStatus;
reviewForm.reviewScore = row.reviewScore;
reviewForm.reviewComment = row.reviewComment || '';
reviewForm.reviewSuggestions = row.reviewSuggestions || '';
reviewVisible.value = true;
};
// 批量通过
const handleBatchApprove = () => {
const pendingItems = selections.value.filter(item => item.reviewStatus === 0)
const pendingItems = selections.value.filter((item) => item.reviewStatus === 0);
if (pendingItems.length === 0) {
ElMessage.warning('请选择待审核的记录')
return
ElMessage.warning('请选择待审核的记录');
return;
}
reviewForm.isBatch = true
reviewForm.reviewStatus = 1
reviewForm.reviewScore = 85 // 默认分数
reviewForm.reviewComment = ''
reviewForm.reviewSuggestions = ''
reviewForm.monthlyIds = pendingItems.map(item => item.monthlyId)
reviewVisible.value = true
}
reviewForm.isBatch = true;
reviewForm.reviewStatus = 1;
reviewForm.reviewScore = 85; // 默认分数
reviewForm.reviewComment = '';
reviewForm.reviewSuggestions = '';
reviewForm.monthlyIds = pendingItems.map((item) => item.monthlyId);
reviewVisible.value = true;
};
// 批量拒绝
const handleBatchReject = () => {
const pendingItems = selections.value.filter(item => item.reviewStatus === 0)
const pendingItems = selections.value.filter((item) => item.reviewStatus === 0);
if (pendingItems.length === 0) {
ElMessage.warning('请选择待审核的记录')
return
ElMessage.warning('请选择待审核的记录');
return;
}
reviewForm.isBatch = true
reviewForm.reviewStatus = 2
reviewForm.reviewScore = undefined
reviewForm.reviewComment = ''
reviewForm.reviewSuggestions = ''
reviewForm.monthlyIds = pendingItems.map(item => item.monthlyId)
reviewVisible.value = true
}
reviewForm.isBatch = true;
reviewForm.reviewStatus = 2;
reviewForm.reviewScore = undefined;
reviewForm.reviewComment = '';
reviewForm.reviewSuggestions = '';
reviewForm.monthlyIds = pendingItems.map((item) => item.monthlyId);
reviewVisible.value = true;
};
// 提交审核
const submitReview = async () => {
try {
await reviewFormRef.value?.validate()
reviewLoading.value = true
await reviewFormRef.value?.validate();
reviewLoading.value = true;
if (reviewForm.isBatch) {
// 批量审核
const batchData: BatchReviewParams = {
reviewItems: reviewForm.monthlyIds!.map(monthlyId => ({
reviewItems: reviewForm.monthlyIds!.map((monthlyId) => ({
monthlyId,
reviewStatus: reviewForm.reviewStatus,
reviewScore: reviewForm.reviewScore,
reviewComment: reviewForm.reviewComment,
reviewSuggestions: reviewForm.reviewSuggestions
}))
}
await batchApproveMonthly(batchData)
ElMessage.success('批量审核成功')
};
await batchApproveMonthly(batchData);
ElMessage.success('批量审核成功');
} else {
// 单个审核
await approveMonthly({
@@ -451,29 +370,29 @@ const submitReview = async () => {
reviewScore: reviewForm.reviewScore,
reviewComment: reviewForm.reviewComment,
reviewSuggestions: reviewForm.reviewSuggestions
})
ElMessage.success('审核成功')
});
ElMessage.success('审核成功');
}
reviewVisible.value = false
getList()
getStatistics()
reviewVisible.value = false;
getList();
getStatistics();
} catch (error) {
console.error('审核失败:', error)
console.error('审核失败:', error);
} finally {
reviewLoading.value = false
reviewLoading.value = false;
}
}
};
// 导出数据
const handleExport = async () => {
try {
await exportReviewData(queryParams)
ElMessage.success('导出成功')
await exportReviewData(queryParams);
ElMessage.success('导出成功');
} catch (error) {
console.error('导出失败:', error)
console.error('导出失败:', error);
}
}
};
// 获取状态类型
const getStatusType = (status: number) => {
@@ -481,9 +400,9 @@ const getStatusType = (status: number) => {
0: 'warning',
1: 'success',
2: 'danger'
}
return statusMap[status] || 'info'
}
};
return statusMap[status] || 'info';
};
// 获取状态文本
const getStatusText = (status: number) => {
@@ -491,15 +410,15 @@ const getStatusText = (status: number) => {
0: '待审核',
1: '已审核',
2: '审核拒绝'
}
return statusMap[status] || '未知'
}
};
return statusMap[status] || '未知';
};
// 组件挂载
onMounted(() => {
getList()
getStatistics()
})
getList();
getStatistics();
});
</script>
<style scoped lang="scss">
@@ -527,20 +446,38 @@ onMounted(() => {
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.table-title {
font-size: 16px;
font-weight: bold;
}
}
.text-primary { color: #409eff; }
.text-success { color: #67c23a; }
.text-warning { color: #e6a23c; }
.text-danger { color: #f56c6c; }
.text-gray-500 { color: #9ca3af; }
.font-bold { font-weight: bold; }
.text-sm { font-size: 12px; }
.mb-4 { margin-bottom: 16px; }
.ml-2 { margin-left: 8px; }
</style>
.text-primary {
color: #409eff;
}
.text-success {
color: #67c23a;
}
.text-warning {
color: #e6a23c;
}
.text-danger {
color: #f56c6c;
}
.text-gray-500 {
color: #9ca3af;
}
.font-bold {
font-weight: bold;
}
.text-sm {
font-size: 12px;
}
.mb-4 {
margin-bottom: 16px;
}
.ml-2 {
margin-left: 8px;
}
</style>
@@ -22,26 +22,13 @@
</el-col>
<el-col :span="12">
<el-form-item label="统一评分">
<el-input-number
v-model="batchForm.reviewScore"
:min="0"
:max="100"
:step="5"
style="width: 100%"
/>
<el-input-number v-model="batchForm.reviewScore" :min="0" :max="100" :step="5" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="统一审核意见">
<el-input
v-model="batchForm.reviewComment"
type="textarea"
:rows="3"
placeholder="输入统一的审核意见"
maxlength="500"
show-word-limit
/>
<el-input v-model="batchForm.reviewComment" type="textarea" :rows="3" placeholder="输入统一的审核意见" maxlength="500" show-word-limit />
</el-form-item>
<el-form-item label="统一改进建议">
@@ -100,13 +87,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="审核评分" :prop="`reviewItems.${index}.reviewScore`">
<el-input-number
v-model="item.reviewScore"
:min="0"
:max="100"
:step="5"
style="width: 100%"
/>
<el-input-number v-model="item.reviewScore" :min="0" :max="100" :step="5" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
@@ -119,25 +100,11 @@
</el-row>
<el-form-item label="审核意见" :prop="`reviewItems.${index}.reviewComment`" required>
<el-input
v-model="item.reviewComment"
type="textarea"
:rows="2"
placeholder="请输入审核意见"
maxlength="500"
show-word-limit
/>
<el-input v-model="item.reviewComment" type="textarea" :rows="2" placeholder="请输入审核意见" maxlength="500" show-word-limit />
</el-form-item>
<el-form-item label="改进建议" :prop="`reviewItems.${index}.reviewSuggestions`">
<el-input
v-model="item.reviewSuggestions"
type="textarea"
:rows="2"
placeholder="请输入改进建议"
maxlength="300"
show-word-limit
/>
<el-input v-model="item.reviewSuggestions" type="textarea" :rows="2" placeholder="请输入改进建议" maxlength="300" show-word-limit />
</el-form-item>
<!-- 快速操作 -->
@@ -167,25 +134,21 @@
</template>
<script setup lang="ts">
import { ref, reactive, defineProps, defineEmits } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
SuccessFilled,
CircleCloseFilled,
Check
} from '@element-plus/icons-vue'
import { batchReviewInternshipMonthly } from '@/api/zsjy/internshipMonthlyReview'
import { ref, reactive, defineProps, defineEmits } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { SuccessFilled, CircleCloseFilled, Check } from '@element-plus/icons-vue';
import { batchReviewInternshipMonthly } from '@/api/zsjy/internshipMonthlyReview';
interface Props {
selectedRows: any[]
selectedRows: any[];
}
const props = defineProps<Props>()
const emit = defineEmits(['refresh'])
const props = defineProps<Props>();
const emit = defineEmits(['refresh']);
// 状态管理
const submitting = ref(false)
const showBatchSetting = ref(true)
const submitting = ref(false);
const showBatchSetting = ref(true);
// 批量设置表单
const batchForm = reactive({
@@ -193,36 +156,38 @@ const batchForm = reactive({
reviewScore: 85,
reviewComment: '',
reviewSuggestions: ''
})
});
// 审核项目列表
const reviewItems = ref(props.selectedRows.map(row => ({
monthlyId: row.monthlyId,
studentName: row.studentName,
studentNumber: row.studentNumber,
summaryMonth: row.summaryMonth,
className: row.className,
reviewStatus: 1,
reviewScore: 85,
reviewComment: '',
reviewSuggestions: ''
})))
const reviewItems = ref(
props.selectedRows.map((row) => ({
monthlyId: row.monthlyId,
studentName: row.studentName,
studentNumber: row.studentNumber,
summaryMonth: row.summaryMonth,
className: row.className,
reviewStatus: 1,
reviewScore: 85,
reviewComment: '',
reviewSuggestions: ''
}))
);
/** 获取分数等级 */
function getScoreLevel(score: number) {
if (score >= 90) return '优秀'
if (score >= 80) return '良好'
if (score >= 70) return '中等'
if (score >= 60) return '及格'
return '不及格'
if (score >= 90) return '优秀';
if (score >= 80) return '良好';
if (score >= 70) return '中等';
if (score >= 60) return '及格';
return '不及格';
}
/** 获取分数标签类型 */
function getScoreTagType(score: number) {
if (score >= 90) return 'success'
if (score >= 80) return 'warning'
if (score >= 70) return 'primary'
return 'danger'
if (score >= 90) return 'success';
if (score >= 80) return 'warning';
if (score >= 70) return 'primary';
return 'danger';
}
/** 应用批量设置 */
@@ -232,60 +197,60 @@ function applyBatchSettings() {
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
reviewItems.value.forEach(item => {
reviewItems.value.forEach((item) => {
if (batchForm.reviewStatus) {
item.reviewStatus = batchForm.reviewStatus
item.reviewStatus = batchForm.reviewStatus;
}
if (batchForm.reviewScore !== null) {
item.reviewScore = batchForm.reviewScore
item.reviewScore = batchForm.reviewScore;
}
if (batchForm.reviewComment) {
item.reviewComment = batchForm.reviewComment
item.reviewComment = batchForm.reviewComment;
}
if (batchForm.reviewSuggestions) {
item.reviewSuggestions = batchForm.reviewSuggestions
item.reviewSuggestions = batchForm.reviewSuggestions;
}
})
ElMessage.success('批量设置已应用')
})
});
ElMessage.success('批量设置已应用');
});
}
/** 清空批量设置 */
function clearBatchSettings() {
batchForm.reviewStatus = 1
batchForm.reviewScore = 85
batchForm.reviewComment = ''
batchForm.reviewSuggestions = ''
batchForm.reviewStatus = 1;
batchForm.reviewScore = 85;
batchForm.reviewComment = '';
batchForm.reviewSuggestions = '';
}
/** 快速设置审核结果 */
function setQuickReview(index: number, status: number, score: number, comment: string) {
const item = reviewItems.value[index]
item.reviewStatus = status
item.reviewScore = score
item.reviewComment = comment
const item = reviewItems.value[index];
item.reviewStatus = status;
item.reviewScore = score;
item.reviewComment = comment;
}
/** 验证表单 */
function validateForm() {
for (let i = 0; i < reviewItems.value.length; i++) {
const item = reviewItems.value[i]
const item = reviewItems.value[i];
if (!item.reviewStatus) {
ElMessage.error(`请为 ${item.studentName} 选择审核结果`)
return false
ElMessage.error(`请为 ${item.studentName} 选择审核结果`);
return false;
}
if (!item.reviewComment || item.reviewComment.trim().length < 10) {
ElMessage.error(`请为 ${item.studentName} 输入审核意见(至少10个字符)`)
return false
ElMessage.error(`请为 ${item.studentName} 输入审核意见(至少10个字符)`);
return false;
}
}
return true
return true;
}
/** 提交批量审核 */
function submitBatchReview() {
if (!validateForm()) {
return
return;
}
ElMessageBox.confirm(`确认批量审核 ${reviewItems.value.length} 条记录?`, '确认批量审核', {
@@ -293,32 +258,35 @@ function submitBatchReview() {
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
submitting.value = true
submitting.value = true;
const reviewData = {
reviewItems: reviewItems.value.map(item => ({
reviewItems: reviewItems.value.map((item) => ({
monthlyId: item.monthlyId,
reviewStatus: item.reviewStatus,
reviewScore: item.reviewScore,
reviewComment: item.reviewComment,
reviewSuggestions: item.reviewSuggestions
}))
}
};
batchReviewInternshipMonthly(reviewData).then(() => {
ElMessage.success('批量审核完成')
emit('refresh')
}).catch(() => {
ElMessage.error('批量审核失败')
}).finally(() => {
submitting.value = false
})
})
batchReviewInternshipMonthly(reviewData)
.then(() => {
ElMessage.success('批量审核完成');
emit('refresh');
})
.catch(() => {
ElMessage.error('批量审核失败');
})
.finally(() => {
submitting.value = false;
});
});
}
/** 取消操作 */
function handleCancel() {
emit('refresh')
emit('refresh');
}
</script>
@@ -67,69 +67,42 @@
<el-col :span="12">
<div class="score-item">
<span class="score-label">专业技能:</span>
<el-rate
:model-value="monthlyData.professionalSkills"
disabled
show-score
text-color="#ff9900"
/>
<el-rate :model-value="monthlyData.professionalSkills" disabled show-score text-color="#ff9900" />
<span class="score-value">{{ monthlyData.professionalSkills || 0 }}分</span>
</div>
</el-col>
<el-col :span="12">
<div class="score-item">
<span class="score-label">沟通能力:</span>
<el-rate
:model-value="monthlyData.communicationSkills"
disabled
show-score
text-color="#ff9900"
/>
<el-rate :model-value="monthlyData.communicationSkills" disabled show-score text-color="#ff9900" />
<span class="score-value">{{ monthlyData.communicationSkills || 0 }}分</span>
</div>
</el-col>
<el-col :span="12">
<div class="score-item">
<span class="score-label">团队协作:</span>
<el-rate
:model-value="monthlyData.teamworkAbility"
disabled
show-score
text-color="#ff9900"
/>
<el-rate :model-value="monthlyData.teamworkAbility" disabled show-score text-color="#ff9900" />
<span class="score-value">{{ monthlyData.teamworkAbility || 0 }}分</span>
</div>
</el-col>
<el-col :span="12">
<div class="score-item">
<span class="score-label">学习能力:</span>
<el-rate
:model-value="monthlyData.learningAbility"
disabled
show-score
text-color="#ff9900"
/>
<el-rate :model-value="monthlyData.learningAbility" disabled show-score text-color="#ff9900" />
<span class="score-value">{{ monthlyData.learningAbility || 0 }}分</span>
</div>
</el-col>
<el-col :span="12">
<div class="score-item">
<span class="score-label">工作态度:</span>
<el-rate
:model-value="monthlyData.workAttitude"
disabled
show-score
text-color="#ff9900"
/>
<el-rate :model-value="monthlyData.workAttitude" disabled show-score text-color="#ff9900" />
<span class="score-value">{{ monthlyData.workAttitude || 0 }}分</span>
</div>
</el-col>
<el-col :span="12">
<div class="score-item">
<span class="score-label">综合评分:</span>
<el-tag :type="getScoreTagType(getAverageScore())" size="large">
{{ getAverageScore().toFixed(1) }}分
</el-tag>
<el-tag :type="getScoreTagType(getAverageScore())" size="large"> {{ getAverageScore().toFixed(1) }}分 </el-tag>
</div>
</el-col>
</el-row>
@@ -147,8 +120,10 @@
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="审核评分">
<el-tag v-if="monthlyData.reviewScore !== null && monthlyData.reviewScore !== undefined"
:type="getReviewScoreTagType(monthlyData.reviewScore)">
<el-tag
v-if="monthlyData.reviewScore !== null && monthlyData.reviewScore !== undefined"
:type="getReviewScoreTagType(monthlyData.reviewScore)"
>
{{ monthlyData.reviewScore }}分
</el-tag>
<span v-else class="text-gray-400">未评分</span>
@@ -178,14 +153,14 @@
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue'
import { defineProps, defineEmits } from 'vue';
interface Props {
monthlyData: any
monthlyData: any;
}
const props = defineProps<Props>()
const emit = defineEmits(['refresh', 'review'])
const props = defineProps<Props>();
const emit = defineEmits(['refresh', 'review']);
/** 获取平均分 */
function getAverageScore() {
@@ -195,50 +170,58 @@ function getAverageScore() {
props.monthlyData.teamworkAbility || 0,
props.monthlyData.learningAbility || 0,
props.monthlyData.workAttitude || 0
]
const total = scores.reduce((sum, score) => sum + score, 0)
return total / scores.length
];
const total = scores.reduce((sum, score) => sum + score, 0);
return total / scores.length;
}
/** 获取评分标签类型 */
function getScoreTagType(score: number) {
if (score >= 9) return 'success'
if (score >= 8) return 'warning'
if (score >= 7) return 'primary'
return 'danger'
if (score >= 9) return 'success';
if (score >= 8) return 'warning';
if (score >= 7) return 'primary';
return 'danger';
}
/** 获取审核状态文本 */
function getReviewStatusText(status: number) {
switch (status) {
case 0: return '待审核'
case 1: return '已通过'
case 2: return '已拒绝'
default: return '未知'
case 0:
return '待审核';
case 1:
return '已通过';
case 2:
return '已拒绝';
default:
return '未知';
}
}
/** 获取审核状态标签类型 */
function getReviewStatusTagType(status: number) {
switch (status) {
case 0: return 'warning'
case 1: return 'success'
case 2: return 'danger'
default: return 'info'
case 0:
return 'warning';
case 1:
return 'success';
case 2:
return 'danger';
default:
return 'info';
}
}
/** 获取审核评分标签类型 */
function getReviewScoreTagType(score: number) {
if (score >= 90) return 'success'
if (score >= 80) return 'warning'
if (score >= 70) return 'primary'
return 'danger'
if (score >= 90) return 'success';
if (score >= 80) return 'warning';
if (score >= 70) return 'primary';
return 'danger';
}
/** 审核按钮点击 */
function handleReview() {
emit('review', props.monthlyData)
emit('review', props.monthlyData);
}
</script>
@@ -145,27 +145,20 @@
</template>
<script setup lang="ts">
import { ref, reactive, defineProps, defineEmits } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
SuccessFilled,
CircleCloseFilled,
InfoFilled,
Check,
Refresh,
View
} from '@element-plus/icons-vue'
import { reviewInternshipMonthly } from '@/api/zsjy/internshipMonthlyReview'
import { ref, reactive, defineProps, defineEmits } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { SuccessFilled, CircleCloseFilled, InfoFilled, Check, Refresh, View } from '@element-plus/icons-vue';
import { reviewInternshipMonthly } from '@/api/zsjy/internshipMonthlyReview';
interface Props {
monthlyData: any
monthlyData: any;
}
const props = defineProps<Props>()
const emit = defineEmits(['refresh'])
const props = defineProps<Props>();
const emit = defineEmits(['refresh']);
// 表单引用
const reviewFormRef = ref()
const reviewFormRef = ref();
// 表单数据
const reviewForm = reactive({
@@ -174,13 +167,11 @@ const reviewForm = reactive({
reviewScore: 85, // 默认85分
reviewComment: '',
reviewSuggestions: ''
})
});
// 表单验证规则
const reviewRules = {
reviewStatus: [
{ required: true, message: '请选择审核结果', trigger: 'change' }
],
reviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
reviewScore: [
{ required: true, message: '请输入审核评分', trigger: 'blur' },
{ type: 'number', min: 0, max: 100, message: '评分范围为0-100分', trigger: 'blur' }
@@ -189,14 +180,12 @@ const reviewRules = {
{ required: true, message: '请输入审核意见', trigger: 'blur' },
{ min: 10, max: 500, message: '审核意见长度在10到500个字符', trigger: 'blur' }
],
reviewSuggestions: [
{ max: 300, message: '改进建议长度不能超过300个字符', trigger: 'blur' }
]
}
reviewSuggestions: [{ max: 300, message: '改进建议长度不能超过300个字符', trigger: 'blur' }]
};
// 状态管理
const submitting = ref(false)
const previewOpen = ref(false)
const submitting = ref(false);
const previewOpen = ref(false);
// 评语模板
const commentTemplates = [
@@ -220,86 +209,89 @@ const commentTemplates = [
label: '需改进',
content: '总结内容过于简单,缺乏具体的工作描述和深入的思考。请重新整理总结内容,确保内容的完整性和深度。'
}
]
];
/** 格式化滑块提示 */
function formatTooltip(value: number) {
return `${value}分`
return `${value}分`;
}
/** 获取分数等级 */
function getScoreLevel(score: number) {
if (score >= 90) return '优秀'
if (score >= 80) return '良好'
if (score >= 70) return '中等'
if (score >= 60) return '及格'
return '不及格'
if (score >= 90) return '优秀';
if (score >= 80) return '良好';
if (score >= 70) return '中等';
if (score >= 60) return '及格';
return '不及格';
}
/** 获取分数标签类型 */
function getScoreTagType(score: number) {
if (score >= 90) return 'success'
if (score >= 80) return 'warning'
if (score >= 70) return 'primary'
return 'danger'
if (score >= 90) return 'success';
if (score >= 80) return 'warning';
if (score >= 70) return 'primary';
return 'danger';
}
/** 插入评语模板 */
function insertTemplate(template: string) {
if (reviewForm.reviewComment) {
reviewForm.reviewComment += '\n\n' + template
reviewForm.reviewComment += '\n\n' + template;
} else {
reviewForm.reviewComment = template
reviewForm.reviewComment = template;
}
}
/** 重置表单 */
function resetForm() {
reviewFormRef.value?.resetFields()
reviewForm.reviewStatus = 1
reviewForm.reviewScore = 85
reviewForm.reviewComment = ''
reviewForm.reviewSuggestions = ''
reviewFormRef.value?.resetFields();
reviewForm.reviewStatus = 1;
reviewForm.reviewScore = 85;
reviewForm.reviewComment = '';
reviewForm.reviewSuggestions = '';
}
/** 预览审核 */
function previewReview() {
reviewFormRef.value?.validate((valid: boolean) => {
if (valid) {
previewOpen.value = true
previewOpen.value = true;
}
})
});
}
/** 提交审核 */
function submitReview() {
reviewFormRef.value?.validate((valid: boolean) => {
if (valid) {
const message = reviewForm.reviewStatus === 1 ? '确认通过此月度总结?' : '确认拒绝此月度总结?'
const message = reviewForm.reviewStatus === 1 ? '确认通过此月度总结?' : '确认拒绝此月度总结?';
ElMessageBox.confirm(message, '确认审核', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
confirmSubmit()
})
confirmSubmit();
});
}
})
});
}
/** 确认提交 */
function confirmSubmit() {
submitting.value = true
previewOpen.value = false
submitting.value = true;
previewOpen.value = false;
reviewInternshipMonthly(reviewForm).then(() => {
ElMessage.success('审核完成')
emit('refresh')
}).catch(() => {
ElMessage.error('审核失败')
}).finally(() => {
submitting.value = false
})
reviewInternshipMonthly(reviewForm)
.then(() => {
ElMessage.success('审核完成');
emit('refresh');
})
.catch(() => {
ElMessage.error('审核失败');
})
.finally(() => {
submitting.value = false;
});
}
</script>
@@ -138,7 +138,8 @@
:disabled="multiple"
@click="handleBatchReview"
v-hasPermi="['zsjy:internshipmonthly:review']"
>批量审核</el-button>
>批量审核</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@@ -165,16 +166,12 @@
<el-table-column label="自我评分" align="center" width="120">
<template #default="scope">
<el-tooltip content="专业/沟通/团队/学习/态度" placement="top">
<el-tag :type="getScoreTagType(getAverageScore(scope.row))">
{{ getAverageScore(scope.row).toFixed(1) }}分
</el-tag>
<el-tag :type="getScoreTagType(getAverageScore(scope.row))"> {{ getAverageScore(scope.row).toFixed(1) }}分 </el-tag>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="字数统计" align="center" width="100">
<template #default="scope">
{{ scope.row.wordCount || 0 }}字
</template>
<template #default="scope"> {{ scope.row.wordCount || 0 }}字 </template>
</el-table-column>
<el-table-column label="审核状态" align="center" prop="reviewStatus" width="100">
<template #default="scope">
@@ -186,9 +183,7 @@
<el-table-column label="审核评分" align="center" prop="reviewScore" width="100">
<template #default="scope">
<span v-if="scope.row.reviewScore !== null && scope.row.reviewScore !== undefined">
<el-tag :type="getReviewScoreTagType(scope.row.reviewScore)">
{{ scope.row.reviewScore }}分
</el-tag>
<el-tag :type="getReviewScoreTagType(scope.row.reviewScore)"> {{ scope.row.reviewScore }}分 </el-tag>
</span>
<span v-else class="text-gray-400">未评分</span>
</template>
@@ -205,19 +200,14 @@
icon="Check"
@click="handleReview(scope.row)"
v-hasPermi="['zsjy:internshipmonthly:review']"
>审核</el-button>
>审核</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 审核详情对话框 -->
@@ -238,25 +228,16 @@
</template>
<script setup name="InternshipMonthlyReview" lang="ts">
import { onMounted, reactive, ref, toRefs, getCurrentInstance } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
DocumentChecked,
Clock,
SuccessFilled,
CircleCloseFilled,
Search,
Refresh,
Check,
View
} from '@element-plus/icons-vue'
import { getReviewList, getReviewStatistics } from '@/api/zsjy/internshipMonthlyReview'
import type { InternshipMonthlyVO, InternshipMonthlyReviewStatisticsVO } from '@/api/zsjy/types'
import ReviewDetail from './components/ReviewDetail.vue'
import ReviewForm from './components/ReviewForm.vue'
import BatchReviewForm from './components/BatchReviewForm.vue'
import { onMounted, reactive, ref, toRefs, getCurrentInstance } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { DocumentChecked, Clock, SuccessFilled, CircleCloseFilled, Search, Refresh, Check, View } from '@element-plus/icons-vue';
import { getReviewList, getReviewStatistics } from '@/api/zsjy/internshipMonthlyReview';
import type { InternshipMonthlyVO, InternshipMonthlyReviewStatisticsVO } from '@/api/zsjy/types';
import ReviewDetail from './components/ReviewDetail.vue';
import ReviewForm from './components/ReviewForm.vue';
import BatchReviewForm from './components/BatchReviewForm.vue';
const { proxy } = getCurrentInstance() as any
const { proxy } = getCurrentInstance() as any;
// 数据状态
const data = reactive({
@@ -289,132 +270,123 @@ const data = reactive({
averageScore: 0,
completionRate: 0
}
})
});
const {
loading,
showSearch,
reviewList,
multipleSelection,
single,
multiple,
total,
queryParams,
daterangeCreateTime,
statistics
} = toRefs(data)
const { loading, showSearch, reviewList, multipleSelection, single, multiple, total, queryParams, daterangeCreateTime, statistics } = toRefs(data);
// 对话框状态
const detailOpen = ref(false)
const reviewOpen = ref(false)
const batchReviewOpen = ref(false)
const detailTitle = ref('')
const currentMonthlyData = ref({})
const detailOpen = ref(false);
const reviewOpen = ref(false);
const batchReviewOpen = ref(false);
const detailTitle = ref('');
const currentMonthlyData = ref({});
// 表单引用
const queryFormRef = ref()
const reviewDetailRef = ref()
const reviewFormRef = ref()
const batchReviewFormRef = ref()
const queryFormRef = ref();
const reviewDetailRef = ref();
const reviewFormRef = ref();
const batchReviewFormRef = ref();
/** 查询列表 */
function getList() {
data.loading = true
data.loading = true;
// 处理时间范围
if (data.daterangeCreateTime && data.daterangeCreateTime.length === 2) {
data.queryParams.startDate = data.daterangeCreateTime[0]
data.queryParams.endDate = data.daterangeCreateTime[1]
data.queryParams.startDate = data.daterangeCreateTime[0];
data.queryParams.endDate = data.daterangeCreateTime[1];
} else {
data.queryParams.startDate = undefined
data.queryParams.endDate = undefined
data.queryParams.startDate = undefined;
data.queryParams.endDate = undefined;
}
getReviewList(data.queryParams).then((response: any) => {
data.reviewList = response.rows
data.total = response.total
data.loading = false
}).catch(() => {
data.loading = false
})
getReviewList(data.queryParams)
.then((response: any) => {
data.reviewList = response.rows;
data.total = response.total;
data.loading = false;
})
.catch(() => {
data.loading = false;
});
}
/** 获取统计数据 */
function getStatistics() {
getReviewStatistics().then((response: any) => {
data.statistics = response.data
})
data.statistics = response.data;
});
}
/** 搜索按钮操作 */
function handleQuery() {
data.queryParams.pageNum = 1
getList()
data.queryParams.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
data.daterangeCreateTime = []
queryFormRef.value?.resetFields()
handleQuery()
data.daterangeCreateTime = [];
queryFormRef.value?.resetFields();
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection: any[]) {
data.multipleSelection = selection
data.single = selection.length !== 1
data.multiple = !selection.length
data.multipleSelection = selection;
data.single = selection.length !== 1;
data.multiple = !selection.length;
}
/** 查看详情 */
function handleDetail(row: any) {
currentMonthlyData.value = { ...row }
detailTitle.value = `${row.studentName}的月度总结详情`
detailOpen.value = true
currentMonthlyData.value = { ...row };
detailTitle.value = `${row.studentName}的月度总结详情`;
detailOpen.value = true;
}
/** 单个审核 */
function handleReview(row: any) {
currentMonthlyData.value = { ...row }
reviewOpen.value = true
currentMonthlyData.value = { ...row };
reviewOpen.value = true;
}
/** 批量审核 */
function handleBatchReview() {
if (data.multipleSelection.length === 0) {
ElMessage.warning('请选择要审核的数据')
return
ElMessage.warning('请选择要审核的数据');
return;
}
// 检查是否都是待审核状态
const pendingRows = data.multipleSelection.filter(row => row.reviewStatus === 0)
const pendingRows = data.multipleSelection.filter((row) => row.reviewStatus === 0);
if (pendingRows.length === 0) {
ElMessage.warning('选择的数据中没有待审核的记录')
return
ElMessage.warning('选择的数据中没有待审核的记录');
return;
}
if (pendingRows.length !== data.multipleSelection.length) {
ElMessage.warning('只能审核状态为"待审核"的记录,请重新选择')
return
ElMessage.warning('只能审核状态为"待审核"的记录,请重新选择');
return;
}
batchReviewOpen.value = true
batchReviewOpen.value = true;
}
/** 审核成功回调 */
function handleReviewSuccess() {
reviewOpen.value = false
getList()
getStatistics()
ElMessage.success('审核完成')
reviewOpen.value = false;
getList();
getStatistics();
ElMessage.success('审核完成');
}
/** 批量审核成功回调 */
function handleBatchReviewSuccess() {
batchReviewOpen.value = false
getList()
getStatistics()
ElMessage.success('批量审核完成')
batchReviewOpen.value = false;
getList();
getStatistics();
ElMessage.success('批量审核完成');
}
/** 获取平均分 */
@@ -425,51 +397,59 @@ function getAverageScore(row: any) {
row.teamworkSkills || 0,
row.learningAbility || 0,
row.workAttitude || 0
]
const total = scores.reduce((sum, score) => sum + score, 0)
return total / scores.length
];
const total = scores.reduce((sum, score) => sum + score, 0);
return total / scores.length;
}
/** 获取评分标签类型 */
function getScoreTagType(score: number) {
if (score >= 9) return 'success'
if (score >= 8) return 'warning'
if (score >= 7) return 'primary'
return 'danger'
if (score >= 9) return 'success';
if (score >= 8) return 'warning';
if (score >= 7) return 'primary';
return 'danger';
}
/** 获取审核状态文本 */
function getReviewStatusText(status: number) {
switch (status) {
case 0: return '待审核'
case 1: return '已通过'
case 2: return '已拒绝'
default: return '未知'
case 0:
return '待审核';
case 1:
return '已通过';
case 2:
return '已拒绝';
default:
return '未知';
}
}
/** 获取审核状态标签类型 */
function getReviewStatusTagType(status: number) {
switch (status) {
case 0: return 'warning'
case 1: return 'success'
case 2: return 'danger'
default: return 'info'
case 0:
return 'warning';
case 1:
return 'success';
case 2:
return 'danger';
default:
return 'info';
}
}
/** 获取审核评分标签类型 */
function getReviewScoreTagType(score: number) {
if (score >= 90) return 'success'
if (score >= 80) return 'warning'
if (score >= 70) return 'primary'
return 'danger'
if (score >= 90) return 'success';
if (score >= 80) return 'warning';
if (score >= 70) return 'primary';
return 'danger';
}
onMounted(() => {
getList()
getStatistics()
})
getList();
getStatistics();
});
</script>
<style scoped>
+65 -68
View File
@@ -68,12 +68,24 @@
</el-col>
<el-col :span="6">
<el-form-item label="实习单位" prop="companyName">
<el-input v-model="queryParams.companyName" placeholder="请输入实习单位名称" clearable style="width: 100%" @keyup.enter="handleQuery" />
<el-input
v-model="queryParams.companyName"
placeholder="请输入实习单位名称"
clearable
style="width: 100%"
@keyup.enter="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="走访人" prop="visitorName">
<el-input v-model="queryParams.visitorName" placeholder="请输入走访人姓名" clearable style="width: 100%" @keyup.enter="handleQuery" />
<el-input
v-model="queryParams.visitorName"
placeholder="请输入走访人姓名"
clearable
style="width: 100%"
@keyup.enter="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="6">
@@ -103,12 +115,10 @@
<el-col :span="12">
<div class="search-btn-container">
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<el-button type="info" plain icon="Search" @click="showSearch = !showSearch">
{{ showSearch ? '隐藏' : '显示' }}搜索
</el-button>
<el-button type="info" plain icon="Search" @click="showSearch = !showSearch"> {{ showSearch ? '隐藏' : '显示' }}搜索 </el-button>
</el-form-item>
</div>
</el-col>
@@ -126,9 +136,7 @@
<div class="button-group">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:internshipVisit:add']">新增走访</el-button>
<el-button type="success" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internshipVisit:export']">导出</el-button>
<el-button type="info" plain icon="Search" @click="showSearch = !showSearch">
{{ showSearch ? '隐藏' : '显示' }}搜索
</el-button>
<el-button type="info" plain icon="Search" @click="showSearch = !showSearch"> {{ showSearch ? '隐藏' : '显示' }}搜索 </el-button>
<el-tooltip content="刷新" placement="top">
<el-button icon="Refresh" circle @click="getList" />
</el-tooltip>
@@ -171,8 +179,6 @@
</template>
</el-table-column>
<el-table-column label="走访状态" prop="status" min-width="100" align="center">
<template #default="scope">
<dict-tag :options="visitStatusOptions" :value="scope.row.status || ''" />
@@ -282,17 +288,10 @@
:value="student.studentId"
/>
<!-- 空数据提示 -->
<el-option
v-if="studentOptions.length === 0 && !studentLoading"
disabled
label="暂无学生数据"
value=""
/>
<el-option v-if="studentOptions.length === 0 && !studentLoading" disabled label="暂无学生数据" value="" />
</el-select>
<!-- 提示信息 -->
<div class="form-item-tip">
系统将自动显示您所管理班级的学生,支持输入姓名或学号搜索
</div>
<div class="form-item-tip">系统将自动显示您所管理班级的学生,支持输入姓名或学号搜索</div>
</el-form-item>
</el-col>
<el-col :span="12">
@@ -457,54 +456,56 @@ function getList() {
}
delete params.visitDateRange;
listInternshipVisit(params).then((response) => {
console.log('API响应数据:', response); // 用于调试
listInternshipVisit(params)
.then((response) => {
console.log('API响应数据:', response); // 用于调试
// 健壮的响应处理逻辑
if (response && typeof response === 'object') {
// 情况1:直接的TableDataInfo格式 {total: number, rows: array}
if (response.rows !== undefined && response.total !== undefined) {
visitList.value = response.rows || [];
total.value = response.total || 0;
}
// 情况2:嵌套在data中的TableDataInfo格式 {data: {total: number, rows: array}}
else if (response.data && response.data.rows !== undefined && response.data.total !== undefined) {
visitList.value = response.data.rows || [];
total.value = response.data.total || 0;
}
// 情况3:直接返回数组格式
else if (Array.isArray(response)) {
visitList.value = response;
total.value = response.length;
}
// 情况4:嵌套的数组格式
else if (response.data && Array.isArray(response.data)) {
visitList.value = response.data;
total.value = response.data.length;
}
// 其他未知格式
else {
console.warn('未识别的API响应格式:', response);
// 健壮的响应处理逻辑
if (response && typeof response === 'object') {
// 情况1:直接的TableDataInfo格式 {total: number, rows: array}
if (response.rows !== undefined && response.total !== undefined) {
visitList.value = response.rows || [];
total.value = response.total || 0;
}
// 情况2:嵌套在data中的TableDataInfo格式 {data: {total: number, rows: array}}
else if (response.data && response.data.rows !== undefined && response.data.total !== undefined) {
visitList.value = response.data.rows || [];
total.value = response.data.total || 0;
}
// 情况3:直接返回数组格式
else if (Array.isArray(response)) {
visitList.value = response;
total.value = response.length;
}
// 情况4:嵌套的数组格式
else if (response.data && Array.isArray(response.data)) {
visitList.value = response.data;
total.value = response.data.length;
}
// 其他未知格式
else {
console.warn('未识别的API响应格式:', response);
visitList.value = [];
total.value = 0;
}
} else {
console.warn('API响应不是对象类型:', response);
visitList.value = [];
total.value = 0;
}
} else {
console.warn('API响应不是对象类型:', response);
loading.value = false;
// 计算统计数据
calculateStatistics();
})
.catch((error) => {
console.error('获取走访记录列表失败:', error);
visitList.value = [];
total.value = 0;
}
loading.value = false;
// 计算统计数据
calculateStatistics();
}).catch((error) => {
console.error('获取走访记录列表失败:', error);
visitList.value = [];
total.value = 0;
loading.value = false;
// 可以添加用户友好的错误提示
proxy?.$modal.msgError('获取数据失败,请稍后重试');
});
loading.value = false;
// 可以添加用户友好的错误提示
proxy?.$modal.msgError('获取数据失败,请稍后重试');
});
}
/** 计算统计数据 */
@@ -760,17 +761,13 @@ function reset() {
function initDictData() {
// 获取走访状态字典
getDicts('zsjy_visit_status').then((response) => {
visitStatusOptions.value = response.data.map(item => ({
visitStatusOptions.value = response.data.map((item) => ({
label: item.dictLabel,
value: item.dictValue
}));
});
}
/** 加载当前班主任班级的学生列表 */
function loadCurrentTeacherStudents() {
const teacherId = userStore.userId;
+57 -83
View File
@@ -7,22 +7,17 @@
<div class="qrcode-header">
<h2 class="qrcode-title">新生报名二维码</h2>
<p class="qrcode-description">请扫码进行新生报名信息填写</p>
</div>
</div>
<!-- 二维码区域 -->
<div class="qrcode-wrapper">
<div class="qrcode-container">
<canvas ref="qrcodeCanvas" class="qrcode-canvas"></canvas>
</div>
</div>
<!-- 二维码URL显示 -->
<div class="qrcode-url">
<el-input
v-model="qrcodeUrl"
placeholder="请输入二维码链接地址"
clearable
@change="generateQrcode"
>
<el-input v-model="qrcodeUrl" placeholder="请输入二维码链接地址" clearable @change="generateQrcode">
<template #prepend>链接地址</template>
</el-input>
</div>
@@ -30,31 +25,13 @@
<!-- 操作按钮 -->
<div class="qrcode-actions">
<el-button
type="primary"
icon="Refresh"
@click="generateQrcode"
:loading="generating"
v-hasPermi="['zsjy:qrcode:view']"
>
<el-button type="primary" icon="Refresh" @click="generateQrcode" :loading="generating" v-hasPermi="['zsjy:qrcode:view']">
重新生成
</el-button>
<el-button
type="success"
icon="Download"
@click="downloadQrcode"
:disabled="!qrcodeGenerated"
v-hasPermi="['zsjy:qrcode:view']"
>
<el-button type="success" icon="Download" @click="downloadQrcode" :disabled="!qrcodeGenerated" v-hasPermi="['zsjy:qrcode:view']">
下载二维码
</el-button>
<el-button
type="info"
icon="Printer"
@click="printQrcode"
:disabled="!qrcodeGenerated"
v-hasPermi="['zsjy:qrcode:view']"
>
<el-button type="info" icon="Printer" @click="printQrcode" :disabled="!qrcodeGenerated" v-hasPermi="['zsjy:qrcode:view']">
打印二维码
</el-button>
</div>
@@ -64,37 +41,35 @@
</template>
<script setup lang="ts" name="QrCode">
import { ref, onMounted, nextTick, getCurrentInstance } from 'vue'
import QRCode from 'qrcode'
import { ElMessage } from 'element-plus'
import { ref, onMounted, nextTick, getCurrentInstance } from 'vue';
import QRCode from 'qrcode';
import { ElMessage } from 'element-plus';
const { proxy } = getCurrentInstance() as any
const { proxy } = getCurrentInstance() as any;
// 响应式数据
const qrcodeCanvas = ref<HTMLCanvasElement>()
const qrcodeUrl = ref<string>('') // 二维码链接地址,可手动配置
const generating = ref<boolean>(false)
const qrcodeGenerated = ref<boolean>(false)
const qrcodeCanvas = ref<HTMLCanvasElement>();
const qrcodeUrl = ref<string>(''); // 二维码链接地址,可手动配置
const generating = ref<boolean>(false);
const qrcodeGenerated = ref<boolean>(false);
// 默认二维码URL(后续可手动配置)
const getDefaultUrl = () => {
// 使用 window.location 来判断环境
const isProduction = window.location.hostname !== 'localhost'
return isProduction
? 'https://domain.com/mobile/#/pages/enrollment/form'
: 'http://localhost:8081/#/pages/enrollment/form'
}
const isProduction = window.location.hostname !== 'localhost';
return isProduction ? 'https://domain.com/mobile/#/pages/enrollment/form' : 'http://localhost:8081/#/pages/enrollment/form';
};
/** 生成二维码 */
const generateQrcode = async () => {
if (!qrcodeUrl.value.trim()) {
ElMessage.warning('请输入有效的链接地址')
return
ElMessage.warning('请输入有效的链接地址');
return;
}
generating.value = true
generating.value = true;
try {
await nextTick()
await nextTick();
if (qrcodeCanvas.value) {
// 生成二维码到canvas
@@ -106,64 +81,64 @@ const generateQrcode = async () => {
light: '#FFFFFF'
},
errorCorrectionLevel: 'M'
})
});
qrcodeGenerated.value = true
ElMessage.success('二维码生成成功')
qrcodeGenerated.value = true;
ElMessage.success('二维码生成成功');
}
} catch (error) {
console.error('生成二维码失败:', error)
ElMessage.error('生成二维码失败,请检查链接地址是否正确')
console.error('生成二维码失败:', error);
ElMessage.error('生成二维码失败,请检查链接地址是否正确');
} finally {
generating.value = false
generating.value = false;
}
}
};
/** 下载二维码 */
const downloadQrcode = () => {
if (!qrcodeCanvas.value || !qrcodeGenerated.value) {
ElMessage.warning('请先生成二维码')
return
ElMessage.warning('请先生成二维码');
return;
}
try {
// 创建下载链接
const link = document.createElement('a')
link.download = `新生报到二维码_${new Date().getTime()}.png`
link.href = qrcodeCanvas.value.toDataURL('image/png')
const link = document.createElement('a');
link.download = `新生报到二维码_${new Date().getTime()}.png`;
link.href = qrcodeCanvas.value.toDataURL('image/png');
// 触发下载
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
ElMessage.success('二维码下载成功')
ElMessage.success('二维码下载成功');
} catch (error) {
console.error('下载二维码失败:', error)
ElMessage.error('下载失败')
console.error('下载二维码失败:', error);
ElMessage.error('下载失败');
}
}
};
/** 打印二维码 */
const printQrcode = () => {
if (!qrcodeCanvas.value || !qrcodeGenerated.value) {
ElMessage.warning('请先生成二维码')
return
ElMessage.warning('请先生成二维码');
return;
}
try {
// 创建打印窗口
const printWindow = window.open('', '_blank')
const printWindow = window.open('', '_blank');
if (!printWindow) {
ElMessage.error('无法打开打印窗口,请检查浏览器设置')
return
ElMessage.error('无法打开打印窗口,请检查浏览器设置');
return;
}
// 获取二维码图片数据
const qrcodeDataUrl = qrcodeCanvas.value.toDataURL('image/png')
const qrcodeDataUrl = qrcodeCanvas.value.toDataURL('image/png');
// 生成打印页面HTML
const scriptTag = 'script'
const scriptTag = 'script';
const printContent = [
'<!DOCTYPE html>',
'<html>',
@@ -196,27 +171,26 @@ const printQrcode = () => {
`</${scriptTag}>`,
'</body>',
'</html>'
].join('')
].join('');
// 写入打印内容
printWindow.document.write(printContent)
printWindow.document.close()
printWindow.document.write(printContent);
printWindow.document.close();
} catch (error) {
console.error('打印二维码失败:', error)
ElMessage.error('打印失败')
console.error('打印二维码失败:', error);
ElMessage.error('打印失败');
}
}
};
// 组件挂载后初始化
onMounted(() => {
// 设置默认URL
qrcodeUrl.value = getDefaultUrl()
qrcodeUrl.value = getDefaultUrl();
// 自动生成二维码
nextTick(() => {
generateQrcode()
})
})
generateQrcode();
});
});
</script>
<style lang="scss" scoped>