finish Question Page component function
This commit is contained in:
parent
cd78b47dcb
commit
5d0a4b2834
@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
<title>Make a Quick Exame!</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
1
package-lock.json
generated
1
package-lock.json
generated
@ -8,6 +8,7 @@
|
||||
"name": "quick-exam-ui",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.6.3",
|
||||
"element-plus": "^2.4.4",
|
||||
"pinia": "^2.1.7",
|
||||
|
@ -13,6 +13,7 @@
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.6.3",
|
||||
"element-plus": "^2.4.4",
|
||||
"pinia": "^2.1.7",
|
||||
|
20
src/App.vue
20
src/App.vue
@ -1,21 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
import { RouterLink, RouterView } from 'vue-router';
|
||||
import HelloWorld from './components/HelloWorld.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
|
||||
|
||||
<div class="wrapper">
|
||||
<HelloWorld msg="You did it!" />
|
||||
|
||||
<nav>
|
||||
<RouterLink to="/">Home</RouterLink>
|
||||
<RouterLink to="/about">About</RouterLink>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<nav>
|
||||
<RouterLink to="/">Home</RouterLink>
|
||||
<RouterLink to="/about">About</RouterLink>
|
||||
</nav>
|
||||
|
||||
<RouterView />
|
||||
</template>
|
||||
|
@ -1,87 +1,154 @@
|
||||
<template>
|
||||
<!-- Condition Filter From -->
|
||||
<el-form :inline="true" :model="query_condition" class="demo-form-inline">
|
||||
<el-form-item label="发布状态">
|
||||
<el-select v-model="query_condition.is_published" placeholder="请选择">
|
||||
<el-option label="全部" value="-1" />
|
||||
<el-option label="已发布" value="1" />
|
||||
<el-option label="编辑中" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题型">
|
||||
<el-select v-model="query_condition.types" multiple placeholder="请选择">
|
||||
<el-option v-for="id in type_ids" :key="id" :label="getQuestionTypeText(id)" :value="id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签">
|
||||
<el-select v-model="query_condition.tag_ids" multiple placeholder="请选择">
|
||||
<el-option v-for="tag in tag_list" :key="tag.id" :label="tag.name" :value="tag.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键字">
|
||||
<el-input v-model="query_condition.search" placeholder="请输入关键字" />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker v-model="timerange_create" type="datarange" range-separator="至" value-format="x"
|
||||
start-placeholder="开始日期" end-placeholder="结束日期" @change="createTimeRangeChange" />
|
||||
</el-form-item>
|
||||
<el-form-item label="更新时间">
|
||||
<el-date-picker v-model="timerange_update" type="datarange" range-separator="至" value-format="x"
|
||||
start-placeholder="开始日期" end-placeholder="结束日期" @change="updateTimeRangeChange" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="fetchQuestionList">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- Table -->
|
||||
<el-table :data="page_data.items" :table-layout="'auto'" :default-sort="{ prop: 'id', order: 'ascending' }"
|
||||
:border="true" :disabled="disabled" @sort-change="handleSortChange">
|
||||
<el-table-column prop="id" label="ID" :sortable="'custom'" />
|
||||
<el-table-column prop="title" label="标题" :sortable="'custom'" />
|
||||
<el-table-column prop="type" label="题型" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ getQuestionTypeText(scope.row.type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="正确率" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ scope.row.correct_count }} / {{ scope.row.reference_count }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="reference_count" label="引用次数" :sortable="'custom'" />
|
||||
<el-table-column prop="is_published" label="发布状态" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.is_published" type="success">已发布</el-tag>
|
||||
<el-tag v-else type="info">编辑中</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ scope.row.created_at }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="更新时间" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ scope.row.updated_at }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- edit -->
|
||||
<el-table-column align="right">
|
||||
<template #header>
|
||||
操作
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- Condition Filter From -->
|
||||
<el-form :inline="true" :model="query_condition" class="demo-form-inline">
|
||||
<el-form-item label="发布状态">
|
||||
<el-select v-model="publish_statu" placeholder="请选择" @change="handlePublishChange">
|
||||
<el-option label="全部" value="-1" />
|
||||
<el-option label="已发布" value="1" />
|
||||
<el-option label="编辑中" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题型">
|
||||
<el-select v-model="types" multiple placeholder="请选择" @change="handleTypeChange">
|
||||
<el-option label="单选题" value="0" />
|
||||
<el-option label="多选题" value="1" />
|
||||
<el-option label="判断题" value="2" />
|
||||
<el-option label="填空题" value="3" />
|
||||
<el-option label="简答题" value="4" />
|
||||
<el-option label="文件上传" value="5" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签">
|
||||
<el-select v-model="query_condition.tag_ids" multiple placeholder="请选择">
|
||||
<el-option v-for="tag in tag_list" :key="tag.id" :label="tag.name" :value="tag.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键字">
|
||||
<el-input v-model="query_condition.search" placeholder="请输入关键字" />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="timerange_create"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
value-format="x"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="createTimeRangeChange"
|
||||
/>
|
||||
<el-button
|
||||
:icon="CircleCloseFilled"
|
||||
@click="
|
||||
timerange_create = [];
|
||||
query_condition.after_create_time = 0;
|
||||
query_condition.before_create_time = 0;
|
||||
"
|
||||
type="info"
|
||||
text
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="更新时间">
|
||||
<el-date-picker
|
||||
v-model="timerange_update"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
value-format="x"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="updateTimeRangeChange"
|
||||
/>
|
||||
<el-button
|
||||
:icon="CircleCloseFilled"
|
||||
@click="
|
||||
timerange_update = [];
|
||||
query_condition.after_update_time = 0;
|
||||
query_condition.before_update_time = 0;
|
||||
"
|
||||
type="info"
|
||||
text
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="fetchQuestionList">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- Table -->
|
||||
<el-table
|
||||
:data="page_data.items"
|
||||
:table-layout="'auto'"
|
||||
:default-sort="{ prop: 'id', order: 'ascending' }"
|
||||
:border="true"
|
||||
:disabled="disabled"
|
||||
@sort-change="handleSortChange"
|
||||
>
|
||||
<el-table-column prop="id" label="ID" :sortable="'custom'" />
|
||||
<el-table-column prop="title" label="标题" :sortable="'custom'" />
|
||||
<el-table-column prop="type" label="题型" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ getQuestionTypeText(scope.row.type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="正确率" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ scope.row.correct_count.value / scope.row.reference_count.value }} %
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="reference_count" label="引用次数" :sortable="'custom'" />
|
||||
<el-table-column prop="is_published" label="发布状态" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.is_published" type="success">已发布</el-tag>
|
||||
<el-tag v-else type="info">编辑中</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="标签">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.tags.length === 0">无</div>
|
||||
<div v-else-if="scope.row.tags.length > 3">
|
||||
<el-tag v-for="tag in scope.row.tags.slice(0, 3)" :key="tag.id" :color="tag.color">{{
|
||||
tag.name
|
||||
}}</el-tag>
|
||||
<el-tag type="info">...</el-tag>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-tag v-for="tag in scope.row.tags" :key="tag.id" type="info">{{ tag.name }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ scope.row.created_at }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="更新时间" :sortable="'custom'">
|
||||
<template #default="scope">
|
||||
{{ scope.row.updated_at }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- edit -->
|
||||
<el-table-column align="right">
|
||||
<template #header> 操作 </template>
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- Pagination -->
|
||||
<el-pagination v-model:current-page="page_data.page" v-model:page-size="page_data.page_size" :page-sizes="[10, 50, 100]"
|
||||
:disabled="disabled" :background="true" layout="prev, pager, next, total, jumper, sizes"
|
||||
:total="page_data.total_count" @current-change="handlePageChange" />
|
||||
<!-- Pagination -->
|
||||
<el-pagination
|
||||
v-model:current-page="page_data.page"
|
||||
v-model:page-size="page_data.page_size"
|
||||
:page-sizes="[10, 50, 100]"
|
||||
:disabled="disabled"
|
||||
:background="true"
|
||||
layout="prev, pager, next, total, jumper, sizes"
|
||||
:total="page_data.total_count"
|
||||
@current-change="handlePageChange"
|
||||
@size-change="handlePageSizeChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@ -92,90 +159,109 @@ import { getQuestionTypeText, QuestionType } from '@/interfaces/question';
|
||||
import type { Tag } from '@/interfaces/tag';
|
||||
import { isNumber } from 'element-plus/es/utils/types.mjs';
|
||||
import { getQuestionsByPage } from '@/apis/question';
|
||||
import { CircleCloseFilled } from '@element-plus/icons-vue';
|
||||
|
||||
const timerange_create = ref<number[]>([])
|
||||
const timerange_update = ref<number[]>([])
|
||||
const createTimeRangeChange = (val: number[]) => {
|
||||
query_condition.value.after_create_time = val[0]
|
||||
query_condition.value.before_create_time = val[1]
|
||||
}
|
||||
const updateTimeRangeChange = (val: number[]) => {
|
||||
query_condition.value.after_update_time = val[0]
|
||||
query_condition.value.before_update_time = val[1]
|
||||
}
|
||||
const timerange_create = ref<number[]>([]);
|
||||
const timerange_update = ref<number[]>([]);
|
||||
const createTimeRangeChange = (val: string[]) => {
|
||||
query_condition.value.after_create_time = Number(val[0]) / 1000;
|
||||
query_condition.value.before_create_time = Number(val[1]) / 1000;
|
||||
};
|
||||
const updateTimeRangeChange = (val: string[]) => {
|
||||
query_condition.value.after_update_time = Number(val[0]) / 1000;
|
||||
query_condition.value.before_update_time = Number(val[1]) / 1000;
|
||||
};
|
||||
|
||||
const type_ids = ref<number[]>([])
|
||||
const disabled = ref<boolean>(false); // before data loaded, disable pagination
|
||||
|
||||
const disabled = ref<boolean>(false) // before data loaded, disable pagination
|
||||
const publish_statu = ref<string>('-1');
|
||||
const types = ref<string[]>([]);
|
||||
|
||||
const page_data = ref<QuestionPage>({
|
||||
page: 0,
|
||||
page_size: 0,
|
||||
total_count: 0,
|
||||
total_page: 0,
|
||||
items: []
|
||||
})
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
total_count: 0,
|
||||
total_page: 0,
|
||||
items: [],
|
||||
});
|
||||
|
||||
const tag_list = ref<Tag[]>([])
|
||||
const tag_list = ref<Tag[]>([]);
|
||||
|
||||
const query_condition = ref<QuestionQueryCondition>({
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
sort_by: 'id',
|
||||
sort_order: ORDER_TYPE.ASC,
|
||||
search: '',
|
||||
is_published: -1,
|
||||
tag_ids: [],
|
||||
types: [],
|
||||
after_create_time: 0,
|
||||
before_create_time: 0,
|
||||
after_update_time: 0,
|
||||
before_update_time: 0
|
||||
})
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
sort_by: 'id',
|
||||
sort_order: ORDER_TYPE.ASC,
|
||||
search: '',
|
||||
is_published: -1,
|
||||
tag_ids: [],
|
||||
types: [],
|
||||
after_create_time: 0,
|
||||
before_create_time: 0,
|
||||
after_update_time: 0,
|
||||
before_update_time: 0,
|
||||
});
|
||||
|
||||
const handlePageChange = (val: number) => {
|
||||
query_condition.value.page = val
|
||||
fetchQuestionList()
|
||||
query_condition.value.page = page_data.value.page
|
||||
query_condition.value.page_size = page_data.value.page_size
|
||||
}
|
||||
query_condition.value.page = val;
|
||||
fetchQuestionList();
|
||||
query_condition.value.page = page_data.value.page;
|
||||
query_condition.value.page_size = page_data.value.page_size;
|
||||
};
|
||||
|
||||
const handlePublishChange = (val: string) => {
|
||||
query_condition.value.is_published = Number(val);
|
||||
};
|
||||
|
||||
const handleTypeChange = (val: string[]) => {
|
||||
types.value = val;
|
||||
query_condition.value.types = val.map((item) => Number(item));
|
||||
};
|
||||
|
||||
const handlePageSizeChange = (val: number) => {
|
||||
query_condition.value.page_size = val;
|
||||
fetchQuestionList();
|
||||
query_condition.value.page = page_data.value.page;
|
||||
query_condition.value.page_size = page_data.value.page_size;
|
||||
};
|
||||
|
||||
const handleSortChange = (val: any) => {
|
||||
query_condition.value.sort_by = val.prop
|
||||
query_condition.value.sort_order = val.order === 'ascending' ? ORDER_TYPE.ASC : ORDER_TYPE.DESC
|
||||
fetchQuestionList()
|
||||
}
|
||||
query_condition.value.sort_by = val.prop;
|
||||
query_condition.value.sort_order = val.order === 'ascending' ? ORDER_TYPE.ASC : ORDER_TYPE.DESC;
|
||||
fetchQuestionList();
|
||||
};
|
||||
|
||||
const handleEdit = (index: number, row: any) => {
|
||||
// todo: go to edit question view
|
||||
}
|
||||
// todo: go to edit question view
|
||||
};
|
||||
|
||||
const handleDelete = (index: number, row: any) => {
|
||||
// todo: pop up a warning
|
||||
}
|
||||
// todo: pop up a warning
|
||||
};
|
||||
|
||||
const fetchQuestionList = () => {
|
||||
disabled.value = true
|
||||
getQuestionsByPage(query_condition.value).then((res) => {
|
||||
page_data.value = res
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
disabled.value = true;
|
||||
getQuestionsByPage(query_condition.value)
|
||||
.then((res) => {
|
||||
page_data.value = res;
|
||||
})
|
||||
disabled.value = false
|
||||
}
|
||||
|
||||
// on mounted
|
||||
const mounted = () => {
|
||||
for (let key in QuestionType) {
|
||||
if (isNumber(key)) {
|
||||
type_ids.value.push(Number(key))
|
||||
}
|
||||
}
|
||||
// todo get tag list
|
||||
fetchQuestionList()
|
||||
|
||||
disabled.value = false
|
||||
}
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
disabled.value = false;
|
||||
};
|
||||
|
||||
// todo get tag list
|
||||
fetchQuestionList();
|
||||
disabled.value = false;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.demo-form-inline {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.demo-form-inline .el-form-item {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
|
@ -45,10 +45,10 @@ export interface Question {
|
||||
correct_count: number;
|
||||
create_at: string;
|
||||
update_at: string;
|
||||
tags: Tag[];
|
||||
}
|
||||
|
||||
export interface QuestionDetail extends Question {
|
||||
tags: Tag[];
|
||||
answers: Answer[];
|
||||
question_contents: QuestionContent[];
|
||||
sub_questions: QuestionDetail[];
|
||||
|
@ -8,8 +8,12 @@ import router from './router';
|
||||
|
||||
import ElementPlus from 'element-plus';
|
||||
import 'element-plus/dist/index.css';
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
|
||||
|
||||
const app = createApp(App);
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component);
|
||||
}
|
||||
app.use(ElementPlus);
|
||||
|
||||
app.use(createPinia());
|
||||
|
Loading…
Reference in New Issue
Block a user