server banner
|
@ -0,0 +1,28 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getBannerAll() {
|
||||||
|
return request({
|
||||||
|
url: '/examtest/banner/',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function createBanner(data) {
|
||||||
|
return request({
|
||||||
|
url: '/examtest/banner/',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function updateBanner(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/examtest/banner/${id}/`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function deleteBanner(id) {
|
||||||
|
return request({
|
||||||
|
url: `/examtest/banner/${id}/`,
|
||||||
|
method: 'delete',
|
||||||
|
})
|
||||||
|
}
|
|
@ -195,6 +195,12 @@ export const asyncRoutes = [
|
||||||
name: 'System',
|
name: 'System',
|
||||||
meta: { title: '系统管理', icon: 'tree', perms: ['system_manage'] },
|
meta: { title: '系统管理', icon: 'tree', perms: ['system_manage'] },
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
path: 'banner',
|
||||||
|
name: 'Banner',
|
||||||
|
component: () => import('@/views/system/banner.vue'),
|
||||||
|
meta: { title: '轮播图', icon: '', perms: ['banner_manage'] }
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'user',
|
path: 'user',
|
||||||
name: 'User',
|
name: 'User',
|
||||||
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-button type="primary" @click="handleAdd" icon="el-icon-plus">新增</el-button>
|
||||||
|
<el-table
|
||||||
|
:data="tableData"
|
||||||
|
style="width: 100%;margin-top:10px;"
|
||||||
|
border
|
||||||
|
fit
|
||||||
|
v-loading="listLoading"
|
||||||
|
highlight-current-row
|
||||||
|
max-height="600"
|
||||||
|
row-key="id"
|
||||||
|
default-expand-all
|
||||||
|
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||||
|
|
||||||
|
>
|
||||||
|
<el-table-column type="index" width="50"></el-table-column>
|
||||||
|
<el-table-column label="图片名称">
|
||||||
|
<template slot-scope="scope">{{ scope.row.name }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="图片">
|
||||||
|
<template scope="scope">
|
||||||
|
<img :src="scope.row.path" width="160" height="90" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="链接">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.url }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="排序数">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.sort }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="操作">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="handleEdit(scope)"
|
||||||
|
icon="el-icon-edit"
|
||||||
|
:disabled="!checkPermission(['banner_update'])"
|
||||||
|
></el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
@click="handleDelete(scope)"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
:disabled="!checkPermission(['banner_delete'])"
|
||||||
|
></el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-dialog :visible.sync="dialogVisible" :title="dialogType==='edit'?'编辑':'新增'" >
|
||||||
|
<el-form :model="banner" label-width="80px" label-position="right" :rules="rule1" ref="Form">
|
||||||
|
<el-form-item label="名称" prop="name">
|
||||||
|
<el-input v-model="banner.name" placeholder="名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="链接" prop="url">
|
||||||
|
<el-input v-model="banner.url" placeholder="链接" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="排序" prop="sort">
|
||||||
|
<el-input-number v-model="banner.sort" :min="1" :max="4"></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="图片" prop="path" >
|
||||||
|
<el-upload
|
||||||
|
class="avatar-uploader"
|
||||||
|
:headers="myHeaders"
|
||||||
|
:action="uploadUrl"
|
||||||
|
accept="image/jpeg, image/gif, image/png, image/bmp"
|
||||||
|
:show-file-list="false"
|
||||||
|
:on-success="handleImgSuccess"
|
||||||
|
:before-upload="beforeImgUpload"
|
||||||
|
>
|
||||||
|
<img v-if="banner.path" :src="banner.path" style="width: 80%;height: auto;display: block;"/>
|
||||||
|
<el-button size="small" type="primary" v-else>点击上传</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div style="text-align:right;">
|
||||||
|
<el-button type="danger" @click="dialogVisible=false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmBanner('Form')">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getBannerAll, createBanner, deleteBanner, updateBanner } from "@/api/banner";
|
||||||
|
import { deepClone } from "@/utils";
|
||||||
|
import checkPermission from "@/utils/permission";
|
||||||
|
import { uploadUrl } from "@/api/file";
|
||||||
|
import { getToken } from "@/utils/auth";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const defaultBanner = {
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
url:"",
|
||||||
|
sort:0,
|
||||||
|
path:""
|
||||||
|
};
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
myHeaders: { Authorization: "JWT " + getToken() },
|
||||||
|
uploadUrl: uploadUrl(),
|
||||||
|
banner: {
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
url:"",
|
||||||
|
sort:0,
|
||||||
|
path:""
|
||||||
|
},
|
||||||
|
search:'',
|
||||||
|
tableData: [],
|
||||||
|
bannerData:[],
|
||||||
|
listLoading: true,
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogType: "new",
|
||||||
|
rule1: {
|
||||||
|
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
||||||
|
path: [{ required: true, message: "请上传文件", trigger: "blur" }],
|
||||||
|
},
|
||||||
|
fileList:[],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkPermission,
|
||||||
|
handleImgSuccess(res, file) {
|
||||||
|
this.banner.path = res.data.path
|
||||||
|
},
|
||||||
|
beforeImgUpload(file) {
|
||||||
|
const isLt2M = file.size / 1024 / 1024 < 0.5;
|
||||||
|
if (!isLt2M) {
|
||||||
|
this.$message.error("上传图片大小不能超过 500KB!");
|
||||||
|
}
|
||||||
|
return isLt2M;
|
||||||
|
},
|
||||||
|
getList() {
|
||||||
|
this.listLoading = true
|
||||||
|
getBannerAll().then(response => {
|
||||||
|
this.tableData = response.data;
|
||||||
|
this.listLoading = false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetFilter() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
// handleFilter() {
|
||||||
|
// let newData = this.bannerData.filter(data => !this.search || data.name.toLowerCase().includes(this.search.toLowerCase()))
|
||||||
|
// },
|
||||||
|
handleAdd() {
|
||||||
|
this.banner = Object.assign({}, defaultBanner);
|
||||||
|
this.dialogType = "new";
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs["Form"].clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleEdit(scope) {
|
||||||
|
this.banner = Object.assign({}, scope.row); // copy obj
|
||||||
|
this.dialogType = "edit";
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs["Form"].clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDelete(scope) {
|
||||||
|
this.$confirm("确认删除?", "警告", {
|
||||||
|
confirmButtonText: "确认",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
await deleteBanner(scope.row.id);
|
||||||
|
this.getList()
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "成功删除!"
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// console.error(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async confirmBanner(form) {
|
||||||
|
this.$refs[form].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
const isEdit = this.dialogType === "edit";
|
||||||
|
if (isEdit) {
|
||||||
|
updateBanner(this.banner.id, this.banner).then(() => {
|
||||||
|
this.getList();
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$notify({
|
||||||
|
title: "成功",
|
||||||
|
message: "编辑成功",
|
||||||
|
type: "success",
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
createBanner(this.banner).then(res => {
|
||||||
|
// this.banner = res.data
|
||||||
|
// this.tableData.unshift(this.banner)
|
||||||
|
this.getList();
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$notify({
|
||||||
|
title: "成功",
|
||||||
|
message: "新增成功",
|
||||||
|
type: "success",
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 3.0.4 on 2020-03-29 13:35
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('examtest', '0016_auto_20200325_1610'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Banner',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_delete', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='名称')),
|
||||||
|
('path', models.CharField(blank=True, max_length=1000, null=True, verbose_name='图片地址')),
|
||||||
|
('url', models.CharField(blank=True, max_length=1000, null=True, verbose_name='链接地址')),
|
||||||
|
('sort', models.IntegerField(default=1, verbose_name='排序数字')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -40,4 +40,11 @@ class AnswerDetail(SoftCommonModel):
|
||||||
is_right = models.BooleanField(default=False, verbose_name='是否正确')
|
is_right = models.BooleanField(default=False, verbose_name='是否正确')
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '答题记录'
|
verbose_name = '答题记录'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
||||||
|
|
||||||
|
class Banner(CommonModel):
|
||||||
|
name = models.CharField(max_length=200, verbose_name='名称')
|
||||||
|
path = models.CharField(max_length=1000, null=True, blank=True, verbose_name='图片地址')
|
||||||
|
url = models.CharField(max_length=1000, null=True, blank=True, verbose_name='链接地址')
|
||||||
|
sort = models.IntegerField(default=1, verbose_name='排序数字')
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from question.models import Questioncat
|
from question.models import Questioncat
|
||||||
from crm.models import Consumer
|
from crm.models import Consumer
|
||||||
from .models import ExamTest, AnswerDetail
|
from .models import ExamTest, AnswerDetail, Banner
|
||||||
from .models_paper import TestRule, WorkScope
|
from .models_paper import TestRule, WorkScope
|
||||||
|
|
||||||
|
|
||||||
|
class BannerSerializer(serializers.ModelSerializer):
|
||||||
|
"""
|
||||||
|
轮播图序列化
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
model = Banner
|
||||||
|
fields = ('id','name','path', 'url', 'sort')
|
||||||
class TestRuleSerializer(serializers.ModelSerializer):
|
class TestRuleSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
规则序列化
|
规则序列化
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
from django.urls import path,include
|
from django.urls import path,include
|
||||||
from .views import TestRuleViewSet, MoniTestView, MyExamTestView, AnswerDetailView, MyExamTestFxView, WorkScopeViewSet
|
from .views import TestRuleViewSet, MoniTestView, MyExamTestView, AnswerDetailView, MyExamTestFxView, WorkScopeViewSet, BannerViewSet
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register('testrule', TestRuleViewSet, basename="testrule")
|
router.register('testrule', TestRuleViewSet, basename="testrule")
|
||||||
router.register('workscope', WorkScopeViewSet, basename="workscope")
|
router.register('workscope', WorkScopeViewSet, basename="workscope")
|
||||||
|
router.register('banner', BannerViewSet, basename='banner')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('monitest/',MoniTestView.as_view()),
|
path('monitest/',MoniTestView.as_view()),
|
||||||
|
|
|
@ -16,9 +16,9 @@ from utils.custom import CommonPagination
|
||||||
from rbac.permission import RbacPermission
|
from rbac.permission import RbacPermission
|
||||||
from question.models import Question
|
from question.models import Question
|
||||||
from question.serializers import QuestionSerializer
|
from question.serializers import QuestionSerializer
|
||||||
from .models import ExamTest, AnswerDetail
|
from .models import ExamTest, AnswerDetail, Banner
|
||||||
from .models_paper import TestRule, WorkScope
|
from .models_paper import TestRule, WorkScope
|
||||||
from .serializers import TestRuleSerializer, MoniTestSerializer, AnswerDetailSerializer, ExamTestListSerializer, AnswerDetailCreateSerializer, WorkScopeSerializer
|
from .serializers import TestRuleSerializer, MoniTestSerializer, AnswerDetailSerializer, ExamTestListSerializer, AnswerDetailCreateSerializer, WorkScopeSerializer, BannerSerializer
|
||||||
from server import settings
|
from server import settings
|
||||||
from crm.authentication import ConsumerTokenAuthentication
|
from crm.authentication import ConsumerTokenAuthentication
|
||||||
from utils.custom import CommonPagination
|
from utils.custom import CommonPagination
|
||||||
|
@ -163,6 +163,35 @@ class WorkScopeViewSet(ModelViewSet):
|
||||||
return Response(ret)
|
return Response(ret)
|
||||||
|
|
||||||
|
|
||||||
|
class BannerViewSet(ModelViewSet):
|
||||||
|
"""
|
||||||
|
轮播图:增删改查
|
||||||
|
"""
|
||||||
|
perms_map = (
|
||||||
|
{'*': 'admin'}, {'*': 'Banner_all'}, {'get': 'Banner_list'}, {'post': 'Banner_create'},
|
||||||
|
{'put': 'Banner_update'}, {'delete': 'Banner_delete'})
|
||||||
|
pagination_class = None
|
||||||
|
queryset = Banner.objects.filter(is_delete=0).all().order_by("sort")
|
||||||
|
serializer_class = BannerSerializer
|
||||||
|
ordering_fields = ('id', 'sort')
|
||||||
|
ordering = ['sort']
|
||||||
|
|
||||||
|
def get_authenticators(self):
|
||||||
|
"""
|
||||||
|
GET请求不做登陆验证
|
||||||
|
"""
|
||||||
|
if self.request.method == 'GET':
|
||||||
|
self.authentication_classes = []
|
||||||
|
return [auth() for auth in self.authentication_classes]
|
||||||
|
|
||||||
|
def get_permissions(self):
|
||||||
|
"""
|
||||||
|
GET请求不做权限验证
|
||||||
|
"""
|
||||||
|
if self.request.method == 'GET':
|
||||||
|
self.permission_classes = []
|
||||||
|
return [permission() for permission in self.permission_classes]
|
||||||
|
|
||||||
class TestRuleViewSet(ModelViewSet):
|
class TestRuleViewSet(ModelViewSet):
|
||||||
"""
|
"""
|
||||||
模考规则:增删改查
|
模考规则:增删改查
|
||||||
|
|
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 20 KiB |