diff --git a/test_client/src/views/crm/consumer.vue b/test_client/src/views/crm/consumer.vue index 3b9b216..805c741 100644 --- a/test_client/src/views/crm/consumer.vue +++ b/test_client/src/views/crm/consumer.vue @@ -99,10 +99,9 @@ @@ -156,14 +155,27 @@ - - + + + + + +
取消 @@ -181,6 +193,7 @@ import { updateConsumer, importConsumer } from "@/api/crm"; +import { getSubjectAll } from "@/api/question" import { getCompanyList } from "@/api/crm"; import { genTree, deepClone } from "@/utils"; import checkPermission from "@/utils/permission"; @@ -192,10 +205,8 @@ const defaultConsumer = { id: "", name: "", username: "", - company: { - id:0, - name:'' - }, + company: null, + subjects:[] }; const listQuery = { page: 1, @@ -237,13 +248,15 @@ export default { }, filterOrgText: "", treeLoding: false, - companyData: [] + companyData: [], + subjectData: [], }; }, computed: {}, created() { this.getList(); this.getCompanyList(); + this.getSubjectAll(); }, methods: { checkPermission, @@ -292,6 +305,11 @@ export default { this.treeLoding = false; }); }, + getSubjectAll() { + // getSubjectAll().then(response => { + // this.subjectData = genTree(response.data); + // }); + }, resetFilter() { this.listQuery = { page: 1, @@ -346,18 +364,18 @@ export default { const isEdit = this.dialogType === "edit"; if (isEdit) { let consumer = this.consumer - consumer.company = consumer.company.id updateConsumer(this.consumer.id, consumer).then(() => { - for (let index = 0; index < this.consumerList.length; index++) { - if (this.consumerList[index].id === this.consumer.id) { - this.consumerList.splice( - index, - 1, - Object.assign({}, this.consumer) - ); - break; - } - } + // for (let index = 0; index < this.consumerList.length; index++) { + // if (this.consumerList[index].id === this.consumer.id) { + // this.consumerList.splice( + // index, + // 1, + // Object.assign({}, this.consumer) + // ); + // break; + // } + // } + this.getList() this.dialogVisible = false; this.$notify({ title: "成功", @@ -367,9 +385,6 @@ export default { }); }); } else { - this.consumer.company.id = this.consumer.company.id.pop(); - let consumer = this.consumer - consumer.company = consumer.company.id createConsumer(consumer).then(res => { // this.consumer = res.data // this.consumerList.unshift(this.consumer) diff --git a/test_mini/app.js b/test_mini/app.js index 6400235..684abc4 100644 --- a/test_mini/app.js +++ b/test_mini/app.js @@ -15,6 +15,12 @@ App({ if(res.code==200){ this.globalData.token = res.data.token this.globalData.userInfo = res.data.userinfo + if(res.data.userinfo.username == null){ + //匿名用户 + wx.reLaunch({ + url: '/pages/login/login', + }) + } } }) } diff --git a/test_mini/images/sologan.png b/test_mini/images/sologan.png new file mode 100644 index 0000000..ba0482c Binary files /dev/null and b/test_mini/images/sologan.png differ diff --git a/test_mini/images/wave.png b/test_mini/images/wave.png new file mode 100644 index 0000000..f3d1ce7 Binary files /dev/null and b/test_mini/images/wave.png differ diff --git a/test_mini/pages/cuoti/index.js b/test_mini/pages/cuoti/index.js index e0e1bb7..3f01ce3 100644 --- a/test_mini/pages/cuoti/index.js +++ b/test_mini/pages/cuoti/index.js @@ -10,7 +10,8 @@ Page({ ctms: [], tm_index: 0, isright:false, - answerP:false + answerP:false, + tmtotal:0 }, radioChange: function (e) { var that = this @@ -26,7 +27,7 @@ Page({ /** * 生命周期函数--监听页面加载 */ - onLoad: function (options) { + onLoad: function () { var that = this wx.showLoading({}) try { diff --git a/test_mini/pages/index/index.js b/test_mini/pages/index/index.js index 3fba5f8..177d47e 100644 --- a/test_mini/pages/index/index.js +++ b/test_mini/pages/index/index.js @@ -4,7 +4,6 @@ const app = getApp() Page({ data: { - motto: 'Hello World', userInfo: {}, hasUserInfo: false, canIUse: wx.canIUse('button.open-type.getUserInfo') diff --git a/test_mini/pages/index/index.wxml b/test_mini/pages/index/index.wxml index 0243bda..d79c207 100644 --- a/test_mini/pages/index/index.wxml +++ b/test_mini/pages/index/index.wxml @@ -7,7 +7,4 @@ {{userInfo.nickName}} - - {{motto}} - diff --git a/test_mini/pages/index/index.wxss b/test_mini/pages/index/index.wxss index 8435be5..fab9dee 100644 --- a/test_mini/pages/index/index.wxss +++ b/test_mini/pages/index/index.wxss @@ -15,7 +15,3 @@ .userinfo-nickname { color: #aaa; } - -.usermotto { - margin-top: 20px; -} \ No newline at end of file diff --git a/test_mini/pages/lianxi/index.js b/test_mini/pages/lianxi/index.js index ee138f8..05e9f9c 100644 --- a/test_mini/pages/lianxi/index.js +++ b/test_mini/pages/lianxi/index.js @@ -20,10 +20,12 @@ Page({ this.setData({ questioncatId: value.id }) + } else{ + wx.switchTab({ + url: '/pages/main/main', + }) } } catch (e) { - wx.navigateBack({ - }) } }, diff --git a/test_mini/pages/login/login.js b/test_mini/pages/login/login.js index 6d0e5fe..fbf4f6d 100644 --- a/test_mini/pages/login/login.js +++ b/test_mini/pages/login/login.js @@ -1,66 +1,86 @@ -// pages/login/login.js +//index.js +//获取应用实例 +const app = getApp() +const api = require("../../utils/request.js"); Page({ - - /** - * 页面的初始数据 - */ data: { - + userInfo: {}, + hasUserInfo: false, + canIUse: wx.canIUse('button.open-type.getUserInfo') }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad: function (options) { - + //事件处理函数 + bindViewTap: function () { + wx.navigateTo({ + url: '../logs/logs' + }) }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady: function () { - + phoneChange: function (e) { + this.data.phone = e.detail.value }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow: function () { - + codeChange: function (e) { + this.data.code = e.detail.value }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide: function () { - + onLoad: function () { + wx.hideHomeButton() + if (app.globalData.userInfo) { + this.setData({ + userInfo: app.globalData.userInfo, + hasUserInfo: true + }) + } else if (this.data.canIUse) { + // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 + // 所以此处加入 callback 以防止这种情况 + app.userInfoReadyCallback = res => { + this.setData({ + userInfo: res.userInfo, + hasUserInfo: true + }) + } + } else { + // 在没有 open-type=getUserInfo 版本的兼容处理 + wx.getUserInfo({ + success: res => { + app.globalData.userInfo = res.userInfo + this.setData({ + userInfo: res.userInfo, + hasUserInfo: true + }) + } + }) + } }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload: function () { - + getUserInfo: function (e) { + app.globalData.userInfo = e.detail.userInfo + this.setData({ + userInfo: e.detail.userInfo, + hasUserInfo: true + }) }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh: function () { - + sendMsg : function (e){ + api.request('crm/consumer/sendcode', 'GET', {phone:this.data.phone}).then(res => { + wx.showToast({ + title: '验证码发送成功!', + icon:'none' + }) + }) }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom: function () { - + onGetInfo : function (e){ + this.setData({ + userInfo: e.detail.userInfo + }) + this.denglu() }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage: function () { - + goMain: function (){ + wx.reLaunch({ + url: '/pages/main/main', + }) + }, + denglu: function () { + api.request('crm/consumer/register/', 'POST', { phone: this.data.phone, code: this.data.code }).then(res => { + getApp().onLaunch() + }) + wx.switchTab({ + url: '/pages/main/main', + }) } -}) \ No newline at end of file +}) diff --git a/test_mini/pages/login/login.wxml b/test_mini/pages/login/login.wxml index 2f17a4e..ec2ae6e 100644 --- a/test_mini/pages/login/login.wxml +++ b/test_mini/pages/login/login.wxml @@ -1,2 +1,37 @@ - -pages/login/login.wxml + + + 开启学习之旅 + 为了更好的为您服务,请注册! + + + 注册 + + + + 手机号 + + + + + + 获取验证码 + + + + + 验证码 + + + + + + + + + 浏览进入 + + + + Copyright © 2018-2020 国检集团 + 中存大数据提供技术支持 + \ No newline at end of file diff --git a/test_mini/pages/login/login.wxss b/test_mini/pages/login/login.wxss index 4827a66..8435be5 100644 --- a/test_mini/pages/login/login.wxss +++ b/test_mini/pages/login/login.wxss @@ -1 +1,21 @@ -/* pages/login/login.wxss */ \ No newline at end of file +/**index.wxss**/ +.userinfo { + display: flex; + flex-direction: column; + align-items: center; +} + +.userinfo-avatar { + width: 128rpx; + height: 128rpx; + margin: 20rpx; + border-radius: 50%; +} + +.userinfo-nickname { + color: #aaa; +} + +.usermotto { + margin-top: 20px; +} \ No newline at end of file diff --git a/test_mini/pages/subject/index.js b/test_mini/pages/subject/index.js index 740cfce..3814950 100644 --- a/test_mini/pages/subject/index.js +++ b/test_mini/pages/subject/index.js @@ -1,5 +1,6 @@ // pages/subject/index.js const api = require("../../utils/request.js"); + Page({ /** @@ -14,11 +15,19 @@ Page({ */ onLoad: function (options) { api.request('question/subject/', 'GET').then(res => { - if (res.code == 200) { + var subjectData = res.data + api.request('crm/consumer/subjectpaid', 'GET').then(res => { + for(var i=0;i所有学科 - +

{{item.name}}

- 已购买 + 已购买 +
购买
diff --git a/test_mini/utils/request.js b/test_mini/utils/request.js index 9453cb4..75a647b 100644 --- a/test_mini/utils/request.js +++ b/test_mini/utils/request.js @@ -12,15 +12,16 @@ function request(url, method, data) { }, success: (res => { wx.hideLoading(); - if (res.data.code >= 400) { + if (res.data.code >= 200 && res.data.code < 400) { + resolve(res.data); + } + else { wx.showToast({ title: JSON.stringify(res.data.msg), icon: 'none', duration: 1000 }) } - resolve(res.data); - }), fail: (res => { diff --git a/test_server/crm/authentication.py b/test_server/crm/authentication.py index 67dc882..5e76228 100644 --- a/test_server/crm/authentication.py +++ b/test_server/crm/authentication.py @@ -10,14 +10,14 @@ class ConsumerTokenAuthentication(JSONWebTokenAuthentication): """ 返回登陆消费者 """ - username = payload['username'] + id = payload['user_id'] - if not username: + if not id: msg = _('签名有误.') raise exceptions.AuthenticationFailed(msg) try: - consumer = Consumer.objects.get(username=username) + consumer = Consumer.objects.get(id=id) except Consumer.DoesNotExist: msg = _('消费者不存在') raise exceptions.AuthenticationFailed(msg) diff --git a/test_server/crm/migrations/0008_auto_20200322_2113.py b/test_server/crm/migrations/0008_auto_20200322_2113.py new file mode 100644 index 0000000..bbba513 --- /dev/null +++ b/test_server/crm/migrations/0008_auto_20200322_2113.py @@ -0,0 +1,33 @@ +# Generated by Django 3.0.4 on 2020-03-22 13:13 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('crm', '0007_auto_20200320_1726'), + ] + + operations = [ + migrations.CreateModel( + name='SendCode', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_delete', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('phone', models.CharField(max_length=11, verbose_name='发送号码')), + ('code', models.CharField(max_length=4, verbose_name='验证码')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AlterField( + model_name='consumer', + name='username', + field=models.CharField(blank=True, max_length=11, null=True, unique=True, verbose_name='手机号码'), + ), + ] diff --git a/test_server/crm/models.py b/test_server/crm/models.py index 1fa0aa2..93e611e 100644 --- a/test_server/crm/models.py +++ b/test_server/crm/models.py @@ -5,34 +5,34 @@ from question.models import Questioncat # Create your models here. class Company(SoftCommonModel): - """ + ''' 客户企业 - """ - name = models.CharField(max_length=60, verbose_name="名称", unique=True) - pid = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="父") + ''' + name = models.CharField(max_length=60, verbose_name='名称', unique=True) + pid = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='父') class Meta: - verbose_name = "客户企业" + verbose_name = '客户企业' verbose_name_plural = verbose_name def __str__(self): return self.name class Consumer(SoftCommonModel): - """ + ''' 学员 - """ - name = models.CharField(max_length=200, verbose_name="姓名") - username = models.CharField(max_length=11, default="", verbose_name="手机号码/邮箱", unique=True) - company = models.ForeignKey("Company", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="所属单位") - openid = models.CharField(max_length=200, verbose_name="openid", null=True, blank=True, unique=True) - avatar = models.CharField(default="/media/default/avatar.png",max_length=1000, null=True, blank=True, verbose_name="头像") - nickname = models.CharField(max_length=200, verbose_name="昵称", null=True, blank=True) - subjects = models.ManyToManyField(Questioncat, verbose_name="付费学科", through="PaySubject") + ''' + name = models.CharField(max_length=200, verbose_name='姓名') + username = models.CharField(max_length=11, verbose_name='手机号码', unique=True, null=True, blank=True) + company = models.ForeignKey('Company', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='所属单位') + openid = models.CharField(max_length=200, verbose_name='openid', null=True, blank=True, unique=True) + avatar = models.CharField(default='/media/default/avatar.png',max_length=1000, null=True, blank=True, verbose_name='头像') + nickname = models.CharField(max_length=200, verbose_name='昵称', null=True, blank=True) + subjects = models.ManyToManyField(Questioncat, verbose_name='付费学科', through='PaySubject') class Meta: - verbose_name = "客户" + verbose_name = '客户' verbose_name_plural = verbose_name def __str__(self): @@ -43,4 +43,11 @@ class PaySubject(CommonModel): 付费学科关联表 ''' consumer = models.ForeignKey(Consumer, on_delete=models.CASCADE) - subject = models.ForeignKey(Questioncat, on_delete=models.CASCADE) \ No newline at end of file + subject = models.ForeignKey(Questioncat, on_delete=models.CASCADE) + +class SendCode(CommonModel): + ''' + 验证码发送记录 + ''' + phone = models.CharField(max_length=11, verbose_name='发送号码') + code = models.CharField(max_length=4, verbose_name= '验证码') \ No newline at end of file diff --git a/test_server/crm/serializers.py b/test_server/crm/serializers.py index d439e61..f9a874b 100644 --- a/test_server/crm/serializers.py +++ b/test_server/crm/serializers.py @@ -20,18 +20,7 @@ class ConsumerSerializer(serializers.ModelSerializer): create_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True) update_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True) company_name = serializers.StringRelatedField(source='company') - - class Meta: - model = Consumer - fields = '__all__' - depth = 1 - -class ConsumerCUSerializer(serializers.ModelSerializer): - """ - 客户新增编辑序列化 - """ - create_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True) - update_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True) + subjects_name = serializers.StringRelatedField(source='subjects', many=True) class Meta: model = Consumer diff --git a/test_server/crm/urls.py b/test_server/crm/urls.py index c59ac8f..e61718d 100644 --- a/test_server/crm/urls.py +++ b/test_server/crm/urls.py @@ -1,5 +1,5 @@ from django.urls import path,include -from .views import CompanyViewSet, ConsumerViewSet, ConsumerMPLoginView +from .views import CompanyViewSet, ConsumerViewSet, ConsumerMPLoginView, ConsumerRegister from rest_framework import routers @@ -9,5 +9,6 @@ router.register('company', CompanyViewSet, basename="company") urlpatterns = [ path('consumer/mplogin/', ConsumerMPLoginView.as_view()), + path('consumer/register/', ConsumerRegister.as_view()), path('', include(router.urls)), ] diff --git a/test_server/crm/views.py b/test_server/crm/views.py index 8ebf927..7d5330a 100644 --- a/test_server/crm/views.py +++ b/test_server/crm/views.py @@ -9,18 +9,48 @@ from rest_framework import status from django_filters.rest_framework import DjangoFilterBackend from openpyxl import Workbook, load_workbook import requests -from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler +from rest_framework_jwt.serializers import jwt_encode_handler import json +import random +from rest_framework_jwt.settings import api_settings +from calendar import timegm +from datetime import datetime +import warnings + + from utils.custom import CommonPagination from rbac.permission import RbacPermission -from .models import Company, Consumer, PaySubject -from .serializers import CompanySerializer, ConsumerSerializer, ConsumerCUSerializer +from crm.authentication import ConsumerTokenAuthentication +from .models import Company, Consumer, PaySubject, SendCode +from .serializers import CompanySerializer, ConsumerSerializer from server import settings from question.models import Questioncat +from crm.zhenzismsclient import ZhenziSmsClient appid = 'wx5c39b569f01c27db' secret = '68762892f8df2b4a0b1940c5250a8dc0' +sms_appid = '104951' +sms_appsecret = '3d0ccaf9-f680-47e3-ad93-9e83093c5a04' +sms_url = 'https://sms_developer.zhenzikj.com' + +def jwt_payload_handler(user): + payload = { + 'user_id': user.pk, + 'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA + } + if api_settings.JWT_ALLOW_REFRESH: + payload['orig_iat'] = timegm( + datetime.utcnow().utctimetuple() + ) + + if api_settings.JWT_AUDIENCE is not None: + payload['aud'] = api_settings.JWT_AUDIENCE + + if api_settings.JWT_ISSUER is not None: + payload['iss'] = api_settings.JWT_ISSUER + + return payload class CompanyViewSet(ModelViewSet): """ @@ -69,23 +99,34 @@ class ConsumerViewSet(ModelViewSet): serializer_class = ConsumerSerializer pagination_class = CommonPagination ordering_fields = ('id',) - ordering = ['id'] + ordering = ['company'] filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter] filterset_fields = ('company',) search_fields = ('^name',) - - def get_serializer_class(self): - if self.action == 'list': - return ConsumerSerializer - else: - return ConsumerCUSerializer - def destroy(self, request, *args, **kwargs): #逻辑删除 - instance = self.get_object() - # self.perform_destroy(instance) - instance.is_delete = True - instance.save() - return Response(status=status.HTTP_204_NO_CONTENT) + @action(methods=['get'], detail=False, permission_classes=[], authentication_classes=[ConsumerTokenAuthentication], + url_path='subjectpaid', url_name='subject_paid') + def has_paid(self, request): + """ + 当前登陆消费者已付费的学科 + """ + queryset = PaySubject.objects.filter(consumer = request.user) + data = queryset.values_list('subject__id',flat=True) + return Response(data) + + @action(methods=['get'], detail=False, permission_classes=[], authentication_classes=[], + url_path='sendcode', url_name='code_send') + def sendcode(self, request): + client = ZhenziSmsClient(sms_url, sms_appid, sms_appsecret) + code = random.randint(1000,9999) + phone = request.query_params.get('phone') + params = {'message':'您的验证码为:' + str(code) +',5分钟内有效', 'number': phone} + result = json.loads(client.send(params)) + if result['code'] == 0: + SendCode.objects.create(phone=phone, code=code) + return Response(status=status.HTTP_200_OK) + else: + return Response({'error':result['data']}) @action(methods=['post'], detail=False, permission_classes=[IsAuthenticated], url_path='import', url_name='import_consumer') @@ -155,11 +196,8 @@ class ConsumerMPLoginView(APIView): info = json.loads(info) openid = info['openid'] session_key = info['session_key'] - try: - consumer = Consumer.objects.get(openid = openid) - serializer = ConsumerSerializer(instance=consumer) - except: - return Response("匿名用户",status=status.HTTP_401_UNAUTHORIZED) + consumer = Consumer.objects.get_or_create(openid = openid)[0] + serializer = ConsumerSerializer(instance=consumer) payload = jwt_payload_handler(consumer) token = jwt_encode_handler(payload) return Response({"token":token,"session_key":session_key, "openid":openid, "userinfo":serializer.data}) @@ -168,4 +206,28 @@ class ConsumerLogoutView(APIView): authentication_classes = () permission_classes = () def get(self, request, *args, **kwargs): - return Response(status=status.HTTP_200_OK) \ No newline at end of file + return Response(status=status.HTTP_200_OK) + +class ConsumerRegister(APIView): + ''' + 验证码登陆和注册 + ''' + authentication_classes = [ConsumerTokenAuthentication] + permission_classes = [] + def post(self, request, *args, **kwargs): + data = request.data + phone = data.get('phone', None) + code = data.get('code', None) + if phone and code: + obj = SendCode.objects.filter(phone=phone).last() + if code == obj.code: # 验证通过 + consumer_queryset = Consumer.objects.filter(username=phone) + if consumer_queryset.exists(): # 是否存在 + consumer = consumer_queryset.first() + openid = request.user.openid + request.user.delete(soft=False) # 彻底删除 + consumer.openid = openid + consumer.save() + return Response(status=status.HTTP_200_OK) + else: + return Response({'error':'验证码错误!'}) \ No newline at end of file diff --git a/test_server/crm/zhenzismsclient.py b/test_server/crm/zhenzismsclient.py new file mode 100644 index 0000000..32d1711 --- /dev/null +++ b/test_server/crm/zhenzismsclient.py @@ -0,0 +1,39 @@ +import requests +from requests.packages.urllib3.exceptions import InsecureRequestWarning + +class ZhenziSmsClient(object): + def __init__(self, apiUrl, appId, appSecret): + self.apiUrl = apiUrl + self.appId = appId + self.appSecret = appSecret + + def send(self, params): + data = params; + data['appId'] = self.appId; + data['appSecret'] = self.appSecret; + requests.packages.urllib3.disable_warnings(InsecureRequestWarning); + response = requests.post(self.apiUrl+'/sms/send.do', data=data, verify=False); + result = str(response.content,'utf-8'); + return result; + + + def balance(self): + data = { + 'appId': self.appId, + 'appSecret': self.appSecret + } + requests.packages.urllib3.disable_warnings(InsecureRequestWarning); + response = requests.post(self.apiUrl+'/account/balance.do', data=data, verify=False); + result = str(response.content,'utf-8'); + return result; + + def findSmsByMessageId(self, messageId): + data = { + 'appId': self.appId, + 'appSecret': self.appSecret, + 'messageId': messageId + } + requests.packages.urllib3.disable_warnings(InsecureRequestWarning); + response = requests.post(self.apiUrl+'/smslog/findSmsByMessageId.do', data=data, verify=False); + result = str(response.content,'utf-8'); + return result; diff --git a/test_server/question/views.py b/test_server/question/views.py index b0d3778..804165f 100644 --- a/test_server/question/views.py +++ b/test_server/question/views.py @@ -16,6 +16,7 @@ from .models import Questioncat, Question from .serializers import QuestioncatSerializer, QuestionSerializer, SubjectSerializer from server import settings from crm.authentication import ConsumerTokenAuthentication +from crm.models import PaySubject class SubjectViewSet(ModelViewSet): @@ -54,6 +55,8 @@ class SubjectViewSet(ModelViewSet): if self.request.method == 'GET': self.permission_classes = [] return [permission() for permission in self.permission_classes] + + class QuestioncatViewSet(ModelViewSet): """ diff --git a/test_server/rbac/models.py b/test_server/rbac/models.py index 5acf02a..91217a3 100644 --- a/test_server/rbac/models.py +++ b/test_server/rbac/models.py @@ -3,17 +3,35 @@ from django.contrib.auth.models import AbstractUser import django.utils.timezone as timezone from django.db.models.query import QuerySet -class SoftDeleteQuerySet(QuerySet): +# 自定义软删除查询基类 +class SoftDeletableQuerySetMixin(object): + """ + QuerySet for SoftDeletableModel. Instead of removing instance sets + its ``is_deleted`` field to True. + """ + def delete(self): + """ + Soft delete objects from queryset (set their ``is_deleted`` + field to True) + """ self.update(is_delete=True) -class SoftDeletManager(models.Manager): - ''' - 仅返回删除的实例 - ''' + +class SoftDeletableQuerySet(SoftDeletableQuerySetMixin, QuerySet): + pass + + +class SoftDeletableManagerMixin(object): + """ + Manager that limits the queryset by default to show only not deleted + instances of model. + """ + _queryset_class = SoftDeletableQuerySet + def get_queryset(self): """ - 在这里处理一下QuerySet, 然后返回没被标记位is_delete的QuerySet + Return queryset limited to not deleted entries. """ kwargs = {'model': self.model, 'using': self._db} if hasattr(self, '_hints'): @@ -21,6 +39,10 @@ class SoftDeletManager(models.Manager): return self._queryset_class(**kwargs).filter(is_delete=False) + +class SoftDeletableManager(SoftDeletableManagerMixin, models.Manager): + pass + class SoftCommonModel(models.Model): create_time = models.DateTimeField(default=timezone.now, verbose_name='创建时间', help_text='创建时间') update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间', help_text='修改时间') @@ -29,7 +51,7 @@ class SoftCommonModel(models.Model): class Meta: abstract = True - objects = SoftDeletManager() + objects = SoftDeletableManager() def delete(self, using=None, soft=True, *args, **kwargs): """ @@ -39,6 +61,7 @@ class SoftCommonModel(models.Model): self.is_delete = True self.save(using=using) else: + return super(SoftCommonModel, self).delete(using=using, *args, **kwargs) class CommonModel(models.Model):