瀏覽代碼

试驾预约

lyh 1 年之前
父節點
當前提交
2017d9656e

+ 7 - 1
apps/images/models.py

@@ -63,6 +63,8 @@ class ImagesManager(models.Manager):
             Images.CUSTOMER_FACE: customer_face_file,
             Images.SHOP_FILE: shop_file,
             Images.VEHICLE_LICENSE: vehicle_license,
+            Images.DRIVE_LICENSE_FRONT: vehicle_license,
+            Images.DRIVE_LICENSE_BACK: vehicle_license,
         }
 
         return path_map[type] + str(user_id) + '/'
@@ -98,7 +100,9 @@ class Images(models.Model):
     VEHICLE_MODEL_THUMBNAIL = 7
     CUSTOMER_FACE = 8
     SHOP_FILE = 9
-    VEHICLE_LICENSE = 9
+    VEHICLE_LICENSE = 10
+    DRIVE_LICENSE_FRONT = 11
+    DRIVE_LICENSE_BACK = 12
     TYPE_CHOICES = (
         (USEDVEHICLE_FILE, u'二手车图片'),
         (USEDVEHICLE_THUMBNAIL, u'二手车缩略图'),
@@ -110,6 +114,8 @@ class Images(models.Model):
         (CUSTOMER_FACE, u'客户头像'),
         (SHOP_FILE, u'门店图片'),
         (VEHICLE_LICENSE, u'行驶证'),
+        (DRIVE_LICENSE_FRONT, u'驾驶证正面'),
+        (DRIVE_LICENSE_BACK, u'驾驶证反面'),
     )
 
     user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=u'操作人', on_delete=models.PROTECT)

+ 4 - 0
apps/product_order/views.py

@@ -6,6 +6,8 @@ from rest_framework.decorators import action
 
 from utils import response_ok
 from utils.custom_modelviewset import CustomModelViewSet
+from apps.foundation.models import BizLog
+from apps.account import tenant_log
 
 from .filters import *
 from .serializers import *
@@ -30,4 +32,6 @@ class ProductOrderViewSet(CustomModelViewSet):
                 raise CustomError(u'订单已完成!')
             order.status = ProductOrder.FINISHED
             order.save()
+            tenant_log(self.request.user, BizLog.UPDATE,
+                       u'修改商品订单状态[%s],id=%d' % (ProductOrder.STATUS_CHOICES[order.status - 1][1], order.id))
         return response_ok()

+ 1 - 1
apps/store/urls.py

@@ -6,7 +6,7 @@ from rest_framework.routers import SimpleRouter
 from .views import *
 
 urlpatterns = [
-
+    url(r'search/$', ShopSearchSearch.as_view()),
 ]
 
 router = SimpleRouter()

+ 22 - 0
apps/store/views.py

@@ -16,6 +16,7 @@ from apps.vehicle.models import Brand
 from apps.store.filters import ShopFilter
 from .serializers import ShopSerializer
 from hashlib import md5
+from rest_framework.views import APIView
 
 
 class ShopViewSet(CustomModelViewSet):
@@ -124,3 +125,24 @@ class ShopViewSet(CustomModelViewSet):
                 else:
                     raise CustomError(u'请求失败')
         return response_ok()
+
+
+class ShopSearchSearch(APIView):
+    def get(self, request):
+
+        keyword = request.GET.get('keyword')
+        rows = Shop.objects.filter(delete=False, enabled=True)
+
+        if keyword:
+            rows = rows.filter(name__icontains=keyword)
+
+        data = []
+        for row in rows:
+            item ={
+                'value': row.id,
+                'id': row.id,
+                'name': row.name
+            }
+            data.append(item)
+
+        return response_ok(data)

+ 0 - 0
apps/vehicle_order/__init__.py


+ 17 - 0
apps/vehicle_order/filters.py

@@ -0,0 +1,17 @@
+# coding=utf-8
+
+import django_filters
+
+from .models import VhicleDriveReserve
+
+
+class VhicleDriveReserveFilter(django_filters.FilterSet):
+    name = django_filters.CharFilter(field_name='name', lookup_expr='icontains')
+    tel = django_filters.CharFilter(field_name='tel', lookup_expr='icontains')
+    shop = django_filters.CharFilter(field_name='shop')
+    status = django_filters.CharFilter(field_name='status')
+    id = django_filters.CharFilter(field_name='id')
+
+    class Meta:
+        model = VhicleDriveReserve
+        fields = '__all__'

