用c#开发微信 (16) 微活动 2 刮刮卡
微信营销是一种新型的营销模式,由于微信更重视用户之间的互动,故而这种营销推广不不能盲目地套用微博营销的单纯大量广告推送方式。这种方式在微信营销中的效果非常差,会令用户反感,继而取消去企业或商家的微信公众账号关注。对于企业来说,做微信推广重要的一个方面就是提高用户和公众账号之间的黏度,而微信刮刮卡就是其中最为常见的活动。
下面详细介绍:
一、使用
1. 新建
2. 奖项设置
3. 测试
保存后,给公众号发一个“刮刮卡”的消息, 就会收到刮刮卡的内容,进入活动后,就可以刮奖了
二、实现
1. 页面
1.1 前台代码
<head id="Head1" runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta content="微布斯、微信营销、微信代运营、微信定制开发、微信托管、微网站、微商城、微营销" name="Keywords">
<meta content="微布斯,国内最大的微信公众智能服务平台,微布斯八大微体系:微菜单、微官网、微会员、微活动、微商城、微推送、微服务、微统计,企业微营销必备。" name="Description">
<meta name="viewport" content=" initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
<meta name="description" content="刮刮卡">
<title>刮刮卡</title>
<link rel="stylesheet" type="text/css" href="css/activity_style.css" media="all" />
<script type="text/javascript" src="js/zepto.js"></script>
<script type="text/javascript" src="js/alert.js"></script>
<script type="text/javascript" src="../../scripts/jquery/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="../../scripts/jquery/jquery.query.js"></script>
<script src="js/wScratchPad.js"></script>
</head>
<body data-role="page" class="activity-scratch-card-winning">
<%if (ggkAction != null)
{ %>
<script type="text/javascript">
function loading(canvas, options) {
this.canvas = canvas;
if (options) {
this.radius = options.radius || 12;
this.circleLineWidth = options.circleLineWidth || 4;
this.circleColor = options.circleColor || 'lightgray';
this.moveArcColor = options.moveArcColor || 'gray';
} else {
this.radius = 12;
this.circelLineWidth = 4;
this.circleColor = 'lightgray';
this.moveArcColor = 'gray';
}
}
loading.prototype = {
show: function () {
var canvas = this.canvas;
if (!canvas.getContext) return;
if (canvas.__loading) return;
canvas.__loading = this;
var ctx = canvas.getContext('2d');
var radius = this.radius;
var me = this;
var rotatorAngle = Math.PI * 1.5;
var step = Math.PI / 6;
canvas.loadingInterval = setInterval(function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var lineWidth = me.circleLineWidth;
var center = { x: canvas.width / 2, y: canvas.height / 2 };
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.strokeStyle = me.circleColor;
ctx.arc(center.x, center.y + 20, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.stroke();
//在圆圈上面画小圆
ctx.beginPath();
ctx.strokeStyle = me.moveArcColor;
ctx.arc(center.x, center.y + 20, radius, rotatorAngle, rotatorAngle + Math.PI * .45);
ctx.stroke();
rotatorAngle += step;
}, 100);
},
hide: function () {
var canvas = this.canvas;
canvas.__loading = false;
if (canvas.loadingInterval) {
window.clearInterval(canvas.loadingInterval);
}
var ctx = canvas.getContext('2d');
if (ctx) ctx.clearRect(0, 0, canvas.width, canvas.height);
}
};
</script>
<form id="form1" runat="server">
<asp:HiddenField ID="hidStatus" runat="server" EnableViewState="false" />
<asp:HiddenField ID="hidErrInfo" runat="server" EnableViewState="false" />
<asp:HiddenField ID="hidAwardId" runat="server" EnableViewState="false" Value="0" />
<div class="main">
<div class="cover" id="jiangqu">
<img src="images/activity-scratch-card-bannerbg.png">
<div id="prize">
<asp:Literal ID="litPrize" runat="server" EnableViewState="false" Text="谢谢参与"></asp:Literal>
</div>
<div id="scratchpad"></div>
</div>
<div class="content">
<div id="zjl" style="display: none" class="boxcontent boxwhite">
<div class="box">
<div class="title-red"><span>恭喜你中奖了</span></div>
<div class="Detail">
<p>你中了:<span class="red"><asp:Literal ID="litJiangPing" runat="server" EnableViewState="false"></asp:Literal></span></p>
<p>兑奖SN码:<span class="red" id="sncode"><asp:Literal ID="litSnCode" runat="server" EnableViewState="false"></asp:Literal></span></p>
<p class="red">
<asp:Literal ID="litContentInfo" runat="server" EnableViewState="false"></asp:Literal>
</p>
<p>
<input name="" class="px" id="tel" value="" type="text" autocomplete="off" placeholder="用户请输入您的手机号">
</p>
<asp:Literal ID="litPwd" runat="server" EnableViewState="false" Text=""></asp:Literal>
<%-- <p>
<input name="" class="px" id="parssword" type="password" value="" placeholder="商家输入兑奖密码">
</p>--%>
<p>
<input class="pxbtn" name="提 交" id="save-btn" type="button" value="用户提交">
</p>
</div>
</div>
</div>
<div class="boxcontent boxwhite" id="result" style="display: none;">
<div class="box">
<div class="title-orange"><span>恭喜你中奖了</span></div>
<div class="Detail">
<p>你中了:<span class="red"><asp:Literal ID="litJp" runat="server" EnableViewState="false" Text=""></asp:Literal></span></p>
<p>兑奖sn码为:<span class="red"><asp:Literal ID="litSNM" runat="server" EnableViewState="false"></asp:Literal></span></p>
<p class="red"><asp:Literal ID="litLQStatus" runat="server" EnableViewState="false" Text=""></asp:Literal></p>
</div>
</div>
</div>
<div class="boxcontent boxwhite">
<div class="box">
<div class="title-red"><span>奖项设置:</span></div>
<div class="Detail">
<asp:Literal ID="litJiangXing" runat="server" EnableViewState="false"></asp:Literal>
</div>
</div>
</div>
<div class="boxcontent boxwhite">
<div class="box">
<div class="title-red">活动说明:</div>
<div class="Detail">
<p class="red">
本次活动总共可以刮<asp:Literal ID="litTTTimes" runat="server" EnableViewState="false"></asp:Literal>
次,
你已经刮了
<asp:Literal ID="litRemainTimes" runat="server" EnableViewState="false" Text="0"></asp:Literal>
次,机会如果没用完重新进入本页面可以再刮!
</p>
<p>
<asp:Literal ID="litRemark" runat="server" EnableViewState="false"></asp:Literal>
</p>
</div>
</div>
</div>
</div>
<div style="clear: both;"></div>
</div>
<script type="text/javascript">
var wid = $.query.get("wid");
var aid = $.query.get("aid");
var thisurl = document.URL;
var status = $("#hidStatus").val();
var showInfo = $("#hidErrInfo").val();
var openid = $.query.get("openid");
var zjl = false;//没中奖为false中奖为true
if (status == "-1") {
window.location.href = "end.aspx?openid=" + openid + "&wid=" + wid + "&aid=" + aid;
}
else if (status == "0") {
alert(showInfo);
}
else if (status == "2") {
zjl = true;
}
else if (status == "100") {
$("#zjl").show();
$("#jiangqu").hide();
}
else if (status == "110") {
$("#result").show();
$("#jiangqu").hide();
}
var num = 0;
var goon = true;
$(function () {
var useragent = window.navigator.userAgent.toLowerCase();
$("#scratchpad").wScratchPad({
width: 150,
height: 40,
color: "#a9a9a7",
scratchMove: function () {
num++;
if (zjl && num > 30 && goon) {
//$("#zjl").fadeIn();
goon = false;
$("#zjl").slideToggle(500);
//$("#outercont").slideUp(500)
}
if (useragent.indexOf("android 4") > 0) {
if ($("#scratchpad").css("color").indexOf("51") > 0) {
$("#scratchpad").css("color", "rgb(50,50,50)");
} else if ($("#scratchpad").css("color").indexOf("50") > 0) {
$("#scratchpad").css("color", "rgb(51,51,51)");
}
}
}
});
});
$("#save-btn").bind("click",
function () {
var btn = $(this);
var tel = $("#tel").val();
var pwd = "";
var hidAwardId = $("#hidAwardId").val();
if ($("#parssword").length > 0 && $.trim($("#parssword").val()) == "") {
alert("请输入兑奖密码!");
return
}
if ($("#parssword").length > 0) {
pwd = $("#parssword").val();
}
if ($.trim(tel) == "") {
alert("请输入手机号!");
return
}
var rad = Math.random();
var submitData = {
id: hidAwardId,
aid: aid,
pwd: pwd,
snumber: $("#sncode").text(),
tel: tel,
rad: rad,
openid: openid
};
$.post('ggkAct.ashx?myact=update', submitData,
function (data) {
if (data.success == "1") {
alert("提交成功!");
$("#result").slideToggle(500);
$("#zjl").slideToggle(500);
} else {
alert(data.msg);
}
},
"json")
});
document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
window.shareData = {
"imgUrl": thisurl,
"timeLineLink": thisurl + "&is_share=1",
"sendFriendLink": thisurl + "&is_share=1",
"weiboLink": thisurl + "&is_share=1",
"tTitle": "<%=ggkAction.actName%>",
"tContent": "<%=ggkAction.actContent%>",
"fTitle": "<%=ggkAction.actName%>",
"fContent": "<%=ggkAction.actContent%>",
"wContent": "<%=ggkAction.actContent%>"
};
// 发送给好友
WeixinJSBridge.on('menu:share:appmessage', function (argv) {
WeixinJSBridge.invoke('sendAppMessage', {
"img_url": window.shareData.imgUrl,
"img_width": "640",
"img_height": "640",
"link": window.shareData.sendFriendLink,
"desc": window.shareData.fContent,
"title": window.shareData.fTitle
}, function (res) {
_report('send_msg', res.err_msg);
})
});
// 分享到朋友圈
WeixinJSBridge.on('menu:share:timeline', function (argv) {
WeixinJSBridge.invoke('shareTimeline', {
"img_url": window.shareData.imgUrl,
"img_width": "640",
"img_height": "640",
"link": window.shareData.timeLineLink,
"desc": window.shareData.tContent,
"title": window.shareData.tTitle
}, function (res) {
_report('timeline', res.err_msg);
});
});
// 分享到微博
WeixinJSBridge.on('menu:share:weibo', function (argv) {
WeixinJSBridge.invoke('shareWeibo', {
"content": window.shareData.wContent,
"url": window.shareData.weiboLink,
}, function (res) {
_report('weibo', res.err_msg);
});
});
}, false)
</script>
</form>
<%}
else
{%>
<div class="main">
<div class="content">
<div class="boxcontent boxwhite">
<div class="box">
<div class="title-red"><span>出现异常:</span></div>
<div class="Detail">
<%=errorInfo %>
</div>
</div>
</div>
</div>
</div>
<%} %>
<div style="display: none">©微布斯科技提供qq 121285904 www.webus.cn</div>
</body>
</html>
这里用到了wScratchPad.js, wScratchPad是jQuery上的一个插件,它能模拟出刮的行为,使你能“擦去”一层覆盖物,这层覆盖物既可是一个图片,也可以是某种颜色涂层。
官方网址为 http://wscratchpad.websanova.com/
1.2 页面加载
public Model.wx_ggkActionInfo ggkAction = new Model.wx_ggkActionInfo();
BLL.wx_ggkActionInfo actbll = new BLL.wx_ggkActionInfo();
BLL.wx_ggkAwardItem itemBll = new BLL.wx_ggkAwardItem();
BLL.wx_ggkAwardUser ubll = new BLL.wx_ggkAwardUser();
BLL.wx_ggkUsersTemp utbll = new BLL.wx_ggkUsersTemp();
string NoAward = "谢谢参与";
protected string errorInfo = "";
protected void Page_Load(object sender, EventArgs e)
{
OnlyWeiXinLook();
if (!IsPostBack)
{
int aid = MyCommFun.RequestInt("aid", 0);
int wid = MyCommFun.RequestInt("wid", 0);
string openid = MyCommFun.RequestOpenid();
if (aid == 0 || wid == 0 || openid.Trim() == "" | openid.Trim() == "loseopenid")
{
errorInfo="访问的参数有问题!";
ggkAction = null;
return;
}
bindData(aid, openid);
}
}
1.3 绑定页面上的基本信息
private void bindData(int id, string openid)
{
#region 活动详情
ggkAction = actbll.GetModel(id);
if (ggkAction == null)
{
errorInfo = "该活动不存在!";
return;
}
if (ggkAction.endDate <= DateTime.Now)
{ //说明活动已经结束
errorInfo = "活动已结束!";
ggkAction = null;
return;
}
else if (ggkAction.beginDate > DateTime.Now)
{
//活动未开始
errorInfo = "活动尚未开始!<br/>活动时间为:" + ggkAction.beginDate.ToString() + "到" + ggkAction.endDate.ToString();
ggkAction = null;
return;
}
this.Title = ggkAction.actName;
List<Model.wx_ggkAwardItem> itemlist = itemBll.GetModelList("actId="+id);
StringBuilder sb = new StringBuilder("");
Model.wx_ggkAwardItem item = new Model.wx_ggkAwardItem();
int ttJpNum = 0;//实际奖品数量
for (int i = 0; i < itemlist.Count; i++)
{
item = itemlist[i];
sb.Append("<p>" +item.jxName + ":" + item.jpName + " 数量:" + item.jpNum + "</p>");
ttJpNum += item.jpRealNum.Value;
}
if (ggkAction.djPwd.Trim().Length > 0)
{
litPwd.Text = " <p> <input name=\"\" class=\"px\" id=\"parssword\" type=\"password\" value=\"\" placeholder=\"商家输入兑奖密码\"></p>";
}
litJiangXing.Text = sb.ToString();
litRemark.Text = ggkAction.brief;
litContentInfo.Text = ggkAction.contractInfo;
litTTTimes.Text = ggkAction.personMaxTimes == null ? "0" : ggkAction.personMaxTimes.Value.ToString();
#endregion
lock (this)
{
ProcZJ(ttJpNum, id, openid, itemlist);
}
}
1.4 处理中奖信息
private void ProcZJ(int ttJpNum, int id, string openid, List<Model.wx_ggkAwardItem> itemlist)
{
BLL.ggkProc gproc = new BLL.ggkProc();
#region 判断
Model.wx_ggkAwardUser awardUser = ubll.getZJinfoByOpenid(id, openid);
litRemainTimes.Text = gproc.personCJTimes(openid, id).ToString();
if (awardUser != null && awardUser.id > 0)
{ //说明已经中奖了
litPrize.Text = awardUser.jxName;
hidAwardId.Value = awardUser.id.ToString();
if (awardUser.uTel != null && awardUser.uTel.Trim() != "")
{ //说明已经提交成功了
hidStatus.Value = "110";
hidErrInfo.Value = "您已中过奖了,欢迎下次再来!";
litJp.Text = awardUser.jxName + " " + awardUser.jpName;
litSNM.Text = awardUser.sn;
if (awardUser.hasLingQu)
{
litLQStatus.Text = "你已经兑奖成功,本SN码自定作废!";
}
else
{
litLQStatus.Text = ggkAction.contractInfo;
}
}
else
{ //中奖了,但是未提交
hidStatus.Value = "100";
hidErrInfo.Value = "您已中奖,请提交!";
litJiangPing.Text = awardUser.jpName;
litSnCode.Text = awardUser.sn;
litJp.Text = awardUser.jxName + " " + awardUser.jpName;
litSNM.Text = awardUser.sn;
}
return;
}
int dayMaxTimes = ggkAction.dayMaxTimes == null ? 0 : ggkAction.dayMaxTimes.Value;
int perMaxTimes = ggkAction.personMaxTimes == null ? 0 : ggkAction.personMaxTimes.Value;
//判断每人最大抽奖次数,是否超过了
if (gproc.personCJTimes(openid, id) >= ggkAction.personMaxTimes)
{
hidStatus.Value = "0";
hidErrInfo.Value = "您已抽过奖了,欢迎下次再来!";
return;
}
int RemainTime = 0;
if (gproc.isTodayOverSum(id, openid, dayMaxTimes, out RemainTime))
{
hidStatus.Value = "0";
hidErrInfo.Value = "每人每天只有" + dayMaxTimes.ToString() + "次抽奖机会。";
litRemainTimes.Text = RemainTime.ToString();
return;
}
litRemainTimes.Text = RemainTime.ToString();
#endregion
#region 计算中奖信息
/// 处理是否中奖
/// hidStatus 状态为-1:不能抽奖,直接跳转到end.aspx页面;
/// 0:抽奖次数超过设置的最高次数;
/// 1:还可以继续抽奖;
/// 2:中奖了;
IList<Model.wx_ggkAwardUser> auserlist = ubll.getHasZJList(id);//已经中奖的人列表
int ZhongJiangNum = 0;
if (auserlist != null)
{
ZhongJiangNum = auserlist.Count; //已经中奖的人数
}
int syZjNum = ttJpNum - ZhongJiangNum; //剩余的奖品数量
if (syZjNum <= 0)
{ //说明已经没有奖品了
hidStatus.Value = "1";
hidErrInfo.Value = ggkAction.cfcjhf;
litPrize.Text = NoAward;
return;
}
ggkAction.personNum = MyCommFun.Obj2Int(ggkAction.personNum, 1);
ggkAction.personMaxTimes = MyCommFun.Obj2Int(ggkAction.personMaxTimes, 1);
int fenmo = ggkAction.personNum.Value * ggkAction.personMaxTimes.Value;
Random rd = new Random((int)DateTime.Now.Ticks);
int radNum = rd.Next(0, fenmo);//从0到fenmo里随机出一个值
if (radNum < syZjNum)
{
//中奖了,再从剩余奖品里抽取一个奖品
Model.wx_ggkAwardItem dajiang = gproc.getZJItem(itemlist, auserlist);
if (dajiang != null)
{
//这是中的中奖了
string snumber = gproc.Get_snumber(id);
int uId = ubll.Add(id, "", "", openid, dajiang.jxName, dajiang.jpName, snumber);
hidStatus.Value = "2";
hidErrInfo.Value = "恭喜你中奖了!";
litPrize.Text = dajiang.jxName;
litJiangPing.Text = dajiang.jpName;
hidAwardId.Value = uId.ToString();
litSnCode.Text = snumber;
litJp.Text = dajiang.jxName + " " + dajiang.jpName;
litSNM.Text = snumber;
return;
}
else
{
//奖品已经全部中完了
hidStatus.Value = "1";
hidErrInfo.Value = ggkAction.cfcjhf;
litPrize.Text = NoAward;
return;
}
}
else
{
//这个条件说明:未中奖
//抛出未中奖的数据
hidStatus.Value = "1";
hidErrInfo.Value = ggkAction.cfcjhf;
litPrize.Text = NoAward;
}
#endregion
}
2. 实现提交手机的逻辑
public class ggkAct : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/json";
string _action = MyCommFun.QueryString("myact");
string openid = MyCommFun.RequestOpenid(); //得到微信用户的openid
if (_action == "update")
{
try
{
#region 提交手机
/// 提交手机号码
string tel = MyCommFun.QueryString("tel");
string pwd = MyCommFun.QueryString("pwd");
string snumber = MyCommFun.QueryString("snumber");
int id = MyCommFun.RequestInt("id");
int aid = MyCommFun.RequestInt("aid");
if (aid==0 || id == 0 || snumber == "" || tel == "")
{
context.Response.Write("{\"msg\":\"提交出现异常!!\",\"success\":\"0\"}");
return;
}
BLL.wx_ggkActionInfo actBll = new BLL.wx_ggkActionInfo();
if (pwd.Trim().Length>0 &&(!actBll.ExistsPwd(aid, pwd)))
{
context.Response.Write("{\"msg\":\"商家兑换密码错误!!\",\"success\":\"0\"}");
return;
}
BLL.wx_ggkAwardUser ubll = new BLL.wx_ggkAwardUser();
Model.wx_ggkAwardUser model = ubll.GetModel(id);
if (model == null)
{
context.Response.Write("{\"msg\":\"提交出现异常2!!\",\"success\":\"0\"}");
return;
}
model.uTel = tel;
if (pwd.Trim().Length > 0)
{
model.hasLingQu = true;
}
else
{
model.hasLingQu = false;
}
ubll.Update(model);
context.Response.Write("{\"msg\":\"提交成功!\",\"success\":\"1\"}");
return;
#endregion
}
catch
{
context.Response.Write("{\"msg\":\"提交出现异常!!\",\"success\":\"0\"}");
return;
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}