Gogs 3 年 前
コミット
8bd15e9203

+ 5 - 0
src/common/common_control.py

@@ -67,6 +67,7 @@ def no_cache(key="*"):
     def _wrapper(func):
         def __wrapper(*args,**kwargs):
             res = func(*args,**kwargs)
+            print 999999999999999
             print cache.delete_pattern("cdata_{}*".format(key))
             return res
         return __wrapper
@@ -83,6 +84,10 @@ def no_cache_list(keys=[]):
         return __wrapper
     return _wrapper
 
+def del_cache(key):
+    """
+    """
+    print cache.delete(key)
 
 def get_page_qset(qset,page,page_size=20):
     """

+ 100 - 0
src/common/models.py

@@ -16,6 +16,13 @@ class UserInfo(models.Model):
 
     is_bind = models.SmallIntegerField(u"是否绑定",default=0)
     utype = models.SmallIntegerField(u"是否激活可用",default=0)
+    zq = models.CharField(u"周期", max_length=255, blank=True, null=True)
+    cw = models.CharField(u"仓位", max_length=255, blank=True, null=True)
+    df = models.CharField(u"打法", max_length=255, blank=True, null=True)
+    pz = models.CharField(u"品种", max_length=255, blank=True, null=True)
+    account_img = models.TextField(u"账号截图", max_length=255, blank=True, null=True)
+    join_time = models.CharField(u"入市时间", max_length=255, blank=True, null=True)
+    badge = models.CharField(u"选手标识", max_length=255,blank=False,null=False,default=u"选手")
 
     ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
 
@@ -45,6 +52,7 @@ class Player(models.Model):
     match_group = models.CharField(u"比赛分组", max_length=255,blank=True,null=True)
     fund = models.FloatField(u"资金",blank=True,null=True)
     match_status = models.SmallIntegerField(u"比赛状态,退赛/暂停/比赛中-1/0/1",default=0)
+    badge = models.CharField(u"选手标识", max_length=255,blank=False,null=False,default=u"选手")
 
     ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
 
@@ -83,6 +91,13 @@ class PlayerRecord(models.Model):
     yesterday_is_markt = models.SmallIntegerField(u"昨日是否开超市",default=0)
     auto_complete = models.SmallIntegerField(u"请假次数",default=0)
     yesterday_auto_complete = models.SmallIntegerField(u"请假次数",default=0)
+    wanzhu_comment = models.TextField(u"点评",blank=True,null=True)
+    experience = models.TextField(u"操盘总结",blank=True,null=True)
+    zq = models.CharField(u"周期", max_length=255, blank=True, null=True)
+    cw = models.CharField(u"仓位", max_length=255, blank=True, null=True)
+    df = models.CharField(u"打法", max_length=255, blank=True, null=True)
+    pz = models.CharField(u"品种", max_length=255, blank=True, null=True)
+    badge = models.CharField(u"选手标识", max_length=255,blank=False,null=False,default=u"选手")
 
     ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
 
@@ -137,6 +152,9 @@ class Stock(models.Model):
     """
     name = models.CharField(u"名称", max_length=255, blank=True,null=True)
     code = models.CharField(u"代码", max_length=255, blank=True,null=True)
+    img = models.TextField(u"封面图",blank=True,null=True)                       
+    desc = models.TextField(u"内容",blank=True,null=True)                       
+    user_num = models.IntegerField(u"排序字段",blank=False,null=False,default=0)
 
     ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
 
@@ -215,6 +233,8 @@ class OperationLog(models.Model):
 class Article(models.Model):                                                       
     # 基础属性                                                                     
     name = models.CharField(u"标题", max_length=255, blank=True,null=True)         
+    type = models.CharField(u"类型", max_length=255, blank=True,null=True)         
+    img = models.TextField(u"封面图",blank=True,null=True)                       
     content = models.TextField(u"内容",blank=True,null=True)                       
     status = models.SmallIntegerField(u"下线/上线/编辑中-1/2/1",default=1)
                                                                                    
@@ -237,3 +257,83 @@ class test(models.Model):
         db_table = "test"                                                       
         verbose_name = u"测试表"                                                 
         app_label = "common"                                                                                                                                                                                                                                                  
+
+class UserFollows(models.Model):
+    """用户关注表
+    """
+    user_id = models.IntegerField(u"选手id", blank=True,null=True)
+    follow_id = models.IntegerField(u"被关注选手id", blank=True,null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "user_follows"
+        verbose_name = u"用户关注表"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.user_id)
+
+
+class UserStock(models.Model):
+    """选手持股情况
+    """
+    player_id = models.IntegerField(u"选手id", blank=True,null=True)
+    stock_id = models.IntegerField(u"股票id", blank=True,null=True)
+    stock_date = models.CharField(u"持股日期", max_length=255,blank=True,null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "user_stock"
+        verbose_name = u"选手持股"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+
+class WinDefendRank(models.Model):
+    """胜率榜
+    """
+    match_id = models.IntegerField(u"选手id", blank=True,null=True)
+    match_group = models.CharField(u"比赛分组", max_length=255,blank=True,null=True)
+    user_id = models.IntegerField(u"用户id", blank=True,null=True)
+    player_id = models.IntegerField(u"选手id", blank=True,null=True)
+    username = models.CharField(u"用户名", max_length=255, blank=True,null=True)
+    today_fund = models.FloatField(u"资产",blank=True,null=True)
+    total_income = models.FloatField(u"总收益",blank=True,null=True)
+    win_rate = models.FloatField(u"胜率",blank=True,null=True)
+    badest_income = models.FloatField(u"最大回撤",blank=True,null=True)
+    zq = models.CharField(u"周期", max_length=255, blank=True, null=True)
+    cw = models.CharField(u"仓位", max_length=255, blank=True, null=True)
+    df = models.CharField(u"打法", max_length=255, blank=True, null=True)
+    pz = models.CharField(u"品种", max_length=255, blank=True, null=True)
+
+    ctime = models.DateTimeField(u"创建时间", auto_now_add=True)
+
+    class Meta:
+        db_table = "win_defend_rank"
+        verbose_name = u"胜率防守榜"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.id, self.username)
+
+
+class HotStockSellCount(models.Model):
+    """热门清仓
+    """
+    stock_id = models.IntegerField(u"股票id", blank=True,null=True)
+    stock_name = models.CharField(u"股票名称", blank=True,null=True,max_length=255)
+    stock_date = models.CharField(u"持股日期", max_length=255,blank=True,null=True)
+    seller_ids = models.TextField(u"清仓选手id",blank=True,null=True)
+    count = models.IntegerField(u"清仓人数",default=1)
+
+    class Meta:
+        db_table = "hot_stock_seller"
+        verbose_name = u"热门清仓"
+        app_label = "common"
+
+    def __str__(self):
+        return u"{}){}".format(self.stock_id, self.stock_name)

+ 263 - 0
src/manage/WXBizMsgCrypt.py