+ 40 - 0
apps/vehicle_order/models.py

@@ -0,0 +1,40 @@
+# coding=utf-8
+
+from django.db import models
+from django.conf import settings
+
+from apps.foundation.models import Option
+from apps.vehicle.models import Model
+from apps.customer.models import Customer
+from apps.store.models import Shop
+from apps.images.models import Images
+
+
+class VhicleDriveReserve(models.Model):
+    WAIT_DRIVE = 1
+    FINISHED = 2
+    REVOKE = 3
+    STATUS_CHOICES = (
+        (WAIT_DRIVE, u'待试驾'),
+        (FINISHED, u'已试驾'),
+        (REVOKE, u'已取消'),
+    )
+    model = models.ForeignKey(Model, verbose_name=u'车型', on_delete=models.PROTECT)
+    shop = models.ForeignKey(Shop, verbose_name=u'门店', on_delete=models.PROTECT)
+    create_time = models.DateTimeField(verbose_name=u"添加时间", auto_now_add=True, editable=False)
+    status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u'状态', default=WAIT_DRIVE)
+    customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT, editable=False)
+    name = models.CharField(max_length=100, verbose_name=u'名称', null=True)
+    tel = models.CharField(max_length=20, verbose_name=u'电话', null=True)
+    date = models.DateField(verbose_name=u'预约日期', null=True)
+    img1 = models.ForeignKey(Images, verbose_name=u'驾驶证正面', on_delete=models.PROTECT,
+                                  related_name=u'vehicle_drive_reserve_front', null=True)
+    img2 = models.ForeignKey(Images, verbose_name=u'驾驶证反面', on_delete=models.PROTECT,
+                                  related_name=u'vehicle_drive_reserve_back', null=True)
+    notes = models.CharField(max_length=500, verbose_name=u'备注', null=True)
+    delete = models.BooleanField(verbose_name=u'删除', default=False, editable=False)
+
+    class Meta:
+        db_table = 'vehicle_drive_reserve'
+        verbose_name = u'试驾预约'
+        default_permissions = ()

+ 39 - 0
apps/vehicle_order/serializers.py

@@ -0,0 +1,39 @@
+# coding=utf-8
+
+from django.conf import settings
+
+from rest_framework import serializers
+
+from utils.exceptions import CustomError
+
+from apps.base import Formater
+from apps.images.models import Images
+
+from .models import VhicleDriveReserve
+
+class VhicleDriveReserveSerializer(serializers.ModelSerializer):
+    shop_name = serializers.CharField(source='shop.name', read_only=True)
+    brand_name = serializers.CharField(source='model.series.brand.name', read_only=True)
+    series_name = serializers.CharField(source='model.series.name', read_only=True)
+    model_name = serializers.CharField(source='model.name', read_only=True)
+    customer_name = serializers.CharField(source='customer.name', read_only=True)
+    status_text = serializers.CharField(source='get_status_display', read_only=True)
+    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', read_only=True)
+    date = serializers.DateField(format='%Y-%m-%d')
+    img1_url = serializers.SerializerMethodField()
+    img2_url = serializers.SerializerMethodField()
+
+    def get_img1_url(self, obj):
+        if obj.img1:
+            return '%s%s' % (settings.MEDIA_URL, obj.img1.picture)
+        return ''
+
+    def get_img2_url(self, obj):
+        if obj.img2:
+            return '%s%s' % (settings.MEDIA_URL, obj.img2.picture)
+        return ''
+
+    class Meta:
+        model = VhicleDriveReserve
+        fields = '__all__'
+

+ 14 - 0
apps/vehicle_order/urls.py

@@ -0,0 +1,14 @@
+# coding=utf-8
+
+from django.conf.urls import url, include
+from rest_framework.routers import SimpleRouter
+
+from .views import *
+
+urlpatterns = [
+
+]
+
+router = SimpleRouter()
+router.register(r'drive_reserve', VhicleDriveReserveViewSet)
+urlpatterns += router.urls

