|
|
|
|
@ -1,169 +1,171 @@
|
|
|
|
|
<!-- PanelResultados.vue (DISEÑO ALTERNATIVO: "Scoreboard" moderno, full responsive) -->
|
|
|
|
|
<!-- PanelResultados.vue (DASH STYLE + RESPONSIVE PRO) -->
|
|
|
|
|
<template>
|
|
|
|
|
<div class="page alt">
|
|
|
|
|
<div class="head">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="hTitle">Resultados del examen</div>
|
|
|
|
|
<div class="hSub">Resumen claro + detalle por curso.</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="headActions">
|
|
|
|
|
<a-space class="headSpace">
|
|
|
|
|
<a-button class="btnSoft" @click="volver" :disabled="cargando">Volver</a-button>
|
|
|
|
|
<a-button class="btnPrimary" type="primary" @click="recalcular" :loading="cargando">
|
|
|
|
|
Actualizar
|
|
|
|
|
</a-button>
|
|
|
|
|
</a-space>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="dashboard-modern">
|
|
|
|
|
<a-spin :spinning="cargando" tip="Cargando resultados...">
|
|
|
|
|
<template v-if="resultado">
|
|
|
|
|
<a-row :gutter="[16, 16]">
|
|
|
|
|
<a-col :xs="24" :lg="10">
|
|
|
|
|
<a-card class="card scoreCard" :bordered="false">
|
|
|
|
|
<div class="scoreTop">
|
|
|
|
|
<div class="chipDone">
|
|
|
|
|
<span class="chipDot" />
|
|
|
|
|
Calificado
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="resultado.orden_merito != null" class="chipRank">
|
|
|
|
|
Puesto: <b>#{{ resultado.orden_merito }}</b>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="scoreMain">{{ fmt2(resultado.total_puntos) }}</div>
|
|
|
|
|
<div class="scoreLabel">Puntaje total</div>
|
|
|
|
|
|
|
|
|
|
<div class="bigProgress">
|
|
|
|
|
<a-progress :percent="notaPercent" />
|
|
|
|
|
<div class="bigProgressMeta">
|
|
|
|
|
<!-- <span>Nota equivalente</span>
|
|
|
|
|
<b>{{ fmt2(resultado.calificacion_sobre_20) }}/20</b> -->
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<a-alert
|
|
|
|
|
class="advice"
|
|
|
|
|
show-icon
|
|
|
|
|
type="success"
|
|
|
|
|
message="Consejo"
|
|
|
|
|
:description="consejo"
|
|
|
|
|
/>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :lg="14">
|
|
|
|
|
<div class="section-container">
|
|
|
|
|
<div class="page alt">
|
|
|
|
|
<!-- Head -->
|
|
|
|
|
<div class="head">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="hTitle">Resultados del examen</div>
|
|
|
|
|
<div class="hSub">Resumen claro + detalle por curso.</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="headActions">
|
|
|
|
|
<a-space class="headSpace">
|
|
|
|
|
<a-button class="btnSoft" @click="volver" :disabled="cargando">Volver</a-button>
|
|
|
|
|
<a-button class="btnPrimary" type="primary" @click="recalcular" :loading="cargando">
|
|
|
|
|
Actualizar
|
|
|
|
|
</a-button>
|
|
|
|
|
</a-space>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<template v-if="resultado">
|
|
|
|
|
<a-row :gutter="[16, 16]">
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="8">
|
|
|
|
|
<a-card class="card kpi" :bordered="false">
|
|
|
|
|
<div class="kpiK">Correctas</div>
|
|
|
|
|
<div class="kpiV">{{ resultado.total_correctas }}</div>
|
|
|
|
|
<div class="kpiHint">Aciertos</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :xs="24" :lg="10">
|
|
|
|
|
<a-card class="card scoreCard" :bordered="false">
|
|
|
|
|
<div class="scoreTop">
|
|
|
|
|
<div class="chipDone">
|
|
|
|
|
<span class="chipDot" />
|
|
|
|
|
Calificado
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="8">
|
|
|
|
|
<a-card class="card kpi" :bordered="false">
|
|
|
|
|
<div class="kpiK">Incorrectas</div>
|
|
|
|
|
<div class="kpiV">{{ resultado.total_incorrectas }}</div>
|
|
|
|
|
<div class="kpiHint">Errores</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
<div v-if="resultado.orden_merito != null" class="chipRank">
|
|
|
|
|
Puesto: <b>#{{ resultado.orden_merito }}</b>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="scoreMain">{{ fmt2(resultado.total_puntos) }}</div>
|
|
|
|
|
<div class="scoreLabel">Puntaje total</div>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="8">
|
|
|
|
|
<a-card class="card kpi" :bordered="false">
|
|
|
|
|
<div class="kpiK">Blanco/Nulas</div>
|
|
|
|
|
<div class="kpiV">{{ resultado.total_nulas }}</div>
|
|
|
|
|
<div class="kpiHint">Sin respuesta</div>
|
|
|
|
|
<div class="bigProgress">
|
|
|
|
|
<a-progress :percent="notaPercent" />
|
|
|
|
|
<div class="bigProgressMeta"></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<a-alert
|
|
|
|
|
class="advice"
|
|
|
|
|
show-icon
|
|
|
|
|
type="success"
|
|
|
|
|
message="Consejo"
|
|
|
|
|
:description="consejo"
|
|
|
|
|
/>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="12">
|
|
|
|
|
<a-card class="card kpiWide" :bordered="false">
|
|
|
|
|
<div class="kpiWideRow">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="kpiK">% Correctas</div>
|
|
|
|
|
<div class="kpiV">{{ fmt2(resultado.porcentaje_correctas) }}%</div>
|
|
|
|
|
</div>
|
|
|
|
|
<a-col :xs="24" :lg="14">
|
|
|
|
|
<a-row :gutter="[16, 16]">
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="8">
|
|
|
|
|
<a-card class="card kpi" :bordered="false">
|
|
|
|
|
<div class="kpiK">Correctas</div>
|
|
|
|
|
<div class="kpiV">{{ resultado.total_correctas }}</div>
|
|
|
|
|
<div class="kpiHint">Aciertos</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="8">
|
|
|
|
|
<a-card class="card kpi" :bordered="false">
|
|
|
|
|
<div class="kpiK">Incorrectas</div>
|
|
|
|
|
<div class="kpiV">{{ resultado.total_incorrectas }}</div>
|
|
|
|
|
<div class="kpiHint">Errores</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="8">
|
|
|
|
|
<a-card class="card kpi" :bordered="false">
|
|
|
|
|
<div class="kpiK">Blanco/Nulas</div>
|
|
|
|
|
<div class="kpiV">{{ resultado.total_nulas }}</div>
|
|
|
|
|
<div class="kpiHint">Sin respuesta</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="12">
|
|
|
|
|
<a-card class="card kpiWide" :bordered="false">
|
|
|
|
|
<div class="kpiWideRow">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="kpiK">% Correctas</div>
|
|
|
|
|
<div class="kpiV">{{ fmt2(resultado.porcentaje_correctas) }}%</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="miniCircle">
|
|
|
|
|
<a-progress type="circle" :percent="notaPercent" :width="96" />
|
|
|
|
|
<div class="miniCircleLabel">
|
|
|
|
|
<div class="miniCircleMain">{{ fmt2(resultado.calificacion_sobre_20) }}</div>
|
|
|
|
|
<div class="miniCircleSub">/20</div>
|
|
|
|
|
<div class="miniCircle">
|
|
|
|
|
<a-progress type="circle" :percent="notaPercent" :width="96" />
|
|
|
|
|
<div class="miniCircleLabel">
|
|
|
|
|
<div class="miniCircleMain">{{ fmt2(resultado.calificacion_sobre_20) }}</div>
|
|
|
|
|
<div class="miniCircleSub">/20</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="12">
|
|
|
|
|
<a-card class="card noteCard" :bordered="false">
|
|
|
|
|
<div class="kpiK">Nota sobre 20</div>
|
|
|
|
|
<div class="kpiV">{{ fmt2(resultado.calificacion_sobre_20) }}/20</div>
|
|
|
|
|
<div class="kpiHint">Equivalencia según puntaje máximo del proceso</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
</a-row>
|
|
|
|
|
</a-col>
|
|
|
|
|
</a-row>
|
|
|
|
|
|
|
|
|
|
<a-col :xs="24" :sm="12" :md="12">
|
|
|
|
|
<a-card class="card noteCard" :bordered="false">
|
|
|
|
|
<div class="kpiK">Nota sobre 20</div>
|
|
|
|
|
<div class="kpiV">{{ fmt2(resultado.calificacion_sobre_20) }}/20</div>
|
|
|
|
|
<div class="kpiHint">Equivalencia según puntaje máximo del proceso</div>
|
|
|
|
|
<a-row :gutter="[16, 16]" class="mt16">
|
|
|
|
|
<a-col :xs="24">
|
|
|
|
|
<a-card title="Desempeño por curso" class="card" :bordered="false">
|
|
|
|
|
<div class="tableWrap">
|
|
|
|
|
<a-table
|
|
|
|
|
:columns="columns"
|
|
|
|
|
:dataSource="rowsCursos"
|
|
|
|
|
:pagination="false"
|
|
|
|
|
size="middle"
|
|
|
|
|
rowKey="curso"
|
|
|
|
|
:scroll="{ x: 760 }"
|
|
|
|
|
class="modernTable"
|
|
|
|
|
>
|
|
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
<template v-if="column.dataIndex === 'curso'">
|
|
|
|
|
<div class="courseCell">
|
|
|
|
|
<span class="courseDot"></span>
|
|
|
|
|
<div>
|
|
|
|
|
<div class="courseName">{{ record.curso }}</div>
|
|
|
|
|
<div class="courseMeta">{{ record.ratio }}%</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'correctas'">
|
|
|
|
|
<span class="pill good">{{ record.correctas }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'incorrectas'">
|
|
|
|
|
<span class="pill bad">{{ record.incorrectas }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'total'">
|
|
|
|
|
<span class="pill neutral">{{ record.total }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'ratio'">
|
|
|
|
|
<a-progress :percent="record.ratio" />
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</a-table>
|
|
|
|
|
</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
</a-row>
|
|
|
|
|
</a-col>
|
|
|
|
|
</a-row>
|
|
|
|
|
|
|
|
|
|
<a-row :gutter="[16, 16]" class="mt16">
|
|
|
|
|
<a-col :xs="24">
|
|
|
|
|
<a-card title="Desempeño por curso" class="card" :bordered="false">
|
|
|
|
|
<div class="tableWrap">
|
|
|
|
|
<a-table
|
|
|
|
|
:columns="columns"
|
|
|
|
|
:dataSource="rowsCursos"
|
|
|
|
|
:pagination="false"
|
|
|
|
|
size="middle"
|
|
|
|
|
rowKey="curso"
|
|
|
|
|
:scroll="{ x: 760 }"
|
|
|
|
|
class="modernTable"
|
|
|
|
|
>
|
|
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
<template v-if="column.dataIndex === 'curso'">
|
|
|
|
|
<div class="courseCell">
|
|
|
|
|
<span class="courseDot"></span>
|
|
|
|
|
<div>
|
|
|
|
|
<div class="courseName">{{ record.curso }}</div>
|
|
|
|
|
<div class="courseMeta">{{ record.ratio }}%</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'correctas'">
|
|
|
|
|
<span class="pill good">{{ record.correctas }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'incorrectas'">
|
|
|
|
|
<span class="pill bad">{{ record.incorrectas }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'total'">
|
|
|
|
|
<span class="pill neutral">{{ record.total }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="column.dataIndex === 'ratio'">
|
|
|
|
|
<a-progress :percent="record.ratio" />
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</a-table>
|
|
|
|
|
</div>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
</a-row>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else>
|
|
|
|
|
<a-empty description="No hay resultados disponibles" class="empty">
|
|
|
|
|
<a-button type="primary" class="btnPrimary" @click="recalcular" :loading="cargando">
|
|
|
|
|
Calcular resultados
|
|
|
|
|
</a-button>
|
|
|
|
|
</a-empty>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template v-else>
|
|
|
|
|
<a-empty description="No hay resultados disponibles" class="empty">
|
|
|
|
|
<a-button type="primary" class="btnPrimary" @click="recalcular" :loading="cargando">
|
|
|
|
|
Calcular resultados
|
|
|
|
|
</a-button>
|
|
|
|
|
</a-empty>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</a-spin>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
@ -242,15 +244,17 @@ const rowsCursos = computed(() => {
|
|
|
|
|
|
|
|
|
|
const rows = Array.from(keys).map((k) => {
|
|
|
|
|
const correctas = parseCorrectas(corr?.[k] ?? 0)
|
|
|
|
|
const total = parseTotal(k) || (() => {
|
|
|
|
|
const val = corr?.[k]
|
|
|
|
|
if (typeof val === 'string' && val.includes('de')) {
|
|
|
|
|
const [, b] = val.split('de')
|
|
|
|
|
const y = Number(b.trim())
|
|
|
|
|
return Number.isFinite(y) ? y : 0
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
})()
|
|
|
|
|
const total =
|
|
|
|
|
parseTotal(k) ||
|
|
|
|
|
(() => {
|
|
|
|
|
const val = corr?.[k]
|
|
|
|
|
if (typeof val === 'string' && val.includes('de')) {
|
|
|
|
|
const [, b] = val.split('de')
|
|
|
|
|
const y = Number(b.trim())
|
|
|
|
|
return Number.isFinite(y) ? y : 0
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
})()
|
|
|
|
|
const incorrectas = parseIncorrectas(k)
|
|
|
|
|
const ratio = total > 0 ? Math.round((correctas / total) * 100) : 0
|
|
|
|
|
return { curso: k, correctas, incorrectas, total, ratio }
|
|
|
|
|
@ -262,7 +266,6 @@ const rowsCursos = computed(() => {
|
|
|
|
|
|
|
|
|
|
const recalcular = async () => {
|
|
|
|
|
if (!examenId.value) return
|
|
|
|
|
|
|
|
|
|
cargando.value = true
|
|
|
|
|
try {
|
|
|
|
|
const r = await examenStore.calificarExamen(examenId.value)
|
|
|
|
|
@ -286,17 +289,58 @@ onMounted(async () => {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
/* ====== MISMO BACKGROUND QUE DASH ====== */
|
|
|
|
|
.dashboard-modern {
|
|
|
|
|
position: relative;
|
|
|
|
|
padding: 22px 0;
|
|
|
|
|
font-family: "Times New Roman", Times, serif;
|
|
|
|
|
background: #fbfcff;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dashboard-modern::before {
|
|
|
|
|
content: "";
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset: 0;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
z-index: 0;
|
|
|
|
|
background-image:
|
|
|
|
|
repeating-linear-gradient(
|
|
|
|
|
to right,
|
|
|
|
|
rgba(13, 27, 82, 0.06) 0,
|
|
|
|
|
rgba(13, 27, 82, 0.06) 1px,
|
|
|
|
|
transparent 1px,
|
|
|
|
|
transparent 24px
|
|
|
|
|
),
|
|
|
|
|
repeating-linear-gradient(
|
|
|
|
|
to bottom,
|
|
|
|
|
rgba(13, 27, 82, 0.06) 0,
|
|
|
|
|
rgba(13, 27, 82, 0.06) 1px,
|
|
|
|
|
transparent 1px,
|
|
|
|
|
transparent 24px
|
|
|
|
|
);
|
|
|
|
|
opacity: 0.55;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-container {
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
max-width: 1200px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
padding: 0 24px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.page {
|
|
|
|
|
padding: 16px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
max-width: 1120px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
.mt16 { margin-top: 16px; }
|
|
|
|
|
|
|
|
|
|
.alt {
|
|
|
|
|
background: transparent;
|
|
|
|
|
}
|
|
|
|
|
.mt16 { margin-top: 16px; }
|
|
|
|
|
.alt { background: transparent; }
|
|
|
|
|
|
|
|
|
|
/* ====== HEADER ====== */
|
|
|
|
|
.head {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
@ -305,35 +349,77 @@ onMounted(async () => {
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
margin-bottom: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hTitle {
|
|
|
|
|
margin: 0;
|
|
|
|
|
font-size: 1.85rem;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
color: #0d1b52;
|
|
|
|
|
line-height: 1.15;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hSub {
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
color: var(--ant-colorTextSecondary, #6b7280);
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.headActions {
|
|
|
|
|
min-width: 260px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
}
|
|
|
|
|
.btnSoft, .btnPrimary { border-radius: 12px; font-weight: 900; }
|
|
|
|
|
|
|
|
|
|
.btnSoft, .btnPrimary {
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ====== CARD (igual dash content-card) ====== */
|
|
|
|
|
.card {
|
|
|
|
|
position: relative;
|
|
|
|
|
border-radius: 18px;
|
|
|
|
|
border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.06));
|
|
|
|
|
box-shadow: var(--ant-boxShadowSecondary, 0 10px 28px rgba(0,0,0,.08));
|
|
|
|
|
background: var(--ant-colorBgContainer, #fff);
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card::before {
|
|
|
|
|
content: "";
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset: 0;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
z-index: 0;
|
|
|
|
|
background-image:
|
|
|
|
|
repeating-linear-gradient(
|
|
|
|
|
to right,
|
|
|
|
|
rgba(13, 27, 82, 0.05) 0,
|
|
|
|
|
rgba(13, 27, 82, 0.05) 1px,
|
|
|
|
|
transparent 1px,
|
|
|
|
|
transparent 24px
|
|
|
|
|
),
|
|
|
|
|
repeating-linear-gradient(
|
|
|
|
|
to bottom,
|
|
|
|
|
rgba(13, 27, 82, 0.05) 0,
|
|
|
|
|
rgba(13, 27, 82, 0.05) 1px,
|
|
|
|
|
transparent 1px,
|
|
|
|
|
transparent 24px
|
|
|
|
|
);
|
|
|
|
|
opacity: 0.35;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card :deep(.ant-card-body),
|
|
|
|
|
.card :deep(.ant-card-head) {
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card :deep(.ant-card-body) { padding: 16px; }
|
|
|
|
|
.scoreCard :deep(.ant-card-body) { padding: 18px; }
|
|
|
|
|
|
|
|
|
|
/* ====== SCORE ====== */
|
|
|
|
|
.scoreTop {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
@ -342,6 +428,7 @@ onMounted(async () => {
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chipDone, .chipRank {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
@ -354,6 +441,7 @@ onMounted(async () => {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
color: #111827;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chipDot {
|
|
|
|
|
width: 8px;
|
|
|
|
|
height: 8px;
|
|
|
|
|
@ -367,38 +455,31 @@ onMounted(async () => {
|
|
|
|
|
color: #111827;
|
|
|
|
|
line-height: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scoreLabel {
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.bigProgress { margin-top: 12px; }
|
|
|
|
|
.bigProgressMeta {
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
}
|
|
|
|
|
.bigProgressMeta b { color: #111827; }
|
|
|
|
|
|
|
|
|
|
.advice { margin-top: 12px; border-radius: 14px; }
|
|
|
|
|
|
|
|
|
|
/* KPIs */
|
|
|
|
|
/* ====== KPIs ====== */
|
|
|
|
|
.kpi .kpiK, .kpiWide .kpiK, .noteCard .kpiK {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.kpi .kpiV, .kpiWide .kpiV, .noteCard .kpiV {
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
font-size: 26px;
|
|
|
|
|
font-weight: 950;
|
|
|
|
|
color: #111827;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.kpiHint {
|
|
|
|
|
margin-top: 2px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
@ -419,29 +500,42 @@ onMounted(async () => {
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.miniCircleLabel {
|
|
|
|
|
position: absolute;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
.miniCircleMain { font-weight: 950; font-size: 16px; color: #111827; line-height: 1; }
|
|
|
|
|
|
|
|
|
|
.miniCircleMain {
|
|
|
|
|
font-weight: 950;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
color: #111827;
|
|
|
|
|
line-height: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.miniCircleSub { font-size: 12px; color: #6b7280; }
|
|
|
|
|
|
|
|
|
|
/* Tabla */
|
|
|
|
|
/* ====== TABLE ====== */
|
|
|
|
|
.tableWrap {
|
|
|
|
|
width: 100%;
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
border-radius: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tableWrap :deep(.ant-table-container) { overflow-x: auto; }
|
|
|
|
|
|
|
|
|
|
:deep(.modernTable .ant-table-thead > tr > th) {
|
|
|
|
|
background: rgba(22,119,255,.04);
|
|
|
|
|
background: rgba(13, 27, 82, 0.03);
|
|
|
|
|
color: #0d1b52;
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.courseCell {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.courseDot {
|
|
|
|
|
width: 10px;
|
|
|
|
|
height: 10px;
|
|
|
|
|
@ -450,6 +544,7 @@ onMounted(async () => {
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.courseName { font-weight: 900; color: #111827; line-height: 1.2; }
|
|
|
|
|
.courseMeta { margin-top: 2px; font-size: 12px; color: #6b7280; }
|
|
|
|
|
|
|
|
|
|
@ -467,27 +562,43 @@ onMounted(async () => {
|
|
|
|
|
background: rgba(0,0,0,.03);
|
|
|
|
|
color: #111827;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.pill.good { border-color: rgba(22,119,255,.25); background: rgba(22,119,255,.08); }
|
|
|
|
|
.pill.bad { border-color: rgba(0,0,0,.10); background: rgba(0,0,0,.04); }
|
|
|
|
|
.pill.neutral { opacity: .92; }
|
|
|
|
|
|
|
|
|
|
.empty { margin-top: 12px; }
|
|
|
|
|
|
|
|
|
|
/* ====== MOBILE: FULL WIDTH, SIN ESPACIOS ====== */
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
.dashboard-modern { padding: 0 0 14px; }
|
|
|
|
|
.section-container { max-width: none; padding: 0 !important; margin: 0 !important; }
|
|
|
|
|
.page { max-width: none; padding: 0; }
|
|
|
|
|
|
|
|
|
|
.head { padding: 0 16px; margin-bottom: 10px; }
|
|
|
|
|
.headActions { width: 100%; min-width: 0; justify-content: flex-start; }
|
|
|
|
|
|
|
|
|
|
.headSpace {
|
|
|
|
|
width: 100%;
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.btnSoft, .btnPrimary { width: 100%; }
|
|
|
|
|
|
|
|
|
|
/* cards full width */
|
|
|
|
|
.card {
|
|
|
|
|
border-radius: 0 !important;
|
|
|
|
|
border-left: 0 !important;
|
|
|
|
|
border-right: 0 !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scoreMain { font-size: 36px; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
|
|
.page { padding: 12px; }
|
|
|
|
|
.head { padding: 0 12px; }
|
|
|
|
|
.scoreMain { font-size: 32px; }
|
|
|
|
|
.bigProgressMeta { flex-direction: column; align-items: flex-start; }
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</style>
|