1. 程式人生 > >使用自己的stark組件實現crm系統

使用自己的stark組件實現crm系統

SM auth mit href 保存 crm label rst custom

因為stark用到了templates裏面的html頁面文件,所以要整合在一個app裏,在stark裏面創建名字為templates的Python Package,將之前的html頁面拷貝在stark組件裏面的templates裏面,然後拷貝stark組件

技術分享圖片


二、實現crm邏輯

CRM即客戶關系管理,是指企業用CRM技術來管理與客戶之間的關系

1、創建數據庫

在app01應用下的models.py文件:

from django.db import models
class Department(models.Model):
    """
    部門表
    市場部     1000
    銷售       1001
    """
    title = models.CharField(verbose_name='部門名稱', max_length=16)
    code = models.IntegerField(verbose_name='部門編號', unique=True, null=False)
    def __str__(self):
        return self.title
class UserInfo(models.Model):
    """
    員工表
    """
    name = models.CharField(verbose_name='員工姓名', max_length=16)
    email = models.EmailField(verbose_name='郵箱', max_length=64)
    depart = models.ForeignKey(verbose_name='部門', to="Department", to_field="code")
    def __str__(self):
        return self.name
class Course(models.Model):
    """
    課程表
    如:
        Linux基礎
        Linux架構師
        Python自動化開發精英班
        Python自動化開發架構師班
        Python基礎班
go基礎班
    """
    name = models.CharField(verbose_name='課程名稱', max_length=32)
    def __str__(self):
        return self.name
class School(models.Model):
    """
    校區表
    如:
        北京沙河校區
        上海校區
    """
    title = models.CharField(verbose_name='校區名稱', max_length=32)
    def __str__(self):
        return self.title
class ClassList(models.Model):
    """
    班級表
    如:
        Python全棧  面授班  5期  10000  2017-11-11  2018-5-11
    """
    school = models.ForeignKey(verbose_name='校區', to='School')
    course = models.ForeignKey(verbose_name='課程名稱', to='Course')
    semester = models.IntegerField(verbose_name="班級(期)")
    price = models.IntegerField(verbose_name="學費")
    start_date = models.DateField(verbose_name="開班日期")
    graduate_date = models.DateField(verbose_name="結業日期", null=True, blank=True)
    memo = models.CharField(verbose_name='說明', max_length=256, blank=True, null=True, )
    # teachers = models.ManyToManyField(verbose_name='任課老師', to='UserInfo',limit_choices_to={'depart_id__in':[1003,1004],})
    teachers = models.ManyToManyField(verbose_name='任課老師', to='UserInfo', related_name="abc",
                         limit_choices_to={"depart_id__in":[1002,1003]}             )
    tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo', related_name='classes',
                              limit_choices_to={"depart": 1005})
    def __str__(self):
        return "{0}({1}期)".format(self.course.name, self.semester)
