Merge remote-tracking branch 'origin/v2.x' into v2.x
commit
69de8fff0b
|
@ -417,15 +417,24 @@ class MessageCenter(CoreModel):
|
|||
title = models.CharField(max_length=100,verbose_name="标题",help_text="标题")
|
||||
content = models.TextField(verbose_name="内容",help_text="内容")
|
||||
target_type=models.IntegerField(default=0,verbose_name="目标类型",help_text="目标类型")
|
||||
target_user = models.ManyToManyField(to=Users,related_name="target_user",blank=True,db_constraint=False,verbose_name="目标用户",help_text="目标用户")
|
||||
target_user = models.ManyToManyField(to=Users,related_name='user',through='MessageCenterTargetUser', through_fields=('messagecenter','users'),blank=True,verbose_name="目标用户",help_text="目标用户")
|
||||
target_dept = models.ManyToManyField(to=Dept, blank=True, db_constraint=False,
|
||||
verbose_name="目标部门", help_text="目标部门")
|
||||
target_role = models.ManyToManyField(to=Role, blank=True, db_constraint=False,
|
||||
verbose_name="目标角色", help_text="目标角色")
|
||||
is_read=models.BooleanField(default=False,blank=True,verbose_name="是否已读",help_text="是否已读")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "message_center"
|
||||
verbose_name = "消息中心"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
class MessageCenterTargetUser(CoreModel):
|
||||
users = models.ForeignKey(Users,related_name="target_user", on_delete=models.CASCADE,db_constraint=False,verbose_name="关联用户表",help_text="关联用户表")
|
||||
messagecenter = models.ForeignKey(MessageCenter, on_delete=models.CASCADE,db_constraint=False,verbose_name="关联消息中心表",help_text="关联消息中心表")
|
||||
is_read = models.BooleanField(default=False,blank=True,null=True,verbose_name="是否已读",help_text="是否已读")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "message_center_target_user"
|
||||
verbose_name = "消息中心目标用户表"
|
||||
verbose_name_plural = verbose_name
|
|
@ -2,13 +2,15 @@
|
|||
from itertools import chain
|
||||
|
||||
from django_restql.fields import DynamicSerializerMethodField
|
||||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action, permission_classes
|
||||
from rest_framework.permissions import IsAuthenticated, AllowAny
|
||||
|
||||
from dvadmin.system.models import MessageCenter, Users
|
||||
from dvadmin.system.models import MessageCenter, Users, MessageCenterTargetUser
|
||||
from dvadmin.system.views.dept import DeptSerializer
|
||||
from dvadmin.system.views.role import RoleSerializer
|
||||
from dvadmin.system.views.user import UserSerializer
|
||||
from dvadmin.utils.json_response import SuccessResponse
|
||||
from dvadmin.utils.json_response import SuccessResponse, DetailResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
||||
|
@ -19,6 +21,8 @@ class MessageCenterSerializer(CustomModelSerializer):
|
|||
"""
|
||||
role_info = DynamicSerializerMethodField()
|
||||
user_info = DynamicSerializerMethodField()
|
||||
dept_info = DynamicSerializerMethodField()
|
||||
is_read = serializers.BooleanField(read_only=True,source='target_user__is_read')
|
||||
def get_role_info(self, instance, parsed_query):
|
||||
roles =instance.target_role.all()
|
||||
# You can do what ever you want in here
|
||||
|
@ -41,12 +45,49 @@ class MessageCenterSerializer(CustomModelSerializer):
|
|||
)
|
||||
return serializer.data
|
||||
|
||||
def get_dept_info(self, instance, parsed_query):
|
||||
dept = instance.target_dept.all()
|
||||
# You can do what ever you want in here
|
||||
# `parsed_query` param is passed to BookSerializer to allow further querying
|
||||
serializer = DeptSerializer(
|
||||
dept,
|
||||
many=True,
|
||||
parsed_query=parsed_query
|
||||
)
|
||||
return serializer.data
|
||||
class Meta:
|
||||
model = MessageCenter
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class MessageCenterTargetUserSerializer(CustomModelSerializer):
|
||||
"""
|
||||
目标用户序列化器-序列化器
|
||||
"""
|
||||
class Meta:
|
||||
model = MessageCenterTargetUser
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
class MessageCenterTargetUserListSerializer(CustomModelSerializer):
|
||||
"""
|
||||
目标用户序列化器-序列化器
|
||||
"""
|
||||
class Meta:
|
||||
model = MessageCenterTargetUser
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
data['title'] = instance.messagecenter.title
|
||||
data['content'] = instance.messagecenter.content
|
||||
data['target_type'] = instance.messagecenter.target_type
|
||||
data['id'] = instance.messagecenter.id
|
||||
return data
|
||||
|
||||
|
||||
class MessageCenterCreateSerializer(CustomModelSerializer):
|
||||
"""
|
||||
消息中心-新增-序列化器
|
||||
|
@ -58,14 +99,21 @@ class MessageCenterCreateSerializer(CustomModelSerializer):
|
|||
target_type = initial_data.get('target_type')
|
||||
# 在保存之前,根据目标类型,把目标用户查询出来并保存
|
||||
users = initial_data.get('target_user',[])
|
||||
if target_type in [1]:
|
||||
if target_type in [1]: #按角色
|
||||
target_role = initial_data.get('target_role')
|
||||
users = Users.objects.exclude(is_deleted=True).filter(role__id__in=target_role).values_list('id',flat=True)
|
||||
if target_type in [2]:
|
||||
if target_type in [2]: #按部门
|
||||
target_dept = initial_data.get('target_dept')
|
||||
users = Users.objects.exclude(is_deleted=True).filter(dept__id__in=target_dept).values_list('id',flat=True)
|
||||
data.save()
|
||||
data.target_user.set(users)
|
||||
if target_type in [3]: #系统通知
|
||||
users = Users.objects.exclude(is_deleted=True).values_list('id',flat=True)
|
||||
targetuser_data = [{
|
||||
"messagecenter": data.id,
|
||||
"users": user
|
||||
} for user in users]
|
||||
targetuser_instance = MessageCenterTargetUserSerializer(data=targetuser_data, many=True, request=self.request)
|
||||
targetuser_instance.is_valid(raise_exception=True)
|
||||
targetuser_instance.save()
|
||||
return data
|
||||
|
||||
class Meta:
|
||||
|
@ -90,16 +138,44 @@ class MessageCenterViewSet(CustomModelViewSet):
|
|||
create_serializer_class = MessageCenterCreateSerializer
|
||||
extra_filter_backends = []
|
||||
|
||||
def get_queryset(self):
|
||||
if self.action=='list':
|
||||
return MessageCenter.objects.filter(creator=self.request.user.id).all()
|
||||
return MessageCenter.objects.all()
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
pk = kwargs.get('pk')
|
||||
user_id = self.request.user.id
|
||||
queryset = MessageCenterTargetUser.objects.filter(users__id=user_id,messagecenter__id=pk).first()
|
||||
if queryset:
|
||||
queryset.is_read = True
|
||||
queryset.save()
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(instance)
|
||||
return DetailResponse(data=serializer.data, msg="获取成功")
|
||||
|
||||
@action(methods=['get'],detail=True,permission_classes=[IsAuthenticated])
|
||||
def receive_view(self, request, pk):
|
||||
"""
|
||||
我的接收-查看
|
||||
"""
|
||||
instance = MessageCenterTargetUser.objects.filter(id=pk).first()
|
||||
instance.is_read = True
|
||||
instance.save()
|
||||
serializer = MessageCenterTargetUserListSerializer(instance)
|
||||
return DetailResponse(data=serializer.data, msg="获取成功")
|
||||
|
||||
@action(methods=['GET'],detail=False,permission_classes=[IsAuthenticated])
|
||||
def get_self_receive(self,request):
|
||||
"""
|
||||
获取接收到的消息
|
||||
"""
|
||||
self_user_id = self.request.user.id
|
||||
queryset = MessageCenter.objects.filter(target_user__id=self_user_id)
|
||||
queryset = MessageCenterTargetUser.objects.filter(users__id=self_user_id).exclude(messagecenter__is_deleted=True)
|
||||
queryset = self.filter_queryset(queryset)
|
||||
page = self.paginate_queryset(queryset)
|
||||
if page is not None:
|
||||
serializer = self.get_serializer(page, many=True, request=request)
|
||||
serializer = MessageCenterTargetUserListSerializer(page, many=True, request=request)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
serializer = self.get_serializer(queryset, many=True, request=request)
|
||||
serializer = MessageCenterTargetUserListSerializer(queryset, many=True, request=request)
|
||||
return SuccessResponse(data=serializer.data, msg="获取成功")
|
|
@ -252,6 +252,10 @@ Vue.prototype.commonEndColumns = function (param = {}) {
|
|||
showForm: (param.update_datetime && param.update_datetime.showForm) !== undefined ? param.update_datetime.showForm : false,
|
||||
showTable: (param.update_datetime && param.update_datetime.showTable) !== undefined ? param.update_datetime.showTable : true
|
||||
},
|
||||
creator_name: {
|
||||
showForm: (param.creator_name && param.creator_name.showForm) !== undefined ? param.creator_name.showForm : false,
|
||||
showTable: (param.creator_name && param.creator_name.showTable) !== undefined ? param.creator_name.showTable : false
|
||||
},
|
||||
create_datetime: {
|
||||
showForm: (param.create_datetime && param.create_datetime.showForm) !== undefined ? param.create_datetime.showForm : false,
|
||||
showTable: (param.create_datetime && param.create_datetime.showTable) !== undefined ? param.create_datetime.showTable : true
|
||||
|
|
|
@ -52,3 +52,16 @@ export function DelObj (id) {
|
|||
data: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的接收-查看
|
||||
* @param obj
|
||||
* @returns {*}
|
||||
*/
|
||||
export function receiveView (obj) {
|
||||
return request({
|
||||
url: urlPrefix + obj.id + '/receive_view/',
|
||||
method: 'get',
|
||||
params: {}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,13 +3,52 @@ import { request } from '@/api/service'
|
|||
export const crudOptions = (vm) => {
|
||||
return {
|
||||
indexRow: { // 或者直接传true,不显示title,不居中
|
||||
width:60,
|
||||
title: '序号',
|
||||
align: 'center'
|
||||
},
|
||||
options: {
|
||||
tableType: 'vxe-table',
|
||||
rowKey: true, // 必须设置,true or false
|
||||
height: '100%' // 表格高度100%, 使用toolbar必须设置
|
||||
},
|
||||
viewOptions: {
|
||||
rowHandle: {
|
||||
width: 160,
|
||||
fixed: 'right',
|
||||
view: false,
|
||||
edit: {
|
||||
thin: true,
|
||||
text: '',
|
||||
show () {
|
||||
return vm.tabActivted !== 'receive'
|
||||
},
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Update')
|
||||
}
|
||||
},
|
||||
remove: {
|
||||
thin: true,
|
||||
text: '',
|
||||
show () {
|
||||
return vm.tabActivted !== 'receive'
|
||||
},
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Delete')
|
||||
}
|
||||
},
|
||||
custom: [
|
||||
{
|
||||
thin: true,
|
||||
text: null,
|
||||
icon: 'el-icon-view',
|
||||
size: 'small',
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Retrieve')
|
||||
},
|
||||
order: 1,
|
||||
emit: 'onView'
|
||||
}
|
||||
]
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
|
@ -24,7 +63,7 @@ export const crudOptions = (vm) => {
|
|||
search: {
|
||||
disabled: false
|
||||
},
|
||||
width: 400,
|
||||
width: 200,
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{
|
||||
|
@ -35,12 +74,40 @@ export const crudOptions = (vm) => {
|
|||
component: { span: 24, placeholder: '请输入标题' }
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '是否已读',
|
||||
key: 'is_read',
|
||||
type: 'select',
|
||||
width: 100,
|
||||
show () {
|
||||
return vm.tabActivted === 'receive'
|
||||
},
|
||||
dict: {
|
||||
data: [
|
||||
{ label: '已读', value: true, color: 'success' },
|
||||
{ label: '未读', value: false, color: 'danger' }
|
||||
]
|
||||
},
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '目标类型',
|
||||
key: 'target_type',
|
||||
type: 'radio',
|
||||
dict: { data: [{ value: 0, label: '按用户' }, { value: 1, label: '按角色' }, { value: 2, label: '按部门' }] },
|
||||
width: 120,
|
||||
show () {
|
||||
return vm.tabActivted === 'send'
|
||||
},
|
||||
dict: { data: [{ value: 0, label: '按用户' }, { value: 1, label: '按角色' }, { value: 2, label: '按部门' }, { value: 3, label: '通知公告' }] },
|
||||
form: {
|
||||
component: {
|
||||
span: 24,
|
||||
props: {
|
||||
type: 'el-radio-button'
|
||||
}
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
|
@ -56,8 +123,11 @@ export const crudOptions = (vm) => {
|
|||
search: {
|
||||
disabled: true
|
||||
},
|
||||
minWidth: 130,
|
||||
width: 130,
|
||||
type: 'table-selector',
|
||||
show () {
|
||||
return vm.tabActivted === 'send'
|
||||
},
|
||||
dict: {
|
||||
cache: false,
|
||||
url: '/api/system/user/',
|
||||
|
@ -124,8 +194,10 @@ export const crudOptions = (vm) => {
|
|||
search: {
|
||||
disabled: true
|
||||
},
|
||||
|
||||
minWidth: 130,
|
||||
show () {
|
||||
return vm.tabActivted === 'send'
|
||||
},
|
||||
width: 130,
|
||||
type: 'table-selector',
|
||||
dict: {
|
||||
cache: false,
|
||||
|
@ -193,11 +265,14 @@ export const crudOptions = (vm) => {
|
|||
search: {
|
||||
disabled: true
|
||||
},
|
||||
minWidth: 130,
|
||||
width: 130,
|
||||
show () {
|
||||
return vm.tabActivted === 'send'
|
||||
},
|
||||
type: 'table-selector',
|
||||
dict: {
|
||||
cache: false,
|
||||
url: '/api/system/dept/',
|
||||
url: '/api/system/dept/all_dept/',
|
||||
isTree: true,
|
||||
value: 'id', // 数据字典中value字段的属性名
|
||||
label: 'name', // 数据字典中label字段的属性名
|
||||
|
@ -207,11 +282,7 @@ export const crudOptions = (vm) => {
|
|||
component
|
||||
}) => {
|
||||
return request({
|
||||
url: url,
|
||||
params: {
|
||||
page: 1,
|
||||
limit: 999
|
||||
}
|
||||
url: url
|
||||
}).then(ret => {
|
||||
return ret.data.data
|
||||
})
|
||||
|
@ -269,7 +340,7 @@ export const crudOptions = (vm) => {
|
|||
{
|
||||
title: '内容',
|
||||
key: 'content',
|
||||
width: 300,
|
||||
minWidth: 300,
|
||||
type: 'editor-quill', // 富文本图片上传依赖file-uploader,请先配置好file-uploader
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
|
@ -295,6 +366,9 @@ export const crudOptions = (vm) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
].concat(vm.commonEndColumns({
|
||||
create_datetime: { showTable: true },
|
||||
update_datetime: { showTable: false }
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
ref="d2Crud"
|
||||
v-bind="_crudProps"
|
||||
v-on="_crudListeners"
|
||||
@form-component-ready="handleFormComponentReady"
|
||||
@onView="onView"
|
||||
>
|
||||
<div slot="header">
|
||||
<crud-search ref="search" :options="crud.searchOptions" @submit="handleSearch" />
|
||||
|
@ -26,9 +26,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { AddObj, GetObj, GetList, UpdateObj, DelObj, GetSelfReceive } from './api'
|
||||
import { AddObj, GetObj, GetList, UpdateObj, DelObj, GetSelfReceive,receiveView } from './api'
|
||||
import { crudOptions } from './crud'
|
||||
import { d2CrudPlus } from 'd2-crud-plus'
|
||||
import viewTemplate from './viewTemplate.js'
|
||||
export default {
|
||||
name: 'messageCenter',
|
||||
components: {},
|
||||
|
@ -83,10 +84,18 @@ export default {
|
|||
return res.data
|
||||
})
|
||||
},
|
||||
handleFormComponentReady (event, key, form) {
|
||||
// console.log('form component ready:', event, key, form)
|
||||
onView ({ row, index }) {
|
||||
this.getD2Crud().showDialog({
|
||||
mode: 'view',
|
||||
rowIndex: index,
|
||||
template: viewTemplate
|
||||
})
|
||||
this.infoRequest(row)
|
||||
this.doRefresh()
|
||||
},
|
||||
onTabClick (obj) {
|
||||
onTabClick (tab) {
|
||||
const { name } = tab
|
||||
this.tabActivted = name
|
||||
this.doRefresh()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
export default {
|
||||
title: {
|
||||
title: '标题',
|
||||
key: 'title',
|
||||
component: {
|
||||
span: 24,
|
||||
placeholder: '请输入标题',
|
||||
disabled: true
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项'
|
||||
}
|
||||
],
|
||||
order: 10
|
||||
},
|
||||
content: {
|
||||
title: '内容',
|
||||
key: 'content',
|
||||
component: {
|
||||
name: 'd2p-quill',
|
||||
span: 24,
|
||||
disabled: true,
|
||||
props: {
|
||||
uploader: {
|
||||
type: 'form'
|
||||
}
|
||||
},
|
||||
events: {}
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项'
|
||||
}
|
||||
],
|
||||
order: 10
|
||||
}
|
||||
}
|
|
@ -206,6 +206,71 @@ export const crudOptions = (vm) => {
|
|||
valueBinding: 'dept_name'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '角色',
|
||||
key: 'role',
|
||||
search: {
|
||||
disabled: true
|
||||
},
|
||||
minWidth: 130,
|
||||
type: 'table-selector',
|
||||
dict: {
|
||||
cache: false,
|
||||
url: '/api/system/role/',
|
||||
value: 'id', // 数据字典中value字段的属性名
|
||||
label: 'name', // 数据字典中label字段的属性名
|
||||
getData: (url, dict, {
|
||||
form,
|
||||
component
|
||||
}) => {
|
||||
return request({
|
||||
url: url,
|
||||
params: {
|
||||
page: 1,
|
||||
limit: 10
|
||||
}
|
||||
}).then(ret => {
|
||||
component._elProps.page = ret.data.page
|
||||
component._elProps.limit = ret.data.limit
|
||||
component._elProps.total = ret.data.total
|
||||
return ret.data.data
|
||||
})
|
||||
}
|
||||
},
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{
|
||||
required: true,
|
||||
message: '必填项'
|
||||
}
|
||||
],
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
},
|
||||
component: {
|
||||
span: 12,
|
||||
pagination: true,
|
||||
props: { multiple: true },
|
||||
elProps: {
|
||||
columns: [
|
||||
{
|
||||
field: 'name',
|
||||
title: '角色名称'
|
||||
},
|
||||
{
|
||||
field: 'key',
|
||||
title: '权限标识'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
component: {
|
||||
name: 'manyToMany',
|
||||
valueBinding: 'role_info',
|
||||
children: 'name'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '手机号码',
|
||||
key: 'mobile',
|
||||
|
@ -320,71 +385,6 @@ export const crudOptions = (vm) => {
|
|||
},
|
||||
helper: '限制文件大小不能超过500k'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '角色',
|
||||
key: 'role',
|
||||
search: {
|
||||
disabled: true
|
||||
},
|
||||
minWidth: 130,
|
||||
type: 'table-selector',
|
||||
dict: {
|
||||
cache: false,
|
||||
url: '/api/system/role/',
|
||||
value: 'id', // 数据字典中value字段的属性名
|
||||
label: 'name', // 数据字典中label字段的属性名
|
||||
getData: (url, dict, {
|
||||
form,
|
||||
component
|
||||
}) => {
|
||||
return request({
|
||||
url: url,
|
||||
params: {
|
||||
page: 1,
|
||||
limit: 10
|
||||
}
|
||||
}).then(ret => {
|
||||
component._elProps.page = ret.data.page
|
||||
component._elProps.limit = ret.data.limit
|
||||
component._elProps.total = ret.data.total
|
||||
return ret.data.data
|
||||
})
|
||||
}
|
||||
},
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{
|
||||
required: true,
|
||||
message: '必填项'
|
||||
}
|
||||
],
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
},
|
||||
component: {
|
||||
span: 12,
|
||||
pagination: true,
|
||||
props: { multiple: true },
|
||||
elProps: {
|
||||
columns: [
|
||||
{
|
||||
field: 'name',
|
||||
title: '角色名称'
|
||||
},
|
||||
{
|
||||
field: 'key',
|
||||
title: '权限标识'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
component: {
|
||||
name: 'manyToMany',
|
||||
valueBinding: 'role_info',
|
||||
children: 'name'
|
||||
}
|
||||
}
|
||||
].concat(vm.commonEndColumns({
|
||||
create_datetime: { showTable: false },
|
||||
|
|
Loading…
Reference in New Issue