增加题目的编辑功能

This commit is contained in:
zhl 2021-04-22 20:52:19 +08:00
parent e12bafe5e4
commit 30ccb6edd5
6 changed files with 216 additions and 154 deletions

48
src/api/question.ts Normal file
View File

@ -0,0 +1,48 @@
import request from '@/utils/request'
export interface IQuestionData {
_id?: string,
question: string,
a1: string,
a2?: string,
a3?: string,
a4?: string,
group?: string,
tag?: string,
quality: number
}
export const defaultQuestionData: IQuestionData = {
quality: 3,
a1: '', question: ''
}
export const getQuestions = (params: any) =>
request({
url: '/puzzles',
method: 'post',
params
})
export const getQuestion = (id: string, params: any) =>
request({
url: `/puzzle/${id}`,
method: 'get',
params
})
export const saveQuestion = (data: any) =>
request({
url: `/puzzle/save`,
method: 'post',
data
})
export const deleteQuestion = (id: string) =>
request({
url: `/puzzle/${id}/delete`,
method: 'post'
})

View File

@ -1,44 +0,0 @@
import axios from 'axios'
import {IQuestionData } from '@/api/types'
export const defaultQuestionData: IQuestionData = {
option: [],
answer: '', attachment: '', parts: [], stars: 0, status: 0, type: 0,
id: '',
title: '',
tags: []
}
/**
*
* @return {Promise<void>}
*/
export async function randomOne() {
let url = ''
return axios.get(url, {})
.then(res => {
return res.data
})
}
/**
*
* @param data
* @return {Promise<void>}
*/
export async function updateOne(data: any) {
let url = ''
return axios.post(url, data)
.then(res => {
return res.data
})
}
/**
*
*/
export async function queryList(str: string) {
let url = ''
return axios.post(url, {key: str})
.then(res => {
return res.data
})
}

27
src/api/types.d.ts vendored
View File