class Customer(models.Model):
    """
    客戶表
    """
    qq = models.CharField(verbose_name='qq', max_length=64, unique=True, help_text='QQ號必須唯一')
    name = models.CharField(verbose_name='學生姓名', max_length=16)
    gender_choices = ((1, '男'), (2, '女'))
    gender = models.SmallIntegerField(verbose_name='性別', choices=gender_choices)
    education_choices = (
        (1, '重點大學'),
        (2, '普通本科'),
        (3, '獨立院校'),
        (4, '民辦本科'),
        (5, '大專'),
        (6, '民辦專科'),
        (7, '高中'),
        (8, '其他')
    )
    education = models.IntegerField(verbose_name='學歷', choices=education_choices, blank=True, null=True, )
    graduation_school = models.CharField(verbose_name='畢業學校', max_length=64, blank=True, null=True)
    major = models.CharField(verbose_name='所學專業', max_length=64, blank=True, null=True)
    experience_choices = [
        (1, '在校生'),
        (2, '應屆畢業'),
        (3, '半年以內'),
        (4, '半年至一年'),
        (5, '一年至三年'),
        (6, '三年至五年'),
        (7, '五年以上'),
    ]
    experience = models.IntegerField(verbose_name='工作經驗', blank=True, null=True, choices=experience_choices)
    work_status_choices = [
        (1, '在職'),
        (2, '無業')
    ]
    work_status = models.IntegerField(verbose_name="職業狀態", choices=work_status_choices, default=1, blank=True,
                                      null=True)
    company = models.CharField(verbose_name="目前就職公司", max_length=64, blank=True, null=True)
    salary = models.CharField(verbose_name="當前薪資", max_length=64, blank=True, null=True)
    source_choices = [
        (1, "qq群"),
        (2, "內部轉介紹"),
        (3, "官方網站"),
        (4, "百度推廣"),
        (5, "360推廣"),
        (6, "搜狗推廣"),
        (7, "騰訊課堂"),
        (8, "廣點通"),
        (9, "高校宣講"),
        (10, "渠道代理"),
        (11, "51cto"),
        (12, "智匯推"),
        (13, "網盟"),
        (14, "DSP"),
        (15, "SEO"),
        (16, "其它"),
    ]
    source = models.SmallIntegerField('客戶來源', choices=source_choices, default=1)
    referral_from = models.ForeignKey(
        'self',
        blank=True,
        null=True,
        verbose_name="轉介紹自學員",
        help_text="若此客戶是轉介紹自內部學員,請在此處選擇內部學員姓名",
        related_name="internal_referral"
    )
    course = models.ManyToManyField(verbose_name="咨詢課程", to="Course")
    status_choices = [
        (1, "已報名"),
        (2, "未報名")
    ]
    status = models.IntegerField(
        verbose_name="狀態",
        choices=status_choices,
        default=2,
        help_text=u"選擇客戶此時的狀態"
    )
    consultant = models.ForeignKey(verbose_name="課程顧問", to='UserInfo', related_name='consultanter',
                                   limit_choices_to={'depart_id': 1001})
    date = models.DateField(verbose_name="咨詢日期", auto_now_add=True)
    recv_date = models.DateField(verbose_name="當前課程顧問的接單日期", null=True)
    last_consult_date = models.DateField(verbose_name="最後跟進日期", )
    def __str__(self):
        return self.name
class ConsultRecord(models.Model):
    """
    客戶跟進記錄
    """
    customer = models.ForeignKey(verbose_name="所咨詢客戶", to='Customer')
    consultant = models.ForeignKey(verbose_name="跟蹤人", to='UserInfo',limit_choices_to={"depart_id":1001})
    date = models.DateField(verbose_name="跟進日期", auto_now_add=True)
    note = models.TextField(verbose_name="跟進內容...")
    def __str__(self):
        return self.customer.name + ":" + self.consultant.name
class Student(models.Model):
    """
    學生表(已報名)
    """
    customer = models.OneToOneField(verbose_name='客戶信息', to='Customer')
    emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='緊急聯系人')
    class_list = models.ManyToManyField(verbose_name="已報班級", to='ClassList', blank=True)
    company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True)
    location = models.CharField(max_length=64, verbose_name='所在區域', blank=True, null=True)
    position = models.CharField(verbose_name='崗位', max_length=64, blank=True, null=True)
    salary = models.IntegerField(verbose_name='薪資', blank=True, null=True)
    welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True)
    date = models.DateField(verbose_name='入職時間', help_text='格式yyyy-mm-dd', blank=True, null=True)
    memo = models.CharField(verbose_name='備註', max_length=256, blank=True, null=True)
    def __str__(self):
        return str(self.customer)
class ClassStudyRecord(models.Model):
    """
    上課記錄表 (班級記錄)
    """
    class_obj = models.ForeignKey(verbose_name="班級", to="ClassList")
    day_num = models.IntegerField(verbose_name="節次", help_text=u"此處填寫第幾節課或第幾天課程...,必須為數字")
    teacher = models.ForeignKey(verbose_name="講師", to='UserInfo', limit_choices_to={"depart_id__in": [1002, 1003]})       #過濾id為1002和1003的部門
    date = models.DateField(verbose_name="上課日期", auto_now_add=True)
    course_title = models.CharField(verbose_name='本節課程標題', max_length=64, blank=True, null=True)
    course_memo = models.TextField(verbose_name='本節課程內容概要', blank=True, null=True)
    has_homework = models.BooleanField(default=True, verbose_name="本節有作業")
    homework_title = models.CharField(verbose_name='本節作業標題', max_length=64, blank=True, null=True)
    homework_memo = models.TextField(verbose_name='作業描述', max_length=500, blank=True, null=True)
    exam = models.TextField(verbose_name='踩分點', max_length=300, blank=True, null=True)
    def __str__(self):
        return "{0} day{1}".format(self.class_obj, self.day_num)
