Merge pull request '优化 班级成绩分析的 分段展示' (#17) from dev into staging
Reviewed-on: #17
This commit is contained in:
commit
fd2fcc2c1b
|
|
@ -1,4 +1,5 @@
|
||||||
import { http } from "@/utils/http";
|
import { http } from "@/utils/http";
|
||||||
|
import { Res } from "@/utils/http/types";
|
||||||
// import type { Res } from "@/utils/http/types";
|
// import type { Res } from "@/utils/http/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -29,7 +30,31 @@ export function ImportExamInfo(id: number, file: File) {
|
||||||
* @return {object}
|
* @return {object}
|
||||||
*/
|
*/
|
||||||
export function DeleteExamInfo(data: { classId: number; examId: number }) {
|
export function DeleteExamInfo(data: { classId: number; examId: number }) {
|
||||||
return http.request<any>("post", `ExamClassInfo/DeleteExamInfo`, {
|
return http.request<Res<any>>("post", `ExamClassInfo/DeleteExamInfo`, {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 重算考试排名
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
export function RecalculateExamRankings(examId: Number) {
|
||||||
|
return http.request<Res<any>>(
|
||||||
|
"get",
|
||||||
|
`ExamClassInfo/RecalculateExamRankings`,
|
||||||
|
{
|
||||||
|
params: { examId }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取班级考试分段排名
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
export function ClassRanking(examId: Number,classId: Number) {
|
||||||
|
return http.request<Res<any>>("get", `ExamClassInfo/ClassRanking`, {
|
||||||
|
params: { examId, classId }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ export class hTableAPI {
|
||||||
delete(data) {
|
delete(data) {
|
||||||
return http.request<Res<any>>("post", `${this.url}/Del`, { data });
|
return http.request<Res<any>>("post", `${this.url}/Del`, { data });
|
||||||
}
|
}
|
||||||
querycombo(data) {
|
querycombo(data = {}) {
|
||||||
return http.request<Res<ComboModel[]>>("post", `${this.url}/QueryCombo`, {
|
return http.request<Res<ComboModel[]>>("post", `${this.url}/QueryCombo`, {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -198,18 +198,18 @@ export class TableColumnSearch {
|
||||||
|
|
||||||
/** 表格列配置 */
|
/** 表格列配置 */
|
||||||
export class TableColumn {
|
export class TableColumn {
|
||||||
constructor(
|
constructor() {
|
||||||
) {
|
|
||||||
|
|
||||||
this.type = "string";
|
this.type = "string";
|
||||||
this.show = true;
|
this.show = true;
|
||||||
this.search = new TableColumnSearch();
|
this.search = new TableColumnSearch();
|
||||||
this.edit = new TableColumnEdit();
|
this.edit = new TableColumnEdit();
|
||||||
|
this.fixed = false;
|
||||||
this.setting = {};
|
this.setting = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 显示标签 */
|
/** 显示标签 */
|
||||||
label: string;
|
label: string;
|
||||||
|
fixed?: 'left' | 'right'| boolean;
|
||||||
/** 查询配置 */
|
/** 查询配置 */
|
||||||
search?: TableColumnSearch;
|
search?: TableColumnSearch;
|
||||||
/** 编辑配置 */
|
/** 编辑配置 */
|
||||||
|
|
@ -327,6 +327,8 @@ export interface TableConfig {
|
||||||
searchCallback?: (s: SearchConditions) => void;
|
searchCallback?: (s: SearchConditions) => void;
|
||||||
/** 新增/修改回调函数 */
|
/** 新增/修改回调函数 */
|
||||||
editCallback?: (from: any) => void;
|
editCallback?: (from: any) => void;
|
||||||
|
/** 展开行的回调 */
|
||||||
|
expandChange?: (row: any, expandedRows: any[]) => void;
|
||||||
/** API地址 */
|
/** API地址 */
|
||||||
apiUrl: string;
|
apiUrl: string;
|
||||||
/** 是否显示选择列 */
|
/** 是否显示选择列 */
|
||||||
|
|
@ -335,6 +337,10 @@ export interface TableConfig {
|
||||||
search: SearchConditions;
|
search: SearchConditions;
|
||||||
/** 是否显示操作列 */
|
/** 是否显示操作列 */
|
||||||
operationColumn: boolean;
|
operationColumn: boolean;
|
||||||
|
/** 操作列是否固定列 */
|
||||||
|
operationColumnFixed?: "left" | "right" | boolean;
|
||||||
|
/** 是否允许展开列 */
|
||||||
|
expandColumn?: boolean;
|
||||||
/** 操作按钮配置 */
|
/** 操作按钮配置 */
|
||||||
operationColumnData: OperationButton[];
|
operationColumnData: OperationButton[];
|
||||||
/** 列配置 */
|
/** 列配置 */
|
||||||
|
|
@ -357,6 +363,8 @@ export function intTableData(tValue: TableConfig): TableConfig {
|
||||||
if (!tValue.data) tValue.data = [];
|
if (!tValue.data) tValue.data = [];
|
||||||
if (!tValue.selectRows) tValue.selectRows = [];
|
if (!tValue.selectRows) tValue.selectRows = [];
|
||||||
if (tValue.border == null) tValue.border = true;
|
if (tValue.border == null) tValue.border = true;
|
||||||
|
if (tValue.operationColumnFixed == null) tValue.operationColumnFixed = false;
|
||||||
|
if (tValue.expandColumn == null) tValue.expandColumn = false;
|
||||||
if (!tValue.pageData) tValue.pageData = { total: 0 };
|
if (!tValue.pageData) tValue.pageData = { total: 0 };
|
||||||
if (tValue.operationTop === undefined) tValue.operationTop = true;
|
if (tValue.operationTop === undefined) tValue.operationTop = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,8 +117,8 @@ function handleResetForm() {
|
||||||
function fetchInitData() {}
|
function fetchInitData() {}
|
||||||
function fetchFormData() {
|
function fetchFormData() {
|
||||||
editData.value.loading = false;
|
editData.value.loading = false;
|
||||||
|
handleResetForm();
|
||||||
if (editData.value.isedit) {
|
if (editData.value.isedit) {
|
||||||
handleResetForm();
|
|
||||||
Api.Info(props.id).then((res) => {
|
Api.Info(props.id).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
editData.value.frorm = res.data;
|
editData.value.frorm = res.data;
|
||||||
|
|
|
||||||
|
|
@ -207,16 +207,20 @@ function handleDelete(obj, row) {
|
||||||
row.forEach((it) => {
|
row.forEach((it) => {
|
||||||
ids.push(it.id);
|
ids.push(it.id);
|
||||||
});
|
});
|
||||||
ElMessageBox.confirm("此操作将永久删除勾选记录, 是否继续?").then(() => {
|
ElMessageBox.confirm("此操作将永久删除勾选记录, 是否继续?")
|
||||||
Api.delete(ids).then((res) => {
|
.then(() => {
|
||||||
if (res.code === 200) {
|
Api.delete(ids).then((res) => {
|
||||||
handleReloadPaged();
|
if (res.code === 200) {
|
||||||
ElMessage.success("删除成功");
|
handleReloadPaged();
|
||||||
} else {
|
ElMessage.success("删除成功");
|
||||||
ElMessage.error(res.message);
|
} else {
|
||||||
}
|
ElMessage.error(res.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage.info("取消删除");
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// 页面完成回调
|
// 页面完成回调
|
||||||
function handleAddCallback() {
|
function handleAddCallback() {
|
||||||
|
|
@ -454,6 +458,7 @@ function fetchPagedData() {
|
||||||
:row-key="rowKeyFun"
|
:row-key="rowKeyFun"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@sort-change="sortChange"
|
@sort-change="sortChange"
|
||||||
|
@expand-change="table.expandChange"
|
||||||
>
|
>
|
||||||
<el-table-column v-if="table.selectColumn" type="selection" width="40" />
|
<el-table-column v-if="table.selectColumn" type="selection" width="40" />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
|
|
@ -461,6 +466,7 @@ function fetchPagedData() {
|
||||||
table.operationColumn &&
|
table.operationColumn &&
|
||||||
table.operationColumnData.filter((s) => !s.topBtn).length > 0
|
table.operationColumnData.filter((s) => !s.topBtn).length > 0
|
||||||
"
|
"
|
||||||
|
:fixed="table.operationColumnFixed"
|
||||||
label="操作"
|
label="操作"
|
||||||
:width="getOperationColumnWidth()"
|
:width="getOperationColumnWidth()"
|
||||||
>
|
>
|
||||||
|
|
@ -483,12 +489,21 @@ function fetchPagedData() {
|
||||||
<!-- 行内按钮组 -->
|
<!-- 行内按钮组 -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
<!-- 拓展列 -->
|
||||||
|
<el-table-column v-if="table.expandColumn" type="expand">
|
||||||
|
<template #default="props">
|
||||||
|
<slot name="expandSlot" :props="props"></slot>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="(item, name, i) of tableShowColumn"
|
v-for="(item, name, i) of tableShowColumn"
|
||||||
:key="i"
|
:key="i"
|
||||||
:prop="name"
|
:prop="name"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:width="item.width"
|
:width="item.width"
|
||||||
|
:fixed="item.fixed"
|
||||||
:sortable="item.search.sort ? `custom` : false"
|
:sortable="item.search.sort ? `custom` : false"
|
||||||
>
|
>
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ const convertKeysToCamelCase = <T>(data: any): T => {
|
||||||
const defaultConfig: AxiosRequestConfig = {
|
const defaultConfig: AxiosRequestConfig = {
|
||||||
baseURL: import.meta.env.VITE_API_BASEURL,
|
baseURL: import.meta.env.VITE_API_BASEURL,
|
||||||
// 请求超时时间
|
// 请求超时时间
|
||||||
timeout: 20 * 1000,
|
timeout: 30 * 1000,
|
||||||
headers: {
|
headers: {
|
||||||
Accept: "application/json, text/plain, */*",
|
Accept: "application/json, text/plain, */*",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import { fa } from "element-plus/es/locales.mjs";
|
||||||
import { hTableAPI } from "@/api/hTable";
|
import { hTableAPI } from "@/api/hTable";
|
||||||
import { getenum } from "@/api/enum";
|
import { getenum } from "@/api/enum";
|
||||||
import { ruleRequired, ruleRequiredNumber } from "@/utils/rules";
|
import { ruleRequired, ruleRequiredNumber } from "@/utils/rules";
|
||||||
|
import { ClassRanking } from "@/api/exam";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
const ControllerName = "ExamClassInfo";
|
const ControllerName = "ExamClassInfo";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
|
|
@ -25,9 +27,11 @@ function searchCallback(data) {}
|
||||||
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||||
const tableData: TableConfig = intTableData({
|
const tableData: TableConfig = intTableData({
|
||||||
apiUrl: ControllerName,
|
apiUrl: ControllerName,
|
||||||
|
expandColumn: true,
|
||||||
selectColumn: false, // 列表选择
|
selectColumn: false, // 列表选择
|
||||||
border: false, // 是否显示表格边框
|
border: false, // 是否显示表格边框
|
||||||
searchCallback: searchCallback,
|
searchCallback: searchCallback,
|
||||||
|
expandChange: expandChange,
|
||||||
search: {
|
search: {
|
||||||
// 查询条件
|
// 查询条件
|
||||||
show: true,
|
show: true,
|
||||||
|
|
@ -73,19 +77,6 @@ const tableData: TableConfig = intTableData({
|
||||||
},
|
},
|
||||||
peopleCount: {
|
peopleCount: {
|
||||||
label: "参考人数",
|
label: "参考人数",
|
||||||
width: "100px",
|
|
||||||
},
|
|
||||||
onLineCount: {
|
|
||||||
label: "重本人数",
|
|
||||||
width: "100px",
|
|
||||||
},
|
|
||||||
onLineRate: {
|
|
||||||
label: "重本率",
|
|
||||||
width: "100px",
|
|
||||||
custom: (row) => `${row.onLineRate * 100}%`,
|
|
||||||
},
|
|
||||||
onLineRanking: {
|
|
||||||
label: "重本率排名",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data: [],
|
data: [],
|
||||||
|
|
@ -101,8 +92,275 @@ onMounted(async () => {
|
||||||
|
|
||||||
showTable.value = true;
|
showTable.value = true;
|
||||||
});
|
});
|
||||||
|
// types/exam.ts 或直接在组件中定义
|
||||||
|
export interface ExamClassTag {
|
||||||
|
Name: string; // 标签名称
|
||||||
|
SubjectStr?: string; // 学科枚举,可空(总分则为 null)
|
||||||
|
OnLineRanking: number; // 上线考试排名
|
||||||
|
OnLineRate: number; // 上线率(注意:C#中是 decimal,TS里用 number)
|
||||||
|
OnLineCount: number; // 上线人数
|
||||||
|
}
|
||||||
|
|
||||||
|
async function expandChange(row: any, expandedRows: any[]) {
|
||||||
|
if (row.rankingList != null) return;
|
||||||
|
let res = await ClassRanking(row.examId, row.classId);
|
||||||
|
if (res.code != 200) return ElMessage.error(res.message || "获取数据失败");
|
||||||
|
row.rankingList = res.data;
|
||||||
|
}
|
||||||
|
// 根据学科获取CSS类名
|
||||||
|
const getSubjectClass = (subjectStr) => {
|
||||||
|
if (!subjectStr) return "";
|
||||||
|
|
||||||
|
const subjectMap = {
|
||||||
|
总分: "total",
|
||||||
|
数学: "math",
|
||||||
|
英语: "english",
|
||||||
|
物理: "physics",
|
||||||
|
化学: "chemistry",
|
||||||
|
生物: "biology",
|
||||||
|
};
|
||||||
|
|
||||||
|
return subjectMap[subjectStr] || "";
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
<div>
|
||||||
|
<ahTable v-if="showTable" ref="table" :tableConfig="tableData">
|
||||||
|
<template #expandSlot="{ props }">
|
||||||
|
<!-- 拓展内容 -->
|
||||||
|
<div class="expanded-content expandSlot">
|
||||||
|
<div
|
||||||
|
v-if="props.row.rankingList && props.row.rankingList.length > 0"
|
||||||
|
class="ranking-list"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(tag, tagIndex) in props.row.rankingList"
|
||||||
|
:key="tagIndex"
|
||||||
|
class="tag-card"
|
||||||
|
:class="getSubjectClass(tag.subjectStr)"
|
||||||
|
>
|
||||||
|
<div class="tag-name">
|
||||||
|
<span>{{ tag.name }}</span>
|
||||||
|
<span class="subject-badge">{{ tag.subjectStr || "总分" }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tag-details">
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">上线排名:</span>
|
||||||
|
<span class="detail-value">第 {{ tag.onLineRanking }} 名</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">上线人数:</span>
|
||||||
|
<span class="detail-value">{{ tag.onLineCount }} 人</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="detail-label">上线率:</span>
|
||||||
|
<span class="detail-value"
|
||||||
|
>{{ (tag.onLineRate * 100).toFixed(0) }}%</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="progress-container">
|
||||||
|
<div
|
||||||
|
class="progress-bar"
|
||||||
|
:style="{ width: tag.onLineRate * 100 + '%' }"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="empty-state">
|
||||||
|
<i class="fas fa-inbox" style="font-size: 3rem; margin-bottom: 15px"></i>
|
||||||
|
<p>暂无标签数据</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ahTable>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<style>
|
||||||
|
.expandSlot {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1200px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(90deg, #3498db, #2c3e50);
|
||||||
|
color: white;
|
||||||
|
padding: 20px 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .subtitle {
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-table th {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 15px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2c3e50;
|
||||||
|
border-bottom: 2px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-table td {
|
||||||
|
padding: 15px;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-table tr:hover {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-btn {
|
||||||
|
background: #3498db;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-btn:hover {
|
||||||
|
background: #2980b9;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ranking-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||||
|
gap: 15px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 15px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
|
||||||
|
border-left: 4px solid #3498db;
|
||||||
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-card.total {
|
||||||
|
border-left-color: #777f8a;
|
||||||
|
}
|
||||||
|
.tag-card.math {
|
||||||
|
border-left-color: #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-card.english {
|
||||||
|
border-left-color: #f39c12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-card.physics {
|
||||||
|
border-left-color: #9b59b6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-card.chemistry {
|
||||||
|
border-left-color: #1abc9c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-card.biology {
|
||||||
|
border-left-color: #2ecc71;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject-badge {
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
background: #ecf0f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-details {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
color: #7f8c8d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-container {
|
||||||
|
height: 8px;
|
||||||
|
background: #ecf0f1;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, #3498db, #2ecc71);
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: width 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px;
|
||||||
|
color: #7f8c8d;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -90,19 +90,19 @@ const tableData: TableConfig = intTableData({
|
||||||
search: new TableColumnSearch(true),
|
search: new TableColumnSearch(true),
|
||||||
},
|
},
|
||||||
|
|
||||||
onLineCount: {
|
// onLineCount: {
|
||||||
label: "重本人数",
|
// label: "重本人数",
|
||||||
width: "80px",
|
// width: "80px",
|
||||||
},
|
// },
|
||||||
onLineRate: {
|
// onLineRate: {
|
||||||
label: "重本率",
|
// label: "重本率",
|
||||||
custom: (row) => `${Math.round(row.onLineRate * 100)}%`,
|
// custom: (row) => `${Math.round(row.onLineRate * 100)}%`,
|
||||||
width: "80px",
|
// width: "80px",
|
||||||
},
|
// },
|
||||||
onLineRanking: {
|
// onLineRanking: {
|
||||||
label: "重本率排名",
|
// label: "重本率排名",
|
||||||
width: "100px",
|
// width: "100px",
|
||||||
},
|
// },
|
||||||
maxScore: {
|
maxScore: {
|
||||||
label: "最高分[赋分]",
|
label: "最高分[赋分]",
|
||||||
width: "130px",
|
width: "130px",
|
||||||
|
|
@ -122,10 +122,10 @@ const tableData: TableConfig = intTableData({
|
||||||
},
|
},
|
||||||
averageRank: {
|
averageRank: {
|
||||||
label: "总平均分排名",
|
label: "总平均分排名",
|
||||||
|
width: "110px",
|
||||||
},
|
},
|
||||||
rank: {
|
rank: {
|
||||||
label: "远端平均/资源校平均",
|
label: "远端平均/资源校平均",
|
||||||
width: "95px",
|
|
||||||
custom: (row) =>
|
custom: (row) =>
|
||||||
`${
|
`${
|
||||||
row.baseSchoolScore == 0
|
row.baseSchoolScore == 0
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,188 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ahTable from "@/components/hTable/index.vue";
|
||||||
|
import {
|
||||||
|
ConditionalType,
|
||||||
|
intTableData,
|
||||||
|
TableColumnSearch,
|
||||||
|
TableConfig,
|
||||||
|
} from "@/components/hTable/hTable";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { fa } from "element-plus/es/locales.mjs";
|
||||||
|
import { hTableAPI } from "@/api/hTable";
|
||||||
|
import { getenum } from "@/api/enum";
|
||||||
|
import {
|
||||||
|
ruleNumber,
|
||||||
|
ruleRequired,
|
||||||
|
ruleRequiredGrade,
|
||||||
|
ruleRequiredI,
|
||||||
|
ruleRequiredNumber,
|
||||||
|
} from "@/utils/rules";
|
||||||
|
import { ImportExamInfo, RecalculateExamRankings } from "@/api/exam";
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
import { entryExamInfo } from "./examFun";
|
||||||
|
const ControllerName = "ExamTags";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: ControllerName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: any;
|
||||||
|
}>();
|
||||||
|
function searchCallback(data) {}
|
||||||
|
|
||||||
|
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||||
|
const tableData: TableConfig = intTableData({
|
||||||
|
apiUrl: ControllerName,
|
||||||
|
selectColumn: false, // 列表选择
|
||||||
|
border: false, // 是否显示表格边框
|
||||||
|
searchCallback: searchCallback,
|
||||||
|
editCallback: async (from) => {
|
||||||
|
if (from.subjectId == -1) from.subjectId = null;
|
||||||
|
from.examId = props.data[0].id;
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
// 查询条件
|
||||||
|
show: false,
|
||||||
|
showPage: false,
|
||||||
|
PageIndex: 0,
|
||||||
|
PageSize: 1000,
|
||||||
|
OrderBy: "Id", // 排序
|
||||||
|
defaultConditions: [
|
||||||
|
{
|
||||||
|
FieldName: "ExamId",
|
||||||
|
FieldValue: props.data[0].id + "",
|
||||||
|
ConditionalType: ConditionalType.Equal,
|
||||||
|
},
|
||||||
|
], // 默认查询条件
|
||||||
|
Conditions: [],
|
||||||
|
},
|
||||||
|
operationColumn: true, // 显示操作按钮
|
||||||
|
operationColumnData: [
|
||||||
|
// {
|
||||||
|
// // 操作按钮
|
||||||
|
// topBtn: false, // 是头部按钮
|
||||||
|
// label: "修改",
|
||||||
|
// btnType: "edit", // 按钮类型 add edit del custom
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
// 操作按钮
|
||||||
|
topBtn: true, // 是头部按钮
|
||||||
|
label: "添加",
|
||||||
|
btnStyle: "success",
|
||||||
|
btnType: "add", // 按钮类型 add edit del custom
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topBtn: false,
|
||||||
|
label: "删除",
|
||||||
|
btnType: "del",
|
||||||
|
btnStyle: "danger",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topBtn: true,
|
||||||
|
label: "重新计算考试上线数据",
|
||||||
|
click: RExamRankings,
|
||||||
|
btnStyle: "info",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
column: {
|
||||||
|
examId: {
|
||||||
|
label: "考试",
|
||||||
|
width: "180px",
|
||||||
|
search: new TableColumnSearch(true, ConditionalType.Equal), // 搜索
|
||||||
|
type: "dropdown",
|
||||||
|
},
|
||||||
|
tagName: {
|
||||||
|
label: "分段名称",
|
||||||
|
width: "180px",
|
||||||
|
edit: {
|
||||||
|
add: true,
|
||||||
|
rules: ruleRequiredI(20, 1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
subjectId: {
|
||||||
|
label: "学科",
|
||||||
|
width: "100px",
|
||||||
|
search: new TableColumnSearch(true),
|
||||||
|
type: "dropdown",
|
||||||
|
custom: (row) =>
|
||||||
|
row.subjectId
|
||||||
|
? tableData.column.subjectId.setting.datasource.find(
|
||||||
|
(s) => s.value == row.subjectId
|
||||||
|
)?.text ?? "--"
|
||||||
|
: "总分",
|
||||||
|
edit: {
|
||||||
|
add: true,
|
||||||
|
rules: ruleRequired,
|
||||||
|
editDefault: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
maxScore: {
|
||||||
|
label: "最大分数",
|
||||||
|
width: "120px",
|
||||||
|
edit: {
|
||||||
|
add: true,
|
||||||
|
rules: ruleRequiredNumber,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
minScore: {
|
||||||
|
label: "最小分数",
|
||||||
|
width: "120px",
|
||||||
|
edit: {
|
||||||
|
add: true,
|
||||||
|
rules: ruleRequiredNumber,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
createTime: {
|
||||||
|
label: "创建时间",
|
||||||
|
type: "datetime",
|
||||||
|
custom: (row) => row.createTime?.replace("T", " ").substring(0, 10) ?? "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: [],
|
||||||
|
pageData: {
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
selectRows: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const Api = new hTableAPI(`Exam`);
|
||||||
|
const showTable = ref(false);
|
||||||
|
onMounted(async () => {
|
||||||
|
//初始化数据原
|
||||||
|
|
||||||
|
tableData.column.examId.setting.datasource = (await Api.querycombo()).data;
|
||||||
|
tableData.column.subjectId.setting.datasource = [
|
||||||
|
{ text: "总分", value: -1 },
|
||||||
|
...(await getenum("SubjectEnum")).data,
|
||||||
|
];
|
||||||
|
|
||||||
|
showTable.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function RExamRankings() {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`重新计算考试上线数据,可能需要较长时间,是否继续?`,
|
||||||
|
"确认",
|
||||||
|
{
|
||||||
|
confirmButtonText: "继续",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const res = await RecalculateExamRankings(props.data[0].id);
|
||||||
|
if (res.code == 200) {
|
||||||
|
ElMessage.success("操作成功");
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || "操作失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.info("取消操作");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||||
|
</template>
|
||||||
|
|
@ -78,6 +78,19 @@ const tableData: TableConfig = intTableData({
|
||||||
height: "800px", // 弹框高度
|
height: "800px", // 弹框高度
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
topBtn: false, // 头部按钮
|
||||||
|
show: true,
|
||||||
|
label: "分段",
|
||||||
|
btnType: "custom", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||||
|
btnStyle: "info",
|
||||||
|
custom: {
|
||||||
|
title: "考试分段", // 弹出框title
|
||||||
|
src: "exam/examTags", // 组件路径
|
||||||
|
width: "1200px", // 弹框宽度
|
||||||
|
height: "800px", // 弹框高度
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
topBtn: false, // 头部按钮
|
topBtn: false, // 头部按钮
|
||||||
show: true,
|
show: true,
|
||||||
|
|
@ -107,7 +120,7 @@ const tableData: TableConfig = intTableData({
|
||||||
edit: {
|
edit: {
|
||||||
add: true,
|
add: true,
|
||||||
edit: true,
|
edit: true,
|
||||||
rules: ruleRequired,
|
rules: ruleRequiredI(20, 2),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gradeLevel: {
|
gradeLevel: {
|
||||||
|
|
@ -210,8 +223,11 @@ const showTable = ref(false);
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
//初始化数据原
|
//初始化数据原
|
||||||
|
|
||||||
tableData.column.gradeLevel.setting.datasource =
|
tableData.column.gradeLevel.setting.datasource = (
|
||||||
(await getenum("GradeLevelEnum")).data.map(s=>{return {value : s.text,text:s.text}});
|
await getenum("GradeLevelEnum")
|
||||||
|
).data.map((s) => {
|
||||||
|
return { value: s.text, text: s.text };
|
||||||
|
});
|
||||||
|
|
||||||
tableData.column.testPaperType.setting.datasource = (
|
tableData.column.testPaperType.setting.datasource = (
|
||||||
await getenum("TestPaperTypeEnum")
|
await getenum("TestPaperTypeEnum")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue