lyh 1 rok temu
rodzic
commit
fc6cfa51e2

+ 97 - 0
apps/customer/models.py

@@ -0,0 +1,97 @@
+# coding=utf-8
+
+import requests
+from django.db import transaction
+from django.db import models
+from django.utils import timezone
+from django.conf import settings
+
+from apps.images.models import Images
+from apps.account.models import User
+
+from utils.wx.wechat import WeChat
+from utils.wx.WXBizDataCrypt import WXBizDataCrypt
+from utils.exceptions import CustomError
+from apps.foundation.models import Config
+
+
+class Customer(models.Model):
+    name = models.CharField(max_length=100, verbose_name=u"姓名")
+    tel = models.CharField(max_length=50, verbose_name=u'电话')
+    gender = models.PositiveSmallIntegerField(choices=settings.GENDER_CHOICES, verbose_name=u'性别', null=True)
+    face = models.ForeignKey(Images, verbose_name=u'头像', on_delete=models.PROTECT, null=True)
+
+    class Meta:
+        db_table = "customer"
+        verbose_name = u"客户管理"
+        ordering = ['-id']
+        index_together = (
+            'name',
+            'tel',
+        )
+        default_permissions = ()
+
+    def setInfo(self, nickName, gender, avatarUrl):
+        self.name = nickName
+        if gender == 1:
+            self.gender = settings.MALE
+        elif gender == 2:
+            self.gender = settings.FEMALE
+        else:
+            self.gender = settings.UNKNOW
+        if self.face == None and avatarUrl != None:
+            self.face = Images.downLoadFace(self, avatarUrl)
+        self.save()
+
+
+class CustomerWechat(models.Model):
+    customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT, editable=False, null=True)
+    openid = models.CharField(max_length=512, verbose_name=u"openid")
+    session_key = models.CharField(max_length=512, verbose_name=u'session_key',null=True)
+
+    class Meta:
+        db_table = 'customer_wechat'
+        verbose_name = u'微信客户'
+        unique_together = [
+            ('openid')
+        ]
+        default_permissions = ()
+
+    @staticmethod
+    def login(code, appid):
+        secret = Config.getConfigValue(Config.KEY_WECHAT_SESSION_KEY)
+        res = WeChat.code2Session(appid, secret, code)
+        instance = CustomerWechat.objects.filter(openid=res['openid']).first()
+        if not instance:
+            instance = CustomerWechat.objects.create(
+                openid=res['openid'],
+                session_key=res['session_key']
+            )
+        else:
+            instance.session_key = res['session_key']
+            instance.save()
+        return instance
+
+    @staticmethod
+    def bindWechat(appid, openid, phoneEncryptedData, phoneIv):
+        customer_wechat = CustomerWechat.objects.filter(openid=openid).first()
+        if not customer_wechat:
+            raise CustomError(u'未找到相应的微信客户!')
+
+        pc = WXBizDataCrypt(appid, customer_wechat.session_key)
+        phon_data = pc.decrypt(phoneEncryptedData, phoneIv)
+
+        tel = phon_data['purePhoneNumber']
+
+        if customer_wechat.customer:
+            if customer_wechat.customer.user.username != tel:
+                raise CustomError(u'微信绑定的手机号与系统记录的不符!')
+            else:
+                return customer_wechat.customer
+
+        customer = Customer.objects.filter(tel=tel).first()
+        if not customer:
+            Customer.objects.create(tel=tel, name=tel)
+        customer_wechat.customer = customer
+        customer_wechat.save()
+        return customer

+ 1 - 1
apps/foundation/views.py

@@ -93,6 +93,6 @@ class ConfigViewSet(CustomModelViewSet):
                         config.value = item['value']
                         config.save()
                     else:
-                        config = Config.objects.create(property=item['key'], value=item['value'])
+                        Config.objects.create(property=item['key'], value=item['value'])
             tenant_log(self.request.user, BizLog.INSERT, u'修改系统设置', data)
         return response_ok()

+ 23 - 0
apps/images/models.py

@@ -78,6 +78,7 @@ usedvehicle_thumbnail_file = "usedvehicle/"
 product_file = "product/file/"
 product_cover = "product/"
 activity_cover = "activity/"
+customer_face_file = 'customer/face/'
 
 class Images(models.Model):
     USEDVEHICLE_FILE = 1
@@ -85,12 +86,14 @@ class Images(models.Model):
     PRODUCT_COVER = 3
     PRODUCT_FILE = 4
     ACTIVITY_COVER = 5