+ 35 - 0
apps/vehicle_order/views.py

@@ -0,0 +1,35 @@
+# coding=utf-8
+
+from django.db import transaction
+
+from rest_framework.decorators import action
+
+from utils import response_ok
+from utils.custom_modelviewset import CustomModelViewSet
+from apps.account import tenant_log
+from apps.foundation.models import BizLog
+
+from .filters import *
+from .serializers import *
+from .models import *
+
+
+class VhicleDriveReserveViewSet(CustomModelViewSet):
+    queryset = VhicleDriveReserve.objects.filter(delete=False)
+    serializer_class = VhicleDriveReserveSerializer
+
+    def filter_queryset(self, queryset):
+        f = VhicleDriveReserveFilter(self.request.GET, queryset=queryset)
+        return f.qs
+
+    @action(methods=['post'], detail=True)
+    def change_status(self, request, pk):
+        order = VhicleDriveReserve.objects.filter(id=pk).first()
+        status = request.GET.get('status')
+        with transaction.atomic():
+            if order.status != VhicleDriveReserve.WAIT_DRIVE:
+                raise CustomError(u'当前状态不允许修改!')
+            order.status = int(status)
+            order.save()
+            tenant_log(self.request.user, BizLog.UPDATE, u'修改试驾单状态[%s],id=%d' % (VhicleDriveReserve.STATUS_CHOICES[order.status-1][1], order.id))
+        return response_ok()

+ 1 - 1
shop/settings.py