class StudentStudyRecord(models.Model):
    '''
    學生記錄
    '''
    class_study_record = models.ForeignKey(verbose_name="第幾天課程", to="ClassStudyRecord")
    student = models.ForeignKey(verbose_name="學員", to='Student')
    record_choices = (('checked', "已簽到"),
                      ('vacate', "請假"),
                      ('late', "遲到"),
                      ('noshow', "缺勤"),
                      ('leave_early', "早退"),
                      )
    record = models.CharField("上課紀錄", choices=record_choices, default="checked", max_length=64)
    score_choices = ((100, 'A+'),
                     (90, 'A'),
                     (85, 'B+'),
                     (80, 'B'),
                     (70, 'B-'),
                     (60, 'C+'),
                     (50, 'C'),
                     (40, 'C-'),
                     (0, ' D'),
                     (-1, 'N/A'),
                     (-100, 'COPY'),
                     (-1000, 'FAIL'),
                     )
    score = models.IntegerField("本節成績", choices=score_choices, default=-1)
    homework_note = models.CharField(verbose_name='作業評語', max_length=255, blank=True, null=True)
    note = models.CharField(verbose_name="備註", max_length=255, blank=True, null=True)
    homework = models.FileField(verbose_name='作業文件', blank=True, null=True, default=None)
    stu_memo = models.TextField(verbose_name='學員備註', blank=True, null=True)
    date = models.DateTimeField(verbose_name='提交作業日期', auto_now_add=True)
    def __str__(self):
        return "{0}-{1}".format(self.class_study_record, self.student)
        
        
        
#數據庫實例化,使用下面的命令
#python3 manage.py makemigrations
#python3 manage.py migrate


2、相關項目設置


settings.py文件設置內容:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    "stark.apps.StarkConfig"
]
STATIC_URL = '/static/'
STATICFILES_DIRS= [
    os.path.join(BASE_DIR,"static")
]

註:

#static目錄下面是Highcharts-6.1.0,是顯示後面的柱形圖所需的插件

#下載地址: https://www.hcharts.cn/download


3、邏輯部分及顯示頁面

urls.py文件:

from django.conf.urls import url
from django.contrib import admin
from stark.service.sites import site
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^stark/', site.urls),
]


stark組件service目錄下sites.py文件:

from django.conf.urls import url
from django.shortcuts import HttpResponse, render, redirect
from django.utils.safestring import mark_safe
from django.urls import reverse
class Show_List(object):
    def __init__(self, config, data_list):
        self.config = config
        self.data_list = data_list
    def get_header(self):
        # 處理表頭
        # header_list=["ID","名稱","價格"]
        header_list = []
        for field in self.config.new_list_display():
            if isinstance(field, str):
                if field == "__str__":
                    val = self.config.model._meta.model_name.upper()
                else:
                    field_obj = self.config.model._meta.get_field(field)
                    val = field_obj.verbose_name
            else:
                val = field(self.config, is_header=True)
            header_list.append(val)
        return header_list
    def get_body(self):
        # 處理表單數據
        new_data_list = []
        for obj in self.data_list:
            temp = []
            for field in self.config.new_list_display():  # ["nid","title","price","authors",edit]    ['__str__']     ["title","price"]
                if isinstance(field, str):
                    try:
                        from django.db.models.fields.related import ManyToManyField
                        field_obj = self.config.model._meta.get_field(field)
                        if isinstance(field_obj, ManyToManyField):
                            l = []
                            for i in getattr(obj, field).all():
                                l.append(str(i))
                            val = ",".join(l)
                        else:
                            val = getattr(obj, field)
                            print("val", val)
                    except Exception as e:
                        val = getattr(obj, field)
                else:
                    val = field(self.config, obj)
                temp.append(val)
            new_data_list.append(temp)
        return new_data_list
    def get_new_actions(self):
        action_list = []
        for i in self.config.actions:  # [patch_init,]
            action_list.append({
                "desc": i.desc,
                "name": i.__name__,
            })
        return action_list
