一个用网页实现游戏充值统计的功能,要求如下:
一、根据指定日期区间,搜索该时间段内每日玩家的整体充值情况。
二、根据指定某个日期,搜索该天所有玩家的记录。
首先想吐槽一句,我的主要工作是用C/C++开发服务器后台,这个任务是web前端的工作。所以,开发这个功能时,我基本上是摸着石头过河,带着大学HTML网页课堂里的些许模糊印记,借助自己的C语言功底,自学JavaScript和Perl两门脚本语言。最终,花了两天半的时间完成这个任务。开发过程中踩了一些坑,工作中有点空闲时间就做一下总结。(附主要源代码)
主要流程:
Step1. 用HTML制作网页,添加3个日期下拉框和2个搜索按键。
Step2.用JavaScript脚本写几个处理函数( 日期同步、闰年判断、按键响应、返回数据处理)。
Step3.用ajax通过GET方式向目标URL发送日期数据并获取充值统计数据。
Step4.用Perl脚本写2个.pl文件用来获取HTML发过来的日期数据,解析日志文件中的充值统计数据,最后返回给HTML。
Step1~3. 编写date.html网页文件,源代码如下:(注意红色字体两个坑点)
(读者可在<script>中补充2个GET返回数据处理函数:setWhole(data)/setDetail(data), 然后在<body>中添加table控件将这些数据在网页中显示出来 )
网页效果如下:
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=utf8'>
</head>
<body>
<!-- form class属性设置为form-inline内联表 使内部的控件呈水平排列 -->
<form name="begin_date" class="form-inline" >
<h4 class="block-title">Start Date: </h4>
<select id="begin_year" name="YYYY" οnchange="YYYYDD(this.value)" class="form-control input-sm m-b-10" style="width:150px">
</select>
<select id="begin_month" name="MM" οnchange="MMDD(this.value)" class="form-control input-sm m-b-10" style="width:150px">
</select>
<select id="begin_day" name="DD" class="form-control input-sm m-b-10" style="width:150px">
</select>
</form>
<form name="end_date" class="form-inline" >
<h4 class="block-title"> EndOf Date: </h4>
<select id="end_year" name="YYYY" οnchange="YYYYDD(this.value)" class="form-control input-sm m-b-10" style="width:150px">
</select>
<select id="end_month" name="MM" οnchange="MMDD(this.value)" class="form-control input-sm m-b-10" style="width:150px">
</select>
<select id="end_day" name="DD" class="form-control input-sm m-b-10" style="width:150px">
</select>
<!--搜索按键--><!-- 按键type设置为buttton 使点击按键时不会重新加载网页-->
<input type="button" value="Search" class="btn btn-primary" οnclick="GetDate1()">
</form>
<form name="one_date" class="form-inline" >
<h4 class="block-title">Select Date: </h4>
<select id="one_year" name="YYYY" οnchange="YYYYDD(this.value)" class="form-control input-sm m-b-10" style="width:150px">
</select>
<select id="one_month" name="MM" οnchange="MMDD(this.value)" class="form-control input-sm m-b-10" style="width:150px">
</select>
<select id="one_day" name="DD" class="form-control input-sm m-b-10" style="width:150px">
</select>
<!--搜索按键-->
<input type="button" value="Search" class="btn btn-primary" οnclick="GetDate2()">
</form>
<script language="JavaScript">
function GetDate1() //点击按钮响应事件1
{
var by = document.getElementById("begin_year").value;
var bm = document.getElementById("begin_month").value;
var bd = document.getElementById("begin_day").value;
var ey = document.getElementById("end_year").value;
var em = document.getElementById("end_month").value;
var ed = document.getElementById("end_day").value;
var mynum = ["00","01","02","03","04","05","06","07","08","09"];
if(bm < 10)
{
bm = mynum[bm];
}
if(bd < 10)
{
bd = mynum[bd];
}
if(em < 10)
{
em = mynum[em];
}
if(ed < 10)
{
ed = mynum[ed];
}
var begin_date = by + bm + bd;
var end_date = ey + em + ed;
$.ajax({
url : '/cgi-bin/WholeMultiDays.pl?begin_date='+begin_date+'&end_date='+end_date, //目标URL+传送的数据begin_date和end_date
type : "GET",
success : function(data) //获取Get请求返回的数据
{
//setWhole(data) //处理返回的数据
},
error : function()
{
}
});
}
function GetDate2() //点击按钮响应事件2
{
var oy = document.getElementById("one_year").value;
var om = document.getElementById("one_month").value;
var od = document.getElementById("one_day").value;
var mynum = ["00","01","02","03","04","05","06","07","08","09"];
if(om < 10)
{
om = mynum[om];
}
if(od < 10)
{
od = mynum[od];
}
var one_date = oy + om + od;
$.ajax({
url : '/cgi-bin/OneDayDetail.pl?one_date='+one_date, //目标URL+传送的数据one_date
type : "GET",
success : function(data)
{
//setDetail(data) //获取Get请求返回的数据
},
error : function()
{
}
});
}
function YYYYMMDDstart()
{
MonHead = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
//先给年下拉框赋内容
var y = new Date().getFullYear();
for (var i = y; i < (y+30); i++) //以今年为准,后30年
document.begin_date.YYYY.options.add(new Option(" "+ i, i));
for (var i = y; i < (y+30); i++) //以今年为准,后30年
document.end_date.YYYY.options.add(new Option(" "+ i, i));
for (var i = y; i < (y+30); i++) //以今年为准,后30年
document.one_date.YYYY.options.add(new Option(" "+ i, i));
//赋月份的下拉框
for (var i = 1; i < 13; i++)
document.begin_date.MM.options.add(new Option(" " + i, i));
//赋月份的下拉框
for (var i = 1; i < 13; i++)
document.end_date.MM.options.add(new Option(" " + i, i));
//赋月份的下拉框
for (var i = 1; i < 13; i++)
document.one_date.MM.options.add(new Option(" " + i, i));
document.begin_date.YYYY.value = y;
document.begin_date.MM.value = new Date().getMonth() + 1;
document.end_date.YYYY.value = y;
document.end_date.MM.value = new Date().getMonth() + 1;
document.one_date.YYYY.value = y;
document.one_date.MM.value = new Date().getMonth() + 1;
var n = MonHead[new Date().getMonth()];
if (new Date().getMonth() ==1 && IsPinYear(y)) n++;
writeDay(n); //赋日期下拉框Author:meizz
document.begin_date.DD.value = new Date().getDate();
document.end_date.DD.value = new Date().getDate();
document.one_date.DD.value = new Date().getDate();
}
if(document.attachEvent)
window.attachEvent("onload", YYYYMMDDstart);
else
window.addEventListener('load', YYYYMMDDstart, false);
function YYYYDD(str) //年发生变化时日期发生变化(主要是判断闰平年)
{
var MMvalue = document.begin_date.MM.options[document.begin_date.MM.selectedIndex].value;
if (MMvalue == ""){ var e = document.begin_date.DD; optionsClear(e); return;}
var n = MonHead[MMvalue - 1];
if (MMvalue ==2 && IsPinYear(str)) n++;
writeDay(n)
var MMvalue2 = document.end_date.MM.options[document.end_date.MM.selectedIndex].value;
if (MMvalue2 == ""){ var e = document.end_date.DD; optionsClear(e); return;}
var n2 = MonHead[MMvalue2 - 1];
if (MMvalue2 ==2 && IsPinYear(str)) n2++;
writeDay(n2)
var MMvalue3 = document.one_date.MM.options[document.one_date.MM.selectedIndex].value;
if (MMvalue3 == ""){ var e = document.one_date.DD; optionsClear(e); return;}
var n3 = MonHead[MMvalue3 - 1];
if (MMvalue3 ==2 && IsPinYear(str)) n3++;
writeDay(n3)
}
function MMDD(str) //月发生变化时日期联动
{
var YYYYvalue = document.begin_date.YYYY.options[document.begin_date.YYYY.selectedIndex].value;
if (YYYYvalue == ""){ var e = document.begin_date.DD; optionsClear(e); return;}
var n = MonHead[str - 1];
if (str ==2 && IsPinYear(YYYYvalue)) n++;
writeDay(n)
var YYYYvalue2 = document.end_date.YYYY.options[document.end_date.YYYY.selectedIndex].value;
if (YYYYvalue2 == ""){ var e = document.end_date.DD; optionsClear(e); return;}
var n2 = MonHead[str - 1];
if (str ==2 && IsPinYear(YYYYvalue2)) n2++;
writeDay(n2)
var YYYYvalue3 = document.one_date.YYYY.options[document.one_date.YYYY.selectedIndex].value;
if (YYYYvalue3 == ""){ var e = document.one_date.DD; optionsClear(e); return;}
var n3 = MonHead[str - 1];
if (str ==2 && IsPinYear(YYYYvalue3)) n3++;
writeDay(n3)
}
function writeDay(n) //据条件写日期的下拉框
{
var e = document.begin_date.DD;
for (var i=1; i<(n+1); i++)
e.options.add(new Option(" "+ i, i));
var e2 = document.end_date.DD;
for (var i=1; i<(n+1); i++)
e2.options.add(new Option(" "+ i, i));
var e3 = document.one_date.DD;
for (var i=1; i<(n+1); i++)
e3.options.add(new Option(" "+ i, i));
}
function IsPinYear(year)//判断是否闰平年
{ return(0 == year%4 && (year%100 !=0 || year%400 == 0));}
function optionsClear(e)
{
e.options.length = 1;
}
</script>
</body>
</html>
Step4.用Perl脚本写两个脚本( WholeMultiDays.pl、OneDayDetail.pl)
1.WholeMultiDays.pl源代码如下:
#!/usr/bin/perl
use Time::Local;
use utf8;
use JSON;
use Switch;
use Data::Dumper;
#获取来自date.html的GET请求
local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "GET")
{
$buffer = $ENV{'QUERY_STRING'};
}
# Split information into name/value pairs
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
# print "<h4>$pair</h4>";
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$FORM{$name} = $value;
}
# key 名为 "begin_date"的键
my $begin_date = $FORM{begin_date};
# key 名为 "end_date"的键
my $end_date = $FORM{end_date};
my $all = [];
for(my $date = $end_date;$date >= $begin_date;$date--)
{
my $today_buy_times = 0; #购买笔数
my $today_buy_money = 0; #购买金额
my %today_buy_count; #购买人数
my $today_buy_all_money = 0; #购买总额
my $fileName = "log.$date"; #文件路径
if(-e $fileName)
{
open HD, $fileName or pexit("open file failed!");
while(<HD>)
{
$_ =~ tr/\n//d;
my ($timeStr,$uid,$name,$money,$payType,$action) = split /\|/, $_;
if($action eq "buy_success")
{
$today_buy_all_money += $money;
$today_buy_count{$uid} = 1;
$today_buy_times++;
}
}
}
else
{
next;
}
my $hero = {};
$hero->{"date"} = $date;
$hero->{"count"} = keys(%today_buy_count);
$hero->{"times"} = $today_buy_times;
$hero->{"money"} = $today_buy_all_money;
push @{$all},$hero;
}
my $json_text = JSON->new->utf8->encode($all);
print $json_text;
2.OneDayDetail.pl源代码如下:
#!/usr/bin/perl
use Time::Local;
use utf8;
use JSON;
use Switch;
use Data::Dumper;
local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "GET")
{
$buffer = $ENV{'QUERY_STRING'};
}
# Split information into name/value pairs
@pairs = split(/&/, $buffer);
foreach $pair (@pairs)
{
# print "<h4>$pair</h4>";
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$FORM{$name} = $value;
}
# key 名为 "one_date"的键
my $date = $FORM{one_date};
my $today = [];
my $fileName = "log.$date";
if(-e $fileName)
{
open HD, $fileName or pexit("open file failed!");
while(<HD>)
{
$_ =~ tr/\n//d;
my ($timeStr,$uid,$name,$money,$payType,$action) = split /\|/, $_;
if($action eq "buy_success")
{
my $hero = {};
$hero->{"date"} = $timeStr;
$hero->{"uid"} = $uid;
$hero->{"name"} = $name;
$hero->{"money"} = $money;
push @{$today},$hero;
}
}
}
my $json_text = JSON->new->utf8->encode($today);
print $json_text;