+    CUSTOMER_FACE = 6
     TYPE_CHOICES = (
         (USEDVEHICLE_FILE, u'二手车图片'),
         (USEDVEHICLE_THUMBNAIL, u'二手车缩略图'),
         (PRODUCT_COVER, u'商品封面图'),
         (PRODUCT_FILE, u'商品图片'),
         (ACTIVITY_COVER, u'活动封面图'),
+        (CUSTOMER_FACE, u'客户头像'),
     )
 
     user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=u'操作人', on_delete=models.PROTECT)
@@ -121,3 +124,23 @@ class Images(models.Model):
     def get_path(self):
         return '%s%s%s' % (settings.SERVER_DOMAIN, settings.MEDIA_URL, self.picture)
 
+    @staticmethod
+    def downLoadFace(customer, url):
+        save_path = customer_face_file + str(customer.user.id) + '/'
+        filename = DownloadFace(url, save_path, 'jpg')
+        name = filename.split('/')[-1]
+        fullname = "%s/%s" % (settings.MEDIA_ROOT, filename)
+        width = None
+        height = None
+        try:
+            img = Image.open(fullname)
+            width, height = img.size
+        except:
+            pass
+        instance = Images.objects.create(
+            user=customer.user, type=Images.CUSTOMER_FACE, name=name, picture=filename,
+            width=width, height=height, create_time=timezone.now()
+        )
+        instance.save()
+        return instance
+

+ 0 - 0
apps/store/__init__.py


+ 43 - 0
apps/store/models.py

@@ -0,0 +1,43 @@
+# coding=utf-8
+
+from django.db import models
+
+from utils.exceptions import CustomError
+
+from apps.images.models import Images
+
+
+class Shop(models.Model):
+    name = models.CharField(max_length=100, verbose_name=u"名称")
+    addr = models.CharField(max_length=1000, verbose_name=u'地址')
+    tel = models.CharField(max_length=50, verbose_name=u'电话')
+    longitude = models.FloatField(verbose_name=u"经度")
+    latitude = models.FloatField(verbose_name=u"纬度")
+    img = models.ForeignKey(Images, verbose_name=u'图片', on_delete=models.PROTECT, null=True)
+    sort = models.PositiveSmallIntegerField(verbose_name=u'排序', help_text=u'越小越靠前', default=0)
+    enabled = models.BooleanField(verbose_name=u"在用", default=True)
+    is_xgj = models.BooleanField(verbose_name=u'销管佳公司', default=False, editable=False)
+    xgj_id = models.IntegerField(verbose_name=u'销管佳id', null=True)
+    delete = models.BooleanField(verbose_name=u'删除', default=False, editable=False)
+
+    class Meta:
+        db_table = "shop"
+        verbose_name = u"门店管理"
+        ordering = ['sort', '-id']
+        index_together = (
+            'name',
+            'tel',
+        )
+        default_permissions = ()
+
+    @staticmethod
+    def getById(id):
+        try:
+            id = int(id)
+        except:
+            raise CustomError(u'无效的门店ID')
+
+        instance = Shop.objects.filter(pk=id).first()
+        if not instance:
+            raise CustomError(u'未找到相应的门店信息')
+        return instance

+ 2 - 1
shop/settings.py