@ -14,33 +14,6 @@ export interface IArticleData {
attachments: [] attachments: []
} }
export interface IQuestionData {
id: string,
title: string,
/**
*
*/
parts?: string[],
tags: string[],
answer: string,
/**
*
*/
option: string[],
/**
*
* 0: 文字题
* 1: 图文
*/
type: number,
attachment?: string,
/**
*
*/
stars: number,
status: number,
}
export interface IShopData { export interface IShopData {
_id?: string, _id?: string,
name: string, name: string,

View File

@ -21,7 +21,7 @@ const questionRoutes: RouteConfig = {
} }
}, },
{ {
path: 'edit/:id(\\d+)', path: 'edit/:id',
component: () => import('@/views/question/editor.vue'), component: () => import('@/views/question/editor.vue'),
name: 'QuestionEditor', name: 'QuestionEditor',
meta: { meta: {

View File

@ -8,23 +8,20 @@
> >
<sticky <sticky
:z-index="10" :z-index="10"
:class-name="'sub-navbar '+postForm.status" class-name="sub-navbar"
> >
<el-button @click="onCancel">
取消
</el-button>
<el-button <el-button
v-loading="loading" v-loading="loading"
style="margin-left: 10px;" style="margin-left: 10px;"
type="success" type="success"
@click="submitForm" @click="submitForm"
> >
Publish 保存
</el-button>
<el-button
v-loading="loading"
type="warning"
@click="draftForm"
>
Draft
</el-button> </el-button>
</sticky> </sticky>
<div class="createPost-main-container"> <div class="createPost-main-container">
@ -35,7 +32,7 @@
prop="title" prop="title"
> >
<material-input <material-input
v-model="postForm.title" v-model="postForm.question"
:maxlength="100" :maxlength="100"
name="name" name="name"
required required
@ -53,9 +50,10 @@
label="答案:" label="答案:"
> >
<el-input <el-input
v-model="postForm.answer" v-model="postForm.a1"
:rows="1" :rows="1"
placeholder="输入答案" placeholder="输入答案"
required
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -66,11 +64,11 @@
class="postInfo-container-item" class="postInfo-container-item"
> >
<el-rate <el-rate
v-model="postForm.stars" v-model="postForm.quality"
:max="5" :max="3"
:colors="['#99A9BF', '#F7BA2A', '#ff5900']" :colors="['#99A9BF', '#F7BA2A', '#ff5900']"
:low-threshold="1" :low-threshold="1"
:high-threshold="5" :high-threshold="3"
style="display:inline-block" style="display:inline-block"
/> />
</el-form-item> </el-form-item>
@ -84,7 +82,7 @@
label="混淆答案1:" label="混淆答案1:"
> >
<el-input <el-input
v-model="postForm.answer" v-model="postForm.a2"
:rows="1" :rows="1"
placeholder="输入答案" placeholder="输入答案"
/> />
@ -97,7 +95,7 @@
label="混淆答案2:" label="混淆答案2:"
> >
<el-input <el-input
v-model="postForm.answer" v-model="postForm.a3"
:rows="1" :rows="1"
placeholder="输入答案" placeholder="输入答案"
/> />
@ -110,7 +108,7 @@
label="混淆答案3:" label="混淆答案3:"
> >
<el-input <el-input
v-model="postForm.answer" v-model="postForm.a4"
:rows="1" :rows="1"
placeholder="输入答案" placeholder="输入答案"
/> />
@ -124,7 +122,6 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator' import { Component, Prop, Vue } from 'vue-property-decorator'
import { getArticle } from '@/api/articles'
import { AppModule } from '@/store/modules/app' import { AppModule } from '@/store/modules/app'
import { TagsViewModule, ITagView } from '@/store/modules/tags-view' import { TagsViewModule, ITagView } from '@/store/modules/tags-view'
import MaterialInput from '@/components/MaterialInput/index.vue' import MaterialInput from '@/components/MaterialInput/index.vue'
@ -132,7 +129,13 @@ import Sticky from '@/components/Sticky/index.vue'
import Tinymce from '@/components/Tinymce/index.vue' import Tinymce from '@/components/Tinymce/index.vue'
import UploadImage from '@/components/UploadImage/index.vue' import UploadImage from '@/components/UploadImage/index.vue'
import { Form } from 'element-ui' import { Form } from 'element-ui'
import { defaultQuestionData } from '@/api/questionPre' import {
defaultQuestionData,
getQuestion,
getQuestions,
saveQuestion
} from '@/api/question'
import { saveCoupon } from '@/api/coupon'
@Component({ @Component({
name: 'QuestionPrepare', name: 'QuestionPrepare',
@ -144,7 +147,6 @@ import { defaultQuestionData } from '@/api/questionPre'
} }
}) })
export default class extends Vue { export default class extends Vue {
@Prop({ default: false }) private isEdit!: boolean
private validateRequire = (rule: any, value: string, callback: Function) => { private validateRequire = (rule: any, value: string, callback: Function) => {
if (value === '') { if (value === '') {
@ -181,9 +183,9 @@ export default class extends Vue {
created() { created() {
if (this.isEdit) { const id = this.$route.params && this.$route.params.id
const id = this.$route.params && this.$route.params.id if (id) {
this.fetchData(parseInt(id)) this.fetchData(id)
} }
// Why need to make a copy of this.$route here? // Why need to make a copy of this.$route here?
// Because if you enter this page and quickly switch tag, may be in the execution of this.setTagsViewTitle function, this.$route is no longer pointing to the current page // Because if you enter this page and quickly switch tag, may be in the execution of this.setTagsViewTitle function, this.$route is no longer pointing to the current page
@ -199,11 +201,11 @@ export default class extends Vue {
private async fetchData(id: number) { private async fetchData(id: number) {
try { try {
const { data } = await getArticle(id, { /* Your params here */ }) const { data } = await getQuestion(id, { /* Your params here */ })
this.postForm = data.article this.postForm = data
// Just for test // Just for test
this.postForm.title += ` Article Id:${this.postForm.id}` this.postForm.title += ` Question Id:${this.postForm.id}`
const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article' const title = this.lang === 'zh' ? '编辑题目' : 'Edit Question'
// Set tagsview title // Set tagsview title
this.setTagsViewTitle(title) this.setTagsViewTitle(title)
// Set page title // Set page title
@ -225,34 +227,38 @@ export default class extends Vue {
document.title = `${title} - ${this.postForm.id}` document.title = `${title} - ${this.postForm.id}`
} }
private submitForm() { private async submitForm() {
(this.$refs.postForm as Form).validate(valid => { const form = <Form>this.$refs.postForm
if (valid) { try {
this.loading = true await form.validate()
this.$notify({ this.loading = true
title: 'Success', const {data} = await saveQuestion(this.postForm)
message: 'The post published successfully', this.postForm = data
type: 'success', this.loading = false
duration: 2000 this.$notify({
}) title: 'Success',
// Just to simulate the time of the request message: '题目保存成功',
setTimeout(() => { type: 'success',
this.loading = false duration: 2000
}, 0.5 * 1000) })
} else { } catch (err) {
console.error('Submit Error!') console.error('Submit Error!')
return false return false
} }
})
} }
private async onCancel() {
try {
await this.$confirm('确认不保存当前记录?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
this.$store.dispatch("delView", this.$route)
this.$router.go(-1)
} catch(e) {
}
private draftForm() {
this.$message({
message: 'The draft saved successfully',
type: 'success',
showClose: true,
duration: 1000
})
} }
} }

View File

@ -1,5 +1,16 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- filter -->
<el-form ref="filterForm" :inline="true" :model="filterForm" class="filter">
<el-form-item label="关键字" prop="key">
<el-input v-model="filterForm.key" placeholder="关键字"/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="resetFilterForm">重置</el-button>
</el-form-item>
</el-form>
<router-link to="/question/create"> <router-link to="/question/create">
<el-button <el-button
type="primary" type="primary"
@ -16,53 +27,67 @@
highlight-current-row highlight-current-row
style="width: 100%;margin-top:30px;" style="width: 100%;margin-top:30px;"
> >
<el-table-column <el-table-column
width="180px" width="180px"
align="center" align="center"
label="时间" label="添加时间"
> >
<template slot-scope="{row}"> <template slot-scope="{row}">
<span>{{ row.displayTime | parseTime }}</span> <span>{{ row.createtime | parseTime }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
width="180px" min-width="200px"
label="类型" label="名称"
>
<template slot-scope="{row}">
<span>{{ row.type }}</span>
</template>
</el-table-column>
<el-table-column
min-width="300px"
label="标题"
> >
<template slot-scope="{row}"> <template slot-scope="{row}">
<router-link <router-link
:to="'/question/edit/'+row._id" :to="'/question/edit/'+row._id"
class="link-type" class="link-type"
> >
<span>{{ row.title }}</span> <span>{{ row.question }}</span>
</router-link> </router-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
label="答案"
>
<template slot-scope="{row}">
<span>{{ row.a1 }}</span>
</template>
</el-table-column>
<el-table-column
label="混淆答案"
>
<template slot-scope="{row}">
<span>{{ row.a2 || '' }} {{ row.a3 || '' }} {{ row.a4 || '' }}</span>
</template>
</el-table-column>
<el-table-column <el-table-column
align="center" align="center"
label="操作" label="操作"
width="120"
> >
<template slot-scope="{row}"> <template slot-scope="scope">
<router-link :to="'/question/edit/'+row.id"> <router-link :to="'/question/edit/'+scope.row._id">
<el-button <el-button
type="primary" type="primary"
size="small" size="small"
icon="el-icon-edit" icon="el-icon-edit"
> >
编辑 编辑
</el-button> </el-button>
</router-link> </router-link>
<el-button
type="danger"
size="small"
style="margin-left: 10px"
@click="handleDelete(scope)"
>
{{ $t('permission.delete') }}
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -79,9 +104,12 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator' import { Component, Vue } from 'vue-property-decorator'
import { getArticles } from '@/api/articles' import { IShopData } from '@/api/types'
import { IArticleData } from '@/api/types'
import Pagination from '@/components/Pagination/index.vue' import Pagination from '@/components/Pagination/index.vue'
import { deleteShop, getShops } from '@/api/shop'
import { parseTime } from '@/utils'
import { Form } from 'element-ui'
import { deleteQuestion, getQuestions, IQuestionData } from '@/api/question'
@Component({ @Component({
name: 'QuestionList', name: 'QuestionList',
@ -90,34 +118,85 @@ import Pagination from '@/components/Pagination/index.vue'
}, },
filters: { filters: {
parseTime: (timestamp: string) => { parseTime: (timestamp: string) => {
return new Date(timestamp).toISOString() return parseTime(timestamp)
},
parseDate: (timestamp: string) => {
if (!timestamp) {
return '-'
}
return parseTime(timestamp, '{y}-{m}-{d}')
},
formatCount: (count: string) => {
if (!count) {
return 0
}
return count
} }
} }
}) })
export default class extends Vue { export default class extends Vue {
private total = 0 private total = 0
private list: IArticleData[] = [] private list: IQuestionData[] = []
private listLoading = true private listLoading = true
private allDepts = []
private listQuery = { private listQuery = {
page: 1, page: 1,
limit: 20 limit: 20,
key: ''
}
private filterForm = {
key: ''
} }
created() { created() {
this.getList() this.getList()
} }
private async getList() { private async getList() {
this.listLoading = true this.listLoading = true
const { data } = await getArticles(this.listQuery) const { data } = await getQuestions(this.listQuery)
this.list = data.items this.listLoading = false
this.list = data.records
this.total = data.total this.total = data.total
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false
}, 0.5 * 1000)
} }
private async handleDelete(scope: any) {
const { $index, row } = scope
await this.$confirm('确认删除该记录?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await deleteQuestion(row._id)
this.list.splice($index, 1)
this.$message({
type: 'success',
message: '删除成功!'
})
}
private search() {
this.filterData()
}
private filterData() {
this.listQuery.key = this.filterForm.key
this.listQuery.page = 1
this.getList()
}
private resetFilterForm() {
const ref = <Form>this.$refs.filterForm
ref.resetFields()
}
private async getRemoteDeptList(name: string) {
const { data } = await getShops({ key: name })
if (!data.records) return
this.allDepts = data.records
}
} }
</script> </script>