网页版在线客服实现代码

网页版在线客服实现代码第一次写,感觉很乱,后面直接上代码吧,代码也有注释,想看思路的朋友可以看前面。有什么建议和意见欢迎砸过来。功能:1、客服需登录进入客服页面。用户无需登录,进入用户页面,直接获取sessionId作为id值。2、用户进入页面并且发送消息时,客服才会获取到该用户,并在左侧列表显示。3、点击用户名即可切换聊天对象,正在聊天的用户,用户名为选中状态。4、每条消息的时间显示在本条消息上方(水平居中)。消息时…

第一次写,感觉很乱,后面直接上代码吧,代码也有注释,想看思路的朋友可以看前面。有什么建议和意见欢迎砸过来。

功能:

1、客服需登录进入客服页面。用户无需登录,进入用户页面,直接获取sessionId作为id值。

2、用户进入页面并且发送消息时,客服才会获取到该用户,并在左侧列表显示。

3、点击用户名即可切换聊天对象,正在聊天的用户,用户名为选中状态。

4、每条消息的时间显示在本条消息上方(水平居中)。消息时间间隔不足1分钟,则此不显示时间。

5、每次读取的消息均为最新消息。

6、客服未与其正在聊天的用户发送新消息时应有新消息提示。

7、用户关闭浏览器或长时间无回应时,将用户置为下线。

       客服界面将清空与下线用户的聊天窗口,且下线用户不显示在左侧列表中。

8、用户长时间无回应置为下线后,刷新可继续在线与客服聊天。

9、发送:1)输入框未输入消息时,提示“发送内容不能为空”。

                2)未选择用户时,提示“请选择用户”。

数据库表:

三张表:客服(user),用户(customer),聊天记录(cs_chat_record)。

客服表主要字段:id,name,password,online,currentPeople;

用户表主要字段:id,name,online,headImg;

聊天记录表主要字段:id,userId,customerId,userContent,customerContent,time;

主要思路:

1、用户进入页面:查看当前用户有没有正在被客服人员接待

①正在被接待:设置用户为在线状态(因为刷新会有下线操作)。

②未被接待:获取所有在线客服每个人正在接待的用户人数,并给该用户分配一个当前接待人数少的客服。

                    修改此客服正在接待的人数,将用户添加到用户表中(设置为在线状态)。

                    将用户和客服均存到session中。

2、客服进入页面:常规验证。

4、用户和客服发送消息时,都先将信息保存到数据库。

5、用户和客服界面,都是一秒刷新一次获取最新消息。

6、客服页面:当前正在沟通的用户列表,每秒获取一次,将不在线的用户在列表清除。

7、长时间无回复的用户置为下线,用到数据库定时器。

8、用户关闭浏览器置为下线,用到的是window.onbeforeunload方法。

9、新消息提醒:保存用户消息将用户头像设置成有红点的,获取消息时将用户头像设置为无红点的。

知识点:

1、获取用户id:getRequest().getSession().getId();

2、获取最新聊天记录时,聊天记录表的id是在前端存储的,一定不要在后台用全局变量存储,方便用户刷新页面时再次获取之前所有聊天记录。

3、c:forEach标签只能在服务器端使用,在页面加载完成后需要用js的for循环。

4、用户列表的显示是foreach循环得到的,为显示用户名的label设置class属性,用户点击切换用户时使用。

    列表用户正在聊天的用户用户名设置为选中状态:$(“div#”+id).css(‘background’,’#00ffff’);

    其他用户取消选中状态:$(“.CustomerBG”).css(‘background’,’#ffffff’);

   ( ps:这里不是很懂,所以给div设置了两个属性,给背景色和取消背景色用到的不是一个属性。)

5、循环得到的用户名:<label id=’labelId’ class=’checkLabel’ style=’font-size: 12pt;’data_id='” +cId +”‘>”

    1)点击用户名触发的事件,此方法在$(function(){})外写,能监听js中拼接的节点(此客服系统用的此方法):

            $(document).off(“click”, “.checkLabel”).on(“click”, “.checkLabel”, function(){

                 //点击用户名之后要执行的内容

            });

    2)此方法在$(function(){})内写,不能监听到js中拼接的节点,

            $(“.checkLabel”).click(function(){

                //要执行的内容

            })

attr:1)$(this).attr(“data_id”);拿到自定义的属性的值。

        2)$(this).attr(“data_id”,“value”);给自定义的属性赋值。

6、清空div中的所有内容:

    $(“#divId”).empty();

    $(“#divId”).html(“”);

7、地址栏不能拼接时间参数,时间格式有空格,地址以空格为终点。

8、给myclass的span节点的内容加样式。

<div class=”myclass” ><span>样式体现在这</span></div>

.myclass span{

    //要写的样式

}

9、数据库定时器的格式

    DELIMITER $$

        ALTER DEFINER=`root`@`localhost` EVENT `test` ON SCHEDULE EVERY 1 MINUTE STARTS ‘2018-04-26 18:40:32’             ON     COMPLETION NOT PRESERVE ENABLE DO BEGIN

                    //要执行的SQL语句

           END$$

    DELIMITER ;

10、将30分钟内未发送消息的用户置为下线(觉得不是很容易写,半个多小时才写出来,记录一下)

    UPDATE customer SET online=0

        WHERE id IN

            (SELECT customerId FROM

                     (SELECT customerId,MAX(`time`) maxTime FROM cs_chat_record GROUP BY customerId) temp

                WHERE maxTime <CURRENT_TIMESTAMP – INTERVAL 30 MINUTE);

未解决的问题:

1、每秒一次获取用户列表,页面会有闪烁。

2、火狐浏览器只在关闭页面时执行window.onbeforeunload方法,关闭整个浏览器时不执行。

3、“发送内容不为空”和“请选择用户”的判断都是在后台做的,感觉应该在前端做。

主要代码:

客服页:

<!DOCTYPE html>
<%@ page language="java" pageEncoding="utf-8"%>
<%@ include file="/platform/common/jsp/taglibs.jsp"%>
<html>
<head>
	<title>客服中心</title>
	<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="apple-mobile-web-app-status-bar-style" content="black">
	<!--微信不缓存东西  start-->
	<meta http-equiv="Pragma" content="no-cache" />
	<meta http-equiv="Expires" content="0" />
	<style type="text/css">
		.myclass{
			width:100%;
			font-size: 12pt;
			padding-bottom: 10px;
		}
		.myclass span{
			width:100px;
			background-color: #66b3ff;
			border: 1px;
		}
	</style>
	<link rel="stylesheet" type="text/css" href="${path}/module/cs/css/easyui.css">
	<script type="text/javascript" src="${path}/module/cs/js/jquery.min.js"></script>
	<script type="text/javascript" src="${path}/module/cs/js/jquery.easyui.min.js"></script>
	<script type="text/javascript">
		var oldId = 1;
		//计算时间间隔
		function computeTime(oldTime){
			date = new Date(oldTime);
			var date2 = date.getTime()-datetemp.getTime();
			//一分钟内再次发消息,则不显示发送消息的时间
			if(date2>60000){
				var flagH="";
				var flagM="";
				var hour = date.getHours();
				var min= date.getMinutes();
				//解决小时和分钟小于10,数字前面不显示0的情况
				if(hour<10)flagH="0";else flagH="";
				if(min<10)flagM=":0";else flagM=":";
				//发送内容时间
				$("#contentCS").append("<div style='text-align:center ;'>"+flagH+hour+flagM+min+"</div>")
				datetemp=date;
			}
		}
		
		function getAllRecord(){
			$.ajax({
			   url : "${path}/cs/getAllChatRecord?idTemp=user_id&id="+id+"&oldId="+oldId,
			   type : "POST",
		       dataType:"json",
		       data :null,
	    	   success : function(data) {
					if (data.success) {
						//将聊天信息显示到页面上
						for ( var i in data.obj) {
							var csChatRecord = data.obj[i];
							if(csChatRecord.userContent != null && csChatRecord.userContent != ''){
								computeTime(csChatRecord.time); 
						        $("#contentCS").append("<div class='myclass' style='text-align:right ;'><span>"				
										+csChatRecord.userContent
								+"</span></div>");				
							}
							if(csChatRecord.customerContent != null && csChatRecord.customerContent != ''){
								computeTime(csChatRecord.time); 
								$("#contentCS").append("<div class='myclass'><span>"				
										+csChatRecord.customerContent
								+"</span></div>");
							}
							oldId=csChatRecord.id;
						}
					} else {
						alert(data.msg);
					}
				} ,	
		       error:function(result){
		             alert("服务器丢了");
		         }	
		     });
		}
		//获取左侧正在沟通的用户列表
		function getCustomerList(){
			$("#westList").html("");
			$.ajax({
			   url : "${path}/cs/getCustomerList",
			   type : "POST",
		       dataType:"json",
	    	   success : function(data) {
					if (data.success) {
						var onlineFlag=1;
						//用户下线,如果客服人员正在与此人沟通,那么清空聊天页面
						for ( var i in data.obj) {
							var customer = data.obj[i];
							if(id==customer.id){
								onlineFlag=0;
							}
						}
						if(onlineFlag==1){
							$("#contentCS").html("");
							id="";
						}
						//获得用户列表,显示到页面上
						for ( var i in data.obj) {
							var customer = data.obj[i];
							cId=customer.id;
							var cHeadImg=customer.headImg;
							var cName=customer.name;
							
							if(customer.online >0){
						        $("#westList").append(
						        	"<div id="+cId+" class='CustomerBG'><img alt='加载中' src='${path }/module/cs/images/"
										+cHeadImg
										+"' height='40px' width='40px' >"
						        	+"<label id='labelId' class='checkLabel' style='font-size: 12pt;'data_id='"				
										+cId
										+"'>"
						        		+cName
						        	+"</div>");
							}
							//防止列表刷新将选中的用户置为未选中状态
					        if(cId==id){
								$("div#"+cId).css('background','#00ffff');
					        }
						}
					} else {
						alert(data.msg);
					}
				} ,	
		       error:function(result){
		             alert("服务器丢了");
		         }	
		     });
		}
		var datetemp=new Date(0);//用于计算时间差的中间变量
		var date;
		$(function(){
			//获取用户列表
			getCustomerList();
			//定时刷新
			setInterval('getCustomerList()',1000);
			//消息存入数据库
			$("#send").click(function() {
				$.ajax({
				   url : "${path}/cs/saveUserChatRecord?id="+id,
				   type : "POST",
			       dataType:"json",
			        /* 向后端传输的数据 */ 
			       data :$("#ff").serialize(),
		    	   success : function(data) {
						if (!data.success) {
							alert(data.msg);
						} 
						$("#textId").textbox('clear');
					} ,	
			       error:function(result){
			             alert("发送失败");
			         }	
			     });
			});
		});
		var id = "";
		$(document).off("click", ".checkLabel").on("click", ".checkLabel", function(){
			oldId = 1;
			datetemp=new Date(0);
			id = $(this).attr("data_id");
			$(".CustomerBG").css('background','#ffffff');
			$("div#"+id).css('background','#00ffff');
			$("#contentCS").html("");
			$("#contentCS").append("<div class='myclass'>当前正在沟通的用户:"+$(this).text()+"</div>");
			//从数据库读取消息
			getAllRecord();
			// 定时刷新组件,读取数据库信息 
			setInterval('getAllRecord()',1000);
		});
	</script>
</head>
<body>
	<div id="cc" class="easyui-layout" style="width:600px;height:500px;" fit="true">   
	    <!-- <div data-options="region:'north'" style="height:10%"></div>   --> 
	    <div data-options="region:'south'" style="height:30%;">   
	    	<form id="ff" style="height:100%;width:100%" >   
			    <div>   
			        <input id="textId" class="easyui-textbox" name="userContent" style="height:120px;width:100%;border: 0;" multiline="true" prompt="说点什么吧..." />   
			    </div>  
			    <div style="float:right" >   
					<button type="button" id="send" >发送</button>
			    </div>   
			</form>  
		</div>
	    <!-- <div data-options="region:'east'" style="width:10%;"></div>    -->
	    <div id="westList" data-options="region:'west'" style="width:20%;">
	    	正在沟通的用户
		    <button type="button" id="list" style="display: none"></button>
	    </div>   
	    <div id="contentCS" data-options="region:'center'" style="padding:5px;" >
	    	
	    </div>   
	</div>   
</body>
</html>

用户页:

<!DOCTYPE html>
<%@ page language="java" pageEncoding="utf-8"%>
<%@ include file="/platform/common/jsp/taglibs.jsp"%>
<html>
<head>
	<title>客服中心</title>
	<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="apple-mobile-web-app-status-bar-style" content="black">
	<!--微信不缓存东西  start-->
	<meta http-equiv="Pragma" content="no-cache" />
	<meta http-equiv="Expires" content="0" />
	<style type="text/css">
		.myclass{
			width:100%;
			font-size: 12pt;
			padding-bottom: 10px;
		}
		span{
			width:100px;
			background-color: #66b3ff;
			border: 1px;
		}
	</style>
	<link rel="stylesheet" type="text/css" href="${path}/module/cs/css/easyui.css">
	<script type="text/javascript" src="${path}/module/cs/js/jquery.min.js"></script>
	<script type="text/javascript" src="${path}/module/cs/js/jquery.easyui.min.js"></script>
	<script type="text/javascript">
		var oldId = 1;
		//计算时间间隔
		function computeTime(oldTime){
			date = new Date(oldTime);
			var date2 = date.getTime()-datetemp.getTime();
			//一分钟内再次发消息,则不显示发送消息的时间
			if(date2>60000){
				var flagH="";
				var flagM="";
				var hour = date.getHours();
				var min= date.getMinutes();
				//解决小时和分钟小于10,数字前面不显示0的情况
				if(hour<10)flagH="0";else flagH="";
				if(min<10)flagM=":0";else flagM=":";
				//发送内容时间
				$("#content").append("<div style='text-align:center ;'>"+flagH+hour+flagM+min+"</div>")
				datetemp=date;
			}
		}
		function getAllRecord(){
			$.ajax({
			   url : "${path}/cs/getAllChatRecord?idTemp=customer_id&oldId="+oldId,
			   type : "POST",
		       dataType:"json",
	    	   success : function(data) {
					if (data.success) {
						for ( var i in data.obj) {
							var csChatRecord = data.obj[i];
							if(csChatRecord.userContent != null && csChatRecord.userContent != ''){
								computeTime(csChatRecord.time); 
								//发送的内容
						        $("#content").append("<div class='myclass'><span>"				
										+csChatRecord.userContent
								+"</span></div>");
							}
							if(csChatRecord.customerContent != null && csChatRecord.customerContent != ''){
								computeTime(csChatRecord.time); 
								$("#content").append("<div class='myclass' style='text-align:right ;'><span>"				
										+csChatRecord.customerContent
								+"</span></div>");
							}
							oldId=csChatRecord.id;
						}
					} else {
						alert(data.msg);
					}
				} ,	
		       error:function(result){
		             alert("获取所有消息失败");
		         }	
		     });
		}
		var datetemp=new Date(0);//用于计算时间差的中间变量
		var date;
		$(function(){
			getAllRecord();
			/* 定时刷新组件,读取数据库信息 */
			setInterval('getAllRecord()',1000);
			/* 定时刷新组件,读取时间 */
			$("#send").click(function() {
				$.ajax({
				   url : "${path}/cs/saveCustomerChatRecord",
				   type : "POST",
			       dataType:"json",
			        /* 向后端传输的数据 */ 
			       data :$("#ff").serialize(),
		    	   success : function(data) {
						if (data.success) {
							$("#textId").textbox('clear');
						} else {
							alert(data.msg);
							$("#textId").textbox('clear');
						}
					} ,	
			       error:function(result){
			             alert("发送失败");
			         }	
			     });
			});
		});
	   window.onbeforeunload = function()  
	    {     
			$.ajax({
				   url : "${path}/cs/customerOffline",
				   type : "POST",
			     });
	    }     
	</script>
</head>
<body>
	<div id="cc" class="easyui-layout" style="width:600px;height:400px;" fit="true">  
	    <div data-options="region:'north'" style="height:15%">
	    	<h1 >客服中心</h1>  
	    </div>   
	    <div data-options="region:'south'" style="height:25%;">   
	    	<form id="ff" style="height:100%;width:100%" >   
			    <div>   
			        <input id="textId" class="easyui-textbox" name="customerContent" style="height:100px;width:100%" multiline="true" prompt="说点什么吧..." />   
			    </div>   
			    <div style="float:right" >   
					<button type="button" id="send">发送</button>
			    </div>   
			</form>  
		</div>
	    <!-- <div data-options="region:'east'" style="width:10%;"></div>   
	    <div data-options="region:'west'" style="width:10%;"></div> -->   
	    <div id="content" data-options="region:'center'" style="padding:5px;" >
	    </div>   
	</div>   
</body>
</html>

controller:

@Controller
@RequestMapping(value = "/cs")
public class CSController extends SpringController{
	@Autowired
	private CSService csService;
	@Autowired
	private UserService userService;
	/**
	 * 将用户发送的消息保存到数据库
	 * @param userContent
	 * @return
	 */
	@RequestMapping(value = "/saveCustomerChatRecord",method=RequestMethod.POST)
	@ResponseBody
	public AjaxJson saveCustomerChatRecord(@RequestParam(value = "customerContent", required = false) String customerContent) {
		AjaxJson ajaxJson =new AjaxJson();
		CSChatRecord csChatRecord = new CSChatRecord();
		try {
			User user = (User) getRequest().getSession().getAttribute("user");
			Customer customer = (Customer) getRequest().getSession().getAttribute("customer");
			//获取当前时间 
			String datetime = DateUtil.getCurrDateSecondString();
			//封装csChatRecord对象
			csChatRecord.setUserId(user.getId());
			csChatRecord.setCustomerId(customer.getId());
			csChatRecord.setTime(datetime);
			customerContent = customerContent.trim();
			if(customerContent != null && !customerContent.equals("")){
				csChatRecord.setCustomerContent(customerContent);
				//将csChatRecord对象保存到数据库
				csService.saveCustomerChatRecord(csChatRecord);
			}else{
				ajaxJson.setSuccess(false);
				ajaxJson.setMsg("发送内容不能为空");
			}
			customer.setHeadImg("C_new.jpg");
			csService.updateHeadImgState(customer);
			return ajaxJson;
		}catch (Exception e) {
			e.printStackTrace();
			ajaxJson.setSuccess(false);
			ajaxJson.setMsg("服务器跑丢了。。");
			return ajaxJson;
		}
	}

	/**
	 * 将客服发送的消息保存到数据库
	 * @param userContent
	 * @return
	 */
	@RequestMapping(value = "/saveUserChatRecord",method=RequestMethod.POST)
	@ResponseBody
	public AjaxJson saveUserChatRecord(@RequestParam(value = "userContent", required = false) String userContent,
			@RequestParam(value = "id", required = false) String id) {
		AjaxJson ajaxJson = new AjaxJson();
		CSChatRecord csChatRecord = new CSChatRecord();
		try {
			if(id==null || id==""){
				ajaxJson.setSuccess(false);
				ajaxJson.setMsg("请选择用户");
				return ajaxJson;
			}
			User user = (User) getRequest().getSession().getAttribute("user");
			//获取当前时间
			String datetime = DateUtil.getCurrDateSecondString();
			//封装csChatRecord对象
			csChatRecord.setUserId(user.getId());
			csChatRecord.setCustomerId(id);
			csChatRecord.setTime(datetime);
			userContent = userContent.trim();
			if(userContent != null && !userContent.equals("")){
				csChatRecord.setUserContent(userContent);
				//将csChatRecord对象保存到数据库
				csService.saveUserChatRecord(csChatRecord);
			}else{
				ajaxJson.setSuccess(false);
				ajaxJson.setMsg("发送内容不能为空");
			}
			return ajaxJson;
		} catch (Exception e) {
			e.printStackTrace();
			return ajaxJson;
		}
	}
	
	/**
	 * 从数据库读取所有聊天记录,展示在页面上
	 * 客服和用户公用同一个方法,
	 * idTemp:为user_id时表示客服,为customer_id时表示用户
	 * id:客服读消息时用到的用户id
	 * oldId:上一次读取新消息的记录,保证每次读取的都是最新消息
	 * @return
	 */
	@RequestMapping(value = "/getAllChatRecord")
	@ResponseBody
	public AjaxJson getAllChatRecord(@RequestParam(value = "idTemp", required = false) String idTemp,
			@RequestParam(value = "id", required = false) String id,
			@RequestParam(value = "oldId", required = false) int oldId) {
		AjaxJson ajaxJson =new AjaxJson();
		CSChatRecord csChatRecord = new CSChatRecord();
		User user = (User) getRequest().getSession().getAttribute("user");
		Customer customer = new Customer();
		try {
			//判断是用户页面还是客服页面读取数据库消息
			if(idTemp.equals("user_id")){//客服
				csChatRecord.setCustomerId(id);
				customer.setId(id);
				customer.setHeadImg("C.jpg");
				csService.updateHeadImgState(customer);
			}else if(idTemp.equals("customer_id")){
				customer = (Customer) getRequest().getSession().getAttribute("customer");
				csChatRecord.setCustomerId(customer.getId());
			}
			csChatRecord.setUserId(user.getId());
			csChatRecord.setId(oldId);
			List<CSChatRecord> alllist = csService.getAllChatRecord(csChatRecord);
			if(alllist.size()>0){
				ajaxJson.setObj(alllist);
			}
			return ajaxJson;
		} catch (Exception e) {
			e.printStackTrace();
			return ajaxJson;
		}
	}
	/**
	 * 客服界面
	 * @return
	 */
	@RequestMapping(value = "/goUser")
	public String goUser() {
		try {
			return "module/cs/jsp/weChat_user";
		} catch (Exception e) {
			e.printStackTrace();
			return "module/weChat/jsp/weChat_404";
		}
	}
	/**
	 * 用户界面
	 * @return
	 */
	@RequestMapping(value = "/goCustomer")
	public String goCustomer() {
		int temp = 0;
		User userTemp = new User();
		Customer customer = new Customer();
		try {
			Customer customer2 = (Customer) getRequest().getSession().getAttribute("customer");
			if(customer2 == null){
				//获取所有在线客服每个人正在接待的用户人数
				List<User> userList = userService.getAllUserState();
				userTemp = userList.get(0);
				temp = userTemp.getCurrentPeople();
				for (User user : userList) {
					if(user.getCurrentPeople()<temp){
						temp = user.getCurrentPeople();
						userTemp = user;
					}
				}
				//修改当前客服接待人数,currentPeople+1
				userService.updateCurrentPeople(userTemp);
				String session = getRequest().getSession().getId();
				customer.setId(session);
				//设置当前用户的在线状态
				customer.setOnline(1);
				int number = (int) ((Math.random()*100)+1);
				customer.setName("用户"+number);
				csService.insertCustomer(customer);
				getRequest().getSession().setAttribute("customer", customer);
				getRequest().getSession().setAttribute("user", userTemp);
			}else{
				customer2.setOnline(1);
				csService.updateCustomerOnline(customer2);
			}
			return "module/cs/jsp/weChat_customer";
		} catch (Exception e) {
			e.printStackTrace();
			return "module/weChat/jsp/weChat_404";
		}
	}
	/**
	 * 用户下线
	 */
	@RequestMapping(value = "/customerOffline",method=RequestMethod.POST)
	@ResponseBody
	public void customerOffline() {
		Customer customer = (Customer) getRequest().getSession().getAttribute("customer");
		customer.setOnline(0);
		customer.setHeadImg("C.jpg");
		csService.updateCustomerOnline(customer);
	}
	/**
	 * 获取当前正在沟通的用户
	 * @return
	 */
	@RequestMapping(value = "/getCustomerList",method=RequestMethod.POST)
	@ResponseBody
	public AjaxJson getCustomerList() {
		User user = (User) getRequest().getSession().getAttribute("user");
		AjaxJson ajaxJson = new AjaxJson();
		List<CSChatRecord> customerList = csService.getCustomerList(user.getId());
		if(customerList.size()>0)
			ajaxJson.setObj(customerList);
		return ajaxJson;
	}
}

今天的文章网页版在线客服实现代码分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23853.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注