实操学习——题目的管理
实操学习——题目的管理
本文主要讲解题目的管理案例
1.题目的基本增删改查
2.题目的权限控制
3.题目的搜索
一、基础配置
-
创建一个名为work的app
-
将work注册到settings.py
-
在models.py中创建模型
from django.contrib.auth.models import User
from django.db import models
from utils.modelsMixin import ModelSetMixin
# Create your models here.
# 标签表
class Label(models.Model):
name = models.CharField(max_length=30, verbose_name='标签名', unique=True)
user = models.ForeignKey(User, on_delete=models.CASCADE) #一个用户可以有多个标签
class Meta:
db_table = 'label' #定义生成的mysql表名
verbose_name = '标签'
verbose_name_plural = verbose_name
def __str__(self):
return self.name #重写__str__方法,返回标签名,这样在Topic模型中的label 字段显示为正常的标签名,而不是object
# 题目表
class Topic(ModelSetMixin):
TYPE_CHOICES = (
(0, '单选题'),
(1, '多选题'),
(2, '判断题'),
(3, '填空题'),
(4, '问答题'),
)
subject = models.TextField(verbose_name='题干')
type = models.IntegerField(verbose_name='类型', choices=TYPE_CHOICES)
score = models.FloatField(verbose_name='分值', default=1.0, null=True, blank=True)
description = models.TextField(verbose_name='题目描述', null=True, blank=True)
answer = models.TextField(verbose_name='答案')
label = models.ForeignKey(Label, on_delete=models.CASCADE)#一个标签可以对应多个题目
user = models.ForeignKey(User, on_delete=models.CASCADE) #一个用户可以有多个题目
class Meta:
ordering = ['-update_time'] #可以在元信息中定义排序方式,倒序排序
db_table = 'topic'
verbose_name = '题目'
verbose_name_plural = verbose_name
这里要导入自己创建的ModelSetMixin,代码如下:
from django.db import models
class DateTimeModelMixin(models.Model):
"""创建和修改时间模型拓展类"""
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
abstract = True # 指定该类为抽象模型类,迁移映射的时候就不会创建对应的表,只是用于封装拓展
class IsDeleteModelMixin(models.Model):
"""逻辑删除模型拓展类"""
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
def delete(self, using=None, keep_parents=False):
# 逻辑删除
self.is_delete = True
self.save()
class Meta:
abstract = True
class ModelSetMixin(DateTimeModelMixin, IsDeleteModelMixin):
"""模型拓展整合类"""
class Meta:
abstract = True
- 编写序列化器serializers.py
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *
# 有对应的模型可以直接继承ModelSerializer
class LabelSerializer(ModelSerializer):
#新增字段,查询时将username 也显示出来
username = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Label
fields = '__all__'
extra_kwargs = {
#将user设置为只写,查询时隐藏不显示user这个字段
'user': {'required': False, 'write_only': True}
}
class TopicSerializer(ModelSerializer):
label_name = serializers.CharField(source='label.name', read_only=True)
user_name = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Topic
exclude = ['is_delete']
- 编写views.py视图函数
from random import sample
from django.db.models import Q
from django.shortcuts import render
# Create your views here.
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *
class LabelViewSet(ModelViewSet):
queryset = Label.objects.all()
serializer_class = LabelSerializer
class TopicViewSet(ModelViewSet):
queryset = Topic.objects.filter(is_delete=False)
serializer_class = TopicSerializer
- 编写路由urls.py
from rest_framework.routers import DefaultRouter
from .views import *
urlpatterns = []
router = DefaultRouter()
router.register('label', LabelViewSet)
router.register('topics', TopicViewSet)
urlpatterns += router.urls
7.配置总路由urls.py
8.启动测试
二、权限控制
- 标签权限分析:
标签的权限:
创建:老师及以上
查看:登录可查看
修改:老师及以上
删除:超级管理员
设置最低基本权限:选择这个事物操作的最低权限,将最低权限定义为视图类的权限。最基础的就是登录。
- 修改视图views.py,增加权限
from random import sample
from django.db.models import Q
from django.shortcuts import render
# Create your views here.
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *
class LabelViewSet(ModelViewSet):
# 设置基础权限:该视图必须登录才能访问
permission_classes = [IsAuthenticated]
queryset = Label.objects.all()
serializer_class = LabelSerializer
#重写create方法
@wrap_permisssion(TeacherPermission) #定义只有老师权限才可以创建
@auto_user
def create(self, request, *args, **kwargs):
return ModelViewSet.create(self, request, *args, **kwargs)
#重写create方法,操作的用户必须是当前登陆的用户
@wrap_permisssion(ActiveUserPermission)
@auto_user
def update(self, request, *args, **kwargs):
return ModelViewSet.update(self, request, *args, **kwargs)
#重写destroy方法,必须为超级管理员权限
@wrap_permisssion(RootPermission)
def destroy(self, request, *args, **kwargs):
return ModelViewSet.destroy(self, request, *args, **kwargs)
- 在permission.py中增加超级管理员的权限类RootPermission,以及其他权限如下。
from functools import update_wrapper
from django.contrib.auth.models import Group
from rest_framework.permissions import BasePermission
class TeacherPermission(BasePermission):
def has_permission(self, request, view):
user = request.user # 当前请求的用户信息
# 判断身份,查询用户在不在老师这个分组里面
group = Group.objects.filter(name='老师').first()
user_groups = user.groups.all()
return user.is_superuser or group in user_groups
class ActiveUserPermission(BasePermission):
def has_permission(self, request, view):
# 操作的用户必须是当前登陆的用户
user = request.user
return user.id == int(view.kwargs['pk'])
#超级管理员权限类
class RootPermission(BasePermission):
def has_permission(self, request, view):
user = request.user
return user.is_superuser
# 更改权限装饰器
def wrap_permisssion(*permissions, validate_permisssion=True):
def decorator(func):
def wrapper(self, request, *args, **kwargs):
self.permission_classes = permissions
if validate_permisssion:
self.check_permissions(request)
return func(self, request, *args, **kwargs)
return update_wrapper(wrapper, func)
return decorator
#创建时自动原则对应的用户,而不是所有用户都能选择
def auto_user(func):
def wrapper(self, request, *args, **kwargs):
request.POST._mutable = True # 让请求参数可以被修改,固定写法
request.data['user'] = request.user.id #将user改为当前登录用户的id
return func(self, request, *args, **kwargs) #返回原本函数执行的结果,即创建
return wrapper
- 题目操作权限分析
题目的权限:
创建:老师及以上
修改:自己
查看:
自带的查询包括答案,权限是老师
查询需要增加额外的接口,没有答案,权限是登录即可。防止被爬虫
删除:超级管理员
- 定义一个学生使用的序列化器TopicStudentSerializer,只能看到题目,无法查看到答案
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *
# 有对应的模型可以直接继承ModelSerializer
class LabelSerializer(ModelSerializer):
username = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Label
fields = '__all__'
extra_kwargs = {
'user': {'required': False, 'write_only': True}
}
class TopicSerializer(ModelSerializer):
label_name = serializers.CharField(source='label.name', read_only=True)
user_name = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Topic
exclude = ['is_delete']
#学生使用的序列化器
class TopicStudentSerializer(ModelSerializer):
label_name = serializers.CharField(source='label.name', read_only=True)
user_name = serializers.CharField(source='user.username', read_only=True)
class Meta:
model = Topic
exclude = ['is_delete', 'answer'] #过滤掉答案
- 修改视图views.py,增加权限
from random import sample
from django.db.models import Q
from django.shortcuts import render
# Create your views here.
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *
class TopicViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Topic.objects.filter(is_delete=False)
serializer_class = TopicSerializer
# pagination_class = TopicPaginationPageNumber
pagination_class = TopicPaginationLimitOffset
def get_queryset(self):
if self.action in ['practice', 'random']:
return Topic.objects.filter(Q(is_delete=False) & ~Q(label__name__contains='试卷'))
return self.queryset
#重写序列化器
def get_serializer(self, *args, **kwargs):
if self.action in ['exam', 'random']: #判断当前的操作是否是exam或者random接口操作
return TopicStudentSerializer(*args, **kwargs) #是的话返回学生使用的序列化器,不包含答案
return self.serializer_class(*args, **kwargs) #不是的话直接返回serializer_class
#重写查所有,只有老师可以查看带答案的数据
@wrap_permisssion(TeacherPermission)
def list(self, request, *args, **kwargs):
return ModelViewSet.list(self, request, *args, **kwargs)
#重写查单一,只有老师可以查看带答案的数据
@wrap_permisssion(TeacherPermission)
def retrieve(self, request, *args, **kwargs):
return ModelViewSet.retrieve(self, request, *args, **kwargs)
@wrap_permisssion(TeacherPermission)
@auto_user
def create(self, request, *args, **kwargs):
return ModelViewSet.create(self, request, *args, **kwargs)
@wrap_permisssion(ActiveUserPermission)
@auto_user
def update(self, request, *args, **kwargs):
return ModelViewSet.update(self, request, *args, **kwargs)
@wrap_permisssion(RootPermission)
def destroy(self, request, *args, **kwargs):
return ModelViewSet.destroy(self, request, *args, **kwargs)
@action(methods=['get'], detail=False)
def practice(self, request):
return ModelViewSet.list(self, request)
@action(methods=['get'], detail=True)
def exam(self, request, pk):
# 获取指定标签,指定试卷
labels = Label.objects.filter(id=pk, name__contains='试卷').first()
# 判断有没有这个试卷,没有返回404
if not labels:
return Response(status=HTTP_404_NOT_FOUND)
# 有,则获取这个试卷的所有题目,不包含答案
topics = labels.topic_set.filter(is_delete=False)
serializer = self.get_serializer(topics, many=True)
return Response(serializer.data)
@action(methods=['get'], detail=False)
def random(self, request):
# 获取随机刷题题目个数
try:
size = int(request.query_params.get('size', 3))
except ValueError:
return Response(status=HTTP_400_BAD_REQUEST)
# 获取查询集,随机抽取指定个数
pool = list(self.get_queryset())
# 判断要获取的随机题目个数是否超出题目总数,如果操作,则给出提示
if len(pool) < size:
return Response({'detail': '超出题目个数,题目总数为:%s' % len(pool)}, status=HTTP_400_BAD_REQUEST)
# 序列化,返回
serializer = self.get_serializer(sample(pool, size), many=True)
return Response(serializer.data)
三、分页
为什么要考虑到分页查询,这里我们假设数据库中有10万条题目,如果发起查询题目的请求,需要返回10万条数据,如果某个用户只需要练习20道题目,速度肯定会很慢,并且资源损耗严重。这时候就要考虑到使用分页。下面介绍DRF中使用的两种分页器。
1. PageNumberPagination分页器
- 在views.py视图中定义分页器类
from rest_framework.pagination import PageNumberPagination
class TopicPaginationPageNumber(PageNumberPagination):
page_size = 3 # 默认每页多少条,如果不传size,默认3条
#page_size_param = 'page' #定义传入页数的参数,默认为page
page_size_query_param = 'size' # 规定哪个参数为分页大小参数,参数可以自己定义,这里定义为size,则前端传入参数size = 10,每页展示10条,但是不会超过设置的最大每页条数100
max_page_size = 100 # 最大每页多少条
- 在题目的视图类TopicViewSet中增加该分页属性
class TopicViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Topic.objects.filter(is_delete=False)
serializer_class = TopicSerializer
#分页器
pagination_class = TopicPaginationPageNumber
- 发送查询请求。
解释:
使用分页器查询后,显示如下:
count:总数
next:下一页网址
previous:上一页网址
results:返回查询的结果集合
如果需要指定返回条数,在前端传入size参数,指定每页展示条数
2. LimitOffsetPagination分页器
- 在views.py视图中定义分页器类
from rest_framework.pagination import LimitOffsetPagination
class TopicPaginationLimitOffset(LimitOffsetPagination):
default_limit = 3 # 默认每页多少条
#limit_query_param = 'limit' #默认每页展示条数的参数为limit
#offset_query_param = 'offset' #默认的偏移的参数为offset
max_limit = 100 # 最大每页多少条
- 在题目的视图类TopicViewSet中增加该分页属性
class TopicViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Topic.objects.filter(is_delete=False)
serializer_class = TopicSerializer
#分页器
pagination_class = TopicPaginationLimitOffset
- 发送查询请求。
返回的数据结构跟PageNumberPagination一样,只是网址中传入的参数区别
3.总结
- 使用PageNumberPagination的场景:
固定点击下一页,再点击下一页 - 使用LimitOffsetPagination的场景:
固定点击下一页,再点击下一页。也可以实现跳转到指定题目,从指定题目开始。
四、题目操作模块
代码参考附件一
1. 考试
没有答案,需要提交答题结果,老师后台审核
- 在标签模型里可以添加试卷名标签
- 在TopicViewSet视图中添加exam接口并将exam接口添加到重写 的get_serializer中,返回没有答案的数据。接口测试可以拿到数据
2. 题目练习——顺序刷题
有答案,程序自动判定结果,也可以直接看答案
- 在TopicViewSet视图中添加practice接口,并重写queryset方法:修改使用’practice’接口时需要返回的数据集,不能查看到标签名包含试卷的题目,只能做练习题
3. 模拟考试
随机获取指定题目
- 在TopicViewSet视图中添加random接口,并在get_queryset和get_serializer中添加random接口
- 访问接口测试
附件一:topic的视图函数
from random import sample
from django.db.models import Q
from django.shortcuts import render
# Create your views here.
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, auto_user, ActiveUserPermission
from .serializers import *
# class TopicPaginationPageNumber(PageNumberPagination):
# page_size = 3 # 默认每页多少条
# page_size_query_param = 'size' # 规定哪个参数为分页大小参数 size = 10
# max_page_size = 100 # 最大每页多少条
class TopicPaginationLimitOffset(LimitOffsetPagination):
default_limit = 3 # 默认每页多少条
max_limit = 100 # 最大每页多少条
class LabelViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Label.objects.all()
serializer_class = LabelSerializer
@wrap_permisssion(TeacherPermission)
@auto_user
def create(self, request, *args, **kwargs):
return ModelViewSet.create(self, request, *args, **kwargs)
@wrap_permisssion(ActiveUserPermission)
@auto_user
def update(self, request, *args, **kwargs):
return ModelViewSet.update(self, request, *args, **kwargs)
@wrap_permisssion(RootPermission)
def destroy(self, request, *args, **kwargs):
return ModelViewSet.destroy(self, request, *args, **kwargs)
class TopicViewSet(ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Topic.objects.filter(is_delete=False)
serializer_class = TopicSerializer
# pagination_class = TopicPaginationPageNumber
pagination_class = TopicPaginationLimitOffset
#重写queryset方法:修改使用'practice', 'random'接口时需要返回的数据集
def get_queryset(self):
if self.action in ['practice', 'random']:
return Topic.objects.filter(Q(is_delete=False) & ~Q(label__name__contains='试卷')) #~Q(label__name__contains='试卷')标签名不包含”试卷“的数据
return self.queryset
#重写serializer方法:修改使用'exam', 'random'接口时调用的序列化器
def get_serializer(self, *args, **kwargs):
if self.action in ['exam', 'random']:
return TopicStudentSerializer(*args, **kwargs)
return self.serializer_class(*args, **kwargs)
@wrap_permisssion(TeacherPermission)
def list(self, request, *args, **kwargs):
return ModelViewSet.list(self, request, *args, **kwargs)
@wrap_permisssion(TeacherPermission)
def retrieve(self, request, *args, **kwargs):
return ModelViewSet.retrieve(self, request, *args, **kwargs)
@wrap_permisssion(TeacherPermission)
@auto_user
def create(self, request, *args, **kwargs):
return ModelViewSet.create(self, request, *args, **kwargs)
@wrap_permisssion(ActiveUserPermission)
@auto_user
def update(self, request, *args, **kwargs):
return ModelViewSet.update(self, request, *args, **kwargs)
@wrap_permisssion(RootPermission)
def destroy(self, request, *args, **kwargs):
return ModelViewSet.destroy(self, request, *args, **kwargs)
@action(methods=['get'], detail=False)
def practice(self, request):
return ModelViewSet.list(self, request)
#传入标签的id
@action(methods=['get'], detail=True)
def exam(self, request, pk):
# 获取指定标签,指定试卷
labels = Label.objects.filter(id=pk, name__contains='试卷').first()
# 判断有没有这个试卷,没有返回404
if not labels:
return Response(status=HTTP_404_NOT_FOUND)
# 有,则获取这个试卷的所有题目,不包含答案
#.topic_set管理器获取到所有题目
topics = labels.topic_set.filter(is_delete=False)
serializer = self.get_serializer(topics, many=True)
return Response(serializer.data)
@action(methods=['get'], detail=False)
def random(self, request):
# 获取随机刷题题目个数
try:
#request.query_params.get获取get请求传入的参数写法
#没传入size,默认为3条
size = int(request.query_params.get('size', 3))
except ValueError:
return Response(status=HTTP_400_BAD_REQUEST)
# 获取查询集,随机抽取指定个数
pool = list(self.get_queryset())
# 判断要获取的随机题目个数是否超出题目总数,如果操作,则给出提示
if len(pool) < size:
return Response({'detail': '超出题目个数,题目总数为:%s' % len(pool)}, status=HTTP_400_BAD_REQUEST)
# 序列化,返回
#sample(pool, size)从pool中随机取size个数据进行序列化
serializer = self.get_serializer(sample(pool, size), many=True)
return Response(serializer.data)
补充:前端调用接口写法
前端完整代码:
<template>
<div class="demo-collapse" v-loading="loading">
<div>
<div style="margin: 15px 0px">
<el-input v-model="search" placeholder="请输入你要搜索内容" class="input-with-select">
<template #prepend>
<el-select v-model="select" placeholder="请选择" style="width: 110px">
<el-option label="题目内容" value="1"></el-option>
</el-select>
</template>
<template #append>
<el-button @click="searchfunc">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
</div>
<div class="start">
从第
<el-input-number v-model="offset" :min="1" :max="topics.data.count" @change="get_topics" />题开始
</div>
</div>
<el-collapse v-model="activeNames" v-infinite-scroll="load" infinite-scroll-disabled="disabled">
<el-collapse-item v-for="(topic, index) in topics.data.results" :name="index" :key="topic.id">
<template #title>
<span>{{ index + offset }}、</span>
<span v-html="topic.subject"></span>
<el-tag>{{ topic.label_name }}</el-tag>
<el-tag>{{ TYPE_CHOICES[topic.type] }}</el-tag>
</template>
<div v-html="topic.description"></div>
<el-form :inline="true" class="demo-form-inline work">
<el-form-item label="作答">
<el-input v-model="topic.work_answer" placeholder="请填写你的答案"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit(index)">提交</el-button>
</el-form-item>
<span v-if="topic.flag">{{ topic.flag }}、正确答案:{{ topic.answer }}</span>
</el-form>
</el-collapse-item>
<el-empty :image-size="20" v-if="!topics.data.next" description="暂无更多题目"></el-empty>
</el-collapse>
</div>
</template>
<script>
import axios from 'axios'
import { reactive, ref } from 'vue-demi'
import { ElMessage } from 'element-plus'
import { Search } from '@element-plus/icons'
export default {
name: 'exercise',
components: {
Search
},
setup() {
let loading = ref(true)
let activeNames = ref([0])
let search = ref('')
let select = ref('1')
const TYPE_CHOICES = ['单选题', '多选题', '判断题', '填空题', '问答题']
let disabled = ref(false)
let topics = reactive({
data: {
count: 0,
next: null,
previous: null,
results: [
{
answer: "B",
create_time: "2021-11-19T20:25:56.885565",
description: "A、x = y = z = 1 \r<br/>B、x = (y = z + 1)\r<br/>C、x, y = y, x\r<br/>D、x += y",
id: 1,
label: 1,
label_name: "python基础",
score: 1,
subject: "下列哪个语句在Python中是非法的",
type: 0,
update_time: "2021-11-19T20:25:56.885594",
user: 1,
user_name: "一个",
}
]
}
})
let offset = ref(1)
function get_topics(offset) {
loading.value = true
axios.get('/api/work/topics/practice/', {
params: {
offset: offset - 1,
limit: 10
},
headers: {
'Authorization': 'JWT ' + (localStorage.getItem('token') ? localStorage.getItem('token') : sessionStorage.getItem('token'))
}
}).then(
response => {
let results = []
response.data.results.forEach(e => {
e.description = e.description.replace(/\n/g, '<br/><br/>')
e.work_answer = ''
e.flag = null
results.push(e)
});
response.data.results = results
console.log(results)
topics.data = response.data
loading.value = false
disabled.value = false
},
error => {
console.log('请求失败', error.message)
}
)
}
get_topics(offset.value)
function onSubmit(index) {
let topic = topics.data.results[index]
if (topic.answer.toUpperCase() == topic.work_answer.toUpperCase()) {
topic.flag = '回答正确'
ElMessage.success(topic.flag)
} else {
topic.flag = '回答错误'
ElMessage.error(topic.flag)
}
}
const load = () => {
if (topics.data.next != null) {
loading.value = true
disabled.value = true
let url = topics.data.next.replace('http://127.0.0.1:8000/', '/api/')
axios.get(url, {
headers: {
'Authorization': 'JWT ' + (localStorage.getItem('token') ? localStorage.getItem('token') : sessionStorage.getItem('token'))
}
}).then(
response => {
let results = []
response.data.results.forEach(e => {
e.description = e.description.replace(/\n/g, '<br/><br/>')
e.work_answer = ''
e.flag = null
results.push(e)
});
response.data.results = topics.data.results.concat(results);
topics.data = response.data
console.log(response.data)
loading.value = false
if (response.data.next == null) {
disabled.value = true
} else {
disabled.value = false
}
},
error => {
console.log('请求失败', error.message)
}
)
}
}
function searchfunc() {
disabled.value = false
axios.get('/api/work/topics/search/', {
params: {
subject: search.value,
},
headers: {
'Authorization': 'JWT ' + (localStorage.getItem('token') ? localStorage.getItem('token') : sessionStorage.getItem('token'))
}
}).then(
response => {
let results = []
response.data.results.forEach(e => {
e.description = e.description.replace(/\n/g, '<br/><br/>')
e.work_answer = ''
e.flag = null
results.push(e)
});
response.data.results = results
console.log(results)
topics.data = response.data
loading.value = false
},
error => {
console.log('请求失败', error.message)
}
)
}
return { topics, TYPE_CHOICES, loading, onSubmit, activeNames, offset, get_topics, load, disabled, search, select, searchfunc }
}
}
</script>
<style scoped>
.el-tag {
margin-left: 20px;
}
.work {
margin-top: 20px;
}
.start {
margin-bottom: 20px;
}
</style>
原文地址:https://blog.csdn.net/m0_51453764/article/details/142365505
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!