@@ -50,7 +50,8 @@ INSTALLED_APPS = [
     'apps.vehicle',
     'apps.product',
     'apps.activity',
-    # 'apps.employee',
+    'apps.customer',
+    'apps.store',
     # 'apps.option',
     # 'apps.package',
     # 'apps.package_order',

+ 218 - 0
uis/views/store/edit.html

@@ -0,0 +1,218 @@
+<!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"/>
+  <script type="text/javascript" src="https://3gimg.qq.com/lightmap/components/geolocation/geolocation.min.js"></script>
+</head>
+<body>
+
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-card-body" pad15>
+            <form class="layui-form" action="" lay-filter="component-form-element">
+                <div class="layui-row layui-col-space10 layui-form-item">
+                    <div style="overflow-y: scroll;">
+                        <div style="width: 40%; height: 100%; float:left;">
+                            <div class="layui-form-item">
+                                <label class="layui-form-label"><font color='red' size="4">*</font>名称:</label>
+                                <div class="layui-input-block">
+                                    <input type="text" name="name" lay-verify="required" placeholder="请输入名称" autocomplete="off" class="layui-input">
+                                </div>
+                            </div>
+                            <div class="layui-form-item">
+                                <label class="layui-form-label"><font color='red' size="4">*</font>地址:</label>
+                                <div class="layui-input-block">
+                                    <input type="text" name="addr" placeholder="请输入地址" lay-verify="required" autocomplete="off" class="layui-input">
+                                </div>
+                            </div>
+                            <div class="layui-form-item">
+                                <label class="layui-form-label"><font color='red' size="4">*</font>电话:</label>
+                                <div class="layui-input-block">
+                                    <input type="text" name="tel" placeholder="请输入电话" lay-verify="required" autocomplete="off" class="layui-input">
+                                </div>
+                            </div>
+                            <div>
+                              <label class="layui-form-label">排序:</label>
+                              <div class="layui-input-block">
+                                <input type="text" name="sort" placeholder="请输入排序" lay-verify="numberGez"  autocomplete="off" class="layui-input">
+                              </div>
+                            </div>
+                            <div class="layui-form-item">
+                                <label class="layui-form-label">经度坐标:</label>
+                                <span id="show_lng"></span>
+                            </div>
+                            <div class="layui-form-item">
+                                <label class="layui-form-label">纬度坐标:</label>
+                                <span id="show_lat"></span>
+                            </div>
+                            <div class="layui-form-item">
+                                <label class="layui-form-label">在用:</label>
+                                <div class="layui-input-block">
+                                    <input type="checkbox" name="enabled" lay-skin="switch" lay-text="是|否" checked="" value="1">
+                                </div>
+                            </div >
+                            <div class="layui-form-item">
+                                <label class="layui-form-label">门店展示:</label>
+                                <div class="layui-input-block">
+                                    <button type="button" class="layui-btn-sm" id="test1">上传图片</button><br><br>
+                                </div>
+                            </div>
+                            <div class="layui-form-item">
+                                <img class="layui-upload-img" id="demo1" style="max-width: 70%;height: 150px;margin-left: 25%;">
+                            </div>
+                        </div>
+                        <div style="width: 55%; height: 100%; float:left; margin-left: 10px;">
+                            <div style="height: 500px;">
+                                <iframe id="markPage" frameborder="0" scrolling="no" width="100%" height="100%"></iframe>
+                            </div>
+                        </div>
+                        <button id="id_save" class="layui-btn" lay-submit lay-filter="component-form-element" style="display: none">保存</button>
+                        <button class="layui-btn" type="button" id="upload_image" style="display: none"></button>
+                    </div>
+                </div>
+            </form>
+        </div>
+    </div>
+</div>
+
+
+  <script src="../../layuiadmin/layui/layui.js"></script>
+  <script>
+  layui.config({
+    base: '../../../layuiadmin/' //静态资源所在路径
+  }).extend({
+    index: 'lib/index',
+    formSelects: 'formSelects-v4'
+  }).use(['index', 'form', 'utils', 'upload'], function(){
+    var $ = layui.$
+    ,admin = layui.admin
+    ,upload = layui.upload
+    ,form = layui.form;
+    var id = layui.view.getParameterByName('id');
+    var longitude = null;
+    var latitude = null;
+
+    window.addEventListener('message', function (e) {
+        var loc = e.data;
+        if (loc && loc.module == 'locationPicker') {
+            longitude = loc.latlng.lng;
+            latitude = loc.latlng.lat;
+            $('#show_lng').html(longitude);
+            $('#show_lat').html(latitude);
+        }
+    }, false);
+    if(id){
+        var editdata = JSON.parse(JSON.stringify(parent.layui.table.editdata)); // 框架有Bug所以这么转换
+        if (editdata.longitude && editdata.latitude) {
+            longitude = editdata.longitude;
+            latitude = editdata.latitude;
+            $('#show_lng').html(longitude);
+            $('#show_lat').html(latitude);
+            reloadMap(latitude, longitude);
+        } else {
+            var markurl = 'https://apis.map.qq.com/tools/locpicker?search=1&type=1&key=6NVBZ-YA43F-UHLJY-JS3WK-26HQH-7ZBLM&referer=myapp';
+            $('#markPage').attr('src',markurl);
+        }
+        if(editdata.img_url){
+            $('#demo1').attr('src', editdata.img_url);
+        }
+        form.val("component-form-element", editdata);
+    }else{
+        var markurl = 'https://apis.map.qq.com/tools/locpicker?search=1&type=1&key=6NVBZ-YA43F-UHLJY-JS3WK-26HQH-7ZBLM&referer=myapp';
+        $('#markPage').attr('src',markurl);
+    }
+
+    function reloadMap(lat, lng) {
+        var markurl = 'https://apis.map.qq.com/tools/locpicker?search=1&type=1&key=6NVBZ-YA43F-UHLJY-JS3WK-26HQH-7ZBLM&referer=myapp&coord=' + lat + ',' + lng;
+        $('#markPage').attr('src',markurl);
+    }
+
+    var form_data = {field:{}};
+
+    if (id){
+          var url = '/tenant/shop/'+id + '/update_shop/';
+      }else{
+          url =  '/tenant/shop/';
+      }
+
+     upload.render({
+         elem: '#test1',
+         url: url,
+         auto: false,
+         field: 'image',
+         bindAction: '#upload_image',
+         choose: function(obj) {
+             obj.preview(
+                 function(index, file, result) {
+                     $('#demo1').attr('src', result);
+                 }
+             );
+         },
+          data:{
+             name: function(){return form_data.field.name;},
+             addr: function(){return form_data.field.addr;},
+             tel: function(){return form_data.field.tel;},
+             latitude: function(){return form_data.field.latitude;},
+             longitude: function(){return form_data.field.longitude;},
+             enabled: function(){
+                 if (form_data.field.enabled){
+                     return form_data.field.enabled;
+                 }else{
+                     return '0';
+                 }
+             }
+             },
+        done: function (res) {
+            if (res.code != 0) {
+                layer.msg(res.msg);
+            }else {
+                parent.layui.onSubmitChild(res.data);
+            }
+        },
+        error: function () {
+            layer.msg('保存失败');
+        }
+    });
+
+    form.on('submit(component-form-element)', function(data){
+      //layer.msg(JSON.stringify(data.field));
+
+        if (!latitude || !longitude) {
+            layer.msg('请选择门店位置');
+            return false;
+        }
+
+        data.field['latitude'] = latitude;
+        data.field['longitude'] = longitude;
+
+        if (data.field.image){
+            form_data = data;
+            $('#upload_image').click();
+        }else{
+            admin.req({
+                url: url
+                ,data: data.field
+                ,type: 'post'
+                ,done: function(res){
+                    parent.layui.onSubmitChild(res.data);
+                }
+              });
+        }
+
+      return false;
+    });
+
+    parent.layui.submitChild = function () {
+      $("#id_save").click();
+    };
+  });
+  </script>
+</body>
+</html>

+ 162 - 0
uis/views/store/index.html

@@ -0,0 +1,162 @@
+<!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;">
+                <div class="layui-col-xs2">
+                    <button class="layui-btn" id="btn_add" data-permission="shop.add_shop"><i class="layui-icon layui-icon-add-circle"></i>添加</button>
+                </div>
+                <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 id="id_search_tel" type="text"  name="tel" autocomplete="off" class="layui-input" placeholder="电话"/>
+                    </div>
+                    <div class="seach_items">
+                        <input id="id_search_name" type="text"  name="name" autocomplete="off" class="layui-input" placeholder="名称"/>
+                    </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="edit" data-permission="shop.edit_shop">修改</a>
+                    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del" data-permission="shop.delete_shop">删除</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', 'upload'], function(){
+    var $ = layui.$
+            ,table = layui.table
+            ,form = layui.form;
+    table.render({
+      elem: '#datagrid'
+      ,url: '/store/'
+      ,cols: [[
+        {field:'name', title:'名称',width: 200}
+       ,{field:'tel', title:'电话',width: 200}
+       ,{field:'addr', title:'地址',width: 200}
+       ,{field:'enabled_text', title:'在用',width: 80}
+       ,{field:'sort', title:'排序', width:80}
+        ,{width:120, align:'center', fixed: 'right', toolbar: '#datagrid-operate-bar'}
+      ]]
+      , done: function () {
+        layui.index.removeNoPermButtons()
+      }
+      ,page: true
+      ,height: 'full-108'
+    });
+    var _params;
+    form.on('submit(query-form-element)', function(data){
+      //layer.msg(JSON.stringify(data.field));
+      _params = 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;
+        if(obj.event === 'edit'){
+        table.editdata = data;
+        layer.open({
+          type: 2,
+          title: '修改',
+          shadeClose: false,
+          area: ['90%', '500px'],
+          btn: ['保存', '取消'],
+          yes: function (index, dom) {
+            layui.onSubmitChild = function (data) {
+                layer.close(index);
+                table.reload('datagrid', {});
+              };
+              layui.submitChild();
+          },
+          btn2: function(index, layero){
+            layer.close(index);//关闭当前按钮
+          },
+          content: 'edit.html?id='+data.id
+        });
+      } else if(obj.event === 'del'){
+         layer.confirm('确定要删除吗?', function(index){
+                layer.close(index);
+                layui.admin.req({
+                    notice: true
+                    ,url: '/shop/'+data.id + '/'
+                    ,type: 'delete'
+                    ,done: function(res){
+                        table.reload('datagrid',{});
+                    }
+                });
+            });
+      }
+    });
+
+    $('#btn_add').on('click', function(){
+        layer.open({
+          type: 2,
+          title: '添加',
+          shadeClose: false,
+          area: ['90%', '500px'],
+          btn: ['保存', '取消'],
+          yes: function (index, dom) {
+            layui.onSubmitChild = function (data) {
+                layer.close(index);
+                table.reload('datagrid', {});
+              };
+              layui.submitChild();
+          },
+          btn2: function(index, layero){
+            layer.close(index);//关闭当前按钮
+          },
+          content: 'edit.html'
+        });
+    });
+  });
+  </script>
+</body>
+</html>
+