Commit e968b151 by rongjun

init

parents
# coding=utf8
\ No newline at end of file
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class BaseConfig(AppConfig):
name = 'apps.base'
# coding=utf8
from django_filters import CharFilter
from django.forms import TextInput
from core.orm.filter import BaseFilterSet
from apps.base.models import Contacts
class ManageContactsFilter(BaseFilterSet):
search = CharFilter(method='filter_search', label='关键字', widget=TextInput(attrs={'placeholder': '',
'class': 'input-brand x2'}))
class Meta:
model = Contacts
fields = []
search_fields = ['name', ]
from django.db import models
from core.orm.model import BaseModel
class Contacts(BaseModel):
name = models.CharField(max_length=200, verbose_name='名称')
email = models.CharField(max_length=200, verbose_name='邮箱')
from rest_framework import serializers
from apps.base.models import Contacts
class ContactsSerializer(serializers.ModelSerializer):
class Meta:
model = Contacts
fields = '__all__'
from django.test import TestCase
# Create your tests here.
from django.shortcuts import render
# Create your views here.
from django.contrib import admin
# Register your models here.
from __future__ import unicode_literals
from django.apps import AppConfig
class ManageConfig(AppConfig):
name = 'apps.manage'
# coding=utf8
\ No newline at end of file
# coding=utf8
\ No newline at end of file
# coding=utf8
from __future__ import absolute_import, unicode_literals
from rest_framework import serializers
from apps.base.models import Contacts
class ManageContactsSerializer(serializers.ModelSerializer):
class Meta:
model = Contacts
fields = ('id', 'name', 'email')
read_only_fields = ['id']
def validate(self, attrs):
return attrs
def to_representation(self, instance):
result = serializers.ModelSerializer.to_representation(self, instance)
return result
# coding=utf8
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from apps.manage.apps.contacts.views import ManageContactsView, ManageContactsAPIViewSet
router = DefaultRouter()
router.register(r'contacts', ManageContactsAPIViewSet, base_name='manage-contacts'),
urlpatterns = [
url(r'^contacts/$', ManageContactsView.as_view(), name='manage_contacts_index'),
url(r'', include(router.urls)),
]
# coding=utf8
from __future__ import absolute_import
from django.db.models.query_utils import Q
from rest_framework.response import Response
from core.framework.manageviews import TemplateHTMLRendererView, \
ManageResponseViewSet, ManageListView, ManageAddView, \
ManageEditView, ManageActiveView, ManageDeleteView
from core.framework.permissions import IsAuthManager
from core.framework.pagination import ManagePagination
from apps.base.models import Contacts
from apps.base.filters import ManageContactsFilter
from apps.manage.apps.contacts.serializers import ManageContactsSerializer
class ManageContactsView(TemplateHTMLRendererView):
template_name = 'manage/apps/contacts/index.html'
permission_classes = [IsAuthManager]
def get(self, request):
manage = {
'filter': ManageContactsFilter,
'actions': [{'id': 'add', 'text': '新建'}],
}
serializer = ManageContactsSerializer()
return Response({'add_serializer': serializer,
'edit_serializer': serializer,
'manage': manage})
class ManageContactsAPIViewSet(ManageListView, ManageAddView,
ManageEditView, ManageActiveView, ManageDeleteView,
ManageResponseViewSet):
model = Contacts
filter_cls = ManageContactsFilter
queryset = Contacts.objects.all()
permission_classes = [IsAuthManager]
serializer_class = ManageContactsSerializer
pagination_class = ManagePagination
# coding=utf8
\ No newline at end of file
# coding=utf8
from rest_framework import serializers
from core.framework.exceptions import ManageAPIException
from apps.task.models import Task
from apps.base.models import Contacts
from fish.instruments import INSTRUMENT_CHOICES, get_instrument_name
from apps.manage.serializers import NamePrimaryKeyRelatedField, DateTimeCharField
class ManageTaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ('id', 'name', 'emails', 'active')
def validate(self, attrs):
return attrs
def to_representation(self, instance):
result = serializers.ModelSerializer.to_representation(self, instance)
result['active_display'] = '正常' if instance.active else '失效'
return result
class ManageTaskAddSerializer(serializers.ModelSerializer):
instrument = serializers.ChoiceField(choices=INSTRUMENT_CHOICES, label='''产品合约''')
code = serializers.CharField(label='编号')
max_val = serializers.DecimalField(max_digits=10, decimal_places=2, label='高点')
min_val = serializers.DecimalField(max_digits=10, decimal_places=2, label='低点')
type = serializers.ChoiceField(choices=(('A', '多'), ('D', '空')), label='趋势')
emails = NamePrimaryKeyRelatedField(label='''通知邮箱''', queryset=Contacts.objects.all(),
select_value='email', flag=True)
class Meta:
model = Task
fields = ('instrument', 'code', 'max_val', 'min_val', 'type', 'emails')
def validate(self, attrs):
if attrs.get('max_val') < attrs.get('min_val'):
raise ManageAPIException(errmsg='高点不能低于低点')
instrument = attrs.get('instrument') + attrs.get('code')
instrument_name = get_instrument_name(attrs.get('instrument')) + attrs.get('code')
attrs['instrument_name'] = instrument_name
attrs['instrument'] = instrument
config = {'max_val': str(attrs.get('max_val')), 'min_val': str(attrs.get('min_val')), 'type': attrs.get('type')}
attrs['config'] = config
emails = attrs.get('emails').split('#')
attrs['emails'] = emails
_r = ''
if attrs.get('max_val') == attrs.get('min_val'):
_r = '预值【{}】'.format(attrs.get('max_val'))
else:
_r = '镜像空间【{}-{}】'.format(attrs.get('max_val'), attrs.get('min_val'))
name = '【{}】,{},预期趋势【{}】'.format(instrument_name, _r, '多' if attrs.get('type') == 'A' else '空')
attrs['name'] = name
attrs.pop('code', None)
attrs.pop('max_val', None)
attrs.pop('min_val', None)
attrs.pop('type', None)
return attrs
def to_representation(self, instance):
result = serializers.ModelSerializer.to_representation(self, instance)
return result
def create(self, validated_data):
task = serializers.ModelSerializer.create(self, validated_data)
task.set_active_list(task.instrument)
return task
# coding=utf8
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from apps.manage.apps.task.views import ManageTaskView, ManageTaskAPIViewSet
router = DefaultRouter()
router.register(r'task', ManageTaskAPIViewSet, base_name='manage-task'),
urlpatterns = [
url(r'^task/$', ManageTaskView.as_view(), name='manage_task_index'),
url(r'', include(router.urls)),
]
# coding=utf8
from __future__ import absolute_import
from django.db.models.query_utils import Q
from rest_framework.response import Response
from core.framework.manageviews import TemplateHTMLRendererView, \
ManageResponseViewSet, ManageListView, ManageAddView, \
ManageEditView, ManageActiveView, ManageDeleteView
from core.framework.permissions import IsAuthManager
from core.framework.pagination import ManagePagination
from apps.task.models import Task
from apps.task.filters import ManageTaskFilter
from apps.manage.apps.task.serializers import ManageTaskSerializer, ManageTaskAddSerializer
class ManageTaskView(TemplateHTMLRendererView):
template_name = 'manage/apps/task/index.html'
permission_classes = [IsAuthManager]
def get(self, request):
manage = {
'filter': ManageTaskFilter,
'actions': [{'id': 'add', 'text': '新建提醒'}],
}
serializer = ManageTaskSerializer()
return Response({'add_serializer': ManageTaskAddSerializer,
'edit_serializer': serializer,
'manage': manage})
class ManageTaskAPIViewSet(ManageListView, ManageAddView,
ManageEditView, ManageActiveView, ManageDeleteView,
ManageResponseViewSet):
model = Task
filter_cls = ManageTaskFilter
queryset = Task.objects.all()
permission_classes = [IsAuthManager]
serializer_class = ManageTaskSerializer
add_serializer_class = ManageTaskAddSerializer
pagination_class = ManagePagination
# coding=utf8
import json
from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.http.response import HttpResponseRedirect
from apps.manage.views import login, first_login
class ManageMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
user = request.user
if user.is_superuser:
return self.get_response(request)
manager = getattr(user, 'manager', None)
if request.path.startswith("/manage/first_login"):
if user.is_authenticated and user.is_staff and manager:
if manager.is_reset_password:
index_url = reverse("manage_home")
return HttpResponseRedirect(index_url)
elif request.path != '/manage/login/' and request.path.startswith("/manage"):
if user.is_authenticated and user.is_staff and manager:
if not manager.is_reset_password:
return first_login(request, pre_url=request.path)
else:
if request.is_ajax():
return HttpResponse(json.dumps({'errcode': -1, 'errmsg': u'身份认证失效,请重新登录'}))
return login(request, pre_url=request.path)
return self.get_response(request)
# coding=utf8
\ No newline at end of file
# -*- coding: utf-8 -*-
\ No newline at end of file
# coding=utf8
import copy
Rules = [
{
'id': 'task',
'icon_cls': 'fa fa-bell-o',
'text': '提醒任务',
'is_pNode': True,
},
{
'id': 'contacts',
'icon_cls': 'fa fa-address-card-o',
'text': '通讯录',
'is_pNode': True,
},
]
def get_rules(rules=None):
self_rules = [str(x) for x in rules] if rules else []
def _get_rules(children):
for child in children:
if child.get('children'):
child['children'] = _get_rules(child.get('children'))
else:
if child.get('id') in self_rules:
child['checked'] = True
continue
return children
_rules = rules if rules else copy.deepcopy(Rules)
return _get_rules(_rules)
def get_shop_rules(rules):
ids = []
for rule in rules:
if rule.get('id') in ['/manage/shop/', '/manage/base/car_brand/', '/manage/base/car_model/',
'/manage/schedule/']:
continue
ids.append(rule.get('id'))
if rule.get('children'):
ids += get_shop_rules(rule.get('children'))
return ids
# coding=utf8
from __future__ import absolute_import
from rest_framework import serializers
class DateTimeCharField(serializers.CharField):
def to_representation(self, value):
ret = super(DateTimeCharField, self).to_representation(value)
if len(ret) > 19:
ret = ret[:19]
return ret
class NamePrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def __init__(self, **kwargs):
self.select_value = kwargs.pop('select_value', None)
self.display_key = kwargs.pop('display_key', None)
self.flag = kwargs.pop('flag', None)
super(NamePrimaryKeyRelatedField, self).__init__(**kwargs)
def display_value(self, instance):
if self.display_key:
return getattr(instance, self.display_key, '')
return instance.name
def to_representation(self, value):
if self.select_value:
r = getattr(value, self.select_value, None)
return r
return super(NamePrimaryKeyRelatedField, self).to_representation(value)
def to_internal_value(self, data):
if self.flag:
return data
return super(NamePrimaryKeyRelatedField, self).to_internal_value(data)
# coding=utf8
\ No newline at end of file
# coding=utf8
from __future__ import unicode_literals
from django import template
from django.db.models.query_utils import Q
from apps.manage.rules import Rules
register = template.Library()
@register.inclusion_tag('manage/tags/menus.html', takes_context=True)
def auth_menus(context):
"""""
# 系统菜单
"""
user = context.request.user
if user.is_superuser:
menus = Rules
else:
if not getattr(user, 'manager', None):
menus = None
else:
menus = user.manager.get_menus()
return {'menus': menus}
@register.inclusion_tag('manage/tags/values.html', takes_context=True)
def render_values(context, values):
"""""
# 数据统计模块
"""
return {'values': values}
@register.inclusion_tag('manage/tags/actions.html', takes_context=True)
def render_actions(context, actions):
"""""
# 页面操作按钮
"""
return {'actions': actions}
\ No newline at end of file
from django.test import TestCase
# Create your tests here.
# coding=utf8
from django.conf.urls import url, include
from apps.manage.views import ManageLogOutView, ManageResetPasswordView, \
ManageHomeView, login, first_login, ManageResetPasswordAPIView, ManageRules, ManageDashboardView
urlpatterns = [
url(r'^login/$', login, name='manage_login'),
url(r'^first_login/$', first_login, name='manage_first_login'),
url(r'^logout/$', ManageLogOutView.as_view(), name='manage_logout'),
url(r'^reset_password_index/$', ManageResetPasswordView.as_view(), name='manage_reset_password_index'),
url(r'^reset_password/$', ManageResetPasswordAPIView.as_view(), name='manage_reset_password'),
url(r'^$', ManageHomeView.as_view(), name='manage_home'),
url(r'^dashboard/$', ManageDashboardView.as_view(), name='manage_dashboard'),
url(r'^rules/$', ManageRules.as_view(), name='manage_rules'),
]
urlpatterns += [
url(r'', include('apps.manage.apps.task.urls')),
url(r'', include('apps.manage.apps.contacts.urls')),
]
# coding=utf8
from datetime import datetime, timedelta
from django.db import connection
from django.db.models import Sum, Count
from django.db.models.query_utils import Q
from django.db.models.functions import TruncDate
from django.shortcuts import render_to_response
from django.urls import reverse
from django.views.decorators.csrf import csrf_exempt
from django.http.response import HttpResponseRedirect
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import authenticate, login as login_, logout as logout_
from django.contrib.auth import login, logout
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer
from rest_framework.decorators import action
from core.framework.manageviews import TemplateHTMLRendererView, ManageResponseView
from core.framework.response import MangeAPIResponse
from core.framework.permissions import IsAuthManager, IsManager
from core.framework.exceptions import ManageAPIException
from apps.manage.rules import Rules
@csrf_exempt
def login(request, pre_url=None, template_name='manage/login.html'):
message = ''
next_url = request.GET.get('next') or request.POST.get('next')
if not next_url:
next_url = pre_url
if next_url is None:
next_url = reverse('manage_home')
if request.method != 'POST':
return render_to_response(template_name, {'next_url': next_url })
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user is not None and user.is_authenticated:
if not user.is_staff:
message = u'该账号未授权登陆!'
else:
if not user.is_active:
message = u'该账号已冻结!'
else:
login_(request, user)
return HttpResponseRedirect(next_url)
else:
message = u'账号不存在或者密码错误!'
return render_to_response(template_name, {'next_url': next_url,
'message': message})
@csrf_exempt
def first_login(request, pre_url=None, template_name='manage/first_login.html'):
old_password = request.POST.get('old_password')
new_password_1 = request.POST.get('new_password1')
new_password_2 = request.POST.get('new_password2')
user = request.user
if not user:
return login(request, pre_url)
next_url = request.GET.get('next') or request.POST.get('next')
if not next_url:
next_url = pre_url
if next_url is None:
next_url = reverse('manage_home')
if old_password:
if user.check_password(old_password):
if new_password_1 != new_password_2:
message = u'两次输入的密码不正确'
else:
user.set_password(new_password_1)
user.save(update_fields=['password', ])
user.manager.is_reset_password = True
user.manager.save(update_fields=['is_reset_password', ])
auth_user = authenticate(username=user.username, password=new_password_1)
if auth_user is not None and auth_user.is_authenticated and auth_user.is_staff and auth_user.is_active:
login_(request, auth_user)
return HttpResponseRedirect(next_url)
else:
message = u'旧密码不正确'
else:
message = ''
return render_to_response(template_name, {'next_url': next_url, 'message': message})
class ManageLoginView(TemplateHTMLRendererView):
template_name = 'manage/login.html'
@csrf_exempt
def post(self, request):
return login(request)
class ManageLogOutView(TemplateHTMLRendererView):
template_name = 'manage/login.html'
def get(self, request):
logout(request)
return Response()
class ManageHomeView(TemplateHTMLRendererView):
template_name = 'manage/home.html'
def get(self, request):
return Response()
class ManageDashboardView(TemplateHTMLRendererView):
template_name = 'manage/apps/dashboard/index.html'
def get(self, request):
return Response()
class ManageResetPasswordView(TemplateHTMLRendererView):
template_name = 'manage/reset_password.html'
permission_classes = [IsManager]
def get(self, request):
return Response()
class ManageResetPasswordAPIView(ManageResponseView):
permission_classes = [IsAuthManager]
def post(self, request):
user = request.user
old_password = request.POST.get('old_password')
if not user.check_password(old_password):
raise ManageAPIException(errmsg='旧密码不正确')
new_password = request.POST.get('new_password')
new_password2 = request.POST.get('new_password2')
if not new_password or not new_password2:
raise ManageAPIException(errmsg='密码不能为空')
if new_password != new_password2:
raise ManageAPIException(errmsg='两次密码不正确')
user.set_password(new_password)
user.save(update_fields=['password'])
return MangeAPIResponse()
class ManageRules(ManageResponseView):
permission_classes = [IsManager]
def get(self, request):
user = request.user
if user.is_superuser:
rules = Rules
else:
manager = user.manager
rules = manager.get_menus()
return MangeAPIResponse(data=rules)
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class MarketConfig(AppConfig):
name = 'apps.market'
from django.test import TestCase
# Create your tests here.
# coding=utf8
from django.conf.urls import url, include
from apps.market.views import push
urlpatterns = [
url(r'^push/$', push, name='market_push'), ]
# coding=utf8
from datetime import datetime
from decimal import Decimal
from django.http.response import HttpResponse
from apps.task.models import Task
from core.utils.email import send
from django_q.tasks import async_task
def cta(timestamp, last_price, task):
print(task)
_type = task.get('type')
max_val = Decimal(task.get('max_val'))
min_val = Decimal(task.get('min_val'))
style = ''
point = ''
over = False
if _type == 'A':
if max_val == min_val:
if last_price > min_val:
style = '突破'
point = '预值'
over = True
else:
if last_price < min_val:
style = '回调'
point = '突破原点'
over = True
m = max_val - min_val
p1 = min_val + m * Decimal('0.333')
p2 = min_val + m * Decimal('0.382')
if last_price >= p1:
style = '突破'
point = '0.333'
if last_price >= p2:
style = '突破'
point = '0.382'
over = True
if _type == 'D':
if max_val == min_val:
if last_price < min_val:
style = '突破'
point = '预值'
over = True
else:
if last_price > max_val:
style = '回调'
point = '突破原点'
over = True
m = max_val - min_val
p1 = max_val - m * Decimal('0.333')
p2 = max_val - m * Decimal('0.382')
if last_price <= p1:
style = '突破'
point = '0.333'
if last_price <= p2:
style = '突破'
point = '0.382'
over = True
_title = '【{}{}】的提醒'
_content = '【{}】,镜像空间【{}-{}】,预期趋势【{}】;在【{}】【{}】点位为【{}】'
times = datetime.fromtimestamp(timestamp)
title = _title.format(style, point)
content = _content.format(task.get('name'), task.get('max_val'), task.get('min_val'), task.get('type'), times,
style, last_price)
if over:
Task.remove_task(task)
send(title, content, task.get('emails'))
def push(request):
data = request.GET.get('data')
data = data.split(',')
timestamp = int(data[0])
instrument = data[1]
last_price = Decimal(data[2])
tasks = Task.get_active_list(instrument)
for task in tasks:
async_task(cta, timestamp, last_price, task)
# cta(timestamp, last_price, task)
return HttpResponse('ok')
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class TaskConfig(AppConfig):
name = 'apps.task'
# coding=utf8
from django_filters import CharFilter
from django.forms import TextInput
from core.orm.filter import BaseFilterSet
from apps.task.models import Task
class ManageTaskFilter(BaseFilterSet):
search = CharFilter(method='filter_search', label='关键字', widget=TextInput(attrs={'placeholder': '',
'class': 'input-brand x2'}))
class Meta:
model = Task
fields = []
search_fields = ['name', ]
from django.db import models
from django.contrib.postgres.fields import JSONField, ArrayField
from core.orm.model import BaseModel
from django.core.cache import cache
class Task(BaseModel):
name = models.CharField(max_length=200, null=True)
instrument = models.CharField(max_length=200)
instrument_name = models.CharField(max_length=200, null=True)
emails = ArrayField(models.CharField(max_length=200, blank=True), verbose_name='通知邮箱')
config = JSONField()
@property
def code(self):
pass
@property
def max_val(self):
pass
@property
def min_val(self):
pass
@property
def type(self):
pass
@staticmethod
def set_active_list(instrument):
active_list = Task.objects.filter(instrument=instrument, active=True)
dd = []
for al in active_list:
d = {'id': al.pk, 'instrument': al.instrument, 'name': al.instrument_name, 'emails': list(al.emails),
'type': al.config.get('type'), 'max_val': str(al.config.get('max_val')),
'min_val': str(al.config.get('min_val'))}
dd.append(d)
cache.set(instrument, dd)
@staticmethod
def get_active_list(instrument):
active_list = cache.get(instrument)
return active_list if active_list else []
@staticmethod
def remove_task(task):
Task.objects.filter(pk=int(task.get('id'))).update(active=False)
Task.set_active_list(task.get('instrument'))
from rest_framework import serializers
from apps.task.models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
from django.test import TestCase
# Create your tests here.
from django.shortcuts import render
# Create your views here.
# coding=utf8
\ No newline at end of file
# coding=utf8
\ No newline at end of file
# coding=utf8
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from rest_framework import exceptions
from rest_framework.authentication import TokenAuthentication, get_authorization_header
from django.core.cache import cache
class MyTokenAuthentication(TokenAuthentication):
def authenticate(self, request):
token = request.GET.get('token')
if token:
return self.authenticate_credentials(token)
auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != b'token':
return None
if len(auth) == 1:
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Token string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
token = auth[1].decode()
except UnicodeError:
msg = _('Invalid token header. Token string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
def _get_cache_token(self, key):
cache_key = 'user_token_%s' % key
token = cache.get(cache_key, None)
if token:
return token.user, token
try:
token = self.model.objects.select_related('user').get(key=key)
except self.model.DoesNotExist:
raise exceptions.AuthenticationFailed(_('Invalid token.'))
if not token.user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
cache.set(cache_key, token, 10 * 60)
return token.user, token
def authenticate_credentials(self, key):
self.model = self.get_model()
return self._get_cache_token(key)
# coding=utf8
import json
from core.utils import log as logging
from rest_framework.views import exception_handler
import traceback
from rest_framework import exceptions
from django.utils.encoding import smart_text
from django.http.response import Http404
from django.core.exceptions import ObjectDoesNotExist
from . import errcode
from .exceptions import CustomAPIException, ManageAPIException
from .response import APIResponse, MangeAPIResponse
def custom_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
# response = exception_handler(exc, context)
if isinstance(exc, CustomAPIException):
response = APIResponse(errcode=exc.errcode, errmsg=exc.errmsg)
elif isinstance(exc, exceptions.Throttled):
response = APIResponse(errcode=errcode.ERRCODE_THROTTLED, errmsg=u'请求过于频繁,请稍后再试!')
elif isinstance(exc, ManageAPIException):
response = MangeAPIResponse(errcode=exc.errcode, errmsg=exc.errmsg)
elif isinstance(exc, exceptions.ValidationError):
if isinstance(exc.detail, list):
detail = exc.detail[1]
elif isinstance(exc.detail, dict):
detail = exc.detail
else:
detail = smart_text(exc.detail)
response = APIResponse(errcode=errcode.ERRCODE_PARAM_ERROR, detail=detail)
elif isinstance(exc, exceptions.APIException):
response = APIResponse(errcode=exc.status_code, errmsg=smart_text(exc))
elif isinstance(exc, (Http404, ObjectDoesNotExist)):
if isinstance(exc.args, (list, dict)):
detail = json.dumps(exc.args, ensure_ascii=False)
else:
detail = smart_text(exc.args)
response = APIResponse(errcode=404, detail=detail)
else:
response = exception_handler(exc, context)
trace = traceback.format_exc()
api_request = context.get('request', None)
request = api_request._request if api_request and hasattr(api_request, '_request') else None
logging.error(trace, exc_info=True, extra={'request': request, })
if not response:
response = APIResponse(errcode=-1)
# logging.error(context['request'].body)
return response
# coding=utf8
ERRCODE_SUCCESS = 200
ERRCODE_NOT_FOUND = 404
ERRCODE_SYSBUSY = -1
ERRCODE_THROTTLED = -2
ERRCODE_PERMISSION_DENIED = -9
ERRCODE_PARAM_MISSING = 4001
ERRCODE_PARAM_ERROR = 4002
ERRCODE_AGENCY_NOT_EXIST = 4003
ERRCODE_ACCOUNT_NOTEXIST = 4004
ERRCODE_ACCOUNT_EXIST = 4005
ERRCODE_PASSWORD_ERROR = 4006
ERRCODE_TWOPASSWORD_ERROR = 4007
ERRCODE_ACCOUNT_BAN = 4008
ERR_MSG = {
ERRCODE_SUCCESS: u'调用成功',
ERRCODE_NOT_FOUND: u'未找到对象',
ERRCODE_SYSBUSY: u'系统升级中,请稍后再试',
ERRCODE_PARAM_MISSING: u'缺少参数',
ERRCODE_PARAM_ERROR: u'参数错误',
ERRCODE_ACCOUNT_NOTEXIST: u'账号不存在',
ERRCODE_ACCOUNT_EXIST: u'账号已存在',
ERRCODE_PASSWORD_ERROR: u'密码不正确',
ERRCODE_TWOPASSWORD_ERROR: u'两次密码不一致',
ERRCODE_ACCOUNT_BAN: u'账号已冻结',
ERRCODE_PERMISSION_DENIED: u'权限不足'
}
# coding=utf8
from rest_framework.exceptions import APIException
from .errcode import ERR_MSG
class CustomAPIException(APIException):
errcode = -1
def __init__(self, errcode=-1, errmsg=''):
self.errcode = errcode
self.errmsg = errmsg
def __str__(self):
return ERR_MSG.get(self.errcode, self.errmsg)
class ManageAPIException(APIException):
errcode = -9
def __init__(self, errcode=-9, errmsg=''):
self.errcode = errcode
self.errmsg = errmsg
def __str__(self):
return ERR_MSG.get(self.errcode, self.errmsg)
# coding=utf8
from rest_framework.generics import GenericAPIView
from .throttling import APIRateThrottle
class ThrottleAPIView(GenericAPIView):
throttle_classes = (APIRateThrottle,)
from django.views.decorators.csrf import csrf_exempt
from django.db.models.query_utils import Q
from rest_framework import viewsets
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import action
from rest_framework.exceptions import MethodNotAllowed
from .response import MangeAPIResponse
from core.utils.excel import export_excel
class TemplateHTMLRendererView(APIView):
renderer_classes = [TemplateHTMLRenderer]
def get(self, request):
return Response()
def post(self, request):
raise MethodNotAllowed(method='post')
class ManageResponseView(APIView):
def get(self, request):
raise MethodNotAllowed(method='get')
def post(self, request):
raise MethodNotAllowed(method='post')
class ManageResponseViewSet(viewsets.GenericViewSet):
model = None
instance = None
manage = None
class ManageListView(object):
def get_query_set(self, request):
if not self.filter_cls:
return self.queryset
return self.filter_cls(request.GET, self.queryset).qs
@action(methods=['get'], detail=False)
def search(self, request, **kwargs):
extra_filter = kwargs.get('extra_filter', Q())
order_by = '-%s' % getattr(self, 'pk_name', 'id')
if getattr(self, 'order_by', None):
order_by = self.order_by
if extra_filter != Q():
query_set = self.get_query_set(request).filter(extra_filter).order_by(order_by)
else:
query_set = self.get_query_set(request).order_by(order_by)
page = self.paginate_queryset(query_set)
serializers = self.get_serializer(page, many=True)
return self.get_paginated_response(data=serializers.data)
class ManageAddView(object):
@action(methods=['post'], detail=False)
def add(self, request, **kwargs):
add_serializer_class = getattr(self, 'add_serializer_class', self.serializer_class)
serializer = add_serializer_class(data=request.data, context={'request': request, 'created': True})
serializer.is_valid(raise_exception=True)
serializer.save(**serializer.validated_data)
return MangeAPIResponse(data=serializer.data)
class ManageDetailView(object):
@action(methods=['get'], detail=False)
def details(self, request, **kwargs):
instance = self.instance
if not instance:
pk = request.GET.get('id', request.data.get('id'))
if getattr(self, 'is_unique_id', False):
instance = self.model.objects.get(unique_id=pk)
else:
instance = self.model.objects.get(pk=pk)
detail_serializer_class = getattr(self, 'detail_serializer_class', self.serializer_class)
serializer = detail_serializer_class(instance=instance, context={'request': request})
return MangeAPIResponse(data=serializer.data)
class ManageEditView(object):
@action(methods=['post'], detail=False)
def edit(self, request, **kwargs):
instance = self.instance
if not instance:
pk = request.GET.get('id', request.data.get('id'))
if getattr(self, 'is_unique_id', False):
instance = self.model.objects.get(unique_id=pk)
else:
instance = self.model.objects.get(pk=pk)
edit_serializer_class = getattr(self, 'edit_serializer_class', self.serializer_class)
serializer = edit_serializer_class(instance=instance, data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
serializer.save(**serializer.validated_data)
return MangeAPIResponse(data=serializer.data)
class ManageDeleteView(object):
@action(methods=['post'], detail=False)
def delete(self, request, **kwargs):
instance = self.instance
if not instance:
pk = request.GET.get('id')
if getattr(self, 'is_unique_id', False):
instance = self.model.objects.get(unique_id=pk)
else:
instance = self.model.objects.get(pk=pk)
field_names = [f.name for f in self.model._meta.fields]
if 'deleted' in field_names:
instance.deleted = True
instance.save(update_fields=['deleted'])
else:
self.model.objects.filter(pk=instance.pk).delete()
return MangeAPIResponse()
class ManageActiveView(object):
@action(methods=['post'], detail=False)
def ban(self, request, **kwargs):
instance = self.instance
if not instance:
pk = request.GET.get('id')
if getattr(self, 'is_unique_id', False):
instance = self.model.objects.get(unique_id=pk)
else:
instance = self.model.objects.get(pk=pk)
instance.active = False
instance.save(update_fields=['active'])
return MangeAPIResponse()
@action(methods=['post'], detail=False)
def reset(self, request, **kwargs):
instance = self.instance
if not instance:
pk = request.GET.get('id')
if getattr(self, 'is_unique_id', False):
instance = self.model.objects.get(unique_id=pk)
else:
instance = self.model.objects.get(pk=pk)
instance.active = True
instance.save(update_fields=['active'])
return MangeAPIResponse()
class ManageExportView(object):
@action(methods=['get'], detail=False)
def export(self, request, **kwargs):
export_conf = kwargs.get('export_conf', {})
return export_excel(self.get_query_set(request).order_by('-id'),
export_conf)
# coding=utf8
from collections import OrderedDict
from rest_framework.pagination import PageNumberPagination
from .response import APIResponse, MangeAPIResponse
class BasePageNumberPagination(PageNumberPagination):
page_size = 25
page_size_query_param = 'page_size'
max_page_size = 100
values = {}
response = APIResponse
def get_response(self):
return self.response
@classmethod
def get_values(cls):
return {}
def get_paginated_response(self, data):
return self.get_response()(data=OrderedDict([
('total', self.page.paginator.count),
('next', self.get_next_link()),
('has_next', True if self.get_next_link() else False),
('page', self.page.number),
('page_size', self.page_size),
('results', data),
('values', self.get_values()),
]))
class ManagePagination(BasePageNumberPagination):
response = MangeAPIResponse
"""
Provides a set of pluggable permission policies.
"""
from __future__ import unicode_literals, absolute_import
from rest_framework.permissions import BasePermission
class IsAuthUser(BasePermission):
"""
Allows access only to auth users.
"""
def has_permission(self, request, view):
user = request.user
return user.is_authenticated
class IsProfileUser(BasePermission):
"""
Allows access only to customer users.
"""
def has_permission(self, request, view):
user = request.user
return user.is_authenticated and getattr(user, 'profile', None)
class IsManager(BasePermission):
"""
Allows access only to managers.
"""
def has_permission(self, request, view):
user = request.user
if user.is_superuser:
return True
manager = getattr(user, 'manager', None)
if user.is_authenticated and manager:
return True
return False
class IsAuthManager(BasePermission):
"""
Allows access only to managers.
"""
def has_permission(self, request, view):
user = request.user
if user.is_superuser:
return True
manager = getattr(user, 'manager', None)
if user.is_authenticated and manager:
path = request.path
if path in manager.rules:
return True
return False
# coding=utf8
from __future__ import unicode_literals
import cgi
import json
from django.core.serializers.json import DjangoJSONEncoder
from rest_framework.response import Response
from . import errcode as err_code
class APIResponse(Response):
"""
An HttpResponse that allows its data to be rendered into
arbitrary media types.
"""
def __init__(self, errcode=err_code.ERRCODE_SUCCESS, errmsg='', detail='', data={}, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
if not errmsg:
errmsg = err_code.ERR_MSG.get(errcode, u'未知错误')
res_data = {'errcode': errcode, 'errmsg': errmsg, 'data': data, 'detail': detail}
super(APIResponse, self).__init__(data=res_data, status=status, template_name=template_name,
headers=headers, exception=exception, content_type=content_type)
class MangeAPIResponse(Response):
"""
An HttpResponse that allows its data to be rendered into
arbitrary media types.
"""
def __init__(self, errcode=err_code.ERRCODE_SUCCESS, errmsg='', detail='', data={}, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
if not errmsg:
errmsg = err_code.ERR_MSG.get(errcode, u'未知错误')
# data = json.dumps(data, cls=DjangoJSONEncoder)
# data = json.loads(cgi.escape(data))
res_data = {'errcode': errcode, 'errmsg': errmsg, 'data': data, 'detail': detail}
super(MangeAPIResponse, self).__init__(data=res_data, status=status, template_name=template_name,
headers=headers, exception=exception, content_type=content_type)
# coding=utf-8
from rest_framework.throttling import SimpleRateThrottle
from django.conf import settings
class CustomRateThrottle(SimpleRateThrottle):
def allow_request(self, request, view):
"""
Implement the check to see if the request should be throttled.
On success calls `throttle_success`.
On failure calls `throttle_failure`.
"""
if not settings.IS_THROTTLE:
return True
if self.rate is None:
return True
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
self.history = self.cache.get(self.key, [])
self.now = self.timer()
# Drop any requests from the history which have now passed the
# throttle duration
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:
return self.throttle_failure()
return self.throttle_success()
def get_cache_key(self, request, view):
if request.user.is_authenticated:
ident = request.user.id
else:
ident = self.get_ident(request)
return self.cache_format % {
'scope': self.scope,
'ident': ident
}
def parse_rate(self, rate):
"""
Given the request rate string, return a two tuple of:
<allowed number of requests>, <period of time in seconds>
"""
if rate is None:
return None, None
num, period = rate.split('/')
period_digit, period = period.split('*')
num_requests = int(num)
duration = int(period_digit) * {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
return num_requests, duration
class ManuallyUpdateCacheThrottle(CustomRateThrottle):
scope = 'manually_update_cache'
def throttle_success(self):
"""
Inserts the current request's timestamp along with the key
into the cache.
"""
return True
def throttle_failure(self):
"""
Called when a request to the API has failed due to throttling.
"""
return False
def throttle_success_update_cache(self, request, view):
"""
Manually update cache
"""
self.key = self.get_cache_key(request, view)
self.history = self.cache.get(self.key, [])
self.now = self.timer()
if self.history:
self.cache.set(self.key, [], self.duration)
def throttle_failure_update_cache(self, request, view):
"""
Manually update cache
"""
self.key = self.get_cache_key(request, view)
self.history = self.cache.get(self.key, [])
self.now = self.timer()
self.history.insert(0, self.now)
self.cache.set(self.key, self.history, self.duration)
class APIRateThrottle(CustomRateThrottle):
scope = 'api'
# coding=utf8
from rest_framework import viewsets
from .throttling import APIRateThrottle
class ThrottleAPIViewSet(viewsets.GenericViewSet):
throttle_classes = (APIRateThrottle,)
class ResponseViewSet(object):
response_serializer_class = None
def get_response_serializer(self, *args, **kwargs):
response_serializer_class = self.get_response_serializer_class()
kwargs['context'] = self.get_serializer_context()
return response_serializer_class(*args, **kwargs)
def get_response_serializer_class(self):
assert self.response_serializer_class is not None, (
"'%s' should either include a `response_serializer_class` attribute, "
"or override the `get_response_serializer_class()` method."
% self.__class__.__name__
)
return self.response_serializer_class
# coding=utf8
\ No newline at end of file
# coding=utf8
from django.db.models.query_utils import Q
from django_filters import FilterSet
class BaseFilterSet(FilterSet):
def filter_search(self, queryset, name, value):
search_fields = getattr(self.Meta, 'search_fields', None)
if search_fields:
search_filter = Q()
for search_field in search_fields:
search_field = search_field.replace('.', '__')
search_filter |= Q(**{search_field + "__contains": value})
return queryset.filter(search_filter)
return queryset
class UIStyle(object):
datebox = {'class': 'easyui-datebox', 'data-options': "editable:false", 'style': 'height: 32px;'}
datemonthbox = {'class': 'easyui-datebox', 'data-options': "editable:false", 'style': 'height: 32px;'}
input = {'class': 'input-brand'}
\ No newline at end of file
from django.db import models
from core.utils.functions import gen_random_str
class UnDeleteManager(models.Manager):
def get_queryset(self):
return super(UnDeleteManager, self).get_queryset().filter(deleted=False)
class BaseModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='修改时间')
deleted = models.BooleanField(default=False)
active = models.BooleanField(default=True)
objects = UnDeleteManager()
class Meta:
ordering = ['-id']
abstract = True
@classmethod
def gen_unique_id(cls, prefix=None, length=8):
return '{}{}'.format((prefix if prefix else ''), gen_random_str(length=length))
@property
def get_active_display(self):
return '正常' if self.active else '禁用'
\ No newline at end of file
# coding=utf8
\ No newline at end of file
# coding=utf8
import traceback
from django.core.mail import EmailMessage
from django.conf import settings
from core.utils import log as logger
def send(subject, content, recipient_list):
try:
if recipient_list:
msg = EmailMessage(subject, content, settings.EMAIL_HOST_USER, recipient_list)
msg.send()
except Exception as e:
trace = traceback.format_exc()
logger.error(trace)
# coding=utf8
from django.http import HttpResponse
from xlwt.Workbook import Workbook
def _init_ws(ws, opts):
for index, opt in enumerate(opts):
ws.write(0, index, opt.get('title'))
ws.col(index).width = opt.get('width')
def _write_ws_instance(ws, index, instance, opts):
for _index, opt in enumerate(opts):
if isinstance(instance, dict):
field = instance.get(opt.get('field'))
else:
field = getattr(instance, opt.get('field'))
if callable(field):
value = field()
elif callable(opt.get('format')):
value = opt.get('format')(field)
else:
value = field
ws.write(index, _index, value)
def _write_ws(ws, instances, opts, is_init_ws):
for index, instance in enumerate(instances):
if is_init_ws:
index += 1
_write_ws_instance(ws, index, instance, opts)
def export_excel(instances, configs=None, write_ws=None, init_ws=None, encoding='utf-8'):
if not configs:
raise Exception('服务器异常')
write_ws_ = write_ws or _write_ws
if write_ws_ and not callable(write_ws_):
raise Exception('服务器异常')
init_ws_ = init_ws or _init_ws
if init_ws_ and not callable(init_ws_):
raise Exception(u'服务器异常')
w = Workbook(encoding=encoding)
ws = w.add_sheet(configs.get('sheet_name'))
response = HttpResponse(content_type='application/ms-excel')
response['Content-Disposition'] = 'attachment; filename=%s' % configs.get('file_name')
is_init_ws = False
if init_ws_:
is_init_ws = True
init_ws_(ws, configs.get('opts'))
write_ws_(ws, instances, configs.get('opts'), is_init_ws)
w.save(response)
return response
import time
import random
import base64
import string
import traceback
from functools import wraps
from datetime import datetime
from django.core.files.base import ContentFile
from django.utils.encoding import smart_text
from core.utils import log as logger
def fn_timer(function):
@wraps(function)
def function_timer(*args, **kwargs):
t0 = time.time()
result = function(*args, **kwargs)
t1 = time.time()
print("Total time running %s: %s seconds" %
(function.func_name, str(t1 - t0))
)
return result
return function_timer
def catch(func):
@wraps(func)
def wrap(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
logger.error(traceback.format_exc())
return None
return wrap
def inner_result(func):
@wraps(func)
def wrap(*args, **kwargs):
code = '0'
msg = ''
data = {}
try:
data = func(*args, **kwargs)
except Exception as e:
logger.error(traceback.format_exc())
code = '-1'
msg = smart_text(e) or '未知错误'
return {'code': code, 'msg': msg, 'data': data}
return wrap
def gen_random_str(chars=None, length=8):
if not chars:
chars = string.digits
return ''.join([random.choice(chars) for i in range(length)])
def gen_key(length=32):
chars = '1234567890abcdefghijklmnopqrstuvwxyz+=/*@='
return gen_random_str(chars, length)
def gen_time_str(t=None, ext_chars=None, ext_length=0):
if not t:
t = datetime.now()
if not ext_chars:
ext_chars = string.digits
time_str = t.strftime('%Y%m%d%H%M%S')
return "{0}{1}".format(time_str, gen_random_str(ext_chars, ext_length))
def get_client_ip(request):
if not request:
return ''
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
def get_webkit(request):
user_agent = request.META.get('HTTP_USER_AGENT').lower()
webkit = 0 # 普通浏览器
if user_agent.find('micromessenger') > -1: # 微信
webkit = 1
if user_agent.find('alipay') > -1: # 支付宝
webkit = 2
return webkit
# def get_base64_image(base64data):
# cur_time = str(time.time())
# rand_num = str(random.randint(0, 1000))
# files = {}
# try:
# img = base64data
# if isinstance(img, basestring) and img.startswith('data:image'):
# fm, img = img.split(';base64')
# ext = fm.split('/')[-1]
# image = ContentFile(base64.b64decode(img), name='pc' + cur_time + rand_num + '.' + ext)
# files['image'] = image
# except:
# pass
# return files
def dict_to_xml(obj_dict):
keys = obj_dict.keys()
keys.sort()
data = '<xml>'
for key in keys:
data += '<%s>%s</%s>' % (key, obj_dict[key], key)
data += '</xml>'
return data
import logging
# from apps.statistics.rstats import RStats
# class NullHandler(logging.Handler): # exists in python 3.1
# def emit(self, record):
# pass
def getlogger():
logger = logging.getLogger('default')
return logger
def debug(msg, *args, **kwargs):
logger = getlogger()
logger.debug(colorize(msg, *args, **kwargs))
def info(msg, *args, **kwargs):
logger = getlogger()
logger.info(colorize(msg, *args, **kwargs))
def error(msg, *args, **kwargs):
logger = getlogger()
logger.error(msg, *args, **kwargs)
def colorize(msg, *args, **kwargs):
# params = {
# r'\-\-\->': '~FB~SB--->~FW',
# r'\*\*\*>': '~FB~SB~BB--->~BT~FW',
# r'\[': '~SB~FB[~SN~FM',
# r'AnonymousUser': '~FBAnonymousUser',
# r'\*(\s*)~FB~SB\]': r'~SN~FR*\1~FB~SB]',
# r'\]': '~FB~SB]~FW~SN',
# }
# colors = {
# '~SB': Style.BRIGHT,
# '~SN': Style.NORMAL,
# '~SK': Style.BLINK,
# '~SU': Style.UNDERLINE,
# '~ST': Style.RESET_ALL,
# '~FK': Fore.BLACK,
# '~FR': Fore.RED,
# '~FG': Fore.GREEN,
# '~FY': Fore.YELLOW,
# '~FB': Fore.BLUE,
# '~FM': Fore.MAGENTA,
# '~FC': Fore.CYAN,
# '~FW': Fore.WHITE,
# '~FT': Fore.RESET,
# '~BK': Back.BLACK,
# '~BR': Back.RED,
# '~BG': Back.GREEN,
# '~BY': Back.YELLOW,
# '~BB': Back.BLUE,
# '~BM': Back.MAGENTA,
# '~BC': Back.CYAN,
# '~BW': Back.WHITE,
# '~BT': Back.RESET,
# }
# for k, v in params.items():
# msg = re.sub(k, v, msg)
# msg = msg + '~ST~FW~BT'
# # msg = re.sub(r'(~[A-Z]{2})', r'%(\1)s', msg)
# for k, v in colors.items():
# msg = msg.replace(k, v)
return msg, args, kwargs
'''
This module generates ANSI character codes to printing colors to terminals.
See: http://en.wikipedia.org/wiki/ANSI_escape_code
'''
COLOR_ESC = '\033['
class AnsiCodes(object):
def __init__(self, codes):
for name in dir(codes):
if not name.startswith('_'):
value = getattr(codes, name)
setattr(self, name, COLOR_ESC + str(value) + 'm')
class AnsiFore:
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
WHITE = 37
RESET = 39
class AnsiBack:
BLACK = 40
RED = 41
GREEN = 42
YELLOW = 43
BLUE = 44
MAGENTA = 45
CYAN = 46
WHITE = 47
RESET = 49
class AnsiStyle:
BRIGHT = 1
DIM = 2
UNDERLINE = 4
BLINK = 5
NORMAL = 22
RESET_ALL = 0
Fore = AnsiCodes(AnsiFore)
Back = AnsiCodes(AnsiBack)
Style = AnsiCodes(AnsiStyle)
# coding=utf8
MOBILE_REGEX = '^[1][3-9]\\d{9}$'
BANK_CARD_REGEX = '^(\d{16}|\d{19})$'
ID_CARD_REGEX = '^([1-9]\d{5}[12]\d{3}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])\d{3}[0-9xX])$'
# coding=utf8
# coding=utf8
INSTRUMENT_CHOICES = (
('zn', '沪锌'),
('rb', '螺纹钢'),
('pp', 'PP'),
)
def get_instrument_name(code):
for i in INSTRUMENT_CHOICES:
if code == i[0]:
return i[1]
return None
"""
Django settings for f project.
Generated by 'django-admin startproject' using Django 2.1.2.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '#vpj)&3qa$0309o%5d&crdcc1t13pvqhcwf-6lhh1jt_oumyj2'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
CURRENT_DIR = os.path.dirname(os.path.dirname(__file__))
TEMPLATE_DIRS = (os.path.join(CURRENT_DIR, 'templates'),)
STATICFILES_DIRS = (os.path.join(CURRENT_DIR, 'static'),)
MEDIA_ROOT = os.path.join(CURRENT_DIR, 'media')
LOG_FILE = os.path.join(CURRENT_DIR, 'logs/project.log')
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'django_filters',
'apps.base',
'apps.task',
'apps.manage',
'django_q'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'fish.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': list(TEMPLATE_DIRS),
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.static',
],
},
},
]
WSGI_APPLICATION = 'fish.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
from django.core.exceptions import ImproperlyConfigured
def get_env_variable(var_name, default_var=None):
try:
return os.environ[var_name]
except KeyError:
if default_var:
return default_var
error_msg = "Set the %s environment variable" % var_name
raise ImproperlyConfigured(error_msg)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': get_env_variable('DATABASE_NAME', 'fish'),
'USER': get_env_variable('DATABASE_USER', 'postgres'),
'PASSWORD': get_env_variable('DATABASE_PASSWORD', 'juan'),
'HOST': get_env_variable('DATABASE_HOST', 'localhost'),
'PORT': get_env_variable('DATABASE_PORT', '5432'),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'root': {
'level': 'WARNING',
'handlers': ['sentry'],
},
'formatters': {
'verbose': {
'format': '[%(asctime)-12s] %(message)s',
'datefmt': '%b %d %H:%M:%S'
},
'simple': {
'format': '%(message)s'
},
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
'sentry': {
'level': 'ERROR',
'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
},
'log_file': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': LOG_FILE,
'maxBytes': 16777216, # 16megabytes
'formatter': 'verbose'
},
'mail_admins': {
'level': 'CRITICAL',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['require_debug_false'],
'include_html': True,
}
},
'loggers': {
'django.request': {
'handlers': ['console', 'log_file'],
'level': 'ERROR',
'propagate': True,
},
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
},
# 'django.security.DisallowedHost': {
# 'handlers': ['null'],
# 'propagate': False,
# },
'default': {
'handlers': ['console', 'log_file'],
'level': 'DEBUG',
'propagate': True,
},
'raven': {
'level': 'DEBUG',
'handlers': ['console'],
'propagate': False,
},
'sentry.errors': {
'level': 'DEBUG',
'handlers': ['console'],
'propagate': False,
},
'apps': {
'handlers': ['log_file'],
'level': 'INFO',
'propagate': True,
},
},
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
}
# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Hong_Kong'
USE_I18N = True
USE_L10N = True
USE_TZ = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
# ==================
# = Rest Framework =
# ==================
IS_THROTTLE = True
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'core.framework.custom_exception_handler.custom_exception_handler',
'DEFAULT_AUTHENTICATION_CLASSES': (
'core.framework.authentication.MyTokenAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_THROTTLE_RATES': {
'api': '10/1*second'
},
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S'
}
# ==========
# = Email =
# ==========
EMAIL_HOST = 'smtp.exmail.qq.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = 'traffic@xiaogu8.com'
EMAIL_HOST_PASSWORD = 'W1ccb4v3rt'
EMAIL_USE_TLS = True
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
Q_CLUSTER = {
'name': 'fish',
'workers': 2,
'recycle': 500,
'timeout': 600,
'compress': True,
'save_limit': 250,
'queue_limit': 500,
'cpu_affinity': 1,
'label': 'Django Q',
'redis': {
'host': '127.0.0.1',
'port': 6379,
'db': 0, }
}
"""f URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.urls import path
from django.conf.urls import url, include
urlpatterns = [
url(r'manage/', include('apps.manage.urls')),
url(r'market/', include('apps.market.urls')),
]
"""
WSGI config for f project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fish.settings')
application = get_wsgi_application()
#!/usr/bin/env python
import os
import sys
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fish.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
/**
* Created by jun on 2017/8/23.
*/
var gulp = require('gulp'),
less = require('gulp-less');
//当发生异常时提示错误 确保本地安装gulp-notify和gulp-plumber
notify = require('gulp-notify'),
plumber = require('gulp-plumber');
gulp.task('less', function () {
gulp.src('manage/less/*.less')
.pipe(plumber({errorHandler: notify.onError('Error: <%= error.message %>')}))
.pipe(less())
.pipe(gulp.dest('manage/css'));
});
gulp.task('watch', function () {
gulp.watch('manage/less/**/*.less', ['less']);
});
\ No newline at end of file
<svg width='200px' height='200px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="uil-balls"><rect x="0" y="0" width="100" height="100" fill="none" class="bk"></rect><g transform="rotate(0 50 50)">
<circle r="5" cx="30" cy="50">
<animateTransform attributeName="transform" type="translate" begin="0s" repeatCount="indefinite" dur="1s" values="0 0;19.999999999999996 -20" keyTimes="0;1"/>
<animate attributeName="fill" dur="1s" begin="0s" repeatCount="indefinite" keyTimes="0;1" values="#c5523f;#f2b736"/>
</circle>
</g><g transform="rotate(90 50 50)">
<circle r="5" cx="30" cy="50">
<animateTransform attributeName="transform" type="translate" begin="0s" repeatCount="indefinite" dur="1s" values="0 0;19.999999999999996 -20" keyTimes="0;1"/>
<animate attributeName="fill" dur="1s" begin="0s" repeatCount="indefinite" keyTimes="0;1" values="#f2b736;#499255"/>
</circle>
</g><g transform="rotate(180 50 50)">
<circle r="5" cx="30" cy="50">
<animateTransform attributeName="transform" type="translate" begin="0s" repeatCount="indefinite" dur="1s" values="0 0;19.999999999999996 -20" keyTimes="0;1"/>
<animate attributeName="fill" dur="1s" begin="0s" repeatCount="indefinite" keyTimes="0;1" values="#499255;#1875e5"/>
</circle>
</g><g transform="rotate(270 50 50)">
<circle r="5" cx="30" cy="50">
<animateTransform attributeName="transform" type="translate" begin="0s" repeatCount="indefinite" dur="1s" values="0 0;19.999999999999996 -20" keyTimes="0;1"/>
<animate attributeName="fill" dur="1s" begin="0s" repeatCount="indefinite" keyTimes="0;1" values="#1875e5;#c5523f"/>
</circle>
</g></svg>
\ No newline at end of file
<svg width="81px" height="81px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-bricks">
<rect ng-attr-fill="{{config.c1}}" ng-attr-x="{{config.x}}" ng-attr-y="{{config.x}}" ng-attr-width="{{config.w}}" ng-attr-height="{{config.w}}" ng-attr-rx="{{config.radius}}" ng-attr-ry="{{config.radius}}" fill="#ff7c81" x="21.5" y="21.5" width="25" height="25" rx="3" ry="3">
<animate attributeName="x" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-1.375s" repeatCount="indefinite"></animate>
<animate attributeName="y" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-1s" repeatCount="indefinite"></animate>
</rect>
<rect ng-attr-fill="{{config.c2}}" ng-attr-x="{{config.x}}" ng-attr-y="{{config.x}}" ng-attr-width="{{config.w}}" ng-attr-height="{{config.w}}" ng-attr-rx="{{config.radius}}" ng-attr-ry="{{config.radius}}" fill="#ffec58" x="21.5" y="53.5" width="25" height="25" rx="3" ry="3">
<animate attributeName="x" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-0.875s" repeatCount="indefinite"></animate>
<animate attributeName="y" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-0.5s" repeatCount="indefinite"></animate>
</rect>
<rect ng-attr-fill="{{config.c3}}" ng-attr-x="{{config.x}}" ng-attr-y="{{config.x}}" ng-attr-width="{{config.w}}" ng-attr-height="{{config.w}}" ng-attr-rx="{{config.radius}}" ng-attr-ry="{{config.radius}}" fill="#7cd7ff" x="53.5" y="42.919" width="25" height="25" rx="3" ry="3">
<animate attributeName="x" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-0.375s" repeatCount="indefinite"></animate>
<animate attributeName="y" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="0s" repeatCount="indefinite"></animate>
</rect>
</svg>
\ No newline at end of file
/**
* Created by jun on 2017/8/25.
*/
/* EasyUI Datebox*/
$.fn.datebox.defaults.cleanText = '清空';
(function ($) {
var buttons = $.extend([], $.fn.datebox.defaults.buttons);
buttons.splice(1, 0, {
text: function (target) {
return $(target).datebox("options").cleanText
},
handler: function (target) {
$(target).datebox("setValue", "");
$(target).datebox("hidePanel");
}
});
$.extend($.fn.datebox.defaults, {
buttons: buttons
});
})(jQuery);
\ No newline at end of file
/**
* Created by jun on 2017/08/22.
*/
var renderTable = function (opts) {
var table = {
tableId: undefined,
table: undefined,
editIndex: undefined,
isEdited: false,
opts: {
width: '100%',
tableId: '#mTable',
toolbar: '#toolbar',
searchBtn: '#searchBtn',
searchForm: '#searchForm',
exportBtn: '#exportBtn',
editable: false,
loadMsg: false,
singleSelect: true,
rownumbers: true,
showFooter: true,
fitColumns: true,
pagination: true,
pageSize: 20,
pageList: [20, 50, 100],
columns: [[]],
data: [],
},
init: function (opts) {
var self = this;
$.extend(self.opts, opts);
var _opts = {
height: $(window).height() - (self.opts.subHeight || 25),
loader: function (params, success, error) {
if (self.opts.url) {
if (self.opts.searchForm) {
var searchParams = $(self.opts.searchForm).serializeArray();
for (var i = 0; i < searchParams.length; i++) {
if (searchParams[i].value.trim() != "") {
params[searchParams[i].name] = searchParams[i].value;
}
}
}
if (self.opts.defaultParams) {
params = $.extend(param, self.opts.defaultParams);
}
params['page_size'] = params.rows;
get(self.opts.url, params, function (result) {
if (result.errcode == 200) {
if (!self.opts.loadCallBack) {
return success(result.data);
}
return self.opts.loadCallBack(result, success);
} else {
showMsg(result.errmsg);
error();
}
});
} else {
return false;
}
},
loadFilter: function (data) {
if (data) {
return {"total": data.total || 0, "rows": data.rows || data.results || []};
}
return false;
},
onLoadSuccess: function (data) {
if (data.total == 0) {
var body = $(this).data().datagrid.dc.body2;
body.find('table tbody').append('<tr><td colspan="100"' +
' style="height: 60px; border: none; font-size: 16px; color: #333;">' +
'<p style=" display: flex; align-items: center;justify-content: center; width: 200px;margin: 0 auto;">' +
'<i class="icon icon-i"></i><span style="margin-left: 8px;">查询无相关条件的记录</span></p></td></tr>');
}
if (data.values) {
for (var v in data.values) {
$(v).text(values[v])
}
}
},
onSelectPage: function (pageNumber, pageSize) {
getData(pageNumber, pageSize);
},
onBeforeEdit: self.opts.onBeforeEdit || function (index, field) {
self.editIndex = index;
},
};
$.extend(self.opts, _opts);
self.tableId = self.opts.tableId;
if (self.opts.editable) {
self.table = $(self.tableId).edatagrid(self.opts);
} else {
self.table = $(self.tableId).datagrid(self.opts);
}
if (self.opts.searchBtn) {
$(self.opts.searchBtn).bind("click", function (e) {
e.preventDefault();
self.table.datagrid("load");
});
}
if (self.opts.exportBtn && self.opts.exportUrl) {
$(self.opts.exportBtn).bind("click", function (e) {
var searchParams = '';
if (self.opts.searchForm) {
searchParams = $(self.opts.searchForm).serialize();
}
if (self.opts.exportUrl) {
$(self.opts.exportBtn).attr('href', self.opts.exportUrl + '?' + searchParams);
}
});
}
if (!self.opts.noResize) {
$(window).resize(function () {
$(self.tableId).datagrid('resize', {height: $(window).height() - (self.opts.subHeight || 25)});
});
}
return self;
},
endEditing: function () {
if (this.editIndex == undefined) {
return true
}
//校验指定的行,如果有效返回true
if ($(this.tableId).datagrid('validateRow', this.editIndex)) {
$(this.tableId).datagrid('endEdit', this.editIndex); //结束编辑
this.editIndex = undefined;
this.isEdited = true;
return true;
} else {
return false;
}
}
}
return table.init(opts);
};
\ No newline at end of file
/**
* Created by jun on 2017/3/29.
*/
// create tree
var createTree = function (opts) {
var tree = {
treeId: opts.treeId,
opts: opts,
init: function (opts) {
var self = this;
$(opts.treeId).tree({
url: opts.url,
method: opts.method || 'get',
checkbox: opts.checkbox || false,
animate: opts.animate || false,
dnd: opts.dnd || false,
lines: opts.lines || false,
onClick: opts.onClick,
onDragEnter: opts.onDragEnter || undefined,
onBeforeDrop: opts.onBeforeDrop || undefined,
onBeforeExpand: opts.onBeforeExpand || undefined,
onContextMenu: function(e, node){
e.preventDefault();
$(opts.treeId).tree('select', node.target);
$(opts.menu).menu('show', {
left: e.pageX,
top: e.pageY
});
},
formatter: function (node) {
if(opts.formatter){
return opts.formatter(node);
}else{
return node.text;
}
},
loadFilter: opts.loadFilter || function (data, parent) {
if(opts.loadCallBack){
opts.loadCallBack(data);
}
if (data.data){
return data.data;
}else{
return data
}
},
onLoadSuccess: opts.onLoadSuccess || function (node, data) {
return false;
}
});
return self
},
getIdChecked: function () {
var self = this;
var idList = [];
var nodes = $(self.opts.treeId).tree('getChecked');
for (var i=0; i<nodes.length; i++) {
if(nodes[i].is_pNode){
continue
}
var parent = $(self.opts.treeId).tree('getParent', nodes[i].target);
if(parent && idList.indexOf(parent.id) == -1){
if(!parent.is_pNode){
idList.push(parent.id);
}
}
idList.push(nodes[i].id);
}
return idList;
}
}
return tree.init(opts);
}
/**
* Created by jun on 2017/8/24.
*/
//自动消失的提示
function showMsg(msg, interval, error) {
var $pop = $("#m-pop");
if (error) {
$pop = $("#m-pop-error");
}
if ($pop.is(":visible")) {
clearTimeout(showMsg.timer);
}
$pop.children(".pop-msg").html(msg);
$pop.css({"top": "0px"});
showMsg.timer = setTimeout(function () {
$pop.css("top", "-90px");
}, interval || 2000);
};
function show_ajax_loading() {
if (document.getElementById("page-loading").style.display == "none") {
$(".ajax-loading").show();
}
};
function hide_ajax_loading() {
$(".ajax-loading").hide();
};
var ajax = function (url, type, params, dataType, callback, sync) {
show_ajax_loading();
$.ajax({
url: url,
data: params,
type: type,
dataType: dataType,
async: !sync,
success: function (response) {
hide_ajax_loading();
if (!(response instanceof Object)) {
response = JSON.parse(response);
}
if (response.errcode == 200) {
callback(response);
} else {
showMsg(response.errmsg, false, true);
}
},
error: function (err) {
hide_ajax_loading();
showMsg('网络请求错误', false, true);
}
});
};
var get = function (url, params, callback) {
ajax(url, 'GET', params, 'json', callback);
};
var getSync = function (url, params, callback) {
ajax(url, 'GET', params, 'json', callback, true);
}
var post = function (url, params, callback) {
ajax(url, 'POST', params, 'json', callback);
};
var postSync = function (url, params, callback) {
ajax(url, 'POST', params, 'json', callback, true);
}
function getFormParams(formId) {
var data = Object();
var params = $(formId).serializeArray();
for (var i = 0; i < params.length; i++) {
if (params[i].value.trim() != "") {
if (data[params[i].name]) {
data[params[i].name] += '#' + params[i].value;
} else {
data[params[i].name] = params[i].value;
}
}
}
return data;
}
function myGetConfirm(title, message, url, callback) {
$.messager.confirm(title, message, function (r) {
if (r) {
get(url, {}, function (response) {
if (response.errcode == 200) {
showMsg('操作成功');
callback(response);
} else {
showMsg(response.errmsg, 2000, true);
}
});
}
});
}
function myPostConfirm(title, message, url, data, callback) {
$.messager.confirm(title, message, function (r) {
if (r) {
post(url, data, function (response) {
if (response.errcode == 200) {
showMsg('操作成功');
callback(response);
} else {
showMsg(response.errmsg, 2000, true);
}
});
}
});
}
$(document).on("click", ".page-refresh", function (e) {
e.preventDefault();
location.reload();
});
$(document).on("change", ".object-pic", function (e) {
var $this = $(this);
lrz(this.files[0], {width: 1500})
.then(function (rst) {
$this.prev('img').attr("src", rst.base64);
})
.catch(function (err) {
// 处理失败会执行
alert(err);
})
.always(function () {
// 不管是成功失败,都会执行
});
});
function ajax_save_form(form, callback) {
show_ajax_loading();
$(form).ajaxSubmit({
data: {},
dataType: 'json',
success: function (response) {
hide_ajax_loading();
if (!(response instanceof Object)) {
response = JSON.parse(response);
}
if (response.errcode == 200) {
callback(response);
} else {
showMsg(response.errmsg, 2000, true);
}
}
});
}
\ No newline at end of file
/**
* Created by jun on 2017/5/7.
*/
$.extend($.fn.validatebox.defaults.rules, {
bank: {
validator: function(value, param){
var reg = /^([1-9]{1})(\d{15}|\d{18})$/;
return reg.test(value);
},
message: '请输入正确的银行卡号'
},
number: {
validator: function(value, param){
var reg = /^\+?[0-9]*$/;
return reg.test(value);
},
message: '请输入正确的正整数'
},
float: {
validator: function(value, param){
var reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
return reg.test(value);
},
message: '请输入正确的两位小数'
},
money: {
validator: function(value, param){
var reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
return reg.test(value);
},
message: '请输入正确的金额'
},
mobile: {
validator: function(value, param){
var reg = /^1[34578]\d{9}$/;
return reg.test(value);
},
message: '请输入正确的手机号码'
},
email: {
validator: function(value, param){
var reg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/;
return reg.test(value);
},
message: '请输入正确的邮箱地址'
}
});
@import "util/variables.less";
@import "util/utilities.less";
@import "util/layout.less";
@import "util/navbar.less";
@import "util/icon.less";
// Base
*,
*::before,
*::after {
box-sizing: inherit;
margin: 0;
padding: 0;
outline: none;
}
ul, ol {
list-style: none;
}
html {
width: 100%;
height: 100%;
box-sizing: border-box;
font-size: @html-font-size;
line-height: @html-line-height;
-webkit-tap-highlight-color: transparent;
}
body {
height: 100%;
background: @body-bg;
color: @body-font-color;
font-family: @body-font-family;
font-size: @body-font-size;
overflow-x: hidden;
text-rendering: optimizeLegibility;
}
a {
color: @core-link-color;
text-decoration: none;
&:focus,
&:hover {
color: darken(@core-link-color, 25%);
}
}
@import "util/page.less";
@import "util/form.less";
@import "util/table.less";
@import "util/window.less";
.flex-center {
display: flex;
align-items: center;
}
/*Data Card*/
.data-card {
padding: 10px 20px;
margin-bottom: 10px;
display: inline-block;
border-top: 2px solid @core-color;
background: #f6f7f8;
min-width: 150px;
margin-right: 10px;
box-shadow: 0px 1px 3px #ccc;
}
.data-card .num {
font-size: 22px;
color: #09c;
}
.text-explode {
color: #CCC !important;
font-weight: normal !important;
margin: 0px 4px !important;
}
.image-input {
background: url(../images/preview.png) no-repeat center;
position: relative;
overflow: hidden;
line-height: 50px;
color: #aaa;
height: 100px;
width: 128px;
cursor: pointer;
margin: 0 auto;
}
.image-input img {
width: 100%;
height: 100%;
}
.object-pic {
position: absolute;
padding: 0px !important;
top: 0;
right: 0;
min-width: 100% !important;
min-height: 100% !important;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: white;
cursor: pointer;
display: block;
height: 100px;
width: 128px;
}
.form-group .image-input {
margin-left: 5px;
}
\ No newline at end of file
.form-group label {
color: @color-txt-gray2;
font-size: 14px;
}
.form-control {
height: 0.32rem;
width: 1.8rem;
line-height: 0.32rem;
text-indent: 0.1rem;
border: 1px solid @core-border-color;
box-shadow: none;
&:focus {
border: 1px solid @core-color;
}
}
.form-inline {
display: inline-block;
margin: 0.1rem;
.form-group {
margin: 0.1rem 0rem;
display: flex;
label {
display: inline-block;
width: 0.8rem;
text-align: left;
}
textarea.form-control {
height: 1.2rem;
}
}
.form-action {
margin-top: 0.15rem;
text-align: left;
}
}
.form-search {
padding: 0.2rem 0.1rem;
.form-group {
float: left;
margin-right: 0.1rem;
margin-bottom: 0.1rem;
}
> p {
float: left;
margin-right: 0.1rem;
margin-bottom: 0.1rem;
label {
color: @color-txt-gray;
font-size: 14px;
}
}
}
/*Input*/
input {
&.x2 {
width: 180px;
}
}
.textbox {
border: 1px solid @core-border-color;
}
.input-brand {
text-indent: 0.08rem;
height: 0.32rem;
line-height: 0.32rem;
border: 1px solid @core-border-color;
}
.input-brand:focus {
border: 1px solid @core-color;
}
.button {
height: 0.32rem;
line-height: 0.32rem;
padding: 0rem 0.14rem;
border: none;
cursor: pointer;
display: inline-block;
}
.button-brand {
background: @core-color;
color: @core-light-color;
margin-right: 7px;
}
.button-brand:hover {
background: lighten(@core-color, 5%);
color: @core-light-color;
}
.button-info {
background: @control-color-info;
color: @core-light-color;
}
.button-info:hover {
background: lighten(@control-color-info, 5%);
color: @core-light-color;
}
.button-inner {
color: #2e8ece;
background: #fff;
border: 1px solid #2e8ece;
}
.button-inner:hover {
color: #fff;
background: #2e8ece;
}
.button-inner-yellow {
color: #f8b55b;
background: #fff;
border: 1px solid #f8b55b;
}
.button-inner-yellow:hover {
color: #fff;
background: #f8b55b;
}
.button-close {
background: @core-light-color;
color: @control-color;
border: 1px solid @core-border-color;
}
.button-close:hover {
background: lighten(@control-color, 5%);
color: @core-light-color;
}
.button-inline {
color: @core-link-color;
}
.button-inline:hover {
text-decoration: underline;
color: lighten(@core-link-color, 5%);
}
.fieldsets {
margin-bottom: 0.1rem;
padding: 15px;
.fieldset {
background: @core-empty-bg;
border: none;
> label {
background: @control-color-info;
color: @core-light-color;
display: inline-block;
padding: 0.04rem 0.06rem;
margin-bottom: 0.1rem;
}
.form-group {
margin-bottom: 7px;
padding: 0rem 0.1rem;
label {
display: inline-block;
width: 1.05rem;
}
}
}
}
\ No newline at end of file
.icon{
display: inline-block;
width: 28px;
height: 28px;
}
.icon-i{
background: url('icons/!.png') no-repeat center;
background-size: contain;
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment