资料清单model

This commit is contained in:
caoqianming 2021-03-11 09:42:16 +08:00
parent 3feb75dc6d
commit ad4e61fee3
20 changed files with 322 additions and 78 deletions

View File

@ -77,7 +77,7 @@ service.interceptors.response.use(
error => {
// console.log(error,response) // for debug
Message({
message: error.message,
message: '服务器错误',
type: 'error',
duration: 5 * 1000
})

View File

@ -13,7 +13,6 @@
v-loading="treeLoding"
class="filter-tree"
:data="dictTypeData"
default-expand-all
highlight-current
:expand-on-click-node="false"
:filter-node-method="filterNode"
@ -46,31 +45,42 @@
<div slot="header" class="clearfix">
<span>字典详情</span>
</div>
<el-button v-show="listQuery.type" type="primary" icon="el-icon-plus" @click="handleAddDict" >新增</el-button>
<div >
<el-button v-show="listQuery.type" type="primary" icon="el-icon-plus" @click="handleAddDict" v-if="checkPermission(['dic_create'])" size="small">新增</el-button>
</div>
<el-table
v-show="listQuery.type"
v-loading="listLoading"
:data="dictList.results"
:data="dictList"
style="width: 100%;margin-top:10px;"
border
fit
stripe
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 align="center" label="名称">
<el-table-column label="名称">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column align="header-center" label="描述">
<el-table-column label="代号/编号">
<template slot-scope="scope">{{ scope.row.code }}</template>
</el-table-column>
<el-table-column label="描述">
<template slot-scope="scope">{{ scope.row.desc }}</template>
</el-table-column>
<el-table-column align="header-center" label="排序">
<template
slot-scope="scope"
>{{ scope.row.sort }}</template>
<el-table-column label="是否有效">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.is_used">有效</el-tag>
<el-tag type="danger" v-else>无效</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="操作">
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
v-if="!scope.row.is_superuser"
@ -79,26 +89,27 @@
size="small"
icon="el-icon-edit"
@click="handleEdit(scope)"
/>
<el-button
<!-- <el-button
v-if="!scope.row.is_superuser"
:disabled="!checkPermission(['dict_delete'])"
type="danger"
size="small"
icon="el-icon-delete"
@click="handleDelete(scope)"
/>
/> -->
</template>
</el-table-column>
</el-table>
<p v-show="!listQuery.type">点击左侧类型查看字典</p>
<pagination
<!-- <pagination
v-show="dictList.count>0"
:total="dictList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
/> -->
</el-card>
</el-col>
</el-row>
@ -115,24 +126,39 @@
<treeselect v-model="dicttype.pid" :multiple="false" :options="dictTypeData" placeholder="父级"/>
</el-form-item>
</el-form>
<div style="text-align:right;">
<span slot="footer">
<el-button type="danger" @click="dgV1=false">取消</el-button>
<el-button type="primary" @click="confirm1('Form1')">确认</el-button>
</div>
</span>
</el-dialog>
<el-dialog :visible.sync="dgV2" :title="dgT2==='edit'?'编辑字典':'新建字典'">
<el-form ref="Form2" :model="dict" label-width="80px" label-position="right" :rules="rule2">
<el-form-item label="编号" prop="code">
<el-input v-model="dict.code" placeholder="编号" />
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="dict.name" placeholder="名称" />
<el-input type="textarea" v-model="dict.name" placeholder="名称" />
</el-form-item>
<el-form-item label="描述" prop="desc">
<el-input v-model="dict.desc" placeholder="描述" />
<el-input type="textarea" v-model="dict.desc" placeholder="描述" />
</el-form-item>
<el-form-item label="父级" prop="pid">
<treeselect v-model="dict.pid" :multiple="false" :options="dictList" placeholder="父级"/>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="dict.sort" :min="1" :max="999"></el-input-number>
</el-form-item>
<el-form-item label="是否有效" prop="is_used">
<el-switch
v-model="dict.is_used">
</el-switch>
</el-form-item>
</el-form>
<div style="text-align:right;">
<span slot="footer">
<el-button type="danger" @click="dgV2=false">取消</el-button>
<el-button type="primary" @click="confirm2('Form2')">确认</el-button>
</div>
</span>
</el-dialog>
</div>
</template>
@ -165,20 +191,20 @@ const defaultDict = {
name: '',
desc: '',
sort: 1,
type: null
type: null,
is_used: true,
pid:null
}
export default {
components: { Pagination, Treeselect },
data() {
return {
dicttype: defaultDictType,
dict: defaultDict,
dictList: { count: 0 },
dicttype: Object.assign({}, defaultDictType),
dict: Object.assign({}, defaultDict),
search:'',
dictList: [],
listLoading: true,
listQuery: {
page: 1,
page_size: 20
},
listQuery: {},
dgV1: false,
dgT1: 'new',
rule1: {
@ -192,7 +218,7 @@ export default {
},
filterDictTypeText: '',
treeLoding: false,
dictTypeData: []
dictTypeData: [],
}
},
computed: {},
@ -202,7 +228,6 @@ export default {
}
},
created() {
this.getList()
this.getDictTypeList()
},
methods: {
@ -212,20 +237,15 @@ export default {
return data.label.indexOf(value) !== -1
},
handleDictTypeClick(obj, node, vue) {
this.listQuery.page = 1
this.listQuery.type = obj.id
this.getList()
},
getList() {
this.listLoading = true
getDictList(this.listQuery).then(response => {
if (response.code >= 200) {
if (response.data.results) {
this.dictList = response.data
}
this.listLoading = false
}
})
getDictList(this.listQuery).then(response =>{
this.dictList = genTree(response.data)
this.listLoading = false
}).catch(error=>{this.listLoading = false})
},
getDictTypeList() {
this.treeLoding = true
@ -259,8 +279,8 @@ export default {
this.$refs['Form2'].clearValidate()
})
},
handleEditDictType(val) {
this.dicttype = val // copy obj
handleEditDictType(data) {
this.dicttype = Object.assign({}, data) // copy obj
this.dgT1 = 'edit'
this.dgV1 = true
this.$nextTick(() => {
@ -277,7 +297,7 @@ export default {
.then(async() => {
const { code } = await deleteDict(scope.row.id)
if (code>=200){
this.dictList.results.splice(scope.row.index, 1)
this.dictList.splice(scope.row.index, 1)
this.$message({
type: 'success',
message: '成功删除!'
@ -294,30 +314,22 @@ export default {
const isEdit = this.dgT1 === 'edit'
if (isEdit) {
updateDictType(this.dicttype.id, this.dicttype).then(res => {
if (res.code >= 200) {
this.getDictTypeList()
this.dgV1 = false
this.$notify({
title: '成功',
this.$message({
message: '编辑成功',
type: 'success',
duration: 2000
})
}
})
}).catch(error=>{})
} else {
createDictType(this.dicttype).then(res => {
if (res.code >= 200) {
this.getDictTypeList()
this.dgV1 = false
this.$notify({
title: '成功',
this.$message({
message: '新增成功',
type: 'success',
duration: 2000
})
}
})
}).catch(error=>{})
}
} else {
return false
@ -330,30 +342,22 @@ export default {
const isEdit = this.dgT2 === 'edit'
if (isEdit) {
updateDict(this.dict.id, this.dict).then(res => {
if (res.code >= 200) {
this.getList()
this.dgV2 = false
this.$notify({
title: '成功',
this.$message({
message: '编辑成功',
type: 'success',
duration: 2000
})
}
})
}).catch(error=>{})
} else {
createDict(this.dict).then(res => {
if (res.code >= 200) {
this.getList()
this.dgV2 = false
this.$notify({
title: '成功',
this.$message({
message: '新增成功',
type: 'success',
duration: 2000
})
}
})
}).catch(error=>{})
}
} else {
return false

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class SupervisionConfig(AppConfig):
name = 'supervision'

View File

@ -0,0 +1,56 @@
# Generated by Django 3.0.5 on 2021-03-11 00:33
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('system', '0007_auto_20210311_0833'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Content',
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_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('name', models.CharField(max_length=100, verbose_name='名称')),
('desc', models.CharField(max_length=1000, verbose_name='详情')),
('can_doself', models.BooleanField(default=False, verbose_name='可随时主动报送')),
('belong_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='content_belong_to', to='system.Organization', verbose_name='所属部门')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='content_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('type', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='system.Dict', verbose_name='材料类型')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='content_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '报送清单',
'verbose_name_plural': '报送清单',
},
),
migrations.CreateModel(
name='Record',
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_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('is_lock', models.BooleanField(default=False, verbose_name='是否锁住')),
('is_yes', models.BooleanField(default=True, verbose_name='是否适用')),
('note', models.TextField(verbose_name='说明')),
('content', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='supervision.Content', verbose_name='材料内容')),
],
options={
'verbose_name': '上报记录',
'verbose_name_plural': '上报记录',
},
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.0.5 on 2021-03-11 00:39
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('supervision', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='content',
name='belong_to',
),
]

View File

@ -0,0 +1,37 @@
from django.db import models
from utils.model import BaseModel
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict
# Create your models here.
class Content(CommonAModel):
"""
资料清单
"""
name = models.CharField('名称', max_length=100)
desc = models.CharField('详情', max_length=1000)
type = models.ForeignKey(Dict, verbose_name='材料类型', on_delete= models.DO_NOTHING)
can_doself = models.BooleanField('可随时主动报送', default=False)
class Meta:
verbose_name = '报送清单'
verbose_name_plural = verbose_name
# class Task(CommonBModel):
# name = models.CharField('名称', max_length=100)
# pass
class Record(BaseModel):
"""
上报记录
"""
content = models.ForeignKey(Content, verbose_name='材料内容', on_delete=models.DO_NOTHING)
# task = models.ForeignKey(Task, verbose_name='关联任务', null=True, blank=True, on_delete=models.SET_NULL)
is_lock = models.BooleanField('是否锁住', default=False)
is_yes = models.BooleanField('是否适用', default=True)
note = models.TextField('说明')
class Meta:
verbose_name = '上报记录'
verbose_name_plural = verbose_name

View File

@ -0,0 +1,21 @@
from rest_framework import serializers
from .models import *
from apps.system.serializers import OrganizationSerializer
class ContentSerializer(serializers.ModelSerializer):
type_ = serializers.SerializerMethodField()
class Meta:
model = Content
fields = '__all__'
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('type')
return queryset
def get_type_ (self, obj):
data = obj.type.name
if obj.type.pid:
data = obj.type.pid.name + '/' + data
return data

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,9 @@
from django.urls import path, include
from rest_framework import routers
from .views import ContentViewSet
router = routers.DefaultRouter()
router.register('content', ContentViewSet, basename="content")
urlpatterns = [
path('', include(router.urls))
]

View File

@ -0,0 +1,28 @@
from django.shortcuts import render
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from .models import *
from .serializers import *
from rest_framework.decorators import action
from django.conf import settings
from rest_framework import status
from rest_framework.response import Response
from apps.system.models import Organization
from openpyxl import Workbook, load_workbook
from django.db.models import Count
from utils.pagination import PageOrNot
from apps.system.mixins import CreateModelAMixin
# Create your views here.
class ContentViewSet(CreateModelAMixin, ModelViewSet):
"""
资料清单增删改查
"""
perms_map = {'get': '*', 'post': 'content_create',
'put': 'content_update', 'delete': 'content_delete'}
queryset = Content.objects.all()
serializer_class = ContentSerializer
search_fields = ['name', 'desc']
filterset_fields = ['type']
ordering = ['type__sort', 'create_time']

View File

@ -0,0 +1,25 @@
# Generated by Django 3.0.5 on 2021-03-11 00:33
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('system', '0006_auto_20201230_1730'),
]
operations = [
migrations.AlterField(
model_name='file',
name='create_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='file_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
),
migrations.AlterField(
model_name='file',
name='update_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='file_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.0.5 on 2021-03-11 01:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0007_auto_20210311_0833'),
]
operations = [
migrations.AddField(
model_name='dict',
name='is_used',
field=models.BooleanField(default=True, verbose_name='是否有效'),
),
migrations.AddField(
model_name='historicaldict',
name='is_used',
field=models.BooleanField(default=True, verbose_name='是否有效'),
),
]

View File

@ -155,6 +155,7 @@ class Dict(SoftModel):
sort = models.IntegerField('排序', default=1)
pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='')
is_used = models.BooleanField('是否有效', default=True)
history = HistoricalRecords()
class Meta:
@ -170,9 +171,9 @@ class CommonAModel(SoftModel):
业务用基本表A,包含create_by, update_by字段
"""
create_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='create_by')
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='%(class)s_create_by')
update_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='update_by')
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='%(class)s_update_by')
class Meta:
abstract = True
@ -182,11 +183,11 @@ class CommonBModel(SoftModel):
业务用基本表B,包含create_by, update_by, belong_to字段
"""
create_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='create_by')
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name='%(class)s_create_by')
update_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='update_by')
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name='%(class)s_update_by')
belong_to = models.ForeignKey(
Organization, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='所属部门', related_name='belong_to')
Organization, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='所属部门', related_name='%(class)s_belong_to')
class Meta:
abstract = True

View File

@ -64,6 +64,9 @@ import datetime
class Login2View(APIView):
"""
邮箱验证码登录
"""
authentication_classes = []
permission_classes = []
def post(self, request):
@ -139,6 +142,16 @@ class DictViewSet(ModelViewSet):
search_fields = ['^name']
ordering_fields = ['id']
ordering = 'id'
def paginate_queryset(self, queryset):
"""
如果查询参数里没有page但有type或type__code时则不分页,否则请求分页
也可用utils.pageornot方法
"""
if self.paginator is None:
return None
elif (not self.request.query_params.get('page', None)) and ((self.request.query_params.get('type__code', None)) or (self.request.query_params.get('type', None))):
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)
class PositionViewSet(ModelViewSet):

Binary file not shown.

View File

@ -43,7 +43,8 @@ INSTALLED_APPS = [
"django_filters",
'apps.system',
'apps.crm',
'apps.ability'
'apps.ability',
'apps.supervision'
]
MIDDLEWARE = [

View File

@ -58,16 +58,14 @@ class MyTokenObtainPairView(TokenViewBase):
urlpatterns = [
path('', TemplateView.as_view(template_name="index.html")),
path('api/admin/', admin.site.urls),
path('api/login/', MyTokenObtainPairView.as_view(), name='my_login'),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token2/', Login2View.as_view(), name='token_obtain_2'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/token/black/', LogoutView.as_view(), name='token_black'),
path('api/system/', include('apps.system.urls')),
path('api/ability/', include('apps.ability.urls')),
path('api/docs/', include_docs_urls(title="接口文档",
authentication_classes=[], permission_classes=[])),
path('api/supervision/', include('apps.supervision.urls')),
path('api/docs/', include_docs_urls(title="接口文档",authentication_classes=[], permission_classes=[])),
path('api/', include(router.urls)),
url(r'^static/(?P<path>.*)$', serve,
{'document_root': settings.STATIC_ROOT}, name='static'),
url(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}, name='static'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)