@@ -0,0 +1,263 @@
+#!/usr/bin/env python
+#-*- encoding:utf-8 -*-
+
+""" 对公众平台发送给公众账号的消息加解密示例代码.
+@copyright: Copyright (c) 1998-2014 Tencent Inc.
+
+"""
+# ------------------------------------------------------------------------
+
+import base64
+import string
+import random
+import hashlib
+import time
+import struct
+from Crypto.Cipher import AES
+import xml.etree.cElementTree as ET
+import sys
+import socket
+reload(sys)
+import ierror
+sys.setdefaultencoding('utf-8')
+
+"""
+关于Crypto.Cipher模块,ImportError: No module named 'Crypto'解决方案
+请到官方网站 https://www.dlitz.net/software/pycrypto/ 下载pycrypto。
+下载后,按照README中的“Installation”小节的提示进行pycrypto安装。
+"""
+class FormatException(Exception):
+    pass
+
+def throw_exception(message, exception_class=FormatException):
+    """my define raise exception function"""
+    raise exception_class(message)
+
+class SHA1:
+    """计算公众平台的消息签名接口"""
+
+    def getSHA1(self, token, timestamp, nonce, encrypt):
+        """用SHA1算法生成安全签名
+        @param token:  票据
+        @param timestamp: 时间戳
+        @param encrypt: 密文
+        @param nonce: 随机字符串
+        @return: 安全签名
+        """
+        try:
+            sortlist = [token, timestamp, nonce, encrypt]
+            sortlist.sort()
+            sha = hashlib.sha1()
+            sha.update("".join(sortlist))
+            return  ierror.WXBizMsgCrypt_OK, sha.hexdigest()
+        except Exception,e:
+            #print e
+            return  ierror.WXBizMsgCrypt_ComputeSignature_Error, None
+
+
+class XMLParse:
+    """提供提取消息格式中的密文及生成回复消息格式的接口"""
+
+    # xml消息模板
+    AES_TEXT_RESPONSE_TEMPLATE = """<xml>
+<Encrypt><![CDATA[%(msg_encrypt)s]]></Encrypt>
+<MsgSignature><![CDATA[%(msg_signaturet)s]]></MsgSignature>
+<TimeStamp>%(timestamp)s</TimeStamp>
+<Nonce><![CDATA[%(nonce)s]]></Nonce>
+</xml>"""
+
+    def extract(self, xmltext):
+        """提取出xml数据包中的加密消息
+        @param xmltext: 待提取的xml字符串
+        @return: 提取出的加密消息字符串
+        """
+        try:
+            xml_tree = ET.fromstring(xmltext)
+            encrypt  = xml_tree.find("Encrypt")
+            print encrypt
+            touser_name    = xml_tree.find("ToUserName")
+            return  ierror.WXBizMsgCrypt_OK, encrypt.text, touser_name.text if touser_name else ""
+        except Exception,e:
+            print e
+            return  ierror.WXBizMsgCrypt_ParseXml_Error,None,None
+
+    def generate(self, encrypt, signature, timestamp, nonce):
+        """生成xml消息
+        @param encrypt: 加密后的消息密文
+        @param signature: 安全签名
+        @param timestamp: 时间戳
+        @param nonce: 随机字符串
+        @return: 生成的xml字符串
+        """
+        resp_dict = {
+                    'msg_encrypt' : encrypt,
+                    'msg_signaturet': signature,
+                    'timestamp'    : timestamp,
+                    'nonce'        : nonce,
+                     }
+        resp_xml = self.AES_TEXT_RESPONSE_TEMPLATE % resp_dict
+        return resp_xml
+
+
+class PKCS7Encoder():
+    """提供基于PKCS7算法的加解密接口"""
+
+    block_size = 32
+    def encode(self, text):
+        """ 对需要加密的明文进行填充补位
+        @param text: 需要进行填充补位操作的明文
+        @return: 补齐明文字符串
+        """
+        text_length = len(text)
+        # 计算需要填充的位数
+        amount_to_pad = self.block_size - (text_length % self.block_size)
+        if amount_to_pad == 0:
+            amount_to_pad = self.block_size
+        # 获得补位所用的字符
+        pad = chr(amount_to_pad)
+        return text + pad * amount_to_pad
+
+    def decode(self, decrypted):
+        """删除解密后明文的补位字符
+        @param decrypted: 解密后的明文
+        @return: 删除补位字符后的明文
+        """
+        pad = ord(decrypted[-1])
+        if pad<1 or pad >32:
+            pad = 0
+        return decrypted[:-pad]
+
+
+class Prpcrypt(object):
+    """提供接收和推送给公众平台消息的加解密接口"""
+
+    def __init__(self,key):
+        #self.key = base64.b64decode(key+"=")
+        self.key = key
+        # 设置加解密模式为AES的CBC模式
+        self.mode = AES.MODE_CBC
+
+
+    def encrypt(self,text,appid):
+        """对明文进行加密
+        @param text: 需要加密的明文
+        @return: 加密得到的字符串
+        """
+        # 16位随机字符串添加到明文开头
+        text = self.get_random_str() + struct.pack("I",socket.htonl(len(text))) + text + appid
+        # 使用自定义的填充方式对明文进行补位填充
+        pkcs7 = PKCS7Encoder()
+        text = pkcs7.encode(text)
+        # 加密
+        cryptor = AES.new(self.key,self.mode,self.key[:16])
+        try:
+            ciphertext = cryptor.encrypt(text)
+            # 使用BASE64对加密后的字符串进行编码
+            return ierror.WXBizMsgCrypt_OK, base64.b64encode(ciphertext)
+        except Exception,e:
+            #print e
+            return  ierror.WXBizMsgCrypt_EncryptAES_Error,None
+
+    def decrypt(self,text,appid):
+        """对解密后的明文进行补位删除
+        @param text: 密文
+        @return: 删除填充补位后的明文
+        """
+        try:
+            cryptor = AES.new(self.key,self.mode,self.key[:16])
+            # 使用BASE64对密文进行解码,然后AES-CBC解密
+            plain_text  = cryptor.decrypt(base64.b64decode(text))
+        except Exception,e:
+            print e
+            return  ierror.WXBizMsgCrypt_DecryptAES_Error,None
+        try:
+            pad = ord(plain_text[-1])
+            # 去掉补位字符串
+            #pkcs7 = PKCS7Encoder()
+            #plain_text = pkcs7.encode(plain_text)
+            # 去除16位随机字符串
+            content = plain_text[16:-pad]
+            xml_len = socket.ntohl(struct.unpack("I",content[ : 4])[0])
+            xml_content = content[4 : xml_len+4]
+            from_appid = content[xml_len+4:]
+            print from_appid
+            print xml_content
+        except Exception,e:
+            print e
+            return  ierror.WXBizMsgCrypt_IllegalBuffer,None
+        if from_appid != appid:
+            print 4444444444444
+            return ierror.WXBizMsgCrypt_ValidateAppid_Error,None
+        return 0,xml_content
+
+    def get_random_str(self):
+        """ 随机生成16位字符串
+        @return: 16位字符串
+        """
+        rule = string.letters + string.digits
+        str = random.sample(rule, 16)
+        return "".join(str)
+
+class WXBizMsgCrypt(object):
+    #构造函数
+    #@param sToken: 公众平台上,开发者设置的Token
+    # @param sEncodingAESKey: 公众平台上,开发者设置的EncodingAESKey
+    # @param sAppId: 企业号的AppId
+    def __init__(self,sToken,sEncodingAESKey,sAppId):
+        try:
+            self.key = base64.b64decode(sEncodingAESKey+"=")
+            assert len(self.key) == 32
+        except:
+            throw_exception("[error]: EncodingAESKey unvalid !", FormatException)
+           #return ierror.WXBizMsgCrypt_IllegalAesKey)
+        self.token = sToken
+        self.appid = sAppId
+
+    def EncryptMsg(self, sReplyMsg, sNonce, timestamp = None):
+        #将公众号回复用户的消息加密打包
+        #@param sReplyMsg: 企业号待回复用户的消息,xml格式的字符串
+        #@param sTimeStamp: 时间戳,可以自己生成,也可以用URL参数的timestamp,如为None则自动用当前时间
+        #@param sNonce: 随机串,可以自己生成,也可以用URL参数的nonce
+        #sEncryptMsg: 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
+        #return:成功0,sEncryptMsg,失败返回对应的错误码None
+        pc = Prpcrypt(self.key)
+        ret,encrypt = pc.encrypt(sReplyMsg, self.appid)
+        if ret != 0:
+            return ret,None
+        if timestamp is None:
+            timestamp = str(int(time.time()))
+        # 生成安全签名
+        sha1 = SHA1()
+        ret,signature = sha1.getSHA1(self.token, timestamp, sNonce, encrypt)
+        if ret != 0:
+            return ret,None
+        xmlParse = XMLParse()
+        return ret,xmlParse.generate(encrypt, signature, timestamp, sNonce)
+
+    def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):
+        # 检验消息的真实性,并且获取解密后的明文
+        # @param sMsgSignature: 签名串,对应URL参数的msg_signature
+        # @param sTimeStamp: 时间戳,对应URL参数的timestamp
+        # @param sNonce: 随机串,对应URL参数的nonce
+        # @param sPostData: 密文,对应POST请求的数据
+        #  xml_content: 解密后的原文,当return返回0时有效
+        # @return: 成功0,失败返回对应的错误码
+         # 验证安全签名
+        xmlParse = XMLParse()
+        print sPostData
+        ret,encrypt,touser_name = xmlParse.extract(sPostData)
+        print ret,encrypt,touser_name
+        if ret != 0:
+            return ret, None
+        sha1 = SHA1()
+        ret,signature = sha1.getSHA1(self.token, sTimeStamp, sNonce, encrypt)
+        print ret,signature,333333333333333
+        if ret  != 0:
+            return ret, None
+        if not signature == sMsgSignature:
+            return ierror.WXBizMsgCrypt_ValidateSignature_Error, None
+        pc = Prpcrypt(self.key)
+        print 777777777777
+        ret,xml_content = pc.decrypt(encrypt,self.appid)
+        return ret,xml_content
+

+ 13 - 0
src/manage/controls.py

@@ -220,6 +220,8 @@ def update_model(cls,**kwargs):
 
         #更新group_rank
         update_group_rank_day(obj.match_id,obj.match_group,obj.stock_date)
+    if model_name == "UserInfo":
+        ccc.del_cache("cdata_get_user_info_(%s,)"%id)
 
     return rst
 
@@ -352,6 +354,10 @@ def get_list_info(cls,**kwargs):
             else:
                 qset = qset.filter(auto_complete=kwargs.get("auto_complete"))
 
+    if model_name == "Article":
+        if kwargs.get("type"):
+            qset = qset.filter(type=kwargs.get("type"))
+
     if model_name == "PlayerRecord":
         data = list(qset.order_by("-total_income").values())
     else:
@@ -549,3 +555,10 @@ def update_group_rank(stock_date=None):
                 cursor.close()
 
 
+def update_comment(**kwargs):
+    """
+    """
+    id = kwargs.get("id")
+    wanzhu_comment = kwargs.get("wanzhu_comment")
+    cm.PlayerRecord.objects.filter(id=id).update(wanzhu_comment=wanzhu_comment)
+

+ 20 - 0
src/manage/ierror.py

@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#########################################################################
+# Author: jonyqin
+# Created Time: Thu 11 Sep 2014 01:53:58 PM CST
+# File Name: ierror.py
+# Description:定义错误码含义 
+#########################################################################
+WXBizMsgCrypt_OK = 0
+WXBizMsgCrypt_ValidateSignature_Error = -40001
+WXBizMsgCrypt_ParseXml_Error = -40002
+WXBizMsgCrypt_ComputeSignature_Error = -40003
+WXBizMsgCrypt_IllegalAesKey = -40004
+WXBizMsgCrypt_ValidateAppid_Error = -40005
+WXBizMsgCrypt_EncryptAES_Error = -40006
+WXBizMsgCrypt_DecryptAES_Error = -40007
+WXBizMsgCrypt_IllegalBuffer = -40008
+WXBizMsgCrypt_EncodeBase64_Error = -40009
+WXBizMsgCrypt_DecodeBase64_Error = -40010
+WXBizMsgCrypt_GenReturnXml_Error = -40011

+ 7 - 1
src/manage/urls_backstage.py

