优化登录与任务管理相关页面交互
This commit is contained in:
+154
-58
@@ -1,36 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {reactive, ref} from "vue";
|
import { reactive, ref } from "vue";
|
||||||
import {ElMessage, type FormInstance, type FormRules} from "element-plus";
|
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
|
||||||
import type {InternalRuleItem, Value} from "async-validator";
|
import type { InternalRuleItem, Value } from "async-validator";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { login } from "@/api/login";
|
import { login } from "@/api/login";
|
||||||
|
|
||||||
interface RegisterData {
|
interface RegisterData {
|
||||||
username: string
|
username: string;
|
||||||
password: string
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const registerData = reactive<RegisterData>({
|
const registerData = reactive<RegisterData>({
|
||||||
username: "",
|
username: "",
|
||||||
password: ""
|
password: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const loginForm = ref<FormInstance>();
|
const loginForm = ref<FormInstance>();
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
const rules = reactive<FormRules<RegisterData>>({
|
const rules = reactive<FormRules<RegisterData>>({
|
||||||
password: [
|
password: [{ validator: isNotEmpty, message: "请输入密码!" }],
|
||||||
{
|
username: [{ validator: isNotEmpty, message: "请输入账号!" }],
|
||||||
validator: isNotEmpty,
|
});
|
||||||
message:"请输入密码!"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
username: [
|
|
||||||
{
|
|
||||||
validator: isNotEmpty,
|
|
||||||
message:"请输入账号!"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
function isNotEmpty(rule: InternalRuleItem, value: Value, callback: any) {
|
function isNotEmpty(rule: InternalRuleItem, value: Value, callback: any) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
@@ -41,52 +32,157 @@ function isNotEmpty(rule: InternalRuleItem, value: Value, callback: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return
|
if (!formEl || loading.value) return;
|
||||||
await formEl.validate((valid, fields) => {
|
await formEl.validate(async (valid) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
login(registerData.username, registerData.password).then(result =>{
|
loading.value = true;
|
||||||
if (result.code === 200) {
|
try {
|
||||||
localStorage.setItem("isLoggedIn", "true");
|
const result = await login(registerData.username, registerData.password);
|
||||||
ElMessage.success(result.message)
|
if (result.code === 200) {
|
||||||
router.push("/welcome")
|
localStorage.setItem("isLoggedIn", "true");
|
||||||
} else {
|
ElMessage.success(result.message);
|
||||||
ElMessage.error(result.message)
|
await router.push("/welcome");
|
||||||
}
|
} else {
|
||||||
})
|
ElMessage.error(result.message);
|
||||||
} else {
|
}
|
||||||
console.log('error submit!', fields)
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="login">
|
<section class="login-page">
|
||||||
<el-form ref="loginForm" :model = "registerData">
|
<div class="login-panel surface-card">
|
||||||
<el-form-item label="账号:" :rules="rules.username" prop="username">
|
<div class="hero">
|
||||||
<el-input v-model= "registerData.username"/>
|
<p class="hero-kicker">LPT · Focus Flow</p>
|
||||||
</el-form-item>
|
<h1>今天的学习,从一次清晰登录开始</h1>
|
||||||
<el-form-item label="密码:" :rules="rules.password" prop="password">
|
<p>
|
||||||
<el-input v-model= "registerData.password" type="password"/>
|
你将看到任务优先级、学习会话和复习数据在同一个系统里自然衔接。
|
||||||
</el-form-item>
|
</p>
|
||||||
<el-form-item>
|
<ul class="hero-points">
|
||||||
<el-button type="primary" @click="submitForm(loginForm)" style="width: 100%;">登录</el-button>
|
<li>明确学习任务</li>
|
||||||
</el-form-item>
|
<li>记录会话与残片</li>
|
||||||
</el-form>
|
<li>持续复盘</li>
|
||||||
</div>
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-area">
|
||||||
|
<h2>账号登录</h2>
|
||||||
|
<el-form ref="loginForm" :model="registerData" class="login-form">
|
||||||
|
<el-form-item label="账号" :rules="rules.username" prop="username">
|
||||||
|
<el-input
|
||||||
|
v-model="registerData.username"
|
||||||
|
placeholder="请输入账号"
|
||||||
|
@keyup.enter="submitForm(loginForm)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码" :rules="rules.password" prop="password">
|
||||||
|
<el-input
|
||||||
|
v-model="registerData.password"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
placeholder="请输入密码"
|
||||||
|
@keyup.enter="submitForm(loginForm)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
class="submit-btn"
|
||||||
|
:loading="loading"
|
||||||
|
@click="submitForm(loginForm)"
|
||||||
|
>
|
||||||
|
进入系统
|
||||||
|
</el-button>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
*{
|
.login-page {
|
||||||
margin: 0;
|
min-height: calc(100vh - 240px);
|
||||||
padding: 0;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login {
|
.login-panel {
|
||||||
min-height: 25vh;
|
width: min(980px, 100%);
|
||||||
min-width: 30vw;
|
display: grid;
|
||||||
background: #22b9fa;
|
grid-template-columns: 1.1fr 1fr;
|
||||||
|
gap: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
padding: 36px;
|
||||||
|
background: linear-gradient(150deg, var(--green-800) 0%, var(--green-600) 100%);
|
||||||
|
color: #effcf4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-kicker {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
letter-spacing: 1.4px;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
margin: 14px 0 10px;
|
||||||
|
line-height: 1.35;
|
||||||
|
font-size: clamp(22px, 2.6vw, 32px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero p {
|
||||||
|
margin: 0;
|
||||||
|
opacity: 0.88;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-points {
|
||||||
|
margin: 20px 0 0;
|
||||||
|
padding-left: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-points li {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-area {
|
||||||
|
background: var(--surface-strong);
|
||||||
|
padding: 32px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-area h2 {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
color: var(--green-900);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form :deep(.el-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.login-panel {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.login-page {
|
||||||
|
min-height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero,
|
||||||
|
.form-area {
|
||||||
|
padding: 22px 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+85
-16
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import request from "@/utils/request";
|
import request from "@/utils/request";
|
||||||
|
|
||||||
interface ReviewTask {
|
interface ReviewTask {
|
||||||
@@ -13,6 +13,12 @@ interface ReviewTask {
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const tasks = ref<ReviewTask[]>([]);
|
const tasks = ref<ReviewTask[]>([]);
|
||||||
|
|
||||||
|
const summary = computed(() => ({
|
||||||
|
totalTasks: tasks.value.length,
|
||||||
|
totalReports: tasks.value.reduce((acc, item) => acc + Number(item.reportCount || 0), 0),
|
||||||
|
totalFragments: tasks.value.reduce((acc, item) => acc + Number(item.fragmentCount || 0), 0),
|
||||||
|
}));
|
||||||
|
|
||||||
const loadTasks = async () => {
|
const loadTasks = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -35,27 +41,90 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-card>
|
<section class="review-page">
|
||||||
<template #header>
|
<header class="surface-card review-head">
|
||||||
<div class="header">
|
<div>
|
||||||
<span>复习任务总览</span>
|
<h1 class="page-title">复习总览</h1>
|
||||||
<el-button type="primary" plain @click="loadTasks">刷新</el-button>
|
<p class="page-subtitle">根据学习报告与残片数量,快速识别需要回顾的任务</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<el-button type="success" plain :loading="loading" @click="loadTasks">刷新</el-button>
|
||||||
|
</header>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="tasks" stripe>
|
<div class="summary-grid">
|
||||||
<el-table-column prop="taskName" label="任务名" min-width="180" />
|
<article class="surface-card metric-card">
|
||||||
<el-table-column prop="effectiveTime" label="累计有效学习时长" min-width="140" />
|
<span>任务数</span>
|
||||||
<el-table-column prop="reportCount" label="学习报告数" min-width="120" />
|
<strong>{{ summary.totalTasks }}</strong>
|
||||||
<el-table-column prop="fragmentCount" label="学习残片数" min-width="120" />
|
</article>
|
||||||
</el-table>
|
<article class="surface-card metric-card">
|
||||||
</el-card>
|
<span>学习报告总数</span>
|
||||||
|
<strong>{{ summary.totalReports }}</strong>
|
||||||
|
</article>
|
||||||
|
<article class="surface-card metric-card">
|
||||||
|
<span>学习残片总数</span>
|
||||||
|
<strong>{{ summary.totalFragments }}</strong>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article class="surface-card table-card">
|
||||||
|
<el-table v-loading="loading" :data="tasks" stripe>
|
||||||
|
<el-table-column prop="taskName" label="任务名" min-width="180" />
|
||||||
|
<el-table-column prop="effectiveTime" label="累计有效学习时长" min-width="150" />
|
||||||
|
<el-table-column prop="reportCount" label="学习报告数" min-width="120" />
|
||||||
|
<el-table-column prop="fragmentCount" label="学习残片数" min-width="120" />
|
||||||
|
</el-table>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.header {
|
.review-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-head {
|
||||||
|
padding: 20px 22px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card {
|
||||||
|
padding: 16px 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card span {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card strong {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 30px;
|
||||||
|
line-height: 1;
|
||||||
|
color: var(--green-900);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-card {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.summary-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-head {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+139
-133
@@ -1,19 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, onMounted, onUnmounted, ref} from 'vue';
|
import { computed, onMounted, onUnmounted, ref } from "vue";
|
||||||
import request from "@/utils/request";
|
import request from "@/utils/request";
|
||||||
import {ElMessage} from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import {useRoute, useRouter} from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
const taskId = route.params.taskId ? Number(route.params.taskId) : null;
|
const taskId = route.params.taskId ? Number(route.params.taskId) : null;
|
||||||
const buttonName = route.meta.buttonText;
|
const buttonName = route.meta.buttonText as string;
|
||||||
|
|
||||||
|
const taskName = ref("");
|
||||||
const taskName = ref('');
|
const taskDescription = ref("");
|
||||||
const taskDescription = ref('');
|
const materialURL = ref("");
|
||||||
const materialURL = ref('');
|
|
||||||
const priority = ref({
|
const priority = ref({
|
||||||
urgency: 0,
|
urgency: 0,
|
||||||
importance: 0,
|
importance: 0,
|
||||||
@@ -23,33 +22,34 @@ const priority = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const priorityOptions = [0, 1, 2, 3, 4, 5];
|
const priorityOptions = [0, 1, 2, 3, 4, 5];
|
||||||
|
const pageTitle = computed(() => (route.name === "update-task" ? "更新学习任务" : "创建学习任务"));
|
||||||
|
const pageSubtitle = computed(() =>
|
||||||
|
route.name === "update-task"
|
||||||
|
? "修改任务信息后保存,后续学习会话将使用最新内容"
|
||||||
|
: "填写任务基本信息与优先级维度,帮助系统更好排序"
|
||||||
|
);
|
||||||
|
|
||||||
const createTask = () => {
|
const createTask = () => {
|
||||||
console.log('创建任务', {
|
request
|
||||||
taskName: taskName.value,
|
.post("/tasks", {
|
||||||
taskDescription: taskDescription.value,
|
taskName: taskName.value,
|
||||||
priority: priority.value,
|
taskDescription: taskDescription.value,
|
||||||
});
|
materialURL: materialURL.value,
|
||||||
|
...priority.value,
|
||||||
request.post("/tasks", {
|
})
|
||||||
taskName: taskName.value,
|
.then((result) => {
|
||||||
taskDescription: taskDescription.value,
|
if (result.code === 200) {
|
||||||
materialURL: materialURL.value,
|
ElMessage.success("创建任务成功");
|
||||||
...priority.value
|
router.back();
|
||||||
}).then(result => {
|
} else {
|
||||||
if (result.code == 200) {
|
ElMessage.error("任务创建失败:" + result.message);
|
||||||
ElMessage.success("创建任务成功,任务id:" + result.message)
|
}
|
||||||
router.back()
|
});
|
||||||
} else {
|
|
||||||
ElMessage.error("任务创建失败,错误原因:" + result.message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadTask = () => {
|
const loadTask = () => {
|
||||||
console.info("开始加载任务信息")
|
|
||||||
if (taskId !== null) {
|
if (taskId !== null) {
|
||||||
request.get(`/tasks/${taskId}`, {}).then(result => {
|
request.get(`/tasks/${taskId}`, {}).then((result) => {
|
||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
const data = result.data;
|
const data = result.data;
|
||||||
taskName.value = data.taskName;
|
taskName.value = data.taskName;
|
||||||
@@ -70,46 +70,41 @@ const loadTask = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateTask = () => {
|
const updateTask = () => {
|
||||||
console.log('更新任务', {
|
request
|
||||||
taskName: taskName.value,
|
.put("/tasks/" + taskId, {
|
||||||
taskDescription: taskDescription.value,
|
id: taskId,
|
||||||
priority: priority.value,
|
taskName: taskName.value,
|
||||||
});
|
taskDescription: taskDescription.value,
|
||||||
|
materialURL: materialURL.value,
|
||||||
request.put("/tasks/" + taskId, {
|
...priority.value,
|
||||||
id: taskId,
|
})
|
||||||
taskName: taskName.value,
|
.then((result) => {
|
||||||
taskDescription: taskDescription.value,
|
if (result.code === 200) {
|
||||||
materialURL: materialURL.value,
|
ElMessage.success("更新任务成功");
|
||||||
...priority.value
|
router.back();
|
||||||
}).then(result => {
|
} else {
|
||||||
if (result.code == 200) {
|
ElMessage.error("任务更新失败:" + result.message);
|
||||||
ElMessage.success("更新任务成功" + result.message)
|
}
|
||||||
router.back()
|
});
|
||||||
} else {
|
|
||||||
ElMessage.error("任务更新失败,错误原因:" + result.message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelTask = () => {
|
const cancelTask = () => {
|
||||||
ElMessage.success("已取消创建")
|
ElMessage.info("已取消操作");
|
||||||
router.back()
|
router.back();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const submitTask = () => {
|
const submitTask = () => {
|
||||||
switch (route.name) {
|
switch (route.name) {
|
||||||
case 'add-task':
|
case "add-task":
|
||||||
createTask();
|
createTask();
|
||||||
break;
|
break;
|
||||||
case 'update-task':
|
case "update-task":
|
||||||
updateTask();
|
updateTask();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ElMessage.error('未知操作类型');
|
ElMessage.error("未知操作类型");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const screenWidth = ref(window.innerWidth);
|
const screenWidth = ref(window.innerWidth);
|
||||||
|
|
||||||
@@ -117,123 +112,134 @@ const updateWidth = () => {
|
|||||||
screenWidth.value = window.innerWidth;
|
screenWidth.value = window.innerWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('resize', updateWidth)
|
window.addEventListener("resize", updateWidth);
|
||||||
if (route.meta.action === 'update' && taskId !== null) {
|
if (route.meta.action === "update" && taskId !== null) {
|
||||||
loadTask();
|
loadTask();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onUnmounted(() => window.removeEventListener('resize', updateWidth));
|
|
||||||
|
|
||||||
const columnSpan = computed(() => {
|
onUnmounted(() => window.removeEventListener("resize", updateWidth));
|
||||||
return screenWidth.value <= 768 ? 20 : 8;
|
|
||||||
});
|
const isMobile = computed(() => screenWidth.value <= 900);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form label-width="100px">
|
<section class="task-form-page">
|
||||||
<el-form-item label="任务名:">
|
<header class="surface-card form-header">
|
||||||
<el-input v-model="taskName" placeholder="请输入任务名"></el-input>
|
<h1 class="page-title">{{ pageTitle }}</h1>
|
||||||
</el-form-item>
|
<p class="page-subtitle">{{ pageSubtitle }}</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
<el-form-item label="任务描述:">
|
<el-form label-position="top" class="surface-card form-shell">
|
||||||
<el-input
|
<div class="group">
|
||||||
v-model="taskDescription"
|
<h3>基础信息</h3>
|
||||||
type="textarea"
|
<el-form-item label="任务名称">
|
||||||
placeholder="请输入任务描述"
|
<el-input v-model="taskName" placeholder="例如:Vue3 组件通信实践" />
|
||||||
rows="6"
|
</el-form-item>
|
||||||
></el-input>
|
<el-form-item label="任务描述">
|
||||||
</el-form-item>
|
<el-input v-model="taskDescription" type="textarea" :rows="5" placeholder="请输入任务描述" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="学习材料地址">
|
||||||
|
<el-input v-model="materialURL" placeholder="例如:https://..." />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-form-item label="材料地址:">
|
<div class="group">
|
||||||
<el-input v-model="materialURL" placeholder="请输入学习材料URL"></el-input>
|
<h3>优先级维度</h3>
|
||||||
</el-form-item>
|
<div class="priority-grid" :class="{ mobile: isMobile }">
|
||||||
|
|
||||||
<el-form-item label="优先级:">
|
|
||||||
<el-row :gutter="10">
|
|
||||||
<el-col :span="columnSpan">
|
|
||||||
<el-form-item label="急迫性">
|
<el-form-item label="急迫性">
|
||||||
<el-select v-model="priority.urgency">
|
<el-select v-model="priority.urgency">
|
||||||
<el-option
|
<el-option v-for="item in priorityOptions" :key="'u' + item" :label="item" :value="item" />
|
||||||
v-for="item in priorityOptions"
|
|
||||||
:key="item"
|
|
||||||
:label="item"
|
|
||||||
:value="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="columnSpan">
|
|
||||||
<el-form-item label="重要性">
|
<el-form-item label="重要性">
|
||||||
<el-select v-model="priority.importance">
|
<el-select v-model="priority.importance">
|
||||||
<el-option
|
<el-option v-for="item in priorityOptions" :key="'i' + item" :label="item" :value="item" />
|
||||||
v-for="item in priorityOptions"
|
|
||||||
:key="item"
|
|
||||||
:label="item"
|
|
||||||
:value="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="columnSpan">
|
|
||||||
<el-form-item label="内容难度">
|
<el-form-item label="内容难度">
|
||||||
<el-select v-model="priority.contentDifficulty">
|
<el-select v-model="priority.contentDifficulty">
|
||||||
<el-option
|
<el-option v-for="item in priorityOptions" :key="'d' + item" :label="item" :value="item" />
|
||||||
v-for="item in priorityOptions"
|
|
||||||
:key="item"
|
|
||||||
:label="item"
|
|
||||||
:value="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="columnSpan">
|
|
||||||
<el-form-item label="未来价值">
|
<el-form-item label="未来价值">
|
||||||
<el-select v-model="priority.futureValue">
|
<el-select v-model="priority.futureValue">
|
||||||
<el-option
|
<el-option v-for="item in priorityOptions" :key="'f' + item" :label="item" :value="item" />
|
||||||
v-for="item in priorityOptions"
|
|
||||||
:key="item"
|
|
||||||
:label="item"
|
|
||||||
:value="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="columnSpan">
|
|
||||||
<el-form-item label="主观优先级">
|
<el-form-item label="主观优先级">
|
||||||
<el-select v-model="priority.subjectivePriority">
|
<el-select v-model="priority.subjectivePriority">
|
||||||
<el-option
|
<el-option v-for="item in priorityOptions" :key="'s' + item" :label="item" :value="item" />
|
||||||
v-for="item in priorityOptions"
|
|
||||||
:key="item"
|
|
||||||
:label="item"
|
|
||||||
:value="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item>
|
<div class="action-row">
|
||||||
<el-button type="primary" @click="submitTask">{{ buttonName }}</el-button>
|
<el-button type="success" size="large" @click="submitTask">{{ buttonName }}</el-button>
|
||||||
<el-button @click="cancelTask">取消</el-button>
|
<el-button size="large" @click="cancelTask">取消</el-button>
|
||||||
</el-form-item>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.el-form-item {
|
.task-form-page {
|
||||||
margin-bottom: 15px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
padding: 20px 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-shell {
|
||||||
|
padding: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group + .group {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group h3 {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
color: var(--green-900);
|
||||||
|
}
|
||||||
|
|
||||||
|
.priority-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 0 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.priority-grid.mobile {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-row {
|
||||||
|
margin-top: 8px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.el-col {
|
.form-shell {
|
||||||
width: 100% !important;
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-row .el-button {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+91
-76
@@ -9,98 +9,113 @@ const startReview = () => {
|
|||||||
router.push("/review");
|
router.push("/review");
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-container class="container">
|
<section class="welcome-page">
|
||||||
<el-header class="header">
|
<div class="welcome-banner surface-card">
|
||||||
欢迎回来,今天也稳步推进学习计划
|
<div>
|
||||||
</el-header>
|
<h1 class="page-title">欢迎回来,准备好继续学习了吗?</h1>
|
||||||
|
<p class="page-subtitle">
|
||||||
|
先挑选任务开始一次会话,再在复习页回顾你的学习轨迹。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<el-tag type="success" effect="dark" size="large">今日模式:稳步推进</el-tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="quick-grid">
|
||||||
|
<article class="quick-card surface-card">
|
||||||
|
<h3>学习会话</h3>
|
||||||
|
<p>进入任务列表,选择当前最重要的一项并开始学习计时。</p>
|
||||||
|
<el-button type="success" size="large" @click="startStudy">开始学习</el-button>
|
||||||
|
</article>
|
||||||
|
|
||||||
<el-main>
|
<article class="quick-card surface-card">
|
||||||
<el-row :gutter="20">
|
<h3>复习回看</h3>
|
||||||
<el-col :span="18">
|
<p>查看学习报告与残片数量,明确哪些内容需要优先复习。</p>
|
||||||
<el-card class="progress-card" shadow="always">
|
<el-button plain type="success" size="large" @click="startReview">开始复习</el-button>
|
||||||
<div class="progress-text">学习进度总揽</div>
|
</article>
|
||||||
</el-card>
|
</div>
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="3">
|
<div class="tips-board surface-card">
|
||||||
<div class="button-group">
|
<h3>建议流程</h3>
|
||||||
<el-button type="success" size="large" @click="startStudy" plain>开始学习</el-button>
|
<ol>
|
||||||
<el-button type="primary" size="large" @click="startReview" plain>开始复习</el-button>
|
<li>进入学习页,确认任务材料地址与优先级。</li>
|
||||||
</div>
|
<li>开始会话并在休息时记录学习残片。</li>
|
||||||
</el-col>
|
<li>结束会话后填写总结,再回到复习页检视数据。</li>
|
||||||
</el-row>
|
</ol>
|
||||||
</el-main>
|
</div>
|
||||||
</el-container>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
*{
|
.welcome-page {
|
||||||
margin: 0px;
|
|
||||||
/*padding: 0;*/
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
min-height: 100vh;
|
|
||||||
font-family: "Helvetica Neue", Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
border-bottom: 1px solid #ebeef5;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-card {
|
|
||||||
height: 400px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-text {
|
|
||||||
font-size: 18px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-group {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 20px;
|
gap: 16px;
|
||||||
margin-top: 80px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.button-group .el-button {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.welcome-banner {
|
||||||
/*滚动样式*/
|
padding: 20px 22px;
|
||||||
.marquee-wrapper {
|
display: flex;
|
||||||
overflow: hidden;
|
align-items: flex-start;
|
||||||
white-space: nowrap;
|
justify-content: space-between;
|
||||||
position: relative;
|
gap: 16px;
|
||||||
height: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.marquee-content {
|
.quick-grid {
|
||||||
display: inline-block;
|
display: grid;
|
||||||
position: absolute;
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
white-space: nowrap;
|
gap: 16px;
|
||||||
will-change: transform;
|
|
||||||
animation: scroll-left 15s linear infinite;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes scroll-left {
|
.quick-card {
|
||||||
0% {
|
padding: 22px;
|
||||||
transform: translateX(100%);
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-card h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--green-900);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-card p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-card .el-button {
|
||||||
|
margin-top: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-board {
|
||||||
|
padding: 20px 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-board h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--green-900);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-board ol {
|
||||||
|
margin: 10px 0 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-board li + li {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.welcome-banner {
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
100% {
|
|
||||||
transform: translateX(-100%);
|
.quick-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user