commit
1310e206a5
|
@ -30,8 +30,6 @@ system_url.register(r'system_config', SystemConfigViewSet)
|
|||
system_url.register(r'message_center',MessageCenterViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('user/export/', UserViewSet.as_view({'post': 'export_data', })),
|
||||
path('user/import/', UserViewSet.as_view({'get': 'import_data', 'post': 'import_data'})),
|
||||
path('system_config/save_content/', SystemConfigViewSet.as_view({'put': 'save_content'})),
|
||||
path('system_config/get_association_table/', SystemConfigViewSet.as_view({'get': 'get_association_table'})),
|
||||
path('system_config/get_table_data/<int:pk>/', SystemConfigViewSet.as_view({'get': 'get_table_data'})),
|
||||
|
|
|
@ -54,25 +54,39 @@ class LoginSerializer(TokenObtainPairSerializer):
|
|||
登录的序列化器:
|
||||
重写djangorestframework-simplejwt的序列化器
|
||||
"""
|
||||
|
||||
captcha = serializers.CharField(
|
||||
max_length=6, required=False, allow_null=True, allow_blank=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
default_error_messages = {"no_active_account": _("账号/密码错误")}
|
||||
class LoginView(TokenObtainPairView):
|
||||
"""
|
||||
登录接口
|
||||
"""
|
||||
serializer_class = LoginSerializer
|
||||
permission_classes = []
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
# username可能携带的不止是用户名,可能还是用户的其它唯一标识 手机号 邮箱
|
||||
username = request.data.get('username',None)
|
||||
if username is None:
|
||||
return ErrorResponse(msg="账号不能为空")
|
||||
password = request.data.get('password',None)
|
||||
if password is None:
|
||||
return ErrorResponse(msg="密码不能为空")
|
||||
|
||||
def validate(self, attrs):
|
||||
captcha = self.initial_data.get("captcha", None)
|
||||
if dispatch.get_system_config_values("base.captcha_state"):
|
||||
captcha = request.data.get('captcha', None)
|
||||
captchaKey = request.data.get('captchaKey', None)
|
||||
if captchaKey is None:
|
||||
return ErrorResponse(msg="验证码不能为空")
|
||||
if captcha is None:
|
||||
raise CustomValidationError("验证码不能为空")
|
||||
self.image_code = CaptchaStore.objects.filter(
|
||||
id=self.initial_data["captchaKey"]
|
||||
id=captchaKey
|
||||
).first()
|
||||
five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
|
||||
if self.image_code and five_minute_ago > self.image_code.expiration:
|
||||
|
@ -87,34 +101,36 @@ class LoginSerializer(TokenObtainPairSerializer):
|
|||
else:
|
||||
self.image_code and self.image_code.delete()
|
||||
raise CustomValidationError("图片验证码错误")
|
||||
data = super().validate(attrs)
|
||||
data["name"] = self.user.name
|
||||
data["userId"] = self.user.id
|
||||
data["avatar"] = self.user.avatar
|
||||
dept = getattr(self.user, 'dept', None)
|
||||
try:
|
||||
# 手动通过 user 签发 jwt-token
|
||||
user = Users.objects.get(username=username)
|
||||
except:
|
||||
return ErrorResponse(msg='该账号未注册')
|
||||
# 获得用户后,校验密码并签发token
|
||||
if not user.check_password(password):
|
||||
return ErrorResponse(msg='密码错误')
|
||||
result = {
|
||||
"name":user.name,
|
||||
"userId":user.id,
|
||||
"avatar":user.avatar,
|
||||
}
|
||||
dept = getattr(user, 'dept', None)
|
||||
if dept:
|
||||
data['dept_info'] = {
|
||||
result['dept_info'] = {
|
||||
'dept_id': dept.id,
|
||||
'dept_name': dept.name,
|
||||
'dept_key': dept.key
|
||||
}
|
||||
role = getattr(self.user, 'role', None)
|
||||
role = getattr(user, 'role', None)
|
||||
if role:
|
||||
data['role_info'] = role.values('id', 'name', 'key')
|
||||
request = self.context.get("request")
|
||||
request.user = self.user
|
||||
result['role_info'] = role.values('id', 'name', 'key')
|
||||
refresh = LoginSerializer.get_token(user)
|
||||
result["refresh"] = str(refresh)
|
||||
result["access"] = str(refresh.access_token)
|
||||
# 记录登录日志
|
||||
request.user = user
|
||||
save_login_log(request=request)
|
||||
return {"code": 2000, "msg": "请求成功", "data": data}
|
||||
|
||||
|
||||
class LoginView(TokenObtainPairView):
|
||||
"""
|
||||
登录接口
|
||||
"""
|
||||
|
||||
serializer_class = LoginSerializer
|
||||
permission_classes = []
|
||||
return DetailResponse(data=result,msg="获取成功")
|
||||
|
||||
|
||||
class LoginTokenSerializer(TokenObtainPairSerializer):
|
||||
|
|
|
@ -34,3 +34,4 @@ class LoginLogViewSet(CustomModelViewSet):
|
|||
queryset = LoginLog.objects.all()
|
||||
serializer_class = LoginLogSerializer
|
||||
extra_filter_backends = []
|
||||
ordering_fields = ['create_datetime']
|
||||
|
|
|
@ -185,11 +185,11 @@ class MenuViewSet(CustomModelViewSet):
|
|||
parent = params.get('parent', None)
|
||||
if params:
|
||||
if parent:
|
||||
queryset = self.queryset.filter(status=1, parent=parent)
|
||||
queryset = self.queryset.filter(parent=parent)
|
||||
else:
|
||||
queryset = self.queryset.filter(status=1)
|
||||
queryset = self.queryset
|
||||
else:
|
||||
queryset = self.queryset.filter(status=1, parent__isnull=True)
|
||||
queryset = self.queryset.filter(parent__isnull=True)
|
||||
queryset = self.filter_queryset(queryset)
|
||||
serializer = MenuSerializer(queryset, many=True, request=request)
|
||||
data = serializer.data
|
||||
|
|
|
@ -86,7 +86,9 @@ class MessageCenterTargetUserListSerializer(CustomModelSerializer):
|
|||
user_id = self.request.user.id
|
||||
message_center_id = instance.id
|
||||
queryset = MessageCenterTargetUser.objects.filter(messagecenter__id=message_center_id,users_id=user_id).first()
|
||||
return queryset.is_read
|
||||
if queryset:
|
||||
return queryset.is_read
|
||||
return False
|
||||
|
||||
class Meta:
|
||||
model = MessageCenter
|
||||
|
@ -121,12 +123,12 @@ class MessageCenterCreateSerializer(CustomModelSerializer):
|
|||
users = initial_data.get('target_user', [])
|
||||
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)
|
||||
users = Users.objects.filter(role__id__in=target_role).values_list('id', flat=True)
|
||||
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)
|
||||
users = Users.objects.filter(dept__id__in=target_dept).values_list('id', flat=True)
|
||||
if target_type in [3]: # 系统通知
|
||||
users = Users.objects.exclude(is_deleted=True).values_list('id', flat=True)
|
||||
users = Users.objects.values_list('id', flat=True)
|
||||
targetuser_data = []
|
||||
for user in users:
|
||||
targetuser_data.append({
|
||||
|
@ -211,6 +213,6 @@ class MessageCenterViewSet(CustomModelViewSet):
|
|||
queryset = MessageCenterTargetUser.objects.filter(users__id=self_user_id).order_by('create_datetime').last()
|
||||
data = None
|
||||
if queryset:
|
||||
serializer = MessageCenterTargetUserListSerializer(queryset, many=False, request=request)
|
||||
serializer = MessageCenterTargetUserListSerializer(queryset.messagecenter, many=False, request=request)
|
||||
data = serializer.data
|
||||
return DetailResponse(data=data, msg="获取成功")
|
||||
|
|
|
@ -219,10 +219,12 @@ class ExportUserProfileSerializer(CustomModelSerializer):
|
|||
|
||||
|
||||
class UserProfileImportSerializer(CustomModelSerializer):
|
||||
password = serializers.CharField(required=True, max_length=50, error_messages={"required": "登录密码不能为空"})
|
||||
|
||||
def save(self, **kwargs):
|
||||
data = super().save(**kwargs)
|
||||
password = hashlib.new(
|
||||
"md5", str(self.initial_data.get("password", "")).encode(encoding="UTF-8")
|
||||
"md5", str(self.initial_data.get("password", "admin123456")).encode(encoding="UTF-8")
|
||||
).hexdigest()
|
||||
data.set_password(password)
|
||||
data.save()
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
from django.core import paginator
|
||||
from django.core.paginator import Paginator as DjangoPaginator
|
||||
from django.core.paginator import Paginator as DjangoPaginator, InvalidPage
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from rest_framework.response import Response
|
||||
|
||||
|
@ -21,13 +21,52 @@ class CustomPagination(PageNumberPagination):
|
|||
max_page_size = 999
|
||||
django_paginator_class = DjangoPaginator
|
||||
|
||||
def paginate_queryset(self, queryset, request, view=None):
|
||||
"""
|
||||
Paginate a queryset if required, either returning a
|
||||
page object, or `None` if pagination is not configured for this view.
|
||||
"""
|
||||
empty = True
|
||||
|
||||
page_size = self.get_page_size(request)
|
||||
if not page_size:
|
||||
return None
|
||||
|
||||
paginator = self.django_paginator_class(queryset, page_size)
|
||||
page_number = request.query_params.get(self.page_query_param, 1)
|
||||
if page_number in self.last_page_strings:
|
||||
page_number = paginator.num_pages
|
||||
|
||||
try:
|
||||
self.page = paginator.page(page_number)
|
||||
except InvalidPage as exc:
|
||||
|
||||
# msg = self.invalid_page_message.format(
|
||||
# page_number=page_number, message=str(exc)
|
||||
# )
|
||||
# raise NotFound(msg)
|
||||
empty = False
|
||||
pass
|
||||
|
||||
if paginator.num_pages > 1 and self.template is not None:
|
||||
# The browsable API should display pagination controls.
|
||||
self.display_page_controls = True
|
||||
|
||||
self.request = request
|
||||
|
||||
if not empty:
|
||||
self.page = []
|
||||
|
||||
return list(self.page)
|
||||
def get_paginated_response(self, data):
|
||||
code = 2000
|
||||
msg = 'success'
|
||||
res = {
|
||||
"page": int(self.get_page_number(self.request, paginator)) or 1,
|
||||
"total": self.page.paginator.count,
|
||||
"total": self.page.paginator.count if self.page else 0,
|
||||
"limit": int(self.get_page_size(self.request)) or 10,
|
||||
"is_next": self.page.has_next(),
|
||||
"is_previous": self.page.has_previous(),
|
||||
"data": data
|
||||
}
|
||||
if not data:
|
||||
|
@ -38,6 +77,6 @@ class CustomPagination(PageNumberPagination):
|
|||
return Response(OrderedDict([
|
||||
('code', code),
|
||||
('msg', msg),
|
||||
# ('total',self.page.paginator.count),
|
||||
('data', res),
|
||||
]))
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
"china-division": "^2.4.0",
|
||||
"core-js": "^3.4.3",
|
||||
"cropperjs": "^1.5.6",
|
||||
"d2-crud-plus": "^2.13.1",
|
||||
"d2-crud-x": "^2.13.1",
|
||||
"d2p-extends": "^2.13.1",
|
||||
"d2-crud-plus": "^2.17.9",
|
||||
"d2-crud-x": "^2.17.9",
|
||||
"d2p-extends": "^2.17.9",
|
||||
"dayjs": "^1.8.17",
|
||||
"echarts": "^5.1.2",
|
||||
"el-phone-number-input": "^1.1.5",
|
||||
|
@ -42,6 +42,7 @@
|
|||
"sortablejs": "^1.10.1",
|
||||
"ua-parser-js": "^0.7.20",
|
||||
"vue": "2.7.14",
|
||||
"vue-grid-layout": "^2.4.0",
|
||||
"vue-i18n": "^8.15.1",
|
||||
"vue-infinite-scroll": "^2.0.2",
|
||||
"vue-router": "^3.6.5",
|
||||
|
|
|
@ -118,7 +118,7 @@ export default {
|
|||
that.$refs.upload.clearFiles()
|
||||
// 是否更新已经存在的用户数据
|
||||
return request({
|
||||
url: util.baseURL() + that.api + 'import_data/',
|
||||
url: that.api + 'import_data/',
|
||||
method: 'post',
|
||||
data: {
|
||||
url: response.data.url
|
||||
|
|
|
@ -62,7 +62,15 @@ Vue.use(d2CrudPlus, {
|
|||
page: { // page接口返回的数据结构配置,
|
||||
request: {
|
||||
current: 'page',
|
||||
size: 'limit'
|
||||
size: 'limit',
|
||||
orderAsc (query, value) {
|
||||
const field = query.orderProp
|
||||
if (value) {
|
||||
query.ordering = field
|
||||
} else {
|
||||
query.ordering = `-${field}`
|
||||
}
|
||||
}
|
||||
},
|
||||
response: {
|
||||
current: 'page', // 当前页码 ret.data.current
|
||||
|
|
|
@ -97,6 +97,12 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 授权后可以删除-->
|
||||
<div class="dvadmin-auth">
|
||||
<span>Powered by Django-Vue-Admin</span>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<span>Copyright dvadmin团队</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -208,4 +214,24 @@ export default {
|
|||
<style lang="scss">
|
||||
// 注册主题
|
||||
@import "~@/assets/style/theme/register.scss";
|
||||
|
||||
// 授权样式
|
||||
.dvadmin-auth{
|
||||
font-size: 0.8em;
|
||||
position: absolute;
|
||||
top: 50vh;
|
||||
right: -9vw;
|
||||
text-align: center;
|
||||
color: #888888;
|
||||
background-image: linear-gradient(to left, #d3d3d3, #989898, #888888, #363636,#888888,#989898,#d3d3d3);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-size: 200% 100%;
|
||||
animation: bgp 6s infinite linear;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
@-webkit-keyframes bgp {
|
||||
0% {background-position: 0 0; }
|
||||
100% {background-position: -100% 0; }
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<el-card shadow="hover" header="关于项目" class="item-background">
|
||||
<p>高性能 / 精致 / 优雅。基于Vue2 + Element-UI 的中后台前端解决方案,如果喜欢就点个星星支持一下。</p>
|
||||
<p>
|
||||
<a href='https://liqianglog.gitee.io/django-vue-admin' target="_blank">
|
||||
<img src='https://liqianglog.gitee.io/django-vue-admin/badge/star.svg?theme=dark' alt='star' style="vertical-align: middle">
|
||||
</a>
|
||||
</p>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
title: '关于项目',
|
||||
icon: 'el-icon-setting',
|
||||
description: '点个星星支持一下',
|
||||
height: 20,
|
||||
width: 8,
|
||||
minH: 20,
|
||||
minW: 4,
|
||||
isResizable: true,
|
||||
data () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-background p {
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,13 @@
|
|||
import { markRaw } from 'vue'
|
||||
|
||||
const resultComps = {}
|
||||
const requireComponent = require.context(
|
||||
'./', // 在当前目录下查找
|
||||
false, // 不遍历子文件夹
|
||||
/\.vue$/ // 正则匹配 以 .vue结尾的文件
|
||||
)
|
||||
requireComponent.keys().forEach(fileName => {
|
||||
const comp = requireComponent(fileName)
|
||||
resultComps[fileName.replace(/^\.\/(.*)\.\w+$/, '$1')] = comp.default
|
||||
})
|
||||
export default markRaw(resultComps)
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<el-card shadow="hover" header="时钟" class="item-background">
|
||||
<div class="time">
|
||||
<h2>{{ time }}</h2>
|
||||
<p>{{ day }}</p>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
title: '时钟',
|
||||
icon: 'el-icon-alarm-clock',
|
||||
description: '演示部件效果',
|
||||
height: 17,
|
||||
minH: 17,
|
||||
width: 8,
|
||||
minW: 4,
|
||||
isResizable: true,
|
||||
data () {
|
||||
return {
|
||||
time: '',
|
||||
day: ''
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.showTime()
|
||||
setInterval(() => {
|
||||
this.showTime()
|
||||
}, 1000)
|
||||
},
|
||||
methods: {
|
||||
showTime () {
|
||||
this.time = dayjs().format('hh:mm:ss')
|
||||
this.day = dayjs().format('YYYY年MM月DD日')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-background {
|
||||
background: linear-gradient(to right, #8E54E9, #4776E6);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.time h2 {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.time p {
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<el-card shadow="hover" header="版本信息">
|
||||
<div style="height: 70px;text-align: center;">
|
||||
<h2 style="margin-top: 5px;">Dvadmin</h2>
|
||||
<p style="margin-top: 5px;">最新版本 {{ ver }}</p>
|
||||
</div>
|
||||
<div style="margin-top: 5px;">
|
||||
<el-button type="primary" plain round @click="golog">更新日志</el-button>
|
||||
<el-button type="primary" plain round @click="gogit">gitee</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
title: '版本信息',
|
||||
icon: 'el-icon-monitor',
|
||||
description: '当前项目版本信息',
|
||||
height: 22,
|
||||
width: 8,
|
||||
minH: 22,
|
||||
minW: 4,
|
||||
isResizable: true,
|
||||
data () {
|
||||
return {
|
||||
ver: 'loading...'
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.getVer()
|
||||
},
|
||||
methods: {
|
||||
async getVer () {
|
||||
this.ver = 'v2.0.9'
|
||||
},
|
||||
golog () {
|
||||
window.open('https://gitee.com/liqianglog/django-vue-admin/releases')
|
||||
},
|
||||
gogit () {
|
||||
window.open('https://gitee.com/liqianglog/django-vue-admin')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<el-card shadow="hover" header="欢迎">
|
||||
<div class="welcome">
|
||||
<div class="logo">
|
||||
<img src="/image/django-vue-admin.png">
|
||||
<h2>欢迎体验 Dvadmin</h2>
|
||||
</div>
|
||||
<div class="tips">
|
||||
<div class="tips-item">
|
||||
<div class="tips-item-icon">
|
||||
<i class="el-icon-menu"></i>
|
||||
</div>
|
||||
<div class="tips-item-message">这里是项目控制台,你可以点击右上方的“自定义”按钮来添加移除或者移动部件。</div>
|
||||
</div>
|
||||
<div class="tips-item">
|
||||
<div class="tips-item-icon">
|
||||
<i class="el-icon-star-on"></i>
|
||||
</div>
|
||||
<div class="tips-item-message">热爱Python和Vue,打造一个低代码开源平台,并且持续着。</div>
|
||||
</div>
|
||||
<div class="tips-item">
|
||||
<div class="tips-item-icon">
|
||||
<i class="el-icon-milk-tea"></i>
|
||||
</div>
|
||||
<div class="tips-item-message">项目目的:让前端和后端工作更快乐</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<el-button type="primary" icon="el-icon-check" size="large" @click="godoc">文档</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
title: '欢迎',
|
||||
icon: 'el-icon-present',
|
||||
description: '项目特色以及文档链接',
|
||||
height: 50,
|
||||
minH: 50,
|
||||
width: 8,
|
||||
minW: 4,
|
||||
isResizable: true,
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
godoc () {
|
||||
window.open('https://www.django-vue-admin.com/')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.welcome {
|
||||
}
|
||||
|
||||
.welcome .logo {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.welcome .logo img {
|
||||
vertical-align: bottom;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.welcome .logo h2 {
|
||||
font-size: 30px;
|
||||
font-weight: normal;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tips {
|
||||
margin-top: 20px;
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
.tips-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 7.5px 0;
|
||||
}
|
||||
|
||||
.tips-item-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
font-size: 18px;
|
||||
margin-right: 20px;
|
||||
color: var(--el-color-primary);
|
||||
background: rgba(180, 180, 180, 0.1);
|
||||
}
|
||||
|
||||
.tips-item-message {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
text-align: center;
|
||||
margin: 40px 0 20px 0;
|
||||
}
|
||||
</style>
|
|
@ -1,313 +1,382 @@
|
|||
<template>
|
||||
<d2-container>
|
||||
<div class="page-header">
|
||||
|
||||
<el-avatar src="https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640" class="user-avatar">
|
||||
|
||||
</el-avatar>
|
||||
<div class="title">
|
||||
<h1>早安, DVAdmin, 开始您一天的工作吧!</h1>
|
||||
<span> 今日晴,20℃ - 32℃! </span>
|
||||
<div class="component-header">
|
||||
<div class="set-btn-class">
|
||||
<el-button v-if="customizing" type="primary" icon="el-icon-check" round @click="save">完成</el-button>
|
||||
<el-button v-else type="primary" icon="el-icon-edit" round @click="custom">自定义</el-button>
|
||||
</div>
|
||||
<div v-if="customizing" class="all-component-class">
|
||||
<el-card style="margin-bottom: 20px">
|
||||
<div slot="header">
|
||||
<i class="el-icon-circle-plus"></i>
|
||||
<span>添加部件</span>
|
||||
<el-button-group style="float: right">
|
||||
<el-button type="primary" size="mini" @click="backDefaul()">恢复默认</el-button>
|
||||
<el-button type="danger" size="mini" @click="close()">关闭</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
<div class="widgets-list">
|
||||
<div v-if="myCompsList.length<=0" class="widgets-list-nodata">
|
||||
<el-empty description="没有部件啦" :image-size="60"></el-empty>
|
||||
</div>
|
||||
<div v-for="item in myCompsList" :key="item.title" class="widgets-list-item" @drag="onDrag($event,item)"
|
||||
@dragend="onDragend($event,item)" draggable="true"
|
||||
unselectable="on">
|
||||
<el-card style="width: 300px">
|
||||
<div slot="header">
|
||||
<i :class="item.icon"></i>
|
||||
<span> {{ item.title }}</span>
|
||||
<el-button type="primary" style="float: right;" size="mini" @click="push(item)">添加</el-button>
|
||||
</div>
|
||||
<div class="item-info">
|
||||
<p>{{ item.description }}</p>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>友情链接</span>
|
||||
|
||||
<el-button style="float: right; padding: 3px 0" type="text">
|
||||
<el-link href="https://bbs.django-vue-admin.com" target="_blank" type="primary">更多</el-link>
|
||||
</el-button>
|
||||
</div>
|
||||
<el-row>
|
||||
<el-col :span="8" v-for="({name,imageUrl,slogan,link},index) in projects" :key="index">
|
||||
<el-card shadow="hover" style="padding: 0">
|
||||
<div class="project-detail">
|
||||
<div>
|
||||
<a :href="link" target="_blank">
|
||||
<img :src="imageUrl" alt="">
|
||||
<span v-text="name" class="name"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div v-text="slogan" class="slogan" :title="slogan"></div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<div class="grid-content bg-purple">
|
||||
|
||||
<el-card class="box-card" >
|
||||
<div slot="header" class="clearfix">
|
||||
<span>快捷导航</span>
|
||||
</div>
|
||||
<el-row>
|
||||
<el-col :span="8" v-for="({name,icon,route,color},index) of navigators" :key="index" style="padding: 0">
|
||||
<el-card shadow="hover">
|
||||
<div style="display: flex;align-items: center;flex-direction: column;cursor: pointer" @click="()=>{gotoRoute(route)}">
|
||||
<d2-icon-svg :name="icon" style="width: 25px;height: 25px;" :style="{fill:color}"/>
|
||||
<div style="text-align: center;font-size: 12px;margin-top: 20px" v-text="name"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card" style="margin-top: 25px">
|
||||
<div class="work">
|
||||
<d2-icon-svg name="work" style="margin-left: 50%;transform: translateX(-50%);height: 216px"/>
|
||||
</div>
|
||||
</el-card>
|
||||
<div class="widgets" ref="widgets">
|
||||
<div :class="['widgets-wrapper',customizing?'widgets-wrapper-bg':'']">
|
||||
<div v-if="nowCompsList.length<=0" class="no-widgets">
|
||||
<el-empty image="img/no-widgets.svg" description="没有部件啦" :image-size="280"></el-empty>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<grid-layout
|
||||
ref="gridlayout"
|
||||
:layout.sync="layout"
|
||||
:col-num="24"
|
||||
:row-height="1"
|
||||
:is-draggable="customizing"
|
||||
:vertical-compact="false"
|
||||
:use-css-transforms="true"
|
||||
:autoSize="true"
|
||||
>
|
||||
<grid-item v-for="(item, index) in layout"
|
||||
:static="item.static"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:w="item.w"
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:key="index"
|
||||
:isResizable="customizing"
|
||||
|
||||
>
|
||||
<div v-if="customizing" class="customize-overlay">
|
||||
<el-button class="close" type="danger" plain icon="el-icon-close" size="small"
|
||||
@click="remove(index)"></el-button>
|
||||
<label>
|
||||
<i :class="allComps[item.element].icon"></i>
|
||||
{{ allComps[item.element].title }}</label>
|
||||
</div>
|
||||
<component :class="customizing?'set-component-bg':''" :is="allComps[item.element]"></component>
|
||||
</grid-item>
|
||||
</grid-layout>
|
||||
</div>
|
||||
</div>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { PieChart } from 'echarts/charts'
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
LegendComponent
|
||||
} from 'echarts/components'
|
||||
|
||||
use([
|
||||
CanvasRenderer,
|
||||
PieChart,
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
LegendComponent
|
||||
])
|
||||
import draggable from 'vuedraggable'
|
||||
import allComps from './components'
|
||||
import util from '@/libs/util'
|
||||
import VueGridLayout from 'vue-grid-layout'
|
||||
import XEUtils from 'xe-utils'
|
||||
const mouseXY = { x: null, y: null }
|
||||
const DragPos = { x: 0, y: 0, w: 1, h: 1, i: null }
|
||||
export default {
|
||||
name: 'workbench',
|
||||
components: {
|
||||
draggable,
|
||||
GridLayout: VueGridLayout.GridLayout,
|
||||
GridItem: VueGridLayout.GridItem
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
projects: [
|
||||
{
|
||||
name: '官方文档',
|
||||
imageUrl: '/image/django-vue-admin.png',
|
||||
slogan: 'Django-Vue-Admin 是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。',
|
||||
link: 'http://django-vue-admin.com'
|
||||
},
|
||||
{
|
||||
name: '官方论坛',
|
||||
imageUrl: '/image/django-vue-admin.png',
|
||||
slogan: 'Django-Vue-Admin 官方论坛',
|
||||
link: 'http://bbs.django-vue-admin.com'
|
||||
},
|
||||
{
|
||||
name: 'D2admin',
|
||||
imageUrl: '/image/d2-pub.png',
|
||||
slogan: 'D2Admin (opens new window)是一个完全 开源免费 的企业中后台产品前端集成方案,使用最新的前端技术栈,' +
|
||||
'小于 60kb 的本地首屏 js 加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助力管理系统快速开发。',
|
||||
link: 'https://d2.pub/zh'
|
||||
},
|
||||
{
|
||||
name: 'SimpleUi',
|
||||
imageUrl: '/image/simple-ui.png',
|
||||
slogan: '一个基于Django Admin的现代化主题。',
|
||||
link: 'https://simpleui.72wo.com/'
|
||||
},
|
||||
{
|
||||
name: '若依',
|
||||
imageUrl: '/image/ruoyi.png',
|
||||
slogan: '基于SpringBoot、Shiro、Mybatis的权限后台管理系统。',
|
||||
link: 'http://ruoyi.vip/'
|
||||
},
|
||||
{
|
||||
name: 'Gin-Vue-Admin',
|
||||
imageUrl: '/image/gin-vue-admin.png',
|
||||
slogan: '使用gin+vue进行极速开发的全栈后台管理系统。',
|
||||
link: 'https://www.gin-vue-admin.com/'
|
||||
},
|
||||
{
|
||||
name: 'DCM',
|
||||
imageUrl: '/image/django-comment-migrate.png',
|
||||
slogan: '这是一个Django model注释迁移的app',
|
||||
link: 'https://github.com/starryrbs/django-comment-migrate'
|
||||
},
|
||||
{
|
||||
name: 'Jetbrains',
|
||||
imageUrl: '/image/jetbrains.jpeg',
|
||||
slogan: '我们构建我们的软件,让您可以享受构建自己的软件的乐趣',
|
||||
link: 'https://www.jetbrains.com/'
|
||||
},
|
||||
{
|
||||
name: 'Django',
|
||||
imageUrl: '/image/django.png',
|
||||
slogan: '有期限的完美主义者的网络框架。',
|
||||
link: 'https://github.com/django/django'
|
||||
}
|
||||
],
|
||||
navigators: [
|
||||
{
|
||||
name: '控制台',
|
||||
icon: 'home',
|
||||
route: {
|
||||
name: 'index'
|
||||
},
|
||||
color: 'rgb(31, 218, 202);'
|
||||
},
|
||||
{
|
||||
name: '部门管理',
|
||||
icon: 'department',
|
||||
route: {
|
||||
name: 'dept'
|
||||
},
|
||||
color: 'rgb(225, 133, 37);'
|
||||
},
|
||||
{
|
||||
name: '角色管理',
|
||||
icon: 'role',
|
||||
route: {
|
||||
name: 'role'
|
||||
},
|
||||
color: 'rgb(191, 12, 44);'
|
||||
},
|
||||
{
|
||||
name: '菜单管理',
|
||||
icon: 'menu',
|
||||
route: {
|
||||
name: 'menu'
|
||||
},
|
||||
color: 'rgb(63, 178, 127);'
|
||||
},
|
||||
{
|
||||
name: '用户管理',
|
||||
icon: 'user',
|
||||
route: {
|
||||
name: 'user'
|
||||
},
|
||||
color: 'rgb(191, 12, 44);'
|
||||
},
|
||||
{
|
||||
name: '日志管理',
|
||||
icon: 'log',
|
||||
route: {
|
||||
name: 'operationLog'
|
||||
},
|
||||
color: 'rgb(0, 216, 255);'
|
||||
}
|
||||
],
|
||||
chartData: {
|
||||
columns: ['日期', '销售额'],
|
||||
rows: [
|
||||
{ 日期: '1月1日', 销售额: 123 },
|
||||
{ 日期: '1月2日', 销售额: 1223 },
|
||||
{ 日期: '1月3日', 销售额: 2123 },
|
||||
{ 日期: '1月4日', 销售额: 4123 },
|
||||
{ 日期: '1月5日', 销售额: 3123 },
|
||||
{ 日期: '1月6日', 销售额: 7123 }
|
||||
customizing: false,
|
||||
allComps: allComps,
|
||||
selectLayout: [],
|
||||
defaultGrid: {
|
||||
// 默认分栏数量和宽度 例如 [24] [18,6] [8,8,8] [6,12,6]
|
||||
layout: [12, 6, 6],
|
||||
// 小组件分布,com取值:views/home/components 文件名
|
||||
copmsList: [
|
||||
['welcome'],
|
||||
['about', 'ver'],
|
||||
['time', 'progress']
|
||||
]
|
||||
},
|
||||
defaultLayout: [],
|
||||
layout: [
|
||||
// { x: 0, y: 0, w: 2, h: 2, i: '0', element: 'welcome' },
|
||||
// { x: 2, y: 0, w: 2, h: 4, i: '1', element: 'about' },
|
||||
// { x: 4, y: 0, w: 2, h: 5, i: '2', element: 'time' },
|
||||
// { x: 6, y: 0, w: 2, h: 3, i: '3', element: 'progress' }
|
||||
]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.layout = JSON.parse(util.cookies.get('grid-layout') || JSON.stringify(this.defaultLayout))
|
||||
},
|
||||
mounted () {
|
||||
document.addEventListener('dragover', function (e) {
|
||||
mouseXY.x = e.clientX
|
||||
mouseXY.y = e.clientY
|
||||
}, false)
|
||||
this.$emit('on-mounted')
|
||||
},
|
||||
computed: {
|
||||
allCompsList () {
|
||||
var allCompsList = []
|
||||
for (var key in this.allComps) {
|
||||
allCompsList.push({
|
||||
key: key,
|
||||
title: allComps[key].title,
|
||||
icon: allComps[key].icon,
|
||||
height: allComps[key].height,
|
||||
width: allComps[key].width,
|
||||
maxH: allComps[key].maxH || Infinity,
|
||||
maxW: allComps[key].maxW || Infinity,
|
||||
isResizable: allComps[key].isResizable || null,
|
||||
description: allComps[key].description
|
||||
})
|
||||
}
|
||||
return allCompsList
|
||||
},
|
||||
myCompsList () {
|
||||
return this.allCompsList
|
||||
},
|
||||
nowCompsList () {
|
||||
return this.allCompsList
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
gotoRoute (route) {
|
||||
this.$router.push(route)
|
||||
// 开启自定义
|
||||
custom () {
|
||||
this.customizing = true
|
||||
const oldWidth = this.$refs.widgets.offsetWidth
|
||||
this.$nextTick(() => {
|
||||
const scale = this.$refs.widgets.offsetWidth / oldWidth
|
||||
this.$refs.widgets.style.setProperty('transform', `scale(${scale})`)
|
||||
})
|
||||
},
|
||||
// 设置布局
|
||||
setLayout (layout) {
|
||||
// 暂定
|
||||
},
|
||||
getLayoutElementNumber (elementName) {
|
||||
// var index = 0
|
||||
// this.layout.map(res => {
|
||||
// if (elementName === res.element) {
|
||||
// index += 1
|
||||
// }
|
||||
// })
|
||||
// return index + 1
|
||||
return elementName + this.layout.length
|
||||
},
|
||||
// 追加
|
||||
push (item) {
|
||||
console.log(1, item)
|
||||
this.layout.push({
|
||||
x: 6,
|
||||
y: 0,
|
||||
w: item.width,
|
||||
h: item.height,
|
||||
isResizable: item.isResizable || null,
|
||||
i: this.getLayoutElementNumber(item.key),
|
||||
element: item.key
|
||||
})
|
||||
},
|
||||
// 删除组件
|
||||
remove (index) {
|
||||
this.layout.splice(index, 1)
|
||||
},
|
||||
// 保存
|
||||
save () {
|
||||
console.log(this.layout)
|
||||
this.customizing = false
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
util.cookies.set('grid-layout', this.layout)
|
||||
},
|
||||
// 恢复默认
|
||||
backDefaul () {
|
||||
this.customizing = false
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
this.layout = JSON.parse(JSON.stringify(this.defaultLayout))
|
||||
util.cookies.remove('grid-layout')
|
||||
},
|
||||
// 关闭
|
||||
close () {
|
||||
this.customizing = false
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
},
|
||||
// 拖拽事件
|
||||
onDrag (e, item) {
|
||||
const { key, width, height } = item
|
||||
const parentRect = this.$refs.widgets.getBoundingClientRect()
|
||||
let mouseInGrid = false
|
||||
if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
|
||||
mouseInGrid = true
|
||||
}
|
||||
const cloneLayout = XEUtils.clone(this.layout, true)
|
||||
if (mouseInGrid === true && (cloneLayout.findIndex(item => item.i === this.getLayoutElementNumber(key)) === -1)) {
|
||||
// this.layout.push({
|
||||
// x: (this.layout.length * 2) % (this.colNum || 12),
|
||||
// y: this.layout.length + (this.colNum || 12), // puts it at the bottom
|
||||
// w: width,
|
||||
// h: height,
|
||||
// i: this.getLayoutElementNumber(key),
|
||||
// element: key
|
||||
// })
|
||||
}
|
||||
const index = this.layout.findIndex(item => item.i === this.getLayoutElementNumber(key))
|
||||
if (index !== -1) {
|
||||
try {
|
||||
this.$refs.gridlayout.$children[this.layout.length].$refs.item.style.display = 'none'
|
||||
} catch {
|
||||
}
|
||||
const el = this.$refs.gridlayout.$children[index]
|
||||
el.dragging = { top: mouseXY.y - parentRect.top, left: mouseXY.x - parentRect.left }
|
||||
const new_pos = el.calcXY(mouseXY.y - parentRect.top, mouseXY.x - parentRect.left)
|
||||
if (mouseInGrid === true) {
|
||||
this.$refs.gridlayout.dragEvent('dragstart', this.getLayoutElementNumber(key), new_pos.x, new_pos.y, 1, 1)
|
||||
DragPos.i = String(index)
|
||||
DragPos.x = this.layout[index].x
|
||||
DragPos.y = this.layout[index].y
|
||||
}
|
||||
if (mouseInGrid === false) {
|
||||
this.$refs.gridlayout.dragEvent('dragend', this.getLayoutElementNumber(key), new_pos.x, new_pos.y, 1, 1)
|
||||
this.layout = this.layout.filter(obj => obj.i !== this.getLayoutElementNumber(key))
|
||||
}
|
||||
}
|
||||
},
|
||||
onDragend (e, item) {
|
||||
const { key, width, height } = item
|
||||
const parentRect = this.$refs.widgets.getBoundingClientRect()
|
||||
let mouseInGrid = false
|
||||
if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
|
||||
mouseInGrid = true
|
||||
}
|
||||
if (mouseInGrid === true) {
|
||||
this.layout.push({
|
||||
x: DragPos.x,
|
||||
y: DragPos.y,
|
||||
w: width,
|
||||
h: height,
|
||||
i: this.getLayoutElementNumber(key),
|
||||
element: key
|
||||
})
|
||||
this.$refs.gridlayout.dragEvent('dragend', this.getLayoutElementNumber(key), DragPos.x, DragPos.y, 1, 1)
|
||||
this.layout = this.layout.filter(obj => obj.i !== this.getLayoutElementNumber(key))
|
||||
// UNCOMMENT below if you want to add a grid-item
|
||||
/*
|
||||
this.layout.push({
|
||||
x: DragPos.x,
|
||||
y: DragPos.y,
|
||||
w: 1,
|
||||
h: 1,
|
||||
i: DragPos.i,
|
||||
});
|
||||
this.$refs.gridLayout.dragEvent('dragend', DragPos.i, DragPos.x,DragPos.y,1,1);
|
||||
try {
|
||||
this.$refs.gridLayout.$children[this.layout.length].$refs.item.style.display="block";
|
||||
} catch {
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.component-header {
|
||||
background-color: #FFFFFF;
|
||||
position: sticky;
|
||||
top: -20px;
|
||||
z-index: 99;
|
||||
|
||||
$userAvatarLength: 72px;
|
||||
.set-btn-class {
|
||||
float: right;
|
||||
z-index: 99;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.page-header{
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
.user-avatar{
|
||||
width: $userAvatarLength;
|
||||
height: $userAvatarLength;
|
||||
line-height: $userAvatarLength;
|
||||
display: inline-block;
|
||||
}
|
||||
.all-component-class {
|
||||
clear: right;
|
||||
|
||||
.title{
|
||||
display: inline-block;
|
||||
padding: 0 0 0 15px;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
.widgets-list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
overflow-x: scroll;
|
||||
padding-bottom: 10px;
|
||||
|
||||
h1{
|
||||
font-size: 1.125rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.75rem;
|
||||
.widgets-list-item {
|
||||
margin-right: 10px;
|
||||
}
|
||||
span{
|
||||
font-size: 14px;
|
||||
color: rgba(0,0,0,.45);
|
||||
|
||||
.widgets-list-item:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.widgets-wrapper-bg {
|
||||
background: rgba(180, 180, 180, .2);
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.project-detail{
|
||||
color: rgba(0,0,0,.45);
|
||||
height: 65px;
|
||||
img {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
.name{
|
||||
margin-left: 1rem;
|
||||
font-size: 1rem;
|
||||
line-height: 2rem;
|
||||
height: 2rem;
|
||||
display: inline-block;
|
||||
color: rgba(0,0,0,.85);
|
||||
position: relative;
|
||||
top: -5px;
|
||||
}
|
||||
.slogan{
|
||||
font-size: 12px;
|
||||
padding: 5px 0;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space:nowrap;
|
||||
}
|
||||
.team{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.widgets-wrapper .sortable-ghost {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.activity{
|
||||
padding: 0;
|
||||
.activity-avatar{
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
.activity-detail{
|
||||
padding: 10px;
|
||||
line-height: 15px;
|
||||
font-size: 14px;
|
||||
color: rgba(0,0,0,.85);
|
||||
}
|
||||
}
|
||||
.chart {
|
||||
height: 408px;
|
||||
}
|
||||
.set-component-bg{
|
||||
background:rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
.el-divider--horizontal{
|
||||
margin: 4px 0;
|
||||
background: 0 0;
|
||||
border-top: 1px solid #e8eaec;
|
||||
.customize-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 5px;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.customize-overlay label {
|
||||
background: #409EFF;
|
||||
color: #fff;
|
||||
height: 40px;
|
||||
padding: 0 30px;
|
||||
border-radius: 40px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.customize-overlay label i {
|
||||
margin-right: 15px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.customize-overlay .close {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.customize-overlay .close:focus, .customize-overlay .close:hover {
|
||||
background: #76B1F9;
|
||||
}
|
||||
|
||||
}
|
||||
.el-card, .el-message {
|
||||
border-radius: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -29,34 +29,35 @@ export const crudOptions = (vm) => {
|
|||
iconLoaded: 'el-icon-loading' // 美化loading图标
|
||||
}
|
||||
},
|
||||
rowHandle: {
|
||||
show: false,
|
||||
width: 140,
|
||||
view: {
|
||||
thin: true,
|
||||
text: '',
|
||||
show: false,
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Retrieve')
|
||||
}
|
||||
},
|
||||
edit: {
|
||||
thin: true,
|
||||
text: '',
|
||||
show: false,
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Update')
|
||||
}
|
||||
},
|
||||
remove: {
|
||||
thin: true,
|
||||
text: '',
|
||||
show: false,
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Delete')
|
||||
}
|
||||
}
|
||||
},
|
||||
// rowHandle: {
|
||||
// show: false,
|
||||
// width: 140,
|
||||
// view: {
|
||||
// thin: true,
|
||||
// text: '',
|
||||
// show: false,
|
||||
// disabled () {
|
||||
// return !vm.hasPermissions('Retrieve')
|
||||
// }
|
||||
// },
|
||||
// edit: {
|
||||
// thin: true,
|
||||
// text: '',
|
||||
// show: false,
|
||||
// disabled () {
|
||||
// return !vm.hasPermissions('Update')
|
||||
// }
|
||||
// },
|
||||
// remove: {
|
||||
// thin: true,
|
||||
// text: '',
|
||||
// show: false,
|
||||
// disabled () {
|
||||
// return !vm.hasPermissions('Delete')
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
rowHandle: false,
|
||||
viewOptions: {
|
||||
componentType: 'form'
|
||||
},
|
||||
|
|
|
@ -15,13 +15,7 @@ export const crudOptions = (vm) => {
|
|||
return !vm.hasPermissions('Retrieve')
|
||||
}
|
||||
},
|
||||
edit: {
|
||||
thin: true,
|
||||
text: '',
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Update')
|
||||
}
|
||||
},
|
||||
edit: false,
|
||||
remove: {
|
||||
thin: true,
|
||||
text: '',
|
||||
|
|
|
@ -4,12 +4,11 @@ export const crudOptions = (vm) => {
|
|||
compact: true
|
||||
},
|
||||
options: {
|
||||
tableType: 'vxe-table',
|
||||
rowKey: true, // 必须设置,true or false
|
||||
// tableType: 'vxe-table',
|
||||
// rowKey: true, // 必须设置,true or false
|
||||
rowId: 'id',
|
||||
height: '100%', // 表格高度100%, 使用toolbar必须设置
|
||||
highlightCurrentRow: false
|
||||
|
||||
highlightCurrentRow: false,
|
||||
},
|
||||
rowHandle: {
|
||||
fixed: 'right',
|
||||
|
@ -284,7 +283,8 @@ export const crudOptions = (vm) => {
|
|||
title: '登录时间',
|
||||
key: 'create_datetime',
|
||||
width: 160,
|
||||
type: 'datetime'
|
||||
type: 'datetime',
|
||||
sortable: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -19,9 +19,7 @@ export const crudOptions = (vm) => {
|
|||
edit: {
|
||||
thin: true,
|
||||
text: '',
|
||||
show () {
|
||||
return vm.tabActivted !== 'receive'
|
||||
},
|
||||
show: false,
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Update')
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ export const crudOptions = (vm) => {
|
|||
},
|
||||
options: {
|
||||
height: '100%',
|
||||
tableType: 'vxe-table',
|
||||
rowKey: true,
|
||||
// tableType: 'vxe-table',
|
||||
//rowKey: true,
|
||||
rowId: 'id'
|
||||
},
|
||||
selectionRow: {
|
||||
|
@ -149,6 +149,7 @@ export const crudOptions = (vm) => {
|
|||
{
|
||||
title: '姓名',
|
||||
key: 'name',
|
||||
sortable: 'custom',
|
||||
minWidth: 90,
|
||||
search: {
|
||||
disabled: false
|
||||
|
|
Loading…
Reference in New Issue