diff --git a/customer/__init__.py b/customer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/customer/__pycache__/__init__.cpython-312.pyc b/customer/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..8ca9451 Binary files /dev/null and b/customer/__pycache__/__init__.cpython-312.pyc differ diff --git a/customer/__pycache__/__init__.cpython-39.pyc b/customer/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..dc6de6a Binary files /dev/null and b/customer/__pycache__/__init__.cpython-39.pyc differ diff --git a/customer/__pycache__/admin.cpython-312.pyc b/customer/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000..1ebf869 Binary files /dev/null and b/customer/__pycache__/admin.cpython-312.pyc differ diff --git a/customer/__pycache__/admin.cpython-39.pyc b/customer/__pycache__/admin.cpython-39.pyc new file mode 100644 index 0000000..afc78e0 Binary files /dev/null and b/customer/__pycache__/admin.cpython-39.pyc differ diff --git a/customer/__pycache__/apps.cpython-312.pyc b/customer/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000..e677e2e Binary files /dev/null and b/customer/__pycache__/apps.cpython-312.pyc differ diff --git a/customer/__pycache__/apps.cpython-39.pyc b/customer/__pycache__/apps.cpython-39.pyc new file mode 100644 index 0000000..939e0c2 Binary files /dev/null and b/customer/__pycache__/apps.cpython-39.pyc differ diff --git a/customer/__pycache__/models.cpython-312.pyc b/customer/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000..f39fa64 Binary files /dev/null and b/customer/__pycache__/models.cpython-312.pyc differ diff --git a/customer/__pycache__/models.cpython-39.pyc b/customer/__pycache__/models.cpython-39.pyc new file mode 100644 index 0000000..ec80d01 Binary files /dev/null and b/customer/__pycache__/models.cpython-39.pyc differ diff --git a/customer/__pycache__/urls.cpython-312.pyc b/customer/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000..a834fad Binary files /dev/null and b/customer/__pycache__/urls.cpython-312.pyc differ diff --git a/customer/__pycache__/urls.cpython-39.pyc b/customer/__pycache__/urls.cpython-39.pyc new file mode 100644 index 0000000..13f3fce Binary files /dev/null and b/customer/__pycache__/urls.cpython-39.pyc differ diff --git a/customer/__pycache__/views.cpython-312.pyc b/customer/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000..0effebe Binary files /dev/null and b/customer/__pycache__/views.cpython-312.pyc differ diff --git a/customer/__pycache__/views.cpython-39.pyc b/customer/__pycache__/views.cpython-39.pyc new file mode 100644 index 0000000..6c52c7c Binary files /dev/null and b/customer/__pycache__/views.cpython-39.pyc differ diff --git a/customer/admin.py b/customer/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/customer/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/customer/apps.py b/customer/apps.py new file mode 100644 index 0000000..ac9e398 --- /dev/null +++ b/customer/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CustomerConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'customer' diff --git a/customer/migrations/0001_initial.py b/customer/migrations/0001_initial.py new file mode 100644 index 0000000..5c53755 --- /dev/null +++ b/customer/migrations/0001_initial.py @@ -0,0 +1,139 @@ +# Generated by Django 3.2.9 on 2024-05-29 16:44 + +from django.db import migrations, models +import django.db.models.deletion +import django.db.models.manager + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Customer', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('khno', models.CharField(max_length=20, unique=True)), + ('name', models.CharField(max_length=20)), + ('area', models.CharField(max_length=20)), + ('cusManager', models.CharField(db_column='cus_manager', max_length=30)), + ('level', models.CharField(max_length=30)), + ('myd', models.CharField(max_length=30)), + ('xyd', models.CharField(max_length=30)), + ('address', models.CharField(max_length=100)), + ('postCode', models.CharField(db_column='post_code', max_length=10)), + ('phone', models.CharField(max_length=18)), + ('fax', models.CharField(max_length=20)), + ('website', models.CharField(db_column='web_site', max_length=50)), + ('yyzzzch', models.CharField(max_length=50)), + ('fr', models.CharField(max_length=20)), + ('zczj', models.CharField(max_length=20)), + ('nyye', models.CharField(max_length=20)), + ('khyh', models.CharField(max_length=20)), + ('khzh', models.CharField(max_length=20)), + ('dsdjh', models.CharField(max_length=20)), + ('gsdjh', models.CharField(max_length=20)), + ('state', models.IntegerField(default=0)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ], + options={ + 'db_table': 't_customer', + }, + managers=[ + ('all', django.db.models.manager.Manager()), + ], + ), + migrations.CreateModel( + name='CustomerLoss', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cusNo', models.CharField(db_column='cus_no', max_length=40)), + ('cusName', models.CharField(db_column='cus_name', max_length=20)), + ('cusManager', models.CharField(db_column='cus_manager', max_length=20)), + ('lastOrderTime', models.DateTimeField(db_column='last_order_time')), + ('confirmLossTime', models.DateTimeField(db_column='confirm_loss_time')), + ('state', models.IntegerField()), + ('lossReason', models.CharField(db_column='loss_reason', max_length=1000)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ], + options={ + 'db_table': 't_customer_loss', + }, + ), + migrations.CreateModel( + name='CustomerOrders', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('orderNo', models.DateTimeField(db_column='order_no')), + ('orderDate', models.DateTimeField(auto_now_add=True, db_column='order_date')), + ('address', models.CharField(db_column='address', max_length=120)), + ('totalPrice', models.FloatField(db_column='total_price')), + ('state', models.IntegerField(choices=[(0, '未回款'), (1, '已回款')])), + ('isValid', models.IntegerField(db_column='is_valid')), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ('customer', models.ForeignKey(db_column='cus_id', on_delete=django.db.models.deletion.DO_NOTHING, to='customer.customer')), + ], + options={ + 'db_table': 't_customer_order', + }, + ), + migrations.CreateModel( + name='LinkMan', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cusId', models.IntegerField(db_column='cus_id')), + ('linkName', models.CharField(db_column='link_name', max_length=20)), + ('sex', models.CharField(max_length=4)), + ('zhiwei', models.CharField(db_column='zhiwei', max_length=20)), + ('officePhone', models.CharField(db_column='office_phone', max_length=20)), + ('phone', models.CharField(db_column='phone', max_length=20)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ], + options={ + 'db_table': 't_customer_linkman', + }, + ), + migrations.CreateModel( + name='OrdersDetail', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('goodsName', models.CharField(db_column='goods_name', max_length=100)), + ('goodsNum', models.IntegerField(db_column='goods_num')), + ('unit', models.CharField(db_column='unit', max_length=10)), + ('price', models.FloatField(db_column='price')), + ('sum', models.FloatField(db_column='sum')), + ('isValid', models.IntegerField(db_column='is_valid')), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ('order', models.ForeignKey(db_column='order_id', on_delete=django.db.models.deletion.DO_NOTHING, to='customer.customerorders')), + ], + options={ + 'db_table': 't_order_details', + }, + ), + migrations.CreateModel( + name='CustomerReprieve', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('measure', models.CharField(db_column='measure', max_length=1000)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ('customerLoss', models.ForeignKey(db_column='loss_id', db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to='customer.customerloss')), + ], + options={ + 'db_table': 't_customer_reprieve', + }, + ), + ] diff --git a/customer/migrations/__init__.py b/customer/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/customer/migrations/__pycache__/0001_initial.cpython-312.pyc b/customer/migrations/__pycache__/0001_initial.cpython-312.pyc new file mode 100644 index 0000000..65c75da Binary files /dev/null and b/customer/migrations/__pycache__/0001_initial.cpython-312.pyc differ diff --git a/customer/migrations/__pycache__/__init__.cpython-312.pyc b/customer/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..4035504 Binary files /dev/null and b/customer/migrations/__pycache__/__init__.cpython-312.pyc differ diff --git a/customer/migrations/__pycache__/__init__.cpython-39.pyc b/customer/migrations/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..b0ea99f Binary files /dev/null and b/customer/migrations/__pycache__/__init__.cpython-39.pyc differ diff --git a/customer/models.py b/customer/models.py new file mode 100644 index 0000000..4901c31 --- /dev/null +++ b/customer/models.py @@ -0,0 +1,171 @@ +from django.db import models + + +class ModelManager(models.Manager): + def get_queryset(self): + return super(ModelManager, self).get_queryset().filter(isValid=1) + + +class Customer(models.Model): + # 主键 + id = models.AutoField(primary_key=True) + # 客户编号 KH + 日期 + khno = models.CharField(max_length=20, unique=True) + # 客户名称 + name = models.CharField(max_length=20) + # 客户所在地区 + area = models.CharField(max_length=20) + # 客户经理 + cusManager = models.CharField(max_length=30, db_column='cus_manager') + # 客户等级 + level = models.CharField(max_length=30) + # 满意度 + myd = models.CharField(max_length=30) + # 信用度 + xyd = models.CharField(max_length=30) + # 地址 + address = models.CharField(max_length=100) + # 邮编 + postCode = models.CharField(max_length=10, db_column='post_code') + # 联系电话 + phone = models.CharField(max_length=18) + # 传真 + fax = models.CharField(max_length=20) + # 网址 + website = models.CharField(max_length=50, db_column='web_site') + # 营业注册号 + yyzzzch = models.CharField(max_length=50) + # 法人 + fr = models.CharField(max_length=20) + # 注册资金 + zczj = models.CharField(max_length=20) + # 年营业额 + nyye = models.CharField(max_length=20) + # 开户银行 + khyh = models.CharField(max_length=20) + # 开户账号 + khzh = models.CharField(max_length=20) + # 地税 + dsdjh = models.CharField(max_length=20) + # 国税 + gsdjh = models.CharField(max_length=20) + # 状态0=正常 1=暂时流失 2=真正流失 + state = models.IntegerField(default=0) + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + all = models.Manager() + objects = ModelManager() + + class Meta: + db_table = 't_customer' + + +# 客户联系人 +class LinkMan(models.Model): + # 客户id,外键 + cusId = models.IntegerField(db_column='cus_id') + linkName = models.CharField(max_length=20, db_column='link_name') + sex = models.CharField(max_length=4) + zhiwei = models.CharField(max_length=20, db_column='zhiwei') + officePhone = models.CharField(max_length=20, db_column='office_phone') + phone = models.CharField(max_length=20, db_column='phone') + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_linkman' + + +# 客户订单 +class CustomerOrders(models.Model): + # 关联的客户 + customer = models.ForeignKey(Customer, db_column='cus_id', + on_delete=models.DO_NOTHING) + # 订单编号 + orderNo = models.DateTimeField(db_column='order_no') + # 下单日期 + orderDate = models.DateTimeField(db_column='order_date', auto_now_add=True) + # 收货地址 + address = models.CharField(max_length=120, db_column='address') + # 订单总金额 + totalPrice = models.FloatField(db_column='total_price') + # 0=未回款 1=已回款 + state_choices = [ + (0, '未回款'), + (1, '已回款') + ] + state = models.IntegerField(choices=state_choices) + isValid = models.IntegerField(db_column='is_valid') + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_order' + + +# 订单详情表 +class OrdersDetail(models.Model): + # 关联订单 + order = models.ForeignKey(CustomerOrders, db_column='order_id', + on_delete=models.DO_NOTHING) + # 商品名称 + goodsName = models.CharField(max_length=100, db_column='goods_name') + # 商品数量 + goodsNum = models.IntegerField(db_column='goods_num') + # 单位 + unit = models.CharField(max_length=10, db_column='unit') + # 单价 + price = models.FloatField(db_column='price') + # 总价 + sum = models.FloatField(db_column='sum') + isValid = models.IntegerField(db_column='is_valid') + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_order_details' + + +# 客户流失表 +class CustomerLoss(models.Model): + # 客户编号 + cusNo = models.CharField(max_length=40, db_column='cus_no') + # 客户名称 + cusName = models.CharField(max_length=20, db_column='cus_name') + # 客户经理 + cusManager = models.CharField(max_length=20, db_column='cus_manager') + # 上次下单日期 + lastOrderTime = models.DateTimeField(db_column='last_order_time') + # 确认流失日期 + confirmLossTime = models.DateTimeField(db_column='confirm_loss_time') + # 状态 0=暂缓流失 1=确认流失 + state = models.IntegerField() + # 流失原因 + lossReason = models.CharField(max_length=1000, db_column='loss_reason') + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_loss' + + +# 流失暂缓措施 +class CustomerReprieve(models.Model): + customerLoss = models.ForeignKey(CustomerLoss, db_column='loss_id', + db_constraint=False, on_delete=models.DO_NOTHING) + # 采取措施 + measure = models.CharField(max_length=1000, db_column='measure') + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_reprieve' diff --git a/customer/tests.py b/customer/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/customer/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/customer/urls.py b/customer/urls.py new file mode 100644 index 0000000..822db1c --- /dev/null +++ b/customer/urls.py @@ -0,0 +1,35 @@ +from django.contrib import admin +from django.urls import path, include +from . import views + +app_name = 'customer' + +urlpatterns = [ + # 首页 + path('index/', views.customer_index, name='customer_index'), + path('select_customer_list/', views.select_customer_list, name='select_customer_list'), + + path('create_or_update_customer_page/', views.create_or_update_customer_page, name='create_or_update_customer_page'), + path('create_or_update_customer/', views.create_or_update_customer, name='create_or_update_customer'), + + path('delete/', views.delete_customer, name='delete_customer'), + + path('order/index/', views.order_index, name='order_index'), + path('order/list/', views.select_orderlist_by_customerid, name='select_orderlist_by_customerid'), + + path('order/detail/index/', views.order_detail_index, name='order_detail_index'), + path('order/detail/list/', views.select_orderdetail_by_orderid, name='select_orderdetail_by_orderid'), + + path('loss/index/', views.loss_index, name='loss_index'), + path('loss/list/', views.select_loss_list, name='select_loss_list'), + + path('loss/detail/index/', views.loss_detail_index, name='loss_detail_index'), + path('loss/reprieve/list/', views.select_reprieve_by_lossid, name='select_reprieve_by_lossid'), + + path('loss/reprieve/index/', views.reprieve_index, name='reprieve_index'), + path('loss/reprieve/create/', views.create_reprieve, name='create_reprieve'), + path('loss/reprieve/update/', views.update_reprieve, name='update_reprieve'), + path('loss/reprieve/delete/', views.delete_reprieve, name='delete_reprieve'), + + path('loss/confirm/', views.update_lossreason_by_lossid, name='update_lossreason_by_lossid'), +] diff --git a/customer/views.py b/customer/views.py new file mode 100644 index 0000000..07e09df --- /dev/null +++ b/customer/views.py @@ -0,0 +1,456 @@ +from datetime import datetime + +from apscheduler.schedulers.background import BackgroundScheduler +from django.core.paginator import Paginator +from django.db import connection +from django.http import JsonResponse +from django.shortcuts import render +from django.views.decorators.clickjacking import xframe_options_exempt +from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.http import require_GET + +from customer.models import Customer, CustomerOrders, OrdersDetail, CustomerLoss, CustomerReprieve + + +# Create your views here. +@xframe_options_exempt +def customer_index(request): + return render(request, 'customer/customer.html') + + +@require_GET +def select_customer_list(request): + try: + page_num = request.GET.get('page') # 页号 + page_size = request.GET.get('limit') # 页容量 + + users = Customer.objects.filter(isValid=1).values() + paginator = Paginator(users, page_size) + count = paginator.count + users_list = paginator.page(page_num).object_list + + user_response = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(users_list) + } + + return JsonResponse(user_response) + + except Exception as e: + return JsonResponse({'code': 400, 'msg': "error"}) + + +@csrf_exempt +@xframe_options_exempt +def create_or_update_customer_page(request): + # 获取需要编辑客户的id并发送,修改客户信息时需要使用 + id = request.GET.get('id') + # 如果查询不到 id 就是添加客户操作,反之就是修改操作 + if id is not None and id != '': + customer = Customer.objects.values().filter(id=id) # 根据id查找数据库客户信息 + return render(request, 'customer/customer_add_update.html', customer[0]) # 修改操作,需要发送id,便于修改时定位客户 + else: + return render(request, 'customer/customer_add_update.html') # 新建操作,无需id + + +def create_or_update_customer(request): + try: # 接收参数 + name = request.GET.get('name') + area = request.GET.get('area') + cusManager = request.GET.get('cusManager') + level = request.GET.get('level') + xyd = request.GET.get('xyd') + postCode = request.GET.get('postCode') + phone = request.GET.get('phone') + fax = request.GET.get('fax') + website = request.GET.get('website') + address = request.GET.get('address') + fr = request.GET.get('fr') + zczj = request.GET.get('zczj') + nyye = request.GET.get('nyye') + khyh = request.GET.get('khyh') + khzh = request.GET.get('khzh') + dsdjh = request.GET.get('dsdjh') + gsdjh = request.GET.get('gsdjh') + + id = request.GET.get('id') + c = None + + # 如果id为空 说明无此用户,故为新建客户操作 + if not id: + # KH + 时间 + khno = 'KH' + datetime.now().strftime('%Y%m%d%H%M%S') + # 添加数据 + Customer.objects.create(khno=khno, name=name, area=area, + cusManager=cusManager, level=level, + xyd=xyd, postCode=postCode, phone=phone, + fax=fax, website=website, + address=address, fr=fr, zczj=zczj, nyye=nyye, + khyh=khyh, + khzh=khzh, dsdjh=dsdjh, gsdjh=gsdjh) + # 如果id有值 说明已经有此用户,故对其进行修改操作 + else: + # 修改数据 + Customer.objects.filter(id=id).update(name=name, area=area, + cusManager=cusManager, level=level, + xyd=xyd, postCode=postCode, + phone=phone, fax=fax, + website=website, + address=address, fr=fr, + zczj=zczj, nyye=nyye, khyh=khyh, + khzh=khzh, dsdjh=dsdjh, + gsdjh=gsdjh, + updateDate=datetime.now()) + # 返回提示信息 + return JsonResponse({'code': 200, 'msg': '保存成功'}) + + except Exception as es: + return JsonResponse({'code': 400, 'msg': '保存失败'}) + + +@csrf_exempt +@require_GET +def delete_customer(request): + """根据主键删除客户信息""" + try: + # 接收参数 + id = request.GET.get('id') + # 逻辑删除 + # Customer.objects.filter(pk=id).update(isValid=0, updateDate=datetime.now()) + Customer.objects.get(pk=id).delete() + return JsonResponse({'code': 200, 'msg': '删除成功'}) + except Exception as e: + return JsonResponse({'code': 400, 'msg': '删除失败'}) + + +@xframe_options_exempt +@require_GET +def order_index(request): + """跳转订单查看页面""" + # 接收参数 + id = request.GET.get('id') + # 查询客户信息 + customer = Customer.objects.get(pk=id) + context = { + 'id': id, + 'khno': customer.khno, + 'name': customer.name, + 'fr': customer.fr, + 'address': customer.address, + 'phone': customer.phone + } + return render(request, 'customer/customer_order.html', context) + + +@xframe_options_exempt +@require_GET +def select_orderlist_by_customerid(request): + """根据客户主键查询订单""" + try: + # 获取第几页 + page_num = request.GET.get('page') + # 获取每页多少条 + page_size = request.GET.get('limit') + # 获取客户主键 + id = request.GET.get('id') + # 查询订单列表 + order_list = CustomerOrders.objects.values().filter(customer=id) + # 初始化分页对象 + p = Paginator(order_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + return JsonResponse({'code': 400, 'msg': 'error'}) + + +@xframe_options_exempt +@require_GET +def order_detail_index(request): + """跳转订单详情页面""" + # 接收参数 + id = request.GET.get('id') + # 查询订单信息 + o = CustomerOrders.objects.get(pk=id) + context = { + 'id': id, + 'orderNo': o.orderNo, + 'totalPrice': o.totalPrice, + 'address': o.address, + 'state': o.get_state_display() + } + return render(request, 'customer/customer_order_detail.html', context) + + +@require_GET +def select_orderdetail_by_orderid(request): + """根据订单主题查询订单详情""" + try: + # 获取第几页 + page_num = request.GET.get('page') + # 获取每页多少条 + page_size = request.GET.get('limit') + # 获取订单主键 + id = request.GET.get('id') + # 查询订单详情 + orderdetail_list = OrdersDetail.objects.values().filter(order=id) + # 初始化分页对象 + p = Paginator(orderdetail_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + return JsonResponse({'code': 400, 'msg': 'error'}) + + +# def create_customer_loss(): +# """添加暂缓流失客户""" +# try: +# # 创建游标对象 +# cursor = connection.cursor() +# # 编写 SQL +# sql = ''' +# SELECT +# c.id id, +# c.khno cusNo, +# c.NAME cusName,c.cus_manager cusManager, +# max( co.order_date ) lastOrderTime +# FROM +# t_customer c +# LEFT JOIN t_customer_order co ON c.id = co.cus_id +# WHERE +# c.is_valid = 1 +# AND c.state = 0 +# AND NOW() > DATE_ADD( c.create_date, INTERVAL 6 MONTH ) +# AND NOT EXISTS ( +# SELECT DISTINCT +# o.cus_id +# FROM +# t_customer_order o +# WHERE +# o.is_valid = 1 +# AND NOW() < DATE_ADD( o.order_date, INTERVAL 6 MONTH ) +# AND c.id = o.cus_id +# ) +# GROUP BY +# c.id; +# ''' +# # 执行sql +# cursor.execute(sql) +# # 返回多条结果行 +# customer_loss_tuple = cursor.fetchall() # 查询当前sql执行后所有的记录,返回元组 +# # 关闭游标 +# cursor.close() +# # 将元组转为列表 +# customer_loss_id = [] # 暂缓流失客户 id 列表 +# customer_loss_list = [] # 暂缓流失客户列表 +# for cl in customer_loss_tuple: +# customer_loss_id.append(cl[0]) +# customer_loss_list.append(CustomerLoss(cusNo=cl[1], +# cusName=cl[2], +# cusManager=cl[3], +# lastOrderTime=cl[4], +# state=0)) # 暂缓流失 +# # 批量插入客户流失表 +# CustomerLoss.objects.bulk_create(customer_loss_list) +# # 修改这些数据客户表中的状态为 1 暂时流失 +# Customer.objects.filter(id__in=customer_loss_id).update(state=1, +# updateDate=datetime.now()) +# except Exception as e: +# print(e) +# finally: +# connection.close() +# +# +# scheduler = BackgroundScheduler() # 创建一个调度器对象 +# scheduler.add_job(create_customer_loss, 'interval', minutes=1) # 创建一个任务 +# scheduler.start() # 启动任务 +@xframe_options_exempt +@require_GET +def loss_index(request): + return render(request, 'customer/customer_loss.html') + + +@require_GET +def select_loss_list(request): + try: + # 获取第几页 + page_num = request.GET.get('page') + # 获取每页多少条 + page_size = request.GET.get('limit') + # 获取客户编号 + cusNo = request.GET.get('cusNo') + # 获取客户名称 + cusName = request.GET.get('cusName') + # 获取客户状态 + state = request.GET.get('state') + # 查询所有 + loss_list = CustomerLoss.objects.values().all().order_by('-lastOrderTime') + # 如果有条件参数,带条件查询 + if cusNo: + loss_list = loss_list.filter(cusNo__icontains=cusNo) + if cusName: + loss_list = loss_list.filter(cusName__icontains=cusName) + if state: + loss_list = loss_list.filter(state=state) + # 初始化分页对象 + p = Paginator(loss_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + return JsonResponse({'code': 400, 'msg': 'error'}) + + +@xframe_options_exempt +@require_GET +def loss_detail_index(request): + try: + # 获取客户流失主键 + id = request.GET.get('id') + # 查询客户流失信息 + cl = CustomerLoss.objects.get(pk=id) + context = {'cl': cl} + return render(request, 'customer/customer_reprieve.html', context) + except CustomerLoss.DoesNotExist as e: + pass + + +@require_GET +def select_reprieve_by_lossid(request): + """根据客户流失主键查询流失措施""" + try: + page_num = request.GET.get('page') + page_size = request.GET.get('limit') + id = request.GET.get('id') + + cp_list = CustomerReprieve.objects.values().filter(customerLoss=id).order_by('-id') + + p = Paginator(cp_list, page_size) + + data = p.page(page_num).object_list + + count = p.count + + context = {'code': 0, 'msg': '', 'count': count, 'data': list(data)} + + return JsonResponse(context) + + except Exception as e: + + return JsonResponse({'code': 400, 'msg': 'error'}) + + +@xframe_options_exempt +@require_GET +def reprieve_index(request): + """添加客户暂缓页面""" + lossId = request.GET.get('lossId') + context = {'lossId': lossId} + + id = request.GET.get('id') + + if id: + cp = CustomerReprieve.objects.get(pk=id) + context['id'] = id + context['cp'] = cp + return render(request, 'customer/customer_reprieve_add_update.html', context) + + +@csrf_exempt +@require_GET +def create_reprieve(request): + """添加客户暂缓""" + # 获取客户流失主键 + lossId = request.GET.get('lossId') + # 获取客户暂缓措施 + measure = request.GET.get('measure') + # 查询流失客户数据 + cl = CustomerLoss.objects.get(pk=lossId) + data = { + 'customerLoss': cl, + 'measure': measure + } + # 添加 + CustomerReprieve.objects.create(**data) + return JsonResponse({'code': 200, 'msg': '添加成功'}) + + +@csrf_exempt +@require_GET +def update_reprieve(request): + """修改客户暂缓""" + # 获取客户暂缓主键 + id = request.GET.get('id') + # 获取客户暂缓措施 + measure = request.GET.get('measure') + data = { + 'measure': measure, + 'updateDate': datetime.now() + } + # 修改 + CustomerReprieve.objects.filter(pk=id).update(**data) + return JsonResponse({'code': 200, 'msg': '修改成功'}) + + +@csrf_exempt +@require_GET +def delete_reprieve(request): + """删除客户暂缓""" + # 获取客户暂缓主键 + id = request.GET.get('id') + # 逻辑删除 + CustomerReprieve.objects.filter(pk=id).update(isValid=0, + updateDate=datetime.now()) + return JsonResponse({'code': 200, 'msg': '删除成功'}) + + +@csrf_exempt +@require_GET +def update_lossreason_by_lossid(request): + """确认流失""" + # 获取客户流失主键 + lossId = request.GET.get('lossId') + # 获取流失原因 + lossReason = request.GET.get('lossReason') + # 根据客户流失主键查询 + cl = CustomerLoss.objects.get(pk=lossId) + # 重新赋值 + cl.lossReason = lossReason + cl.state = 1 + cl.confirmLossTime = datetime.now() + # 保存 + cl.save() + # 修改客户表状态 + Customer.objects.filter(khno=cl.cusNo).update(state=2, + updateDate=datetime.now()) + return JsonResponse({'code': 200, 'msg': '保存成功'}) diff --git a/report/__init__.py b/report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/report/__pycache__/__init__.cpython-312.pyc b/report/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..c7d0059 Binary files /dev/null and b/report/__pycache__/__init__.cpython-312.pyc differ diff --git a/report/__pycache__/__init__.cpython-39.pyc b/report/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..30c3f88 Binary files /dev/null and b/report/__pycache__/__init__.cpython-39.pyc differ diff --git a/report/__pycache__/admin.cpython-312.pyc b/report/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000..ed503c9 Binary files /dev/null and b/report/__pycache__/admin.cpython-312.pyc differ diff --git a/report/__pycache__/admin.cpython-39.pyc b/report/__pycache__/admin.cpython-39.pyc new file mode 100644 index 0000000..5d4d508 Binary files /dev/null and b/report/__pycache__/admin.cpython-39.pyc differ diff --git a/report/__pycache__/apps.cpython-312.pyc b/report/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000..4fbab9c Binary files /dev/null and b/report/__pycache__/apps.cpython-312.pyc differ diff --git a/report/__pycache__/apps.cpython-39.pyc b/report/__pycache__/apps.cpython-39.pyc new file mode 100644 index 0000000..0074094 Binary files /dev/null and b/report/__pycache__/apps.cpython-39.pyc differ diff --git a/report/__pycache__/models.cpython-312.pyc b/report/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000..5da7625 Binary files /dev/null and b/report/__pycache__/models.cpython-312.pyc differ diff --git a/report/__pycache__/models.cpython-39.pyc b/report/__pycache__/models.cpython-39.pyc new file mode 100644 index 0000000..a68f199 Binary files /dev/null and b/report/__pycache__/models.cpython-39.pyc differ diff --git a/report/__pycache__/urls.cpython-312.pyc b/report/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000..5b1469f Binary files /dev/null and b/report/__pycache__/urls.cpython-312.pyc differ diff --git a/report/__pycache__/urls.cpython-39.pyc b/report/__pycache__/urls.cpython-39.pyc new file mode 100644 index 0000000..f82a6bc Binary files /dev/null and b/report/__pycache__/urls.cpython-39.pyc differ diff --git a/report/__pycache__/views.cpython-312.pyc b/report/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000..5b61cf2 Binary files /dev/null and b/report/__pycache__/views.cpython-312.pyc differ diff --git a/report/__pycache__/views.cpython-39.pyc b/report/__pycache__/views.cpython-39.pyc new file mode 100644 index 0000000..4731e20 Binary files /dev/null and b/report/__pycache__/views.cpython-39.pyc differ diff --git a/report/admin.py b/report/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/report/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/report/apps.py b/report/apps.py new file mode 100644 index 0000000..1ed8809 --- /dev/null +++ b/report/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ReportConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'report' diff --git a/report/migrations/__init__.py b/report/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/report/migrations/__pycache__/__init__.cpython-312.pyc b/report/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..7625b3f Binary files /dev/null and b/report/migrations/__pycache__/__init__.cpython-312.pyc differ diff --git a/report/migrations/__pycache__/__init__.cpython-39.pyc b/report/migrations/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..a00c57f Binary files /dev/null and b/report/migrations/__pycache__/__init__.cpython-39.pyc differ diff --git a/report/models.py b/report/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/report/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/report/tests.py b/report/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/report/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/report/urls.py b/report/urls.py new file mode 100644 index 0000000..543d71e --- /dev/null +++ b/report/urls.py @@ -0,0 +1,14 @@ +from django.urls import path +from . import views + +app_name = 'report' + +urlpatterns = [ + path('/index/', views.report_index, name='report_index'), + path('contribute/', views.select_contribute, name='select_contribute'), + path('composition/', views.select_composition, name='select_composition'), + path('serve/', views.select_serve, name='select_serve'), + + path('loss/index/', views.loss_index, name='loss_index'), + path('loss/list/', views.select_loss_list, name='select_loss_list'), +] diff --git a/report/views.py b/report/views.py new file mode 100644 index 0000000..b317184 --- /dev/null +++ b/report/views.py @@ -0,0 +1,99 @@ +from django.shortcuts import render +from django.core.paginator import Paginator +from django.db.models import Sum, Count, Case, When, Value +from django.http import JsonResponse +from django.shortcuts import render +from django.views.decorators.clickjacking import xframe_options_exempt +from django.views.decorators.http import require_GET +from customer.models import Customer +from serve.models import CustomerServe + +from customer.views import loss_index, select_loss_list + + +# Create your views here. + +@xframe_options_exempt +@require_GET +def report_index(request, template): + """统计报表子菜单首页""" + ''' + contribute 客户贡献分析首页 + composition 客户构成分析首页 + serve 客户服务分析首页 + loss 客户流失分析首页 + ''' + return render(request, 'report/%s.html' % template) + + +@require_GET +def select_contribute(request): + """查询客户贡献""" + try: + + # """ + # SELECT c.id, c.name, sum(od.sum) sum FROM t_customer c + # LEFT JOIN t_customer_order co ON c.id = co.cus_id + # LEFT JOIN t_order_details od ON co.id = od.order_id + # WHERE c.is_valid = 1 AND c.id = 1 GROUP BY c.id, c.name; + # """ + # 获取第几页 + page_num = request.GET.get('page', 1) # 添加默认值,防止没有参数导致的异常错误 + # 获取每页多少条 + page_size = request.GET.get('limit', 10) # 添加默认值,防止没有参数导致的异常错误 + customer_list = Customer.objects.values('id', 'name') \ + .annotate(sum=Sum('customerorders__ordersdetail__sum')) \ + .order_by('-sum') + # 按条件查询 + # 客户名称 + customerName = request.GET.get('customerName') + if customerName: + customer_list = customer_list.filter(name__icontains=customerName) + # 金额区间 + type = request.GET.get('type') + if type == '1': + customer_list = customer_list.filter(sum__gte=0, sum__lte=1000) + elif type == '2': + customer_list = customer_list.filter(sum__gt=1000, sum__lte=3000) + elif type == '3': + customer_list = customer_list.filter(sum__gt=3000, sum__lte=5000) + elif type == '4': + customer_list = customer_list.filter(sum__gt=5000) + # 初始化分页对象 + p = Paginator(customer_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '查询成功', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + pass + + +@require_GET +def select_composition(request): + """查询客户构成数据""" + level = Customer.objects.values('level') \ + .annotate(amount=Count('level')).order_by('level') + return JsonResponse(list(level), safe=False) + + +@require_GET +def select_serve(request): + """查询客户服务类型数据""" + serve = CustomerServe.objects.values('serveType') \ + .annotate(type=Case(When(serveType=6, then=Value("咨询")), + When(serveType=7, then=Value("建议")), + When(serveType=8, then=Value("投诉"))), amount=Count('serveType')) \ + .order_by('serveType') + return JsonResponse(list(serve), safe=False) + + +