class ModelStark():
    list_display = ["__str__", ]
    search_fields = []
    actions = []
    def __init__(self, model, site):
        self.model = model
        self.site = site
    def edit(self, obj=None, is_header=False):
        if is_header:
            return "操作"
        return mark_safe("<a href='%s/change'>編輯</a>" % obj.pk)
    def delete(self, obj=None, is_header=False):
        if is_header:
            return "操作"
        return mark_safe("<a href='%s/delete'>刪除</a>" % obj.pk)
    def checkbox(self, obj=None, is_header=False):
        if is_header:
            return "選擇"
        return mark_safe("<input type='checkbox' name='selected_pk' value=%s>" % obj.pk)
    def get_list_url(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        _url = reverse("%s_%s_list" % (app_label, model_name))
        return _url
    def new_list_display(self):
        temp = []
        temp.append(ModelStark.checkbox)
        temp.extend(self.list_display)
        temp.append(ModelStark.edit)
        temp.append(ModelStark.delete)
        return temp
    def get_search_condition(self, request):
        from django.db.models import Q
        search_condition = Q()
        val = request.GET.get("q")
        if val:
            search_condition.connector = "or"
            for field in self.search_fields:
                search_condition.children.append((field + "__contains", val))
        return search_condition
    def list_view(self, request):
        if request.method == "POST":
            action = request.POST.get("action")
            selected_pk = request.POST.getlist("selected_pk")
            action = getattr(self, action)
            action(selected_pk)
        # search
        search_condition = self.get_search_condition(request)
        # fliter
        from django.db.models import Q
        filter_condition = Q()
        for key, value in request.GET.items():
            filter_condition.children.append((key, value))
        data_list = self.model.objects.all().filter(search_condition).filter(filter_condition)
        print("list_display", self.list_display)  # ["nid","title","price",edit]
        sl = Show_List(self, data_list)
        return render(request, "list_view.html", locals())
    def get_mdoelForm(self):
        from django.forms import ModelForm
        class DemoModelForm(ModelForm):
            class Meta:
                model = self.model
                fields = "__all__"
        return DemoModelForm
    def add(self, request):
        if request.method == "POST":
            form = self.get_mdoelForm()(request.POST)
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url())
            else:
                return render(request, "add.html", locals())
        form = form = self.get_mdoelForm()()
        return render(request, "add.html", locals())
    def change(self, request, id):
        obj = self.model.objects.filter(pk=id).first()
        if request.method == "POST":
            form = self.get_mdoelForm()(request.POST, instance=obj)
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url())
        form = self.get_mdoelForm()(instance=obj)
        return render(request, "change.html", locals())
    def delete_view(self, request, id):
        if request.method == "POST":
            self.model.objects.get(pk=id).delete()
            return redirect(self.get_list_url())
        url = self.get_list_url()
        return render(request, "delete.html", locals())
    def extra_url(self):
        return []
    def get_urls2(self):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label
        temp = [
            url("^add/$", self.add, name="%s_%s_add" % (app_label, model_name)),
            url("^$", self.list_view, name="%s_%s_list" % (app_label, model_name)),
            url("^(\d+)/change/$", self.change, name="%s_%s_change" % (app_label, model_name)),
            url("^(\d+)/delete/$", self.delete_view, name="%s_%s_delete" % (app_label, model_name)),
        ]
        temp.extend(self.extra_url())                                      #額外添加一條url
        return temp
    @property
    def urls2(self):
        return self.get_urls2(), None, None
        
class StarkSite():
    def __init__(self, ):
        self._registry = {}
    # 一級分發
    def get_urls(self):
        temp = []
        for model, model_class_obj in self._registry.items():  # {Book:ModelAdmin(Book),Publish:ModelAdmn(Publish),....}
            app_name = model._meta.app_label
            model_name = model._meta.model_name
            temp.append(url(r"%s/%s/" % (app_name, model_name), model_class_obj.urls2))
        return temp
    @property
    def urls(self):
        return self.get_urls(), None, None
    def register(self, model, admin_class=None, **options):
        if not admin_class:
            admin_class = ModelStark
        self._registry[model] = admin_class(model, self)
site = StarkSite()


app01應用下的stark.py文件:


