前言
业务系统有一个分享返现的活动。用户在知乎或者小红书发表一篇使用心得,然后申请返现。已经支付的订单就会返还。原先订单少的时候,都是手动处理。随着订单量的增加,申请返现的也越来越多。有点处理不过来,同时已经返现的订单,有多少也不知道。于是有开发一个推广管理系统的想法,花一周时间实现了。特此记录实现过程,一切从简能用就好。
设计思路
后端采用自己比较熟悉的django框架,数据库使用mysql。
前端页面使用html+js。几个页面比较简单。以后使用过程中逐步完善吧。
photo模块
模型设计
#文章级别
# 关键词
A = 0
B = 1
C = 2
D = 3
E = 4
#来源
SRC_CHOICE = {
A: '知乎',
B: '小红书',
}
#文章级别
LEVEL_CHOICE = {
A: '审核中',
B: '未通过',
C: '普通',
D: '精品',
E: '被删除',
}
# Create your models here.
class Article(models.Model):
'''
图鲁班文章模型类
'''
id = models.AutoField(primary_key=True)
src_choices = ((k, v) for k,v in SRC_CHOICE.items())
level_choices = ((k, v) for k,v in LEVEL_CHOICE.items())
sno = models.CharField(max_length=32, verbose_name='编号', default='')
title = models.CharField(max_length=255, verbose_name='标题', default='')
url = models.CharField(max_length=255, verbose_name='链接', default='')
uid = models.IntegerField(default=1, verbose_name='用户id')
addtime = models.DateTimeField(auto_now_add=True, verbose_name= '添加时间')
stype = models.SmallIntegerField(default='1', choices=src_choices, verbose_name='平台')
slevel = models.SmallIntegerField(default='0', choices=level_choices, verbose_name='级别')
note = models.CharField(max_length=1024, default='无', verbose_name='备注')
def __str__(self):
return self.sno
class Meta:
db_table = 'photo_article'
verbose_name = '推广记录'
verbose_name_plural = '推广记录'
code here...
后台展示自定义
# Register your models here.
class ArticleAdmin(admin.ModelAdmin):
#后台展示字段
list_display = ['sno', 'show_firm_url', 'slevel', 'stype', 'addtime', 'repay_info', 'show_kefu', 'note']
#过滤字段
list_filter = ["slevel", "stype"]
#搜索字段
search_fields = ['title']
#只读字段
readonly_fields = ['sno', 'uid', 'addtime']
@admin.display(description='返现信息', ordering='')
def repay_info(self, obj):
num = 0 #条数
w_p = 0 #未结算金额
y_p = 0 #已结算金额
repays = Repay.objects.filter(sno=obj.sno).all()
if repays:
for repay in repays:
num = num + 1
if repay.status == 0:
w_p = w_p + repay.price
if repay.status == 1:
y_p = y_p + repay.price
data = {'name':'返现记录', 'url':'/admin/photo/repay/?q={}'.format(obj.sno)}
return format_html("<a href='javascript:;' onclick='self.parent.app.openTab({data})'>共{n}条, 已结算: {y}, 未结算: {w}</a>", data=data, n=num, y=y_p, w=w_p)
#标题带链接
@admin.display(description='标题', ordering='')
def show_firm_url(self, obj):
return format_html("<a href='{url}' target='_blank'>{title}</a>", url=obj.url, title=obj.title)
#客服回复提示
@admin.display(description='客服回复', ordering='')
def show_kefu(self, obj):
text = '您的返现申请已提交,结果可通过(http://tg.tuluban.top)自助查询。查询码:{}'.format(obj.sno)
return format_html(f"""
<input type="text" id="{obj.id}" value="{text}" style="position: absolute; top: -10000px">
<a href="#" onclick="document.getElementById('{obj.id}').select(); document.execCommand('copy')">提示</a>
""")
#隐藏不需要编辑的字段
def get_form(self, request, obj=None, **kwargs):
self.exclude = ('sno', 'uid', 'addtime')
form = super(ArticleAdmin, self).get_form(request, obj, **kwargs)
return form
#重写保存函数
def save_model(self, request, obj, form, change):
#新增
if not change:
obj.uid = request.user.id
obj.sno = datetime.now().strftime('%Y%m%d%H%M%S') + ''.join(str(i) for i in random.sample(range(0,9),4))
repay = Repay.objects.filter(sno=obj.sno).filter(status=0)
if obj.slevel == 2:
if repay:
repay.update(price=290)
else:
repay = Repay()
repay.sno = obj.sno
repay.price = 290
repay.uid = obj.uid
repay.note = obj.note
repay.save()
elif obj.slevel == 3:
if repay:
repay.update(price=490)
else:
repay = Repay()
repay.sno = obj.sno
repay.price = 490
repay.uid = obj.uid
repay.note = obj.note
repay.save()
#保存
super(ArticleAdmin, self).save_model(request, obj, form, change)
新增订单接口
def photo_add(request):
#定义返回字典
resp = {}
#获取请求参数
if request.method == 'GET':
u = request.GET.get('u', default=False)
n = request.GET.get('n', default='xwzy1130')
else:
u = False
if not u:
resp['msg'] = '参数非法,提交失败!'
else:
data = get_info_by_url(u)
if data:
art = Article()
art.sno = datetime.now().strftime('%Y%m%d%H%M%S') + ''.join(str(i) for i in random.sample(range(0,9),4))
art.title = data[0]
art.url = u
art.stype = data[1]
payinfo = PayInfo.objects.filter(username=n).last()
if payinfo:
art.uid = payinfo.uid
else:
art.uid = 1
art.note = n
art.save()
resp['msg'] = '更新成功!查询码:{}'.format(art.sno)
else:
resp['msg'] = '提交失败!'
return JsonResponse(resp)
frontend模块
view模版
#搜索结果页
def search_view(request,*args, **kwargs):
return render(request, 'frontend/search.html')
#自助提交页
def submit_view(request,*args, **kwargs):
return render(request, 'frontend/submit.html')
submit.html
$(function () {
// 搜索时执行ajax 查询匹配的数据 返回到list
$(".handIpt").click(function () {
var username = $("#username").val();
var url = $("#url").val();
if (isValidURL(url) && url.trim()) {
$.ajax({
type: "GET",
url: "/photo/add?u=" + url + "&n=" + username,
dataType: "json",
success: function (data) {
alert(data.msg);
},
//打印错误
error:function(jqXHR,textStatus,errorThrown){
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
}
});
} else {
alert("请检查推广链接!");
}
});
其他细节
js校验url是否合法
function isValidURL(str_url) {
var strRegex = "^((https|http|ftp|rtsp|mms)?://)"
+ "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" //ftp的user@
+ "(([0-9]{1,3}.){3}[0-9]{1,3}" // IP形式的URL- 199.194.52.184
+ "|" // 允许IP和DOMAIN(域名)
+ "([0-9a-z_!~*'()-]+.)*" // 域名- www.
+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]." // 二级域名
+ "[a-z]{2,6})" // first level domain- .com or .museum
+ "(:[0-9]{1,4})?" // 端口- :80
+ "((/?)|" // a slash isn't required if there is no file name
+ "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
var re=new RegExp(strRegex);
//re.test()
if (re.test(str_url)){
return (true);
}else{
return (false);
}
}
js 转码url
// var e_url = encodeURIComponent (list[i].url);
function movieDetail (url) {
console.log(url);
window.location.href= decodeURIComponent(url);
}
Django设置静态文件目录
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
simpleUI 设置默认首页
#simpleui配置
SIMPLEUI_HOME_PAGE = '/photo/index'
评论 (0)