@@ -53,7 +53,7 @@ INSTALLED_APPS = [
     'apps.customer',
     'apps.store',
     'apps.product_order',
-    # 'apps.package',
+    'apps.vehicle_order',
     # 'apps.package_order',
     # 'apps.pay',
     # 'apps.poster',

+ 1 - 0
shop/urls.py

@@ -32,6 +32,7 @@ urlpatterns = [
     url(r'^store/', include('apps.store.urls')),
     url(r'^customer/', include('apps.customer.urls')),
     url(r'^product_order/', include('apps.product_order.urls')),
+    url(r'^vehicle_order/', include('apps.vehicle_order.urls')),
     # url(r'^api/', include('apps.api.urls')),
 ]
 

+ 2 - 2
uis/views/index.html

@@ -73,7 +73,7 @@
                   <a lay-href="customer/index.html">询价管理</a>
                 </dd>
                 <dd data-name="button">
-                  <a lay-href="customer/index.html">试驾预约</a>
+                  <a lay-href="vehicle_order/drive_reserve.html">试驾预约</a>
                 </dd>
               </dl>
             </li>
@@ -109,7 +109,7 @@
               </a>
               <dl class="layui-nav-child">
                 <dd data-name="button">
-                  <a lay-href="product_order/index.html">商品销售</a>
+                  <a lay-href="product_order/order.html">商品销售</a>
                 </dd>
               </dl>
             </li>

+ 0 - 0
uis/views/product_order/index.html → uis/views/product_order/order.html


+ 195 - 0
uis/views/vehicle_order/drive_reserve.html

@@ -0,0 +1,195 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>活动管理</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
+  <link rel="stylesheet" href="../../layuiadmin/layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="../../layuiadmin/style/admin.css" media="all">
+  <link rel="stylesheet" type="text/css" href="../../layuiadmin/style/formSelects-v4.css"/>
+    <style type="text/css">
+    .LAY-btns .layui-nav {padding-left:0;padding-right:10px;top:-4px;margin: 0 10px;border: 0;background-color: #009688;}
+    .LAY-btns .layui-nav .layui-nav-item{line-height: 30px;}
+    .LAY-btns .layui-nav .layui-nav-child{top:34px;}
+    .LAY-btns .layui-nav .layui-nav-bar{display: none;}
+    .LAY-btns .layui-nav .layui-nav-child dd.layui-this a{color:#333;background-color:#fff;}
+    .LAY-btns .layui-nav .layui-nav-child dd.layui-this a:hover {background-color: #f2f2f2;color: #000;}
+    .seach_items {float:right;margin-left: 10px;}
+  </style>
+</head>
+<body>
+
+  <div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-card-body" pad15>
+        <div class="layui-row layui-col-space15">
+          <div class="layui-col-md12">
+            <div class="LAY-btns" style="margin-bottom: 10px;">
+
+                <form class="layui-form" lay-filter="query-form-element">
+                    <div class="seach_items">
+                        <button class="layui-btn" lay-submit lay-filter="query-form-element"><i class="layui-icon layui-icon-search"></i>查询</button>
+                    </div>
+                    <div class="seach_items">
+                        <input type="text"  name="tel" autocomplete="off" class="layui-input" placeholder="电话"/>
+                    </div>
+
+                    <div class="seach_items">
+                        <input type="text"  name="name" autocomplete="off" class="layui-input" placeholder="试驾人"/>
+                    </div>
+                    <div class="seach_items">
+                         <select  name="shop" id="seach_shop">
+                            <option value="">门店</option>
+                        </select>
+                    </div>
+                    <div class="seach_items">
+                       <select  name="status">
+                            <option value="">状态</option>
+                            <option value="1">待试驾</option>
+                            <option value="2">已试驾</option>
+                            <option value="3">已取消</option>
+                        </select>
+                    </div>
+
+                </form>
+                <div style="clear: both;"></div>
+            </div>
+            <table class="layui-hide" id="datagrid" lay-filter="datagrid-operate"></table>
+
+            <script type="text/html" id="datagrid-operate-bar">
+                <div class="layui-btn-group">
+                    <a class="layui-btn layui-btn-xs" lay-event="images">驾证</a>
+                    <a class="layui-btn layui-btn-xs" lay-event="finish">完成</a>
+                    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="revoke">取消</a>
+                </div>
+            </script>
+          </div>
+        </div>
+        </div>
+    </div>
+  </div>
+
+  <script src="../../layuiadmin/layui/layui.js?t=1"></script>
+  <script>
+  layui.config({
+    base: '../../../layuiadmin/' //静态资源所在路径
+  }).extend({
+    index: 'lib/index' //主入口模块
+     ,formSelects: 'formSelects-v4'
+  }).use(['index', 'table', 'form', 'formSelects'], function(){
+    var $ = layui.$
+        ,table = layui.table
+        ,admin = layui.admin
+        ,form = layui.form;
+
+    admin.req({
+        url: '/store/search/',
+        done: function (res) {
+            var shops = res.data;
+            var shop_node = $('#seach_shop');
+            for (var i in shops) {
+                var pid = shops[i].id;
+                var value = shops[i].name;
+                shop_node.append("<option value='" + pid + "'>" + value + "</option>");
+            }
+            form.render();
+        }
+    });
+
+    table.render({
+      elem: '#datagrid'
+      ,url: '/vehicle_order/drive_reserve/'
+      ,cols: [[
+        {field:'shop_name', title:'门店',width: 100}
+       ,{field:'status_text', title:'状态',width: 100}
+       ,{field:'customer_name', title:'客户',width: 100}
+       ,{field:'brand_name', title:'品牌',width: 100}
+       ,{field:'series_name', title:'车系',width: 100}
+       ,{field:'model_name', title:'车型',width: 150}
+       ,{field:'name', title:'试驾人',width: 100}
+       ,{field:'tel', title:'电话',width: 120}
+       ,{field:'date', title:'预约日期',width: 150}
+       ,{field:'create_time', title:'创建时间',width: 150}
+       ,{field:'notes', title:'备注',width: 150}
+        ,{width:150, align:'center', fixed: 'right', toolbar: '#datagrid-operate-bar'}
+      ]]
+      ,page: true
+      ,height: 'full-108'
+      , done: function () {
+        layui.index.removeNoPermButtons()
+      }
+    });
+    form.on('submit(query-form-element)', function(data){
+      //layer.msg(JSON.stringify(data.field));
+      table.reload('datagrid', {
+          where: data.field
+          ,page:{curr:1}
+      });
+      layer.closeAll();
+      return false;
+    });
+    //监听工具条
+    table.on('tool(datagrid-operate)', function(obj){
+      var data = obj.data;
+      table.editdata = data;
+        if(obj.event === 'finish'){
+            if (data.status !== 1){
+                 layer.msg('当前状态不允许修改');
+                return;
+            }
+         layer.confirm('确定订单已完成吗?', function(index){
+             layer.close(index);
+            admin.req({
+                url: '/vehicle_order/drive_reserve/'+data.id + '/change_status/?status=2'
+                ,type: 'post'
+                ,done: function(res){
+                    if(res.code === 1){
+                        layer.msg(res.msg);
+                        return;
+                    }
+                    table.reload('datagrid',{});
+                }
+            });
+        });
+      }else if(obj.event === 'revoke'){
+             if (data.status !== 1){
+                 layer.msg('当前状态不允许修改');
+                return;
+            }
+         layer.confirm('确定取消预约单吗?', function(index){
+             layer.close(index);
+            admin.req({
+                url: '/vehicle_order/drive_reserve/'+data.id + '/change_status/?status=3'
+                ,type: 'post'
+                ,done: function(res){
+                    if(res.code === 1){
+                        layer.msg(res.msg);
+                        return;
+                    }
+                    table.reload('datagrid',{});
+                }
+            });
+        });
+        }else if(obj.event === 'images'){
+        layer.open({
+          type: 2,
+          title: '驾驶证',
+          area: ['800px', '500px'],
+          yes: function(index, dom){
+              table.reload('datagrid',{});
+             layer.close(index);
+          },
+          btn2: function(index, layero){
+            layer.close(index);//关闭当前按钮
+          },
+          content: 'drive_reserve_imgs.html?id='+data.id
+        });
+      }
+    });
+  });
+  </script>
+</body>
+</html>
+

+ 77 - 0
uis/views/vehicle_order/drive_reserve_imgs.html

@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>配件出库</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
+  <link rel="stylesheet" href="../../layuiadmin/layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="../../layuiadmin/style/admin.css" media="all">
+</head>
+<body>
+
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-card-body" pad15>
+            <div class="layui-row layui-col-space15">
+                <div class="layui-col-md12">
+                    <form class="layui-form" action="" lay-filter="component-form-element">
+                        <div class="layui-upload">
+                          <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
+                            <div class="layui-upload-list" id="show_image" style="display: flex;flex-wrap: wrap;"></div>
+                         </blockquote>
+                        </div>
+
+                    </form>
+
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+  <script src="../../layuiadmin/layui/layui.js"></script>
+  <script>
+   var main_id = null;
+  layui.link('../../../layuiadmin/style/autocomplete.css');
+  layui.config({
+    base: '../../../layuiadmin/' //静态资源所在路径
+  }).extend({
+    index: 'lib/index',
+    autocomplete: 'autocomplete'
+  }).use(['index','utils', 'form', 'element', 'upload'], function(){
+    var $ = layui.$
+    ,admin = layui.admin
+    ,element = layui.element
+    ,form = layui.form
+    ,upload = layui.upload;
+
+    var id = layui.view.getParameterByName('id');
+    main_id = id;
+
+    form.render(null, 'component-form-element');
+    element.render('breadcrumb', 'breadcrumb');
+    admin.req({
+        url: '/vehicle_order/drive_reserve/?id=' + id,
+        done: function (res) {
+            $('#show_image').html('');
+            var data = res.data[0];
+            if (data.img1_url) {
+                var html1 = '<div style="margin-top: 10px;"><a href="' + data.img1_url + '" target="_blank"><img src="' + data.img1_url + '" class="layui-upload-img" style="margin-left: 5px;min-width: 80px; height: 100px;max-width: 200px;"></a>'+
+                      '<div align="center" style="margin-top: 3px;" >驾驶证正面</div></div>';
+                $('#show_image').append(html1)
+            }
+            if (data.img2_url) {
+                var html2 = '<div style="margin-top: 10px;"><a href="' + data.img2_url + '" target="_blank"><img src="' + data.img2_url + '" class="layui-upload-img" style="margin-left: 5px;min-width: 80px; height: 100px;max-width: 200px;"></a>'+
+                      '<div align="center" style="margin-top: 3px;" >驾驶证反面</div></div>';
+                $('#show_image').append(html2)
+            }
+        }
+    });
+  });
+
+
+  </script>
+</body>
+</html>