from stark.service.sites import site,ModelStark
from django.utils.safestring import mark_safe
from app01 import models
from django.conf.urls import url
from django.shortcuts import HttpResponse,redirect,render
from django.http import JsonResponse
site.register(models.Department)
site.register(models.School)
site.register(models.UserInfo)
site.register(models.Course)
site.register(models.ClassList)

class Studentconfig(ModelStark):                                  #學生表的配置類
    def display_score(self,obj=None,is_header=False):
        if is_header:
            return "個人成績"
        return mark_safe("<a href='score/%s'>個人成績</a>"%obj.pk)
    list_display = ["customer","class_list",display_score]        #定義顯示學生字段增加客戶信息,已報班級,個人成績三組字段
    def score(self,request,sid):
        if request.is_ajax():
            cid=request.GET.get("cid")
            sid=request.GET.get("sid")
            ret=student_study_record_list=list(models.StudentStudyRecord.objects.filter(student_id=sid,class_study_record__class_obj_id=cid).values_list("class_study_record__day_num","score"))
            print(ret)
            ret=[["day"+str(i[0]),i[1]] for i in ret]
            # print(ret)
            return JsonResponse(ret,safe=False)
        student=models.Student.objects.get(pk=sid)
        class_list=student.class_list.all()
        return render(request,"score.html",locals())
    def extra_url(self):
        temp=[]
        temp.append(url("score/(\d+)",self.score))
        return temp
        
site.register(models.Student,Studentconfig)
site.register(models.Customer)
site.register(models.ConsultRecord)

class ClassStudyRecordConfig(ModelStark):
    def detail(self,obj=None,is_header=False):
        if is_header:
            return "詳細信息"
        return mark_safe("<a href='/stark/app01/studentstudyrecord/?class_study_record=%s'>詳細信息</a>"%obj.pk)  #url跳轉到當前班級的詳細信息
    def record_score(self, obj=None, is_header=False):
        if is_header:
            return "錄入成績"
        return mark_safe("<a href='record_score/%s'>錄入成績</a>"%obj.pk)                                   #url跳轉到當前班級的錄入成績
    list_display = ["class_obj","day_num",detail,record_score]
    def patch_init(self,selected_pk):                           #定義批量初始化,對所有班級批量生成對應的學生記錄對象
        classstudyrecord_list=self.model.objects.filter(pk__in=selected_pk)
        for classstudyrecord in classstudyrecord_list:
            student_list=models.Student.objects.filter(class_list=classstudyrecord.class_obj)
            for student in student_list:
                models.StudentStudyRecord.objects.create(class_study_record=classstudyrecord,student=student)
    patch_init.desc="批量初始化"
    actions = [patch_init]
    def record_score(self,request,id):
        csr = models.ClassStudyRecord.objects.get(pk=id)              #班級學習對象
        student_study_record_list = models.StudentStudyRecord.objects.filter(class_study_record=csr)
        score_choices = models.StudentStudyRecord.score_choices
        update=False
        if request.method=="POST":                                 #提交數據
            print("POST",request.POST)
            for key,val in request.POST.items():                    #頁面取到的鍵值進行處理
                if key=="csrfmiddlewaretoken":continue
                field,pk=key.rsplit("_",1)                          #以下劃線作為分割標準,取右邊第一個
                dic={field:val}
                models.StudentStudyRecord.objects.filter(pk=pk).update(**dic)    #更新的字典,使用**
            update=True
        return render(request,"record_score.html",locals())
    def extra_url(self):
        temp=[]
        temp.append(url("record_score/(\d+)",self.record_score))
        return temp
        
site.register(models.ClassStudyRecord,ClassStudyRecordConfig)

class StudentStudyRecordConfig(ModelStark):
    def display_record(self,obj=None,is_header=False):
        if is_header:
            return "考勤"
        return obj.get_record_display()                       #返回需要的考勤狀態
    def display_score(self,obj=None,is_header=False):
        if is_header:
            return "成績"
        return obj.get_score_display()                           #顯示對應的後面的字母表示的成績,而不是數字
    list_display = ["student","class_study_record",display_record,display_score]
    def patch_late(self,selected_pk):                             #批量修改考勤狀態為遲到
        self.model.objects.filter(pk__in=selected_pk).update(record="late")
    patch_late.desc="遲到"
    actions = [patch_late]
    