@@ -5,8 +5,8 @@ from django.conf.urls import url
 from . import views,views_backstage
 
 urlpatterns = [
+    #管理后台
     url(r'^uploadfile$', views.UploadFileView.as_view()),
-
     url(r'^user$', views.UserInfoView.as_view()),
     url(r'^user/list$', views.UserInfoListView.as_view()),
     url(r'^player$', views.PlayerView.as_view()),
@@ -28,6 +28,12 @@ urlpatterns = [
     url(r'^article$', views.ArticleView.as_view()),
     url(r'^article/list$', views.ArticleListView.as_view()),
     url(r'^flushrank$', views.FlushRankView.as_view()),
+    url(r'^stock$', views.StockView.as_view()),
+    url(r'^stock/list$', views.StockListView.as_view()),
+    url(r'^player/record/comment$', views.PlayerRecordCommentView.as_view()),
+
+    url(r'^wxtest$', views.WxTestView.as_view()),
+    url(r'^wxtest/(?P<appid>\w+)/callback$', views.WxTestCallbackView.as_view()),
 
 ]
 

+ 197 - 2
src/manage/views.py

@@ -92,7 +92,7 @@ class UserInfoView(cv.AdminView):
         if mse:
             raise ce.TipException(mse)
         try:
-            need_params.extend(["usercode"])
+            need_params.extend(["usercode","badge","zq","cw","df"])
             vals = ccf.get_need_params(*need_params,**qdata)
             if not vals.get("usercode"):
                 vals["usercode"] = self.gen_code()
@@ -115,7 +115,7 @@ class UserInfoView(cv.AdminView):
         if mse:
             raise ce.TipException(mse)
         try:
-            need_params.extend(["is_bind"])
+            need_params.extend(["is_bind","badge","zq","cw","df"])
             vals = ccf.get_need_params(*need_params,**qdata)
             rst = ctl.update_model(self,**vals)
             return cv.to_suc(rst)
@@ -685,6 +685,7 @@ class ArticleView(cv.AdminView):
         if mse:
             raise ce.TipException(mse)
         try:
+            need_params.extend(["type","img"])
             vals = ccf.get_need_params(*need_params,**qdata)
             rst = ctl.add_model(self,**vals)
             return cv.to_suc(rst)
@@ -704,6 +705,7 @@ class ArticleView(cv.AdminView):
         if mse:
             raise ce.TipException(mse)
         try:
+            need_params.extend(["type","img"])
             vals = ccf.get_need_params(*need_params,**qdata)
             rst = ctl.update_model(self,**vals)
             return cv.to_suc(rst)
@@ -759,3 +761,196 @@ class FlushRankView(cv.AdminView):
         except Exception as e:
             cv.tracefail()
             return cv.to_fail(e)
+
+class StockView(cv.AdminView):
+    def get(self, request):
+        """#赛事详情(平台管理后台)
+        @id:1
+        """
+        qdata = request.json
+        need_params = ["id"]
+        mse = ccf.check_params(*need_params,**qdata)
+        if mse:
+            raise ce.TipException(mse)
+        try:
+            vals = ccf.get_need_params(*need_params,**qdata)
+            rst = ctl.get_detail_info(self,**vals)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+    def post(self,request):
+        """#新增股票(平台管理后台)
+        @name:"赛事名称"
+        @content:"详情"
+        """
+        qdata = request.json
+        need_params = ["name","code"]
+        mse = ccf.check_params(*need_params,**qdata)
+        if mse:
+            raise ce.TipException(mse)
+        try:
+            need_params.extend(["desc","img"])
+            vals = ccf.get_need_params(*need_params,**qdata)
+            rst = ctl.add_model(self,**vals)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+    def put(self,request):
+        """#修改股票(平台管理后台)
+        @id:"1"
+        @name:"名称"
+        @content:"详情"
+        """
+        qdata = request.json
+        need_params = ["id","name","code"]
+        mse = ccf.check_params(*need_params,**qdata)
+        if mse:
+            raise ce.TipException(mse)
+        try:
+            need_params.extend(["desc","img"])
+            vals = ccf.get_need_params(*need_params,**qdata)
+            rst = ctl.update_model(self,**vals)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+    def delete(self,request):
+        """#删除股票(平台管理后台)
+        @id:"1",多个逗号分隔
+        """
+        qdata = request.json
+        need_params = ["id"]
+        mse = ccf.check_params(*need_params,**qdata)
+        if mse:
+            raise ce.TipException(mse)
+        try:
+            vals = ccf.get_need_params(*need_params,**qdata)
+            rst = ctl.delete_model(self,**vals)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+
+class PlayerRecordCommentView(cv.AdminView):
+    def put(self,request):
+        """#顽主点评(平台管理后台)
+        @id:"1"
+        @wanzhu_comment:"顽主点评"
+        """
+        qdata = request.json
+        need_params = ["id","wanzhu_comment"]
+        mse = ccf.check_params(*need_params,**qdata)
+        if mse:
+            raise ce.TipException(mse)
+        try:
+            vals = ccf.get_need_params(*need_params,**qdata)
+            rst = ctl.update_comment(**vals)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+
+class StockListView(cv.AdminView):
+    def get(self, request):
+        """#股票仓库列表(平台管理后台)
+        @name:"用户名"
+        @page:1
+        @page_size:20
+        """
+        qdata = request.json
+        try:
+            total,rst = ctl.get_list_info(self,**qdata)
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+
+class WxTestView(cv.BaseView):
+    def get(self,request):
+        """
+        """
+        return HttpResponse("success")
+
+
+    def get_wx_auth_ticket(self,xml,timestamp,nonce,msg_signature):
+        """获取微信通过授权URL推送的票据
+        """
+        import xml.etree.cElementTree as ET
+        from WXBizMsgCrypt import WXBizMsgCrypt
+        encodingAESKey = "NBFPgHxUIlQ628bYwDJOZQNMp7T1YGykpzzYklo9tmY"
+        token = "1234567890987654321"
+        APPID = "wx02753c07bbfce783"
+
+        decrypt_test = WXBizMsgCrypt(token,encodingAESKey,APPID)
+
+        ret,decryp_xml = decrypt_test.DecryptMsg(xml,msg_signature,timestamp, nonce)
+        if decryp_xml: 
+            xml_tree = ET.fromstring(decryp_xml)
+            print xml_tree,999999999999999
+            ComponentVerifyTicket  = xml_tree.find("ComponentVerifyTicket")
+            return ComponentVerifyTicket
+        return None
+
+    def post(self, request):
+        """#更新排名(平台管理后台)
+        @name:""
+        @page:1
+        @page_size:20
+        """
+        print request.body
+        qdata = request.GET
+        try:
+            postxml = request.body
+            timestamp = request.GET.get("timestamp")
+            nonce = request.GET.get("nonce")
+            msg_signature = request.GET.get("msg_signature")
+            ticket = self.get_wx_auth_ticket(postxml,timestamp,nonce,msg_signature)
+            print "ticket:",ticket
+            return HttpResponse("success")
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+
+class WxTestCallbackView(cv.BaseView):
+    def get(self,request):
+        """
+        """
+        print request.GET
+        print request.REQUEST
+        print request.body
+        return HttpResponse("success")
+
+    def post(self, request,appid):
+        """#更新排名(平台管理后台)
+        @name:""
+        @page:1
+        @page_size:20
+        """
+        print request.POST
+        print 11111111111
+        print request.body
+        print 22222222222222
+        print request.json
+        qdata = request.GET
+        try:
+            openid = qdata.get("openid")
+            from wechatpy import WeChatClient
+            client = WeChatClient("wx84a42c807ed07198", "e2de849dfef826b1854c0b18407a6be2")
+            #client.message.send_mass_text(None,u"欢迎关注四川环宇星创科技有限公司公众号!",True)
+            client.message.send_text(openid,u"点击绑定手机号查看您的电子证书:http://testcaos.tederen.com/zs.jpg")
+
+            return HttpResponse(qdata.get("timestamp"))
+
+            return HttpResponse("success")
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)

+ 1 - 1
src/settings/settings_dev.py

@@ -71,5 +71,5 @@ LOGGING = {
 
 RANK_LIST = "RANK_LIST"
 
-HOST = "https://www.hunanwanzhu.com"
+HOST = "https://wx.scxjc.club"
 PROJECT_NAME = u"顽主杯"

+ 78 - 2
src/tools/rank_server.py

@@ -13,6 +13,7 @@ django.setup()
 
 import common.models as cm
 import common.common_control as ccc
+import common.common_functions as ccf
 
 def rank_server():
     """
@@ -26,10 +27,51 @@ def rank_server():
         if "15:00"<datetime.datetime.now().strftime("%H:%M") < "15:30":
             update_cache_rank(match_id,match_group,stock_date)
         else:
+            update_cache_rank(match_id,match_group,stock_date)
             sync_group_rank(match_id,match_group,stock_date)
+            update_hot_seller(record)
+        #更新胜率榜
+        update_win_defend_rank(record)
 
-def update_cache_rank(match_id,match_group,stock_date):
+def update_win_defend_rank(record):
+    """更新胜率防守榜
     """
+    player_id = record.player_id
+    match_id = record.match_id
+    match_group = record.match_group
+    user_id = record.user_id
+    user_name = record.username
+    today_fund = record.today_fund
+    total_income = record.total_income
+    zq = record.zq
+    cw = record.cw
+    df = record.df
+    pz = record.pz
+    #胜率
+    qset = cm.PlayerRecord.objects.filter(match_id=match_id,player_id=player_id)
+    win_rate = qset.filter(today_income__gt=0).count()/float(qset.count()) if qset else 0.0
+    win_rate = round(win_rate,3)
+    #win_rate = "{}%".format(win_rate*100)
+    #最大回撤
+    badest_income = qset.order_by("today_income").first().today_income
+    badest_income = round(badest_income,3)
+
+    obj,flag = cm.WinDefendRank.objects.get_or_create(
+        user_id = user_id, 
+        player_id = player_id, 
+        match_id = match_id, 
+        match_group = match_group 
+    )
+    obj.user_name = user_name
+    obj.today_fund = today_fund
+    obj.total_income = total_income
+    obj.win_rate = win_rate
+    obj.badest_income = badest_income
+    obj.save()
+
+
+def update_cache_rank(match_id,match_group,stock_date):
+    """更新redis排名数据
     """
     print "update cache rank..."
     delkey = "*_%s_%s_%s" % (match_id,match_group,stock_date)
@@ -51,7 +93,7 @@ def update_cache_rank(match_id,match_group,stock_date):
     ccc.pl.execute()
 
 def sync_group_rank(match_id,match_group,stock_date):
-    """
+    """更新数据库排名数据
     """
     print "sync group rank..."
     delkey = "*_%s_%s_%s" % (match_id,match_group,stock_date)
@@ -84,6 +126,40 @@ def sync_group_rank(match_id,match_group,stock_date):
         cursor.execute(sql)
         cursor.close()
 
+def update_hot_seller(record):
+    """更新热门清仓
+    """
+    stock_date = record.stock_date
+
+    stock_date_time = ccf.str_to_datetime(stock_date,"%Y-%m-%d")
+    yesterday = (stock_date_time - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
+    #昨天所有持股id
+    all_stock_ids = list(cm.UserStock.objects.filter(stock_date=yesterday).values_list("stock_id",flat=True))
+    all_stock_ids = list(set(all_stock_ids))
+    for stock_id in all_stock_ids:
+        print stock_date,stock_id
+        stock = cm.Stock.objects.filter(id=stock_id).first()
+        #昨天持股选手
+        yes_players = list(cm.UserStock.objects.filter(stock_date=yesterday,stock_id=stock_id).values_list("player_id",flat=True))
+        #今天持股选手
+        td_players = list(cm.UserStock.objects.filter(stock_date=stock_date,stock_id=stock_id).values_list("player_id",flat=True))
+
+        if yes_players and td_players:
+            #清仓选手
+            sell_players = list(set(yes_players)-set(td_players))
+            if sell_players:
+                seller_ids = json.dumps(sell_players)
+                count = len(sell_players)
+
+                obj,flag = cm.HotStockSellCount.objects.get_or_create(
+                    stock_id = stock_id, 
+                    stock_name = stock.name, 
+                    stock_date = stock_date
+                )
+                obj.seller_ids = seller_ids
+                obj.count = count
+                obj.save()
+
 if __name__ == "__main__":
     print "start update group rank..."
     while True:

+ 160 - 0
src/tools/sync_data.py

@@ -0,0 +1,160 @@
+#coding:utf-8
+import os,json
+import time
+import datetime
+import sys
+import django
+from django.core.cache import cache
+from django.db import connection
+from django.db.models import Q,Sum,Count,F
+
+sys.path.append('/mnt/wzbapi/src')
+os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
+django.setup()
+
+import common.models as cm
+import common.common_functions as ccf
+
+def sync_stock():
+    """同步用户持股和股票仓库数据
+    """
+    prset = cm.PlayerRecord.objects.order_by("stock_date")
+    for index,pr in enumerate(prset):
+        player_id = pr.player_id
+        match_id = pr.match_id
+        match_group = pr.match_group
+        stock_date = pr.stock_date
+        today_stock = pr.today_stock
+        yesterday_stock = pr.yesterday_stock
+        print pr.username,stock_date
+        
+        today_stock = json.loads(today_stock) if today_stock else []
+        yesterday_stock = json.loads(yesterday_stock) if yesterday_stock else []
+        
+        new_today_stock = []
+        for ts in today_stock:
+            if ts["name"] and ts["fund"]:
+                stock,flag = cm.Stock.objects.get_or_create(name=ts["name"])
+                ts["stock_id"] = stock.id
+                new_today_stock.append(ts)
+                #更新用户持股情况
+                cm.UserStock.objects.get_or_create(
+                    player_id = player_id, 
+                    stock_id = stock.id, 
+                    stock_date = stock_date
+                )
+
+        yes_today_stock = []
+        for ts in yesterday_stock:
+            if ts["name"] and ts["fund"]:
+                stock,flag = cm.Stock.objects.get_or_create(name=ts["name"])
+                ts["stock_id"] = stock.id
+                yes_today_stock.append(ts)
+
+        pr.today_stock = json.dumps(new_today_stock)
+        pr.yesterday_stock = json.dumps(yes_today_stock)
+
+        pr.save()
+
+
+def sync_win_defend():
+    """更新胜率和最大回撤
+    """
+    match_id = 7
+    players = cm.Player.objects.filter(match_id=match_id)
+    for pl in players:
+        record = cm.PlayerRecord.objects.filter(match_id=match_id,player_id=pl.id).order_by("-stock_date").first()
+        if record:
+            print record.username,record.stock_date
+            from threading import Thread
+            t = Thread(target=update_win_defend_rank,args=(record,))
+            t.start()
+
+
+def update_win_defend_rank(record):
+    """更新胜率防守榜
+    """
+    player_id = record.player_id
+    user_id = record.user_id
+    match_id = record.match_id
+    match_group = record.match_group
+    user_name = record.username
+    today_fund = record.today_fund
+    total_income = record.total_income
+    zq = record.zq
+    cw = record.cw
+    df = record.df
+    pz = record.pz
+    #胜率
+    qset = cm.PlayerRecord.objects.filter(match_id=match_id,player_id=player_id)
+    win_rate = qset.filter(today_income__gt=0).count()/float(qset.count()) if qset else 0.0
+    win_rate = round(win_rate,3)
+    #win_rate = "{}%".format(win_rate*100)
+    #最大回撤
+    badest_income = qset.order_by("today_income").first().today_income
+    badest_income = round(badest_income,3)
+
+    obj,flag = cm.WinDefendRank.objects.get_or_create(
+        user_id = user_id, 
+        player_id = player_id, 
+        match_id = match_id, 
+        match_group = match_group 
+    )
+    obj.username = user_name
+    obj.today_fund = today_fund
+    obj.total_income = total_income
+    obj.win_rate = win_rate
+    obj.badest_income = badest_income
+    obj.save()
+
+def sync_hot_seller():
+    """同步热门清仓数据
+    """
+    all_dates = list(cm.UserStock.objects.order_by("stock_date").values_list("stock_date",flat=True))
+    all_dates = list(set(all_dates))
+    all_dates.sort()
+
+    for stock_date in all_dates:
+        stock_date_time = ccf.str_to_datetime(stock_date,"%Y-%m-%d")
+        yesterday = (stock_date_time - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
+        #昨天所有持股id
+        all_stock_ids = list(cm.UserStock.objects.filter(stock_date=yesterday).values_list("stock_id",flat=True))
+        all_stock_ids = list(set(all_stock_ids))
+        for stock_id in all_stock_ids:
+            print stock_date,stock_id
+            stock = cm.Stock.objects.filter(id=stock_id).first()
+            #昨天持股选手
+            yes_players = list(cm.UserStock.objects.filter(stock_date=yesterday,stock_id=stock_id).values_list("player_id",flat=True))
+            #今天持股选手
+            td_players = list(cm.UserStock.objects.filter(stock_date=stock_date,stock_id=stock_id).values_list("player_id",flat=True))
+
+            if yes_players and td_players:
+                #清仓选手
+                sell_players = list(set(yes_players)-set(td_players))
+                if sell_players:
+                    seller_ids = json.dumps(sell_players)
+                    count = len(sell_players)
+
+                    obj,flag = cm.HotStockSellCount.objects.get_or_create(
+                        stock_id = stock_id, 
+                        stock_name = stock.name, 
+                        stock_date = stock_date
+                    )
+                    obj.seller_ids = seller_ids
+                    obj.count = count
+                    obj.save()
+
+
+
+if __name__ == "__main__":
+    print "start sync stock..."
+    st = time.time()
+    sync_stock()
+    sync_win_defend()
+    sync_hot_seller()
+    print "time cost:",time.time()-st
+
+
+
+
+

+ 36 - 3
src/tools/update_group_rank.py

@@ -1,10 +1,9 @@
 #coding:utf-8
-import os
+import os,json
 import time
 import datetime
 import sys
 import django
-import common.common_control as ccc
 from django.db import connection
 
 sys.path.append('/mnt/wzbapi/src')
@@ -12,6 +11,7 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
 django.setup()
 
 import common.models as cm
+import common.common_control as ccc
 
 def update_group_rank(stock_date=None):
     """
@@ -54,11 +54,44 @@ def update_group_rank(stock_date=None):
             cursor.close()
 
 
+def update_group_rank_cache(stock_date=None):
+    """
+    """
+    match_id = 7
+    prset = cm.PlayerRecord.objects.filter(match_id=match_id).order_by("-stock_date")
+    if prset:
+        records = prset.values()
+        case_id = " case id "
+        cases = []
+        where = []
+        for index,pr in enumerate(prset):
+            case = "WHEN %s THEN %s" % (pr.id,index+1)
+            cases.append(case)
+            where.append(str(pr.id))
+
+            record = records[index]
+            #
+            key = "%s_%s_%s_%s" % (pr.player_id,pr.match_id,pr.match_group,pr.stock_date)
+            if pr.player_id == 434:
+                print key
+
+            ccc.pl.set(key,json.dumps(record,cls=ccc.CusJSONEncoder))
+        ccc.pl.execute()
+
+        #case = case_id + " ".join(cases)
+        #where = ",".join(where)
+        #sql = "update player_record set group_rank = %s ELSE 0 END where id in (%s)" % (case,where)
+        #cursor = connection.cursor()
+        #cursor.execute(sql)
+        #cursor.close()
+
+
 
 if __name__ == "__main__":
     print "start update group rank..."
     st = time.time()
-    update_group_rank()
+    #update_group_rank()
+    update_group_rank_cache()
     print "time cost:",time.time()-st
 
 

+ 7 - 1
src/weixin/control_auth.py

@@ -32,9 +32,15 @@ def get_wxauth_info(request):
     """
     #
     uid = request.user.id
-    print uid
+    player = request.player
     user = cm.UserInfo.objects.filter(id=uid).values().first()
     user["nickname"] = user["username"]
+    #
+    #if not user["zq"] or not user["cw"] or not user["df"] or not player.fund:
+    if not player.fund:
+        user["need_fill"] = 1
+    else:
+        user["need_fill"] = 0
     return user
 
 

+ 720 - 33
src/weixin/controls.py

@@ -20,13 +20,14 @@ from utils.jgpush import send_notification_by_registration_ids
 import wzhifuSDK as wxpay
 from utils.exceltool import ExcelTool
 from utils.qrcodetool import gen_general_qrcode
-from django.db.models import Q,Sum,Count
+from django.db.models import Q,Sum,Count,F
 from PIL import Image
 from PIL import Image,ImageDraw,ImageFont
 from django.db import transaction
 from threading import Thread
 #from django.core.cache import cache
 from django.db import connection
+import calendar
 
 import xlrd
 import xlwt
@@ -43,6 +44,7 @@ def async(f):
 
 
 def get_today_date():
+    return '2021-11-25'
     if datetime.datetime.now().strftime("%H:%M") < "15:00":
         if datetime.datetime.now().weekday() in [5,6] or datetime.datetime.now().strftime("%Y-%m-%d") in MISS_DATES:
             today = cm.PlayerRecord.objects.all().order_by("-stock_date").first().stock_date
@@ -79,7 +81,7 @@ def update_group_rank(match_id,match_group,stock_date):
 def get_notices():
     """
     """
-    notices = list(cm.Article.objects.filter(status=2).values())
+    notices = list(cm.Article.objects.filter(status=2,type="notice").values())
     return notices
 
 def get_index_data(request):
@@ -159,9 +161,11 @@ def get_player_match_detail(request):
     """
     qdata = request.json
     player_id = request.player.id
+    org_player_id = request.player.id
     match_group = request.player.match_group
     match_id = qdata.get("id")
     record_id = qdata.get("record_id")
+
     if record_id:
         records_set = cm.PlayerRecord.objects.filter(id=record_id)
         match_id = records_set.first().match_id
@@ -169,18 +173,21 @@ def get_player_match_detail(request):
         player_id = records_set.first().player_id
         records_set = cm.PlayerRecord.objects.filter(player_id=player_id,match_id=match_id).order_by("-stock_date")
     else:
+        if qdata.get("player_id"):
+            player_id = qdata.get("player_id")
+            match_group = cm.Player.objects.filter(id=player_id).first().match_group
         records_set = cm.PlayerRecord.objects.filter(player_id=player_id,match_id=match_id).order_by("-stock_date")
 
+
     match = cm.Match.objects.filter(id=match_id).values().first()
     groups = list(cm.MatchGroup.objects.filter(match_id=match_id).values_list("name",flat=True))
     match["groups"] = groups
     if records_set:
-        #today_record = records_set.values().first()
         records = list(records_set.values())
     else:
-        #today_record = {}
         records = []
-    today = get_today_date()
+
+    today = records_set.first().stock_date
     today_record = get_today_record(player_id,int(match_id),int(match_group),today)
 
     for item in records:
@@ -191,31 +198,56 @@ def get_player_match_detail(request):
         item["today_income"] = "{}%".format(item["today_income"]*100)
         item["total_income"] = "{}%".format(item["total_income"]*100)
     if today_record:
+        today_record["today_stock_img"] = json.loads(today_record["today_stock_img"]) if today_record["today_stock_img"] else []
+        today_record["today_stock"] = json.loads(today_record["today_stock"]) if today_record["today_stock"] else []
         today_record["today_income"] = "{}%".format(today_record["today_income"]*100)
         today_record["total_income"] = "{}%".format(today_record["total_income"]*100)
         today_record["match_group_name"] = cm.MatchGroup.objects.filter(id=today_record["match_group"]).first().name
+        today_record["players_num"] = cm.Player.objects.filter(match_group=today_record["match_group"]).count()
+        today_record["win_rate"] = calc_win_rate(player_id,today_record["match_id"])
+        badest = cm.PlayerRecord.objects.filter(player_id=player_id,match_id=match_id).order_by("today_income").first()
+        if badest:
+            today_record["badest_income"] = "{}%".format(badest.today_income*100)
+
     match["groups"] = [today_record["match_group_name"]] if today_record else []
-    records = sorted(records,key=lambda x:x["stock_date"],reverse=True)
-    ret = {"match":match,"today_record":today_record,"records":records}
+    records = sorted(records,key=lambda x:x["stock_date"],reverse=True)[:5]
+    if cm.UserFollows.objects.filter(user_id=org_player_id,follow_id=player_id).exists():
+        is_follow = 1
+    else:
+        is_follow = 0
+    ret = {"match":match,"today_record":today_record,"records":records,"is_follow":is_follow}
 
     return ret
 
 
-#@ccc.cache_data()
-#def get_today_record(player_id,match_id,match_group,today):
-#    records_set = cm.PlayerRecord.objects.filter(player_id=player_id,match_id=match_id,match_group=match_group,stock_date=today)
-#    if records_set:
-#        today_record = records_set.values().first()
-#    else:
-#        today_record = {}
-#    return today_record
-
 def get_today_record(player_id,match_id,match_group,today):
     """
     """
     key = "%s_%s_%s_%s" % (player_id,match_id,match_group,today)
     today_record = ccc.cache.get(key)
     today_record = json.loads(today_record) if today_record else {}
+
+    try:
+        if today_record:
+            user_info = get_user_info(today_record["user_id"])
+            if user_info:
+                user_info.pop("id")
+                today_record.update(user_info)
+
+            #仓位
+            today_stock_total = 0
+            today_stock = json.loads(today_record["today_stock"])
+            for ts in today_stock:
+                if ts["fund"]:
+                    try:
+                        today_stock_total += float(ts["fund"])
+                    except Exception as e:
+                        print e
+            today_record["cangwei"] = "{}%".format(round(today_stock_total/today_record["today_fund"],4)*100)
+            today_record["today_stock_total"] = today_stock_total
+    except Exception as e:
+        import traceback
+        traceback.print_exc()
     return today_record
 
 @ccc.cache_data()
@@ -232,7 +264,7 @@ def get_match_groups(match_id):
     return match,groups
 
 #@ccc.cache_data()
-def get_cache_rank_list(player_id,match_id):
+def get_cache_rank_list(player_id,match_id,today):
     """
     """
     match,groups = get_match_groups(match_id)
@@ -241,7 +273,6 @@ def get_cache_rank_list(player_id,match_id):
     #    today = (datetime.datetime.now()-datetime.timedelta(days=1)).strftime("%Y-%m-%d")
     #else:
     #    today = datetime.datetime.now().strftime("%Y-%m-%d")
-    today = get_today_date()
 
     for item in groups:
         new_players = []
@@ -257,13 +288,21 @@ def get_cache_rank_list(player_id,match_id):
             if today_record:
                 player.update(today_record)
                 player["username"] = username
+                player["org_today_income"] = player["today_income"]
                 player["total_income"] = "{}%".format(today_record["total_income"]*100)
+                player["today_income"] = "{}%".format(today_record["today_income"]*100)
 
                 player["fund"] = round(player["fund"],4)
                 player["init_fund"] = round(player["init_fund"],4)
                 player["today_fund"] = round(player["today_fund"],4)
                 new_players.append(player)
         new_players = sorted(new_players,key=lambda x:x["group_rank"])
+        win_count = filter(lambda x:x["org_today_income"]>=0.05,new_players)
+        loss_count = filter(lambda x:x["org_today_income"]<=-0.05,new_players)
+        #item["players_num"] = cm.Player.objects.filter(match_group=item["id"]).count()
+        item["players_num"] = len(players)
+        item["win_count"] = len(win_count)
+        item["loss_count"] = len(loss_count)
         item["players"] = new_players[:3]
     return match,groups
 
@@ -274,7 +313,9 @@ def get_rank_list(request):
     qdata = request.json
     player_id = request.player.id
     match_id = request.player.match_id
-    match,groups = get_cache_rank_list(player_id,match_id)
+    today = qdata.get("stock_date")
+
+    match,groups = get_cache_rank_list(player_id,match_id,today)
 
     ret = {"match":match,"groups":groups}
 
@@ -284,6 +325,14 @@ def get_rank_list(request):
 @ccc.cache_data()
 def get_user_info(uid):
     user = cm.UserInfo.objects.filter(id=uid).values().first()
+    if user:
+        user["style"] = []
+        if user["zq"]:
+            user["style"].append(user["zq"])
+        if user["cw"]:
+            user["style"].append(user["cw"])
+        if user["df"]:
+            user["style"].append(user["df"])
     return user
 
 @ccc.cache_data()
@@ -294,6 +343,7 @@ def get_match_info(match_id):
 @ccc.cache_data()
 def get_group_info(group_id):
     group = cm.MatchGroup.objects.filter(id=group_id).values().first()
+    group["players_num"] = cm.Player.objects.filter(match_group=group["id"]).count()
     return group
 
 
@@ -306,17 +356,11 @@ def get_group_rank_list(request):
     group_id = qdata.get("id")
     player_id = request.player.id
     match_id = request.player.match_id
+    today = qdata.get("stock_date")
 
     match = get_match_info(match_id)
     group = get_group_info(group_id)
 
-    #if datetime.datetime.now().hour < 15:
-    #    today = (datetime.datetime.now()-datetime.timedelta(days=1)).strftime("%Y-%m-%d")
-    #else:
-    #    today = datetime.datetime.now().strftime("%Y-%m-%d")
-
-    today = get_today_date()
-    #players = list(cm.Player.objects.filter(match_id=match_id,match_group=group_id).values())
     players = get_match_group_players(match_id,group_id)
     new_players = []
     for player in players:
@@ -331,12 +375,24 @@ def get_group_rank_list(request):
         if today_record:
             player.update(today_record)
             player["username"] = username
+            player["org_today_income"] = player["today_income"]
+            player["org_total_income"] = player["total_income"]
             player["total_income"] = "{}%".format(player["total_income"]*100)
+            player["today_income"] = "{}%".format(player["today_income"]*100)
             player["fund"] = round(player["fund"],4)
             player["init_fund"] = round(player["init_fund"],4)
             player["today_fund"] = round(player["today_fund"],4)
             new_players.append(player)
-    new_players = sorted(new_players,key=lambda x:x["group_rank"])
+    if kwargs.get("order_by") == "today_income__asc":
+        new_players = sorted(new_players,key=lambda x:x["org_today_income"])
+    elif kwargs.get("order_by") == "today_income__desc" :
+        new_players = sorted(new_players,key=lambda x:x["org_today_income"],reverse=True)
+    elif kwargs.get("order_by") == "total_income__asc": 
+        new_players = sorted(new_players,key=lambda x:x["org_total_income"])
+    elif kwargs.get("order_by") == "total_income__desc": 
+        new_players = sorted(new_players,key=lambda x:x["org_total_income"],reverse=True)
+    else:
+        new_players = sorted(new_players,key=lambda x:x["group_rank"])
 
     #分页
     page = int(kwargs.get("page",0))
@@ -346,7 +402,16 @@ def get_group_rank_list(request):
         total,new_players = ccf.get_page_list(new_players,page,page_size)
     else:
         total = len(new_players)
-    ret = {"group":group,"players":new_players,"total":total}
+    #应到、实到、请假人数
+    total_person = cm.Player.objects.filter(match_group=group_id,match_status=1).count()
+    actual_person = cm.PlayerRecord.objects.filter(match_group=group_id,stock_date=today).count()
+    leave_person = total_person - actual_person
+
+    win_person = cm.PlayerRecord.objects.filter(match_group=group_id,stock_date=today,total_income__gte=0).count()
+    loss_person = cm.PlayerRecord.objects.filter(match_group=group_id,stock_date=today,total_income__lt=0).count()
+
+    ret = {"group":group,"players":new_players,"total":total,"total_person":total_person,
+        "actual_person":actual_person,"leave_person":leave_person,"win_person":win_person,"loss_person":loss_person}
 
     return ret
 
@@ -423,6 +488,11 @@ def add_model(cls,**kwargs):
         username = user.username
         usercode = user.usercode
         match_group = player.match_group
+        zq = user.zq
+        cw = user.cw
+        df = user.df
+        badge = player.badge
+
         match = cm.Match.objects.filter(id=match_id).first()
         if player.match_status < 1:
             raise ce.TipException(u"该账号已暂停/退出比赛,如有疑问请联系管理员获取详情信息!")
@@ -445,6 +515,24 @@ def add_model(cls,**kwargs):
             yesterday_stock_img = "" 
             yesterday_is_markt = 0
         with transaction.atomic():
+            #记录持股情况
+            new_stock_list = []
+            today_stock_list = json.loads(today_stock)
+            for ts in today_stock_list:
+                if ts["name"]:
+                    stock,flag = cm.Stock.objects.get_or_create(
+                        name = ts["name"] 
+                    )
+                    stock_id = stock.id
+                    usobj,flag = cm.UserStock.objects.get_or_create(
+                        player_id = player_id, 
+                        stock_id = stock_id,
+                        stock_date = stock_date
+                    )
+                    ts["stock_id"] = stock_id
+                    new_stock_list.append(ts)
+            today_stock = json.dumps(new_stock_list)
+
             obj,flag = cm.PlayerRecord.objects.get_or_create(
                             player_id=player_id,
                             match_id=match_id,
@@ -462,6 +550,10 @@ def add_model(cls,**kwargs):
             obj.match_group = match_group
             obj.is_markt = is_markt
             obj.yesterday_is_markt = yesterday_is_markt
+            obj.zq = zq
+            obj.cw = cw
+            obj.df = df
+            obj.badge = badge
             #计算今日和昨日盈亏
             if float(today_fund)>9999 or float(today_fund)<=0:                              
                 raise ce.TipException(u"数据错误,今日净资产不能超过9999万元,不能低于0万元,请仔细核对数据!")                                                                                                                                                                       
@@ -477,8 +569,11 @@ def add_model(cls,**kwargs):
                 obj.ctime = datetime.datetime.now()
             obj.save()
 
+            #更新股票持股人数
+            for stock in new_stock_list:
+                cm.Stock.objects.filter(id=stock["stock_id"]).update(user_num=F("user_num")+1)
+
             #更新group_rank
-            #update_group_rank(match_id,match_group,obj.stock_date)
             ccc.cache.lpush(settings.RANK_LIST,obj.id)
             return obj.id
 
@@ -515,14 +610,21 @@ def get_search_list(cls,**kwargs):
     model_name = re.search(r'.*\.(\w+)SearchView',str(cls.__class__)).groups()[0]
     model = getattr(cm,model_name)
     qset = model.objects.all()
-    if kwargs.get("name"):
-        qset = qset.filter(name__icontains=kwargs.get("name"))
+    if model_name == "Stock":
+        if kwargs.get("name"):
+            qset = qset.filter(Q(name__icontains=kwargs.get("name"))|Q(code__icontains=kwargs.get("name")))
+    else:
+        if kwargs.get("name"):
+            qset = qset.filter(name__icontains=kwargs.get("name"))
     if model_name == "Player":
         data = list(qset.values("id","username"))
     if model_name == "Stock":
         data = list(qset.values("id","name","code"))
         for item in data:
-            item["label"] = "%s(%s)" % (item["name"],item["code"])
+            if item["code"]:
+                item["label"] = "%s(%s)" % (item["name"],item["code"])
+            else:
+                item["label"] = "%s" % item["name"]
     else:
         data = list(qset.values("id","name"))
     return data
@@ -552,6 +654,8 @@ def get_detail_info(cls,**kwargs):
 
     #    rst["today_income"] = "{}%".format(rst["today_income"]*100)
     #    rst["total_income"] = "{}%".format(rst["total_income"]*100)
+    if model_name == "Article":
+        rst["ctime"] = ccf.datetime_to_str(rst["ctime"],"%Y-%m-%d")
     return rst
 
 #@ccc.cache_data()
@@ -656,6 +760,25 @@ def add_player_record_single(**kwargs):
         yesterday_fund = init_fund 
         yesterday_stock = ""
         yesterday_stock_img = "" 
+
+    #记录持股情况
+    new_stock_list = []
+    today_stock_list = json.loads(today_stock)
+    for ts in today_stock_list:
+        if ts["name"]:
+            stock,flag = cm.Stock.objects.get_or_create(
+                name = ts["stock"] 
+            )
+            stock_id = stock.id
+            usobj,flag = cm.UserStock.objects.get_or_create(
+                player_id = player_id, 
+                stock_id = stock_id,
+                stock_date = stock_date
+            )
+            ts["stock_id"] = stock_id
+            new_stock_list.append(ts)
+    today_stock = json.dumps(new_stock_list)
+
     obj,flag = cm.PlayerRecord.objects.get_or_create(
                     player_id=player_id,
                     match_id=match_id,
@@ -676,15 +799,20 @@ def add_player_record_single(**kwargs):
     today_income = (today_fund - yesterday_fund)/float(yesterday_fund)
     total_income = (today_fund - init_fund)/float(init_fund)
     if int(today_fund)>9999 or int(today_fund)<0:                              
-        raise ce.TipException(u"数据错误,今日净资产不能超过9999万元,不能低于0万元,请仔细核对数据!")                                                                                                                                                                       
+        raise ce.TipException(u"数据错误,今日净资产不能超过9999万元,不能低于0万元,请仔细核对数据!") 
     if int(today_income)>2:                                                    
         raise ce.TipException(u"数据错误,今日盈利已超过2倍,请仔细核对数据!")
+
     obj.today_income = round(today_income,4)
     obj.total_income = round(total_income,4)
     if not flag:
         obj.ctime = datetime.datetime.now()
     obj.save()
 
+    #更新股票持股人数
+    for stock in new_stock_list:
+        cm.Stock.objects.filter(id=stock["id"]).update(user_num=F("user_num")+1)
+
     #更新group_rank
     #update_group_rank(match_id,match_group,obj.stock_date)
     ccc.cache.lpush(settings.RANK_LIST,obj.id)
@@ -719,3 +847,562 @@ def get_cur_record(request):
         data["today_stock"] = json.loads(data["today_stock"]) if data["today_stock"] else []
     return data
 
+
+def follow_player(**kwargs):
+    """
+    """
+    user_id = kwargs.get("player_id")
+    follow_id = kwargs.get("follow_id")
+    if kwargs.get("action") == "cancel":
+        cm.UserFollows.objects.filter(user_id=user_id,follow_id=follow_id).delete()
+        return True
+    else:
+        obj,flag = cm.UserFollows.objects.get_or_create(user_id=user_id,follow_id=follow_id)
+        return obj.id
+
+def calc_win_rate(player_id,match_id):
+    """计算胜率
+    """
+    qset = cm.PlayerRecord.objects.filter(match_id=match_id,player_id=player_id)
+    win_rate = qset.filter(today_income__gte=0).count()/float(qset.count()) if qset else 0.0
+    win_rate = round(win_rate,3)
+    win_rate = "{}%".format(win_rate*100)
+    return win_rate
+
+
+def get_user_follows(request):
+    """获取用户关注的选手列表
+    """
+    user_id = request.player.id
+    print user_id
+    match_id = request.player.match_id
+    match_group = request.player.match_group
+    qdata = request.json
+    today = get_today_date()
+    print today
+
+    data = []
+
+    qset = cm.UserFollows.objects.filter(user_id=user_id)
+    follow_ids = list(qset.values_list("follow_id",flat=True))
+
+    for player_id in follow_ids:
+        last = cm.PlayerRecord.objects.filter(player_id=player_id,match_id=match_id).order_by("-stock_date").first()
+        if last:
+            today = last.stock_date
+
+            today_record = get_today_record(player_id,match_id,last.match_group,today)
+            if today_record:
+                data.append(today_record)
+    data = sorted(data,key=lambda x:x["group_rank"])
+    page = int(qdata.get("page",1))
+    page_size = int(qdata.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+        for item in data:
+            item["today_stock"] = json.loads(item["today_stock"])
+            item["today_stock_img"] = json.loads(item["today_stock_img"])
+            item["win_rate"] = calc_win_rate(item["player_id"],item["match_id"])
+            item["today_income"] = "{}%".format(item["today_income"]*100)
+            item["total_income"] = "{}%".format(item["total_income"]*100)
+        return total,data
+    else:
+        return len(data),data
+
+
+def get_hot_stock_rank(**kwargs):
+    """
+    """
+    data = {
+            "hot_buy":[
+                {"stock_name":u"创业黑马","count":12} 
+            ],
+            "hot_sell":[
+                {"stock_name":u"创业黑马","count":12} 
+            ]
+        }
+    return data
+
+
+def get_hot_stock_buy(**kwargs):
+    """
+    """
+    stock_date = kwargs.get("stock_date")
+    qset = cm.UserStock.objects.filter(stock_date=stock_date)
+    qset = qset.values("stock_id").annotate(count=Count("stock_id")).order_by("-count")
+    data = []
+    for q in qset:
+        stock_id = q["stock_id"]
+        count = q["count"]
+        data.append(
+            {
+                "stock_name":cm.Stock.objects.filter(id=stock_id).first().name,
+                "count":count,
+                "id":stock_id
+            } 
+        )
+
+    if kwargs.get("name"):
+        data = filter(lambda x:kwargs.get("name") in x["stock_name"],data)
+
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+        return total,data
+    else:
+        return len(data),data
+    return data
+
+
+def get_hot_follow(**kwargs):
+    """
+    """
+    stock_date = kwargs.get("stock_date")
+    #qset = cm.UserFollows.objects.filter(stock_date=stock_date)
+    qset = cm.UserFollows.objects.all()
+    qset = qset.values("follow_id").annotate(count=Count("follow_id")).order_by("-count")
+    data = []
+    for q in qset:
+        player_id = q["follow_id"]
+        count = q["count"]
+        player = cm.Player.objects.filter(id=player_id).first()
+        today = cm.PlayerRecord.objects.filter(player_id=player_id).order_by("-stock_date").first().stock_date
+        badest_income = cm.PlayerRecord.objects.filter(player_id=player_id).order_by("-today_income").first().today_income
+        today_record = get_today_record(player_id,int(player.match_id),int(player.match_group),today)
+        userinfo = get_user_info(today_record["user_id"])
+
+        data.append(
+            {
+                "player_name":player.username,
+                "count":count,
+                "id":player_id,
+                "today_fund":today_record["today_fund"],
+                "total_income":"{}%".format(today_record["total_income"]*100),
+                "today_income":"{}%".format(today_record["today_income"]*100),
+                "badest_income":"{}%".format(badest_income*100),
+                "style":userinfo.get("style"),
+                "badge":userinfo.get("badge"),
+                "match_id":player.match_id,
+                "win_rate":calc_win_rate(player_id,player.match_id)
+            } 
+        )
+
+    if kwargs.get("name"):
+        data = filter(lambda x:kwargs.get("name") in x["player_name"],data)
+
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+        return total,data
+    else:
+        return len(data),data
+    return data
+
+
+def get_hot_stock_sell(**kwargs):
+    """
+    """
+    stock_date = kwargs.get("stock_date")
+    stock_date_time = ccf.str_to_datetime(kwargs.get("stock_date"),"%Y-%m-%d")
+    yesterday = (stock_date_time - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
+
+    ##昨天所有股票
+    #yes_stock_ids = list(cm.UserStock.objects.filter(stock_date=yesterday).values_list("stock_id",flat=True))
+    #yes_stock_ids = list(set(yes_stock_ids))
+    #data = []
+    #for ysi in yes_stock_ids:
+    #    yes_count = cm.UserStock.objects.filter(stock_date=yesterday,stock_id=ysi).count()
+    #    td_count = cm.UserStock.objects.filter(stock_date=stock_date,stock_id=ysi).count()
+    #    if td_count < yes_count:
+    #        stock_name = cm.Stock.objects.filter(id=ysi).first().name
+    #        data.append({"stock_name":stock_name,"count":yes_count-td_count,"id":ysi})
+    qset = cm.HotStockSellCount.objects.filter(stock_date=stock_date).order_by("-count")
+
+    data = list(qset.values("stock_name","stock_id","count"))
+    for item in data:
+        item["id"] = item["stock_id"]
+
+    page = int(kwargs.get("page",0))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+        return total,data
+    else:
+        return len(data),data
+    return data
+
+
+def get_stock_info(_id):
+    """
+    """
+    data = cm.Stock.objects.filter(id=_id).values().first()
+    return data
+
+
+def get_hot_stock_sell_players(**kwargs):
+    """
+    """
+    _id = kwargs.get("id")
+    stock_date = kwargs.get("stock_date")
+    stock_date_time = ccf.str_to_datetime(kwargs.get("stock_date"),"%Y-%m-%d")
+    yesterday = (stock_date_time - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
+
+    #昨天持股选手
+    yes_players = list(cm.UserStock.objects.filter(stock_date=yesterday,stock_id=_id).values_list("player_id",flat=True))
+    td_players = list(cm.UserStock.objects.filter(stock_date=stock_date,stock_id=_id).values_list("player_id",flat=True))
+    sell_players = list(set(yes_players)-set(td_players))
+
+    data = []
+    for player_id in sell_players:
+        player = cm.Player.objects.filter(id=player_id).first()
+        if player:
+            match_id = player.match_id
+            match_group = player.match_group
+            today_record = get_today_record(player_id,match_id,match_group,stock_date)
+
+            if today_record:
+                today_record["today_stock_img"] = json.loads(today_record["today_stock_img"]) if today_record["today_stock_img"] else []
+                today_record["today_stock"] = json.loads(today_record["today_stock"]) if today_record["today_stock"] else []
+                today_record["today_income"] = "{}%".format(today_record["today_income"]*100)
+                today_record["total_income"] = "{}%".format(today_record["total_income"]*100)
+                data.append(today_record)
+
+    page = int(kwargs.get("page",0))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+        return total,data
+    else:
+        return len(data),data
+    return data
+
+
+def get_win_rate_rank(request):
+    """
+    """
+    player_id = request.player.id
+    match_id = request.player.match_id
+    match_group = request.player.match_group
+    kwargs = request.json
+
+    qset = cm.WinDefendRank.objects.filter(match_id=match_id).order_by("-win_rate")
+    data = list(qset.values())
+
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+    else:
+        total = len(data)
+    for item in data:
+        item["win_rate"] = "{}%".format(item["win_rate"]*100)
+        item["badest_income"] = "{}%".format(item["badest_income"]*100)
+        item["total_income"] = "{}%".format(item["total_income"]*100)
+        userinfo = get_user_info(item["user_id"])
+        item["badge"] = userinfo.get("badge")
+        item["style"] = userinfo.get("style")
+
+
+    return total,data
+
+
+def get_defend_rank(request):
+    """
+    """
+    player_id = request.player.id
+    match_id = request.player.match_id
+    match_group = request.player.match_group
+    kwargs = request.json
+
+    qset = cm.WinDefendRank.objects.filter(match_id=match_id).order_by("-badest_income")
+    data = list(qset.values())
+
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+    else:
+        total = len(data)
+    for item in data:
+        item["win_rate"] = "{}%".format(item["win_rate"]*100)
+        item["badest_income"] = "{}%".format(item["badest_income"]*100)
+        item["total_income"] = "{}%".format(item["total_income"]*100)
+        item["style"] = []
+        if item["zq"]:
+            item["style"].apepnd(item["zq"])
+        if item["cw"]:
+            item["style"].apepnd(item["cw"])
+        if item["df"]:
+            item["style"].apepnd(item["df"])
+        item["badge"] = cm.Player.objects.filter(id=item["player_id"]).first().badge
+
+    return total,data
+
+
+def get_champion_articles_list(request):
+    """
+    """
+    kwargs = request.json
+    qset = cm.Article.objects.filter(status=2,type="champion")
+
+    page = int(kwargs.get("page",0))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,qset = ccf.get_page_qset(qset,page,page_size)
+    else:
+        total = qset.count()
+    data = list(qset.values())
+    for item in data:
+        item["ctime"] = ccf.datetime_to_str(item["ctime"],"%Y-%m-%d")
+    return total,data
+
+def get_wanzhu_comment(**kwargs):
+    """
+    """
+    match_id = kwargs.get("match_id")
+    group_id = kwargs.get("group_id")
+    print match_id
+    today = get_today_date()
+    players = get_match_group_players(match_id,group_id)
+    new_players = []
+    for player in players:
+        user_id = player["user_id"]
+        user = get_user_info(user_id) 
+        username = user["username"] if user else ""
+
+        player_id = player["id"]
+        match_group = group_id
+        today_record = get_today_record(player_id,match_id,int(match_group),today)
+        if today_record and today_record.get("wanzhu_comment"):
+            player.update(today_record)
+            player["username"] = username
+            player["total_income"] = "{}%".format(player["total_income"]*100)
+            player["fund"] = round(player["fund"],4)
+            player["init_fund"] = round(player["init_fund"],4)
+            player["today_fund"] = round(player["today_fund"],4)
+            player["today_stock"] = json.loads(player["today_stock"]) if player["today_stock"] else []
+            new_players.append(player)
+    new_players = sorted(new_players,key=lambda x:x["group_rank"])
+    data = new_players
+
+    page = int(kwargs.get("page",0))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+    else:
+        total = len(data)
+
+    return total,data
+
+
+def get_enum_list(request):
+    """
+    """
+    data = {
+        "zq":[
+            u"短线博弈", 
+            u"长线价投", 
+            u"长短兼备" 
+        ], 
+        "cw":[
+            u"分仓开超市", 
+            u"重仓押注", 
+            u"全仓单钓", 
+            u"融资加倍" 
+        ], 
+        "df":[
+            u"低吸", 
+            u"半路", 
+            u"首板", 
+            u"接力", 
+            u"撬板", 
+            u"T加0",
+            u"隔夜卖",
+            u"格局锁仓",
+            u"核按钮"
+        ], 
+        "pz":[
+            u"N/C字头新股", 
+            u"次新股", 
+            u"可转债", 
+            u"港股", 
+            u"基金", 
+            u"逆回购" 
+        ]
+    }
+    return data
+
+def get_player_list(**kwargs):
+    """选手列表
+    """
+    match_id = kwargs.get("match_id")
+    today = get_today_date()
+
+    qset = cm.Player.objects.filter(match_id=match_id,match_status=1)
+    if kwargs.get("name"):
+        qset = qset.filter(username__icontains=kwargs.get("name"))
+    data = list(qset.values())
+
+    for item in data:
+        match_id = item["match_id"]
+        match_group = item["match_group"]
+        user_id = item["user_id"]
+        player_id = item["id"]
+        #user = cm.UserInfo.objects.filter(id=user_id).first()
+        today_record = get_today_record(player_id,match_id,match_group,today)
+        if today_record:
+            today_record.pop("id")
+            item.update(today_record)
+        user_info = get_user_info(user_id)
+        if user_info:
+            user_info.pop("id")
+            item.update(user_info)
+
+    if kwargs.get("zq"):
+        data = filter(lambda x:kwargs.get("zq") == x["zq"],data)
+    if kwargs.get("cw"):
+        data = filter(lambda x:kwargs.get("cw") == x["cw"],data)
+    if kwargs.get("df"):
+        data = filter(lambda x:kwargs.get("df") == x["df"],data)
+
+    page = int(kwargs.get("page",0))
+    page_size = int(kwargs.get("page_size",20))
+
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+    else:
+        total = len(data)
+
+    return total,data
+
+
+def get_mine_style(request):
+    """
+    """
+    user = request.user
+    player = request.player
+    data = {
+        "zq":user.zq,     
+        "cw":user.cw,     
+        "df":user.df,     
+        "pz":user.pz,     
+        "join_time":user.join_time,     
+        "account_img":user.account_img,     
+    }
+    if player:
+        data["is_player"] = 1
+        data["init_fund"] = player.fund
+    else:
+        data["is_player"] = 0
+        data["init_fund"] = None
+    return data
+
+
+def update_user_style(**kwargs):
+    """
+    """
+    user_id = kwargs.pop("user_id")
+    player_id = kwargs.pop("player_id")
+    init_fund = kwargs.pop("init_fund")
+    cm.UserInfo.objects.filter(id=user_id).update(**kwargs)
+    if player_id and init_fund:
+        cm.Player.objects.filter(id=player_id).update(fund=init_fund)
+    return True
+
+
+def get_stock_players(**kwargs):
+    """
+    """
+    stock_id = kwargs.get("stock_id")
+    stock_date = kwargs.get("stock_date")
+    data = []
+    user_stocks = cm.UserStock.objects.filter(stock_id=stock_id,stock_date=stock_date)
+    for us in user_stocks:
+        player_id = us.player_id
+        player = cm.Player.objects.filter(id=player_id).first()
+        if player:
+            match_id = player.match_id
+            match_group = player.match_group
+            if stock_date:
+                today_record = get_today_record(player_id,match_id,match_group,stock_date)
+            else:
+                today_record = get_today_record(player_id,match_id,match_group,us.stock_date)
+            if today_record:
+                today_record["today_stock_img"] = json.loads(today_record["today_stock_img"]) if today_record["today_stock_img"] else []
+                today_record["today_stock"] = json.loads(today_record["today_stock"]) if today_record["today_stock"] else []
+                today_record["today_income"] = "{}%".format(today_record["today_income"]*100)
+                today_record["total_income"] = "{}%".format(today_record["total_income"]*100)
+                data.append(today_record)
+
+    #分页
+    page = int(kwargs.get("page",1))
+    page_size = int(kwargs.get("page_size",20))
+    if page and page_size:
+        total,data = ccf.get_page_list(data,page,page_size)
+    else:
+        total = len(data)
+
+    return data
+        
+
+def update_user_fund(**kwargs):
+    """
+    """
+    user_id = kwargs.pop("user_id")
+    player_id = kwargs.pop("player_id")
+    init_fund = kwargs.pop("init_fund")
+    if player_id and init_fund:
+        cm.Player.objects.filter(id=player_id).update(fund=init_fund)
+    return True
+
+
+def get_player_match_calendar(**kwargs):
+    """
+    """
+    player_id = kwargs.get("player_id")
+    match_id = kwargs.get("match_id")
+    month = kwargs.get("month")
+
+    print kwargs
+
+    week,eday = calendar.monthrange(int(month.split("-")[0]),int(month.split("-")[1]))
+    sday = "01"
+    eday = str(eday).zfill(2)
+    sdate = month + "-" + sday
+    edate = month + "-" + eday
+
+    print sdate,edate
+
+    qset = cm.PlayerRecord.objects.filter(player_id=player_id,match_id=match_id)\
+        .filter(stock_date__gte=sdate,stock_date__lte=edate)
+    data = list(qset.values())
+
+    dct = {}
+    for item in data:
+        item["today_income"] = "{}%".format(item["today_income"]*100)
+        dct[item["stock_date"]] = item["today_income"]
+
+    newdata = []
+    for i in range(1,int(eday)+1):
+        stock_date = month + "-" + str(i).zfill(2)
+        newdata.append({
+            "stock_date":stock_date,     
+            "today_income":dct.get(stock_date,""),     
+        })
+
+    return newdata
+
+
+
+

+ 21 - 1
src/weixin/urls_backstage.py

@@ -5,7 +5,7 @@ from django.conf.urls import url
 from . import views
 
 urlpatterns = [
-    # 运营
+    #1.0
     url(r'^uploadfile$', views.UploadFileView.as_view()),
     url(r'^auth$', views.AuthView.as_view()),
     url(r'^authinfo$', views.AuthinfoView.as_view()),
@@ -24,6 +24,26 @@ urlpatterns = [
     url(r'^group/rank$', views.GroupRankView.as_view()),
     url(r'^player/currecord$', views.PlayerCurRecordView.as_view()),
     url(r'^article$', views.ArticleView.as_view()),
+    url(r'^player/fund$', views.PlayerFundView.as_view()),
+    #2.0
+    url(r'^v2/user/follow$', views.FollowUserView.as_view()),
+    url(r'^v2/user/follow/list$', views.FollowUserListView.as_view()),
+    url(r'^v2/hot/stock/rank$', views.HotStockListView.as_view()),
+    url(r'^v2/hot/stock/buy/list$', views.HotStockBuyListView.as_view()),
+    url(r'^v2/hot/stock/sell/list$', views.HotStockSellListView.as_view()),
+    url(r'^v2/hot/stock/sell/players$', views.HotStockSellPlayersListView.as_view()),
+    url(r'^v2/hot/follow/list$', views.HotFollowListView.as_view()),
+    url(r'^v2/winrate/rank$', views.WinRateRankView.as_view()),
+    url(r'^v2/defend/rank$', views.DefendRankView.as_view()),
+    url(r'^v2/champion/article/list$', views.ChampionArticleListView.as_view()),
+    url(r'^v2/wanzhu/comment/list$', views.WanzhuCommentListView.as_view()),
+    url(r'^v2/enum/list$', views.EnumListView.as_view()),
+    url(r'^v2/player/list$', views.PlayerListView.as_view()),
+    url(r'^v2/mine/style$', views.MineStyleView.as_view()),
+    url(r'^v2/stock$', views.StockView.as_view()),
+    url(r'^v2/notices/list$', views.NoticesListView.as_view()),
+    url(r'^v2/default/date$', views.DefaultDateView.as_view()),
+    url(r'^v2/player/match/calendar$', views.PlayerMatchCalendarView.as_view()),
 
 ]
 

+ 369 - 2
src/weixin/views.py

@@ -178,7 +178,7 @@ class PlayerRecordView(cv.AuthView):
         if mse:
             raise ce.TipException(mse)
         try:
-            need_params.extend(["is_markt","today_stock","today_stock_img"])
+            need_params.extend(["is_markt","today_stock","today_stock_img","experience"])
             vals = ccf.get_need_params(*need_params,**qdata)
             vals["player_id"] = player.id
             vals["match_id"] = player.match_id
@@ -286,7 +286,7 @@ class PlayerRecordSingleView(cv.BaseView):
         if mse:
             raise ce.TipException(mse)
         try:
-            need_params.extend(["is_markt","today_stock"])
+            need_params.extend(["is_markt","today_stock","experience"])
             vals = ccf.get_need_params(*need_params,**qdata)
             vals["today_fund"] = round(float(vals["today_fund"]),4)
             rst = ctl.add_player_record_single(**vals)
@@ -340,5 +340,372 @@ class ArticleView(cv.AuthView):
             return cv.to_suc(rst)                                                  
         except Exception as e:                                                     
             cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+class FollowUserView(cv.AuthView):                                                    
+    def post(self, request):                                                        
+        """#关注选手(2.0小程序)                                                       
+        @follow_id:1,被关注选手id
+        @action:"cancel",取消关注
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["follow_id"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            need_params.extend(["action"])
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            vals["player_id"] = request.player.id
+            rst = ctl.follow_player(**vals)
+            return cv.to_suc(rst)                                                  
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
             return cv.to_fail(e)                                                                                                                                                                                                                                              
+class FollowUserListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#我的关注(2.0小程序)                                                       
+        """                                                                        
+        try:                                                                       
+            total,rst = ctl.get_user_follows(request)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class HotStockListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#热门股票(2.0小程序)                                                       
+        @stock_date:"",持股日期
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["stock_date"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            need_params.extend(["name"])
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            rst = ctl.get_hot_stock_rank(**vals)                                 
+            return cv.to_suc(rst)
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+class HotFollowListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#热门关注(2.0小程序)
+        @stock_date:"",持股日期
+        @page:1
+        @page_size:20
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["stock_date"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            need_params.extend(["name"])
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            total,rst = ctl.get_hot_follow(**vals)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+class HotStockBuyListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#热门持仓股票(2.0小程序)
+        @stock_date:"",持股日期
+        @page:1
+        @page_size:20
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["stock_date"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            need_params.extend(["name"])
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            total,rst = ctl.get_hot_stock_buy(**vals)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class HotStockSellListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#热门清仓股票(2.0小程序)
+        @stock_date:"",持股日期
+        @page:1
+        @page_size:20
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["stock_date"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            total,rst = ctl.get_hot_stock_sell(**vals)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class HotStockSellPlayersListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#获取股票清仓选手列表(2.0小程序)
+        @id:"",股票id
+        @stock_date:"",持股日期
+        @page:1
+        @page_size:20
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["stock_date","id"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            _id = vals["id"]
+            total,rst = ctl.get_hot_stock_sell_players(**vals)                                 
+            data =  {"total":total,"list":rst}
+            stock = ctl.get_stock_info(_id)
+            data.update(stock)
+            return cv.to_suc(data)
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class WinRateRankView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#胜率榜(2.0小程序)                                                       
+        """                                                                        
+        try:                                                                       
+            total,rst = ctl.get_win_rate_rank(request)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class DefendRankView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#防守榜(2.0小程序)                                                       
+        """                                                                        
+        try:                                                                       
+            total,rst = ctl.get_defend_rank(request)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class ChampionArticleListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#冠军心得(2.0小程序)                                                       
+        """                                                                        
+        try:                                                                       
+            total,rst = ctl.get_champion_articles_list(request)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class WanzhuCommentListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#顽主点评(2.0小程序)
+        @group_id:1,分组id
+        @page:1
+        @page_size:20
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["group_id","page","page_size"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            vals["match_id"] = request.player.match_id
+            total,rst = ctl.get_wanzhu_comment(**vals)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class EnumListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#枚举值(2.0小程序)
+        """                                                                        
+        try:                                                                       
+            rst = ctl.get_enum_list(request)
+            return cv.to_suc(rst)
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class PlayerListView(cv.AuthView):                                                    
+    def get(self, request):                                                        
+        """#选手列表搜索(2.0小程序)
+        @name:"选手名"
+        @zq:"短线",周期
+        @cw:"分仓",仓位
+        @df:"首板",打法
+        @page:1
+        @page_size:20
+        """                                                                        
+        qdata = request.json                                                       
+        need_params = ["page","page_size"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            need_params.extend(["name","zq","cw","df"])
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            vals["match_id"] = request.player.match_id
+            total,rst = ctl.get_player_list(**vals)                                 
+            return cv.to_suc({"total":total,"list":rst})
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class MineStyleView(cv.AuthView):
+    def get(self, request):
+        """#我的风格(2.0小程序)
+        """
+        try:
+            rst = ctl.get_mine_style(request)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+    def put(self, request):
+        """#修改我的风格(小程序)
+        @zq:"",周期
+        @cw:"",仓位
+        @df:"",打法
+        @pz:"",品种
+        @join_time:"",入市时间
+        @init_fund:"",参数金额
+        @account_img:"",账号截图
+        """
+        qdata = request.json                                                       
+        need_params = ["zq","cw","df","pz","join_time","account_img"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            need_params.extend(["init_fund"])
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            vals["user_id"] = request.user.id
+            vals["player_id"] = request.player.id if request.player else None
+            rst = ctl.update_user_style(**vals)
+            return cv.to_suc(rst)
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class PlayerFundView(cv.AuthView):
+    def put(self, request):
+        """#修改初始资金(小程序)
+        @init_fund:"",参数金额
+        """
+        qdata = request.json                                                       
+        need_params = ["init_fund"]                                                       
+        mse = ccf.check_params(*need_params,**qdata)                               
+        if mse:                                                                    
+            raise ce.TipException(mse)                                             
+        try:                                                                       
+            vals = ccf.get_need_params(*need_params,**qdata)                       
+            vals["user_id"] = request.user.id
+            vals["player_id"] = request.player.id if request.player else None
+            rst = ctl.update_user_fund(**vals)
+            return cv.to_suc(rst)
+        except Exception as e:                                                     
+            cv.tracefail()                                                         
+            return cv.to_fail(e)
+
+
+class StockView(cv.AuthView):
+    def get(self, request):
+        """#股票詳情(2.0小程序)
+        @id:1
+        @page:1
+        @page_size:1
+        """
+        qdata = request.json
+        need_params = ["id"]
+        mse = ccf.check_params(*need_params,**qdata)
+        if mse:
+            raise ce.TipException(mse)
+        try:
+            need_params.extend(["page","page_size","stock_date"])
+            vals = ccf.get_need_params(*need_params,**qdata)
+            vals["user_id"] = request.user.id
+            vals["player_id"] = request.player.id if request.player else None
+            rst = ctl.get_detail_info(self,**vals)
+            vals["stock_id"] = rst["id"]
+            rst["list"] = ctl.get_stock_players(**vals)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+
+class DefaultDateView(cv.AuthView):
+    def get(self, request):
+        """#默认日期(2.0小程序)
+        @id:1
+        """
+        try:
+            rst = ctl.get_today_date()
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
 
+
+class NoticesListView(cv.AuthView):
+    def get(self, request):
+        """#公告列表(2.0小程序)
+        @id:1
+        """
+        try:
+            rst = ctl.get_notices()
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)
+
+
+class PlayerMatchCalendarView(cv.AuthView):
+    def get(self, request):
+        """#获取日历收益(2.0小程序)
+        @match_id:1
+        @player_id:1
+        @month:2021-12
+        """
+        qdata = request.json
+        need_params = ["player_id","match_id","month"]
+        mse = ccf.check_params(*need_params,**qdata)
+        if mse:
+            raise ce.TipException(mse)
+        try:
+            vals = ccf.get_need_params(*need_params,**qdata)
+            rst = ctl.get_player_match_calendar(**vals)
+            return cv.to_suc(rst)
+        except Exception as e:
+            cv.tracefail()
+            return cv.to_fail(e)

+ 2 - 2
src/weixin/wzhifuSDK.py

@@ -55,9 +55,9 @@ class WxPayConf_pub(object):
 
     ##=======【基本信息设置】=====================================
     #微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
-    APPID = "wxb299e10e65157301"
+    APPID = "wxefb72c1e5fb5add2"
     #JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
-    APPSECRET = "20e278a60d52ad63822a07e49931435c"
+    APPSECRET = "a5992b99de94131d738a1ce9da9beb42"
     #受理商ID,身份标识
     MCHID = ""
     #商户支付密钥Key。审核通过后,在微信发送的邮件中查看