site.register(models.StudentStudyRecord,StudentStudyRecordConfig)


record_score.html錄入成績頁面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.css">
</head>
<body>
<h3>錄入成績</h3>
<div>
    <div>
        <div>
            <form action="" method="post">
                {% csrf_token %}
                <table class="table table-bordered table-striped table-hover">
                    <thead>
                    <tr>
                        <th>編號</th>
                        <th>姓名</th>
                        <th>考勤</th>
                        <th>成績</th>
                        <th>批語</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for student_study_record in  student_study_record_list %}
                        <tr>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ student_study_record.student }}</td>
                            <td>
                                {{ student_study_record.get_record_display }}
                            </td>
                            <td>
                                <select name="score_{{ student_study_record.pk }}" id="">     {#下拉框顯示當前學生成績#}
                                    {% for foo in score_choices %}
                                        {% if student_study_record.score == foo.0 %}
                                         <option selected value="{{ foo.0 }}">{{ foo.1 }}</option>          {#已經有成績的顯示器成績,沒有的顯示默認#}
                                        {% else %}
                                         <option value="{{ foo.0 }}">{{ foo.1 }}</option>
                                        {% endif %}
                                    {% endfor %}
                                </select>
                            </td>
                            <td><textarea name="homework_note_{{ student_study_record.pk }}" id="" cols="40" rows="5">{{ student_study_record.homework_note|default_if_none:"" }}</textarea>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
                <input type="submit" class="btn btn-warning pull-right" value="保存">                           {#保存按鈕#}
                {% if update %}
                <span style="color:green">更新成功</span>
                {% endif %}
            </form>
        </div>
    </div>
</div>
</body>

<script>
setTimeout(function(){document.getElementById("show_text").style.display="none";},2000);      {# 更新成功顯示2秒後消失 #}
</script>
</html>


score.html查看個人成績頁面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.1/css/bootstrap.css">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script src="/static/Highcharts-6.1.0/code/highcharts.js"></script>
</head>
<body>
<h2>查看{{ student }}成績</h2>
<div>
    <div>
        <div class="col-md-8 col-md-offset-1">
            <table class="table table-bordered table-striped table-hover">
                <thead>
                <tr>
                    <th>編號</th>
                    <th>班級</th>
                    <th>班主任</th>
                    <th>成績柱狀圖</th>
                </tr>
                </thead>
                <tbody>
                {% for cls in  class_list %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ cls.course }}({{ cls.semester }})</td>
                        <td>{{ cls.tutor }}</td>
                        <td><a cid="{{ cls.pk }}">成績柱狀圖</a></td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
<div id="container" style="width: 600px"></div>

<script>
                $(".chart_score").click(function () {
                    var cid=$(this).attr("cid");
                    $.ajax({
                        url:"",
                        type:"get",
                        data:{
                            sid:"{{ student.pk }}",
                            cid:cid
                        },
                        success:function (data) {
                             var chart = Highcharts.chart('container', {
                        chart: {
                            type: 'column'
                        },
                        title: {
                            text: '個人成績分布圖'
                        },
                        subtitle: {
                            text: '數據截止 2017-03,來源: <a href="https://en.wikipedia.org/wiki/List_of_cities_proper_by_population">Wikipedia</a>'
                        },
                        xAxis: {
                            type: 'category',
                            labels: {
                                rotation: -45  // 設置軸標簽旋轉角度
                            }
                        },
                        yAxis: {
                            min: 0,
                            title: {
                                text: '分數'
                            }
                        },
                        legend: {
                            enabled: false
                        },
                        tooltip: {
                            pointFormat: '分數: <b>{point.y:.2f} 百萬</b>'
                        },
                        series: [{
                            name: '總人口',
                            data: data,
                            dataLabels: {
                                enabled: true,
                                rotation: -90,
                                color: 'red',
                                align: 'right',
                                format: '{point.y:.1f}',        // :.1f 為保留 1 位小數
                                y: 10
                            }
                        }]
                    });
                        }
                    })
                })
            </script>
</body>
</html>


頁面顯示效果圖如下:

技術分享圖片

技術分享圖片

技術分享圖片


技術分享圖片

技術分享圖片







使用自己的stark組件實現crm系統