window.print() 打印学时证明

本文介绍了一个基于MVC架构的项目实现细节,包括使用Struts框架进行页面展示和交互控制的方法。探讨了前台打印功能、复选框多选操作等关键技能点,并通过具体示例展示了如何组织代码和配置文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[size=medium]

主要按照MVC的顺序,+mapper.xml文件.
参考前台打印. //
主要技能点:
1.复选框的多选.
2.window.print();


[img]http://dl2.iteye.com/upload/attachment/0111/6996/1fe96e4d-b3b8-3301-9d3c-2be037f53016.png[/img]

[img]http://dl2.iteye.com/upload/attachment/0111/6998/640a6abd-5a0d-3786-b7b3-df75cec5544d.jpg[/img]


deptViewPersonList.jsp 培训组织者的学员查询页面. 含有打印按钮和复选框的批量打印.
[/size]

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<%@ include file="/common/common.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>学员查询</title>

<%--北京方面制定的样式 添加. --%>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/common/jquery/jquery-1.7.2.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/common/myLand.js"></script>
<%--分页用CSS --%>
<link href="${pageContext.request.contextPath}/css/adminx/common_style.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/webcustomer/pagination.js"></script>

<link href="${pageContext.request.contextPath}/css/adminx/jquery.fancybox-1.3.4.css" rel="stylesheet" type="text/css" media="screen"></link>
<link href="${pageContext.request.contextPath}/css/adminx/basic_layout.css" rel="stylesheet" type="text/css">

<script type="text/javascript" src="${pageContext.request.contextPath}/js/adminx/commonAll.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/adminx/fancybox/jquery.fancybox-1.3.4.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/adminx/fancybox/jquery.fancybox-1.3.4.pack.js"></script>

<%--时间控件部分 放在上面--%>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/common/My97DatePicker/WdatePicker.js"></script>
<!-- artDialog样式: 3+1-->
<link id="artDialogSkin" href="${pageContext.request.contextPath }/js/adminx/artDialog/skins/blue.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="${pageContext.request.contextPath }/js/adminx/artDialog/jquery.artDialog.source.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/adminx/artDialog/plugins/iframeTools.source.js"></script>
<!-- artDialog样式 end-->

<!-- 树形图专属 3个js+2个css -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/adminx/catType.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/common/ztree/jquery.ztree.core-3.5.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/jsp/demo/ztreeNodes.js"></script>
<link href="${pageContext.request.contextPath}/css/common/zTreeStyle/demo.css" rel="stylesheet" type="text/css" />
<link href="${pageContext.request.contextPath}/css/adminx/zTreeStyle_special.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var zNodes = ${jsonTree};
var isIE;

$(document).ready(function(){
$.fn.zTree.init($("#treeDemo"),setting,zNodes);
if(document.all){
isIE = true;
}else{
isIE = false;
}
});
//打印学时证明预览 单打.
function printac(startDate,endDate,targetTime,courseName,realName,idCard,certificationNum,registerFaceImage,pId){

var url = "${pageContext.request.contextPath}/adminx/personAction!enterPrintAc.do?startDate="+startDate+"&endDate="+endDate+"&targetTime="+targetTime
+"&courseName="+courseName+"&realName="+realName+"&idCard="+idCard+"&certificationNum="+certificationNum
+"&id="+pId+"&isIE="+isIE; //personAction | +"&registerFaceImage="+registerFaceImage


url = encodeURI(encodeURI(url));
var res = showModalDialog(url,window,"dialogHeight=630px;dialogWidth=1000px;status=no;");

}


/*
* 批量打印
*/
function printAll(){
var ids = $("input[name='ids']:checked").length;
if(ids == 0){
mylandAlert("信息提示", "请选择要打印的学时证明!");
return;
}else{
var s = "";
$("input[name='ids']:checked").each(function(){
if($(this).attr("checked")){
s+=$(this).val()+",";
}
});
// alert("s:"+s); //把选中结合起来.
mylandConfirmByFunc("批量打印", "确定批量打印吗?",

function(){

//way2:直接请求返回页面中. 判断是否是IE,是IE提示.
var url = '${pageContext.request.contextPath}/adminx/personAction!batchPrintByOnePage.do?act=printer_all&idsString='+s+"&isIE="+isIE;

url = encodeURI(encodeURI(url));
//resizable=yes ;测试过程中; 提交的时候要改为不可调整.
//window.open(url,'newwindow','height=630,width=1000,top=0,left=0,toolbar=no,menubar=no,scrollbars=yes, resizable=yes,location=no, status=no')
var res = showModalDialog(url, window,"dialogHeight=630px;dialogWidth=1000px;status=no;");
//way1:ajax请求.
//myLandAjaxJson("${pageContext.request.contextPath}/adminx/personAction!batchPrint.do", "agentAction", showView);
},
function(){
return;
}
);
}

}



function showView(code,ajaxPara){
var temp = eval("("+ajaxPara+")");
if(code == "00" && temp.code == "00"){
//myLandAlert("提示", temp.message); 批量获取成功.

//批量打印
var data= temp.message; //

data_count = 0;
var jsonarray = $.parseJSON(data);

printer(jsonarray,data_count); //

//way2:pringBatchByOnePage(); //在一个页面实现批量打印,通过分页的方式.
}else{
return;
}
}

/*
5s弹出,打印
*/
function printer(jsonarray,data_count){ //

/*
在前台,使用jquery的parseJSON方法来进行解析,并用jquery的foreach的方法来进行解析
*/
if(jsonarray.length == data_count){ return false; }

//.B
//alert(jsonarray[data_count].realName);
/* var url = "${pageContext.request.contextPath}/adminx/personAction!enterPrintAc.do?startDate="+startDate+"&endDate="+endDate+"&targetTime="+targetTime
+"&courseName="+courseName+"&realName="+realName
+"&idCard="+idCard+ "&certificationNum="+certificationNum+"&registerFaceImage="+registerFaceImage +"&id="+pId; */
var url = '${pageContext.request.contextPath}/adminx/personAction!enterPrintAc.do?act=printer_all&realName='+jsonarray[data_count].realName+'&idCard='+jsonarray[data_count].idCard+'&startDate='+jsonarray[data_count].startDate+
'&endDate='+jsonarray[data_count].endDate+'&courseName='+jsonarray[data_count].courseName+'&targetTime='+jsonarray[data_count].targetTime+'&currentDate='+jsonarray[data_count].currentDate
+"&idCard="+jsonarray[data_count].idCard+ "&certificationNum="+jsonarray[data_count].certificationNum+"&registerFaceImage="+jsonarray[data_count].registerFaceImage +"&id="+jsonarray[data_count].pId;
+'&print=1';
//alert("url转码前:"+url);
url = encodeURI(encodeURI(url));
//alert("url转码后:"+url);
//way2:window.open(); 请求action. //${pageContext.request.contextPath}/adminx/viewPerson/printAc.jsp || +Math.random()
window.open(url,'newwindow','height=630,width=1000,top=0,left=0,toolbar=no,menubar=no,scrollbars=no, resizable=no,location=no, status=no')

//way1.B :showModalDialog(); //"${pageContext.request.contextPath}/adminx/personAction!enterPrintAc.do?startDate="+startDate+"&endDate="+endDate+"&targetTime="+targetTime+"&courseName="+courseName+"&realName="+realName+"&idCard="+idCard; //personAction |
if(data_count < jsonarray.length){
data_count++;
window.setTimeout(printer,5000,jsonarray,data_count);
}

/*
$.each(jsonarray,function(i,n)){
alert(n.realName);
}
*/

}

/*
需注意: setTimeout()
如果传入的是一个对象,那么它是不支持的。我要传的参数那必须是有obj的。通过网络的力量得到解决,假如此方法,就可以传obj参数了:
*/
var __sto = setTimeout;
window.setTimeout = function(callback,timeout,param)
{
var args = Array.prototype.slice.call(arguments,2);
var _cb = function()
{
callback.apply(null,args);
}
__sto(_cb,timeout);
}

</script>

</head>
<body>

<%--学员信息列表查询 --%>
<form id="agentAction" name="quryForm" action="${pageContext.request.contextPath}/adminx/deptViewPerson.do" method="post">
<s:hidden name="flag" id="flag"></s:hidden>
<div id="container"><!-- 总外容器 含两部分,头部条件,下部分列表显示的-->
<div class="ui_content"> <!-- 头部 溢出隐藏. -->
<div class="ui_text_indent">
<%--整体盒子分 三大部分.头部 搜索提示 --%>
<div id="box_border" > <%--头部的css --%>
<c:if test="${ agent_id==null}">
<%--如果没有agent_id,就是从组织者学员查询来的;有则是从代理明细/学员查询过来的. --%>
<div id="box_center" style="height: 110px;"> <!--css 时间,普通用2,select用4.提交的时候,不管我的form -->
<table > <%--border="2px black solid;" --%>
<tr>
<td>
身份证号:</td>
<td>
<input id="pIdCard" class="ui_input_txt02" name="viewPerson.pIdCard" value="${qc.conditionsObj.pIdCard }"/>
</td>
<td>
姓名:</td>
<td>
<input id="pRealName" name="viewPerson.pRealName" class="ui_input_txt02" value="${qc.conditionsObj.pRealName }"/>
</td>
<td>
组织机构:</td>
<td>
<select id="deptId" name="deptId" class="ui_input_txt05">
<option value="all">全部</option>
<c:if test="${deptList!=null && fun:length(deptList)>0 }"> <%--和数据统计的 对比. ★ --%>
<c:forEach var="t" items="${deptList }">
<option value="${t.id }"<c:if test="${qc.conditionsStr.deptId==t.id }">selected</c:if>>${t.name }</option>
</c:forEach>
</c:if>
</select>
</td>
</tr>
<tr>
<td>
类别体系:
</td>
<td>
<div class="menuContent">
<div class="zTreeDemoBackground left"> <%--value="${qc.conditionsStr.licenseType}" 对应7--%>
<input type="text" id="catTypeId" name="catTypeId" style="width:220px; readonly="readonly" class="ui_input_txt02" onclick="showMenu(); return false;" value="${qc.conditionsStr.catTypeId }"/>
<input type="hidden" name="licenseType" id="licenseType"/>
</div>
</div>

<div id="menuContent" class="menuContent" style="display:none;position:absolute;z-index: 100;">
<ul id="treeDemo" class="ztree" style="margin-top: 0;height:120px;"></ul>
</div>
</td>
<td>
时间段:
</td>
<td>
<input id="begintime" class="Wdate ui_input_txt02" name="begintime" value="<s:date name="begintime" format="yyyy-MM-dd"/>" onfocus="WdatePicker({maxDate:'#F{$dp.$D(\'endtime\')}'})" />

<input id="endtime" class="Wdate ui_input_txt02" name="endtime" value="<s:date name="endtime" format="yyyy-MM-dd"/>" onfocus="WdatePicker({minDate:'#F{$dp.$D(\'begintime\')}'})"/>
<%--style="height:28px;"
1.B原,精确到s onfocus="WdatePicker({lang:'zh-cn',dateFmt:'yyyy-MM-dd HH:mm:ss'})"
2.B <s:textfield id="begintime" name="begintime" cssClass="ui_select01" onfocus="WdatePicker({lang:'zh-cn',dateFmt:'yyyy-MM-dd'})"></s:textfield> 缺陷:onfocus
关键控制显示的值.否则,onclick变为1900年的.
--%>
</td>
<td>
学习状态:
</td>
<td>
<select id="planStatus" name="viewPerson.ppPlanStatus" class="ui_input_txt05">
<option value="all">全部</option>
<option value="0" <c:if test="${qc.conditionsStr.ppPlanStatus == '0' }">selected</c:if>>未开通</option>
<option value="1" <c:if test="${qc.conditionsStr.ppPlanStatus == '1' }">selected</c:if>>未支付</option>
<option value="2" <c:if test="${qc.conditionsStr.ppPlanStatus == '2' }">selected</c:if>>支付中</option>
<option value="3" <c:if test="${qc.conditionsStr.ppPlanStatus == '3' }">selected</c:if>>学习中</option>
<option value="4" <c:if test="${qc.conditionsStr.ppPlanStatus == '4' }">selected</c:if>>已完成</option>
<option value="9" <c:if test="${qc.conditionsStr.ppPlanStatus == '9' }">selected</c:if>>已取消</option>
</select>
</td>
</tr>
</table>
</div> <!-- 中间部分的搜索条件 **) end-->

<div id="box_bottom" style="text-align:left;border: 2px;">
<input type="submit" value="查询" class="ui_input_btn01" /><!--   -->
<input type="button" value="打印合格证明" class="ui_input_btn01" onclick="javascript:printAll();"/>
<font class="tip">注:打印功能仅限完成学习的学员</font>
</div>
</c:if>
</div>
</div> <!-- ui_text_indent end-->
</div> <!-- ui_content end -->
<div class="ui_content">
<div class="ui_tb">
<table id="dataTable" class="table" cellspacing="0" cellpadding="0" width="100%" align="center" border="0">
<tr>
<th width="5%">
<input name="chkAll" id="chkAll" type="checkbox" onclick="javascript:checkAll('chkAll', 'ids');" value="checkbox"/>
</th>
<th width="50">序号</th>
<th>身份证号</th>
<th>姓名</th>
<%--<th>性别</th> --%>
<th>联系电话</th>
<%-- <th>学员状态</th>--%>
<th>最后登录时间</th>
<th>计划名称</th>
<%--
<th>计划状态</th>
--%>
<th>注册时间</th>
<%--<th>有效期开始</th>
<th>有效期结束</th> --%>
<th>当前学时/目标学时</th>
<th>最后学习时间</th>
<th>操作</th>
</tr>
<c:choose>
<c:when test="${empty viewList}">
<tr>
<td colspan="15">
无相关记录
</td>
</tr>
</c:when>
<c:otherwise>
<c:forEach var="viewList" items="${viewList}" varStatus="stats">
<tr>
<td align="center"> <%--disabled="disabled" --%>

<input name="ids" id="ids" type="checkbox" value="${viewList.ppId }" <c:if test="${ viewList.ppPlanStatus != '4'}">disabled="true"</c:if>/>
</td>
<td>
<%-- <input type="text" name="ppId" id="ppId" value="${viewList.ppId }"/> --%>
<myland:index qc="${qc}" step="${stats.index+1}"/><%-- ppId为:${viewList.ppId } --%>
</td>
<td>${viewList.pIdCard}</td>
<td>${viewList.pRealName}</td>
<%-- <td>
<c:choose>
<c:when test="${viewList.pSex=='0'}">男</c:when>
<c:when test="${viewList.pSex=='1'}">女</c:when>
<c:when test="${viewList.pSex=='2'}">未知</c:when>
</c:choose>
</td> --%>
<td>${viewList.pTel}</td>
<%-- <td>
<c:choose>
<c:when test="${viewList.pPStatus=='0'}">注册</c:when>
<c:when test="${viewList.pPStatus=='1'}">已付费</c:when>
<c:when test="${viewList.pPStatus=='2'}">付费中</c:when>
<c:when test="${viewList.pPStatus=='3'}">学习中</c:when>
<c:when test="${viewList.pPStatus=='4'}">完成</c:when>
</c:choose>
</td> --%>
<td>${viewList.pLastLogin}</td>
<td>${viewList.planName}</td>
<%--
<td>
<c:choose>
<c:when test="${viewList.ppPlanStatus=='0'}">测试学员</c:when>
<c:when test="${viewList.ppPlanStatus=='1'}">普通学员</c:when>
</c:choose>
<td>
<c:choose>
<c:when test="${viewList.ppAddType=='0'}">注册</c:when>
<c:when test="${viewList.ppAddType=='1'}">导入</c:when>
</c:choose>
</td>
</td>
--%>
<td>
${viewList.pAddTime }<%--datetime的显示方式 --%>
</td><%-- String的显示方式 s:date format="yyyy-MM-dd" datetime 数据类型 只显示时分秒--%>
<td>${viewList.ppSumStudyTime}/${viewList.ppTargetStudyTime}</td>
<td>
<fmt:formatDate value="${viewList.ppLastDate}" pattern="yyyy-MM-dd HH:mm:ss"/>
</td>
<td width="80">
<span class="chakan">
<a href="${pageContext.request.contextPath}/adminx/personRecordAction.do?personId=${viewList.ppPersonId}&personPlanId=${viewList.ppId}">学习记录</a>
</span>
<span class="chakan">
<a href="${pageContext.request.contextPath}/adminx/personExamAction.do?personPlanId=${viewList.ppId}">考试记录</a>
</span>
<span class="chakan">
<myland:adminx_auth action="/adminx/personPhotoCheckAction.do">
<a href="${pageContext.request.contextPath}/adminx/personPhotoCheckAction.do?personPlanId=${viewList.ppId}">照片审核</a>
</myland:adminx_auth>
</span>
<span class="chakan">
<%-- <myland:adminx_auth action=""></myland:adminx_auth>
ppStartDate,
pp_end_date AS ppEndDate,

${viewList.ppRegisterFaceImage }--%>
<c:if test="${ viewList.ppPlanStatus == '4'}">
<a href="#" onclick="printac('<fmt:formatDate value="${viewList.startLearnTime}" pattern="yyyy-MM-dd"/>','<fmt:formatDate value="${viewList.finishLearnTime}" pattern="yyyy-MM-dd"/>','${viewList.ppTargetStudyTime }','${viewList.planName }','${viewList.pRealName }','${viewList.pIdCard}','${viewList.certificationNum }','${viewList.ppRegisterFaceImage }','${viewList.pId }');return false;" >打印学时证明</a>
</c:if>
</span>
</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
</table>
</div> <%--中部 end --%>
<myland:page pagination="${qc.pagination}" showType="002"/>
</div><%--ui_content end --%>
</div><!-- 总外容器 end-->
</form> <!-- 总form end -->
<%-- 提交打印的表单 --%>
<form action="" id="printForm" name="printForm" method="post">
<input type="hidden" id="startDate" name="startDate"/>
<input type="hidden" id="endDate" name="endDate"/>
<input type="hidden" id="targetTime" name="targetTime"/>
<input type="hidden" id="courseName" name="courseName" />
<input type="hidden" id="realName" name="realName" />
<input type="hidden" id="idCard" name="idCard" />
</form>
</body>
</html>


PersonAction.java 主要方法printAc(); 打印;
printAcBatch(); 批量打印

package com.myland.jp.adminx.person.action;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.google.gson.Gson;
import com.myland.framework.annotation.Token;
import com.myland.framework.base.AjaxHead;
import com.myland.framework.base.BaseAction;
import com.myland.framework.init.BaseConf;
import com.myland.framework.mybatis.query.Condition;
import com.myland.framework.mybatis.query.CxxString;
import com.myland.framework.mybatis.query.QueryCriterion;
import com.myland.framework.mybatis.query.QueryRulesCreator;
import com.myland.framework.util.ExceptionPrintUtil;
import com.myland.framework.util.LogUtil;
import com.myland.framework.util.collections.ListUtil;
import com.myland.framework.util.collections.MapUtil;
import com.myland.framework.util.time.DateFormatUtil;
import com.myland.jp.common.CommonMessage;
import com.myland.jp.common.service.AgentService;
import com.myland.jp.common.service.PersonFaceImageService;
import com.myland.jp.common.service.PersonPlanService;
import com.myland.jp.common.service.PersonService;
import com.myland.jp.common.service.PlanService;
import com.myland.jp.common.service.ViewPersonPersonPlanService;
import com.myland.pojo.Person;
import com.myland.pojo.PersonFaceImage;
import com.myland.pojo.Plan;
import com.myland.pojo.User;


/**学员管理
*
* @create 2015年1月12日
*/
public class PersonAction extends BaseAction {

/**
* 序列号
*/
private static final long serialVersionUID = 1759551448629970681L;

/**
* 日志工具类
*/
private static final Logger log = LogManager.getLogger(PersonAction.class);

/**
* 学员业务逻辑操作
*/
private PersonService personService;

/**
* 学习计划业务逻辑操作
*/
private PlanService planService;

/**
* 学员学习计划业务逻辑操作
*/
private PersonPlanService personPlanService;

/**
* 代理商业务逻辑处理类
*/
private AgentService agentService;

/**
* 学员权限Map
*/
private Map<String, String> resDatasMap;

/**
* 学员对应的权限
*/
private String resDatas_dept;

/**
* 代理商对应的权限
*/
private String resDatas_agent;

/**
* 学习计划ids
*/
private String planIds;

/**
* 学员id
*/
private String id;

private String personPlanStatus;


/**
* 学员实体
*/
private Person person;

/**
* 学员身份证(登录账号)
*/
private String loginId;

/**
* 学员姓名
*/
private String realName;

/**
* 代理商Id
*/
private String agentId;

/**
* 代理商列表
*/
private List agentList;

/**
* 学员列表
*/
private List<Map> personList;

private List<Person> impPersonList = new ArrayList<Person>();

private String newFileName; //新生成的文件名

private String errFlag ;

/**
* 学习计划集合列表
*/
private List<Plan> planList;

/**
* 标准查询
*/
private QueryCriterion qc;

/**
* 学员列表页脚
*/
private String bar;

/**
* 权限不足跳转的页面
*/
final String loginPage = BaseConf.get().getString(BaseConf._ADMINX_NAMED_RESOURCES_LOGIN);

/**
* 上传文件
*/
private File impPerson;

/**
* 上传文件名
*/
private String impPersonFileName ;

/*startDate").attr("value",startDate);
$("#endDate").attr("value",endDate);
$("#targetTime").attr("value",targetTime);
$("#courseName
*/
//打印相关 开始时间etc.
private String startDate;
private String endDate;
private String targetTime;
private String courseName;
private String idCard;

/**
* id数组
*/
private String ids[];

/**
* ,拼接的ids
*/
private String idsString;
/**
* 学员信息列表
*/
private List<Map<String, Object>> viewList;

private List<Map<String,Object>> ppInfoAndImage = new ArrayList<Map<String,Object>>();

/**
* json返回信息
*/
private AjaxHead bm = new AjaxHead("00", null);

/**
* 当前时间
*/
private String currentDate;

/**
* 是否是批量打印. print_all为批量打印.
*/
private String act;

/**
* 从业资格证件号
*/
private String certificationNum;

/**
* 获取人脸识别的照片
*/
private PersonFaceImageService personFaceImageService;
/**
* 注册人脸照片
*/
private String registerFaceImage;

/**
* 学员的最后四张照片.
*/
private List<PersonFaceImage> personFaceImages = new ArrayList<PersonFaceImage>();

/**
* 判断浏览器是否是IE
*/
private String isIE;

@Override
public String execute() throws Exception {
int ret = this.initPerson();
if(ret != 0) {
getRequest().setAttribute("err","权限不足!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
return SUCCESS;
}

/**
* 学员列表初始化
* @author wangdaiwei
* @create 2015年1月12日 下午7:00:12
*/
public int initPerson(){
//从session中获取数据权限Map并找到部门信息访问权限,进行控制
resDatasMap = (Map<String, String>) getSession().getAttribute("resDatas");
if (MapUtil.isNotEmpty(resDatasMap)) {
resDatas_dept = resDatasMap.get("ORGANIZER_DATA");
resDatas_agent = resDatasMap.get("AGENT_DATA");
}
if(StringUtils.isBlank(resDatas_dept)){
return -1;
}

// 查询数据权限范围内的代理商
agentList = agentService.getAgentByIds(resDatas_agent);
StringBuffer sbf = new StringBuffer();
for(String deptId : resDatas_dept.split(",")){
sbf.append("'").append(deptId).append("',");
}
final String deptIds = sbf.toString();
qc = this.getQueryCriterion(new QueryRulesCreator(){

@Override
public Map<String, Condition> createConditions() {
// TODO Auto-generated method stub
Map<String, Condition> conditions = new HashMap<String, Condition>();
conditions.put("deptId",new CxxString(deptIds.substring(0,deptIds.length()-1)));
if (!"".equals(loginId) && loginId != null) {
conditions.put("pLoginId", new CxxString(loginId));
}
if (!"".equals(realName) && realName != null) {
conditions.put("pRealName", new CxxString(realName));
}
if (!"all".equals(agentId) && agentId != null) {
conditions.put("agentId", new CxxString(agentId));
}
return conditions;
}

@Override
public String createKeyFlds() {
// TODO Auto-generated method stub
return null;
}

});

//分页样式
qc.getPagination().setShowType("002");
//根据标准查询获得银行信息分页列表
personList = personService.queryPersonForPage(qc);
// 获取分页页脚
bar = qc.getPagination().toBar();
return 0;
}

/**
* 添加学员及学员的学习计划
* @author wangdaiwei
* @create 2015年1月13日 下午7:48:39
* @return
*/
public String addPerson(){
//从session中获取数据权限Map并找到部门信息访问权限,进行控制
resDatasMap = (Map<String, String>) getSession().getAttribute("resDatas");
if (MapUtil.isNotEmpty(resDatasMap)) {
resDatas_dept = resDatasMap.get("ORGANIZER_DATA");
}
if(StringUtils.isBlank(resDatas_dept)){
getRequest().setAttribute("err","权限不足!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}

StringBuffer sbf = new StringBuffer();
for(String deptId : resDatas_dept.split(",")){
sbf.append("'").append(deptId).append("',");
}
final String deptIds = sbf.toString().substring(0,sbf.toString().length()-1);
planList = planService.getPlanListByDeptIds(deptIds);
return "addPerson";
}

/**
* 修改学员及学员的学习计划
* @author wangdaiwei
* @create 2015年1月15日 上午9:32:08
* @return
*/
public String modifyPerson(){
//从session中获取数据权限Map并找到部门信息访问权限,进行控制
resDatasMap = (Map<String, String>) getSession().getAttribute("resDatas");
if (MapUtil.isNotEmpty(resDatasMap)) {
resDatas_dept = resDatasMap.get("ORGANIZER_DATA");
}
if(StringUtils.isBlank(resDatas_dept)){
getRequest().setAttribute("err","权限不足!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
person = personService.getPersonById(Long.valueOf(id));
if(person != null) {
// 查询取消的计划学员是否已重新绑定计划
int cnt = personPlanService.getPersonPlanCountForNotCancel(person.getId());
if(cnt > 0) {
personPlanStatus = "0";
}
}

planIds = personPlanService.getPlanIdsByPersonId(person.getId().toString());
StringBuffer sbf = new StringBuffer();
for(String deptId : resDatas_dept.split(",")){
sbf.append("'").append(deptId).append("',");
}
final String deptIds = sbf.toString().substring(0,sbf.toString().length()-1);
planList = planService.getPlanListByDeptIds(deptIds);
return "modifyPerson";
}

/**
* 删除学员
* @author wangdaiwei
* @create 2015年1月15日 下午5:21:29
* @return
*/
public String deletePerson(){
User curuser = (User) getRequest().getSession().getAttribute("curuser");
if (null == curuser) {
getRequest().setAttribute("err", "session信息丢失!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
if(StringUtils.isBlank(id)){
getRequest().setAttribute("err","参数不正确!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
try{
Person ps = new Person();
ps.setId(Long.valueOf(id));
ps.setPStatus("9");
personService.updatePerson(ps);
LogUtil.Log("13", curuser.getId(), curuser.getName(), "删除学员" ,"Person",Long.valueOf(id),"3");
}catch(Exception e){
ExceptionPrintUtil.PrintErrorMessage(e, log);
getRequest().setAttribute("err",e.getMessage());
getRequest().setAttribute("rtnurl",loginPage);
return ERROR;
}
this.initPerson();
return SUCCESS;
}

/**
* 根据学员身份证号(登录账号)检查是否有该学员,有 把相关信息查出来
* @author wangdaiwei
* @create 2015年1月14日 下午8:38:46
*/
public void checkPersonByloginId(){
Gson gson = new Gson();
Map<String,Object> paraMap = new HashMap<String,Object>();
paraMap.put("loginId", loginId);
List<Person> personList = personService.queryPersonByLoginId(paraMap);
if(ListUtil.isEmpty(personList)){
CommonMessage cm = new CommonMessage(false, null);
String rsMsg = gson.toJson(cm);
printAjaxMessage(rsMsg);
} else {
CommonMessage cm = new CommonMessage(true, personList.get(0));
String rsMsg = gson.toJson(cm);
printAjaxMessage(rsMsg);
}
}

/**
* 添加保存学员及学员的学习计划
* @author wangdaiwei
* @create 2015年1月14日 下午1:53:39
* @return
*/
@Token
public String savePerson(){
User curuser = (User) getRequest().getSession().getAttribute("curuser");
if (null == curuser) {
getRequest().setAttribute("err", "session信息丢失!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
if(null == person || StringUtils.isBlank(planIds)){
getRequest().setAttribute("err","参数不正确!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
try{
personService.addPersonAndPersonPlan(person, planIds);
LogUtil.Log("13", curuser.getId(), curuser.getName(), "新增学员" ,"Person",person.getId(),"1");
}catch(Exception e){
ExceptionPrintUtil.PrintErrorMessage(e, log);
getRequest().setAttribute("err",e.getMessage());
getRequest().setAttribute("rtnurl",loginPage);
return ERROR;
}
this.initPerson();
return SUCCESS;
}

/**
* 修改保存学员及学员的学习计划
* @author wangdaiwei
* @create 2015年1月15日 下午4:05:28
* @return
*/
@Token
public String updatePerson(){
User curuser = (User) getRequest().getSession().getAttribute("curuser");
if (null == curuser) {
getRequest().setAttribute("err", "session信息丢失!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
if(null == person){
getRequest().setAttribute("err","参数不正确!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
try{
Person oldPerson = personService.getPersonById(person.getId());
String oldPlanIds = personPlanService.getPlanIdsByPersonId(person.getId().toString());
personService.updatePersonAndPersonPlan(person, planIds);
//记录日志
Map<String,String> fieldsMap = new HashMap<String,String>();
fieldsMap.put("姓名", "realName");
fieldsMap.put("性别", "sex");
fieldsMap.put("手机号", "tel");
fieldsMap.put("电子邮件", "email");
fieldsMap.put("地址", "address");
String logContStr = LogUtil.getObjectChangeLogInfo(oldPerson,person,fieldsMap);
StringBuffer contStrbuf = new StringBuffer();
contStrbuf.append(logContStr);
if(StringUtils.isNotBlank(planIds)){
contStrbuf.append("学习计划:").append(oldPlanIds).append("-->").append(oldPlanIds);
contStrbuf.append(",").append(planIds);
}
LogUtil.Log("13", curuser.getId(), curuser.getName(), contStrbuf.toString() ,"Person",person.getId(),"2");
}catch(Exception e){
ExceptionPrintUtil.PrintErrorMessage(e, log);
getRequest().setAttribute("err",e.getMessage());
getRequest().setAttribute("rtnurl",loginPage);
return ERROR;
}
this.initPerson();
return SUCCESS;
}

/**
* 打开导入学员信息页面
* @return
*/
public String impPerson(){
return "impPerson";
}


/**
* 加载excel文件中学员信息
* @return
*/
@SuppressWarnings("unchecked")
public String readExcelPerson(){
User curuser = (User) getRequest().getSession().getAttribute("curuser");
//从session中获取数据权限Map并找到部门信息访问权限,进行控制
resDatasMap = (Map<String, String>) getSession().getAttribute("resDatas");
if (MapUtil.isNotEmpty(resDatasMap)) {
resDatas_dept = resDatasMap.get("ORGANIZER_DATA");
}
if(StringUtils.isBlank(resDatas_dept)){
getRequest().setAttribute("err","权限不足!");
getRequest().setAttribute("rtnurl", loginPage);
return ERROR;
}
//文件大小不能大于1M
if(impPerson != null && impPerson.length() > 1048576) { // 2097152 =2M 1048576大于1M 1M= 1*1024*1024
getRequest().setAttribute("err","导入文件不能大于1M!");
getRequest().setAttribute("rtnurl", "");
return ERROR;
}
StringBuffer sbf = new StringBuffer();
for(String deptId : resDatas_dept.split(",")){
sbf.append("'").append(deptId).append("',");
}
final String deptIds = sbf.toString().substring(0,sbf.toString().length()-1);
planList = planService.getPlanListByDeptIds(deptIds);

//加载文件 读取excel 并验证
Map<String, String> flagMap = new HashMap<String, String>();
Map<String, String> fileNameMap = new HashMap<String, String>();
impPersonList = personService.impAndCheckFile(impPerson, impPersonFileName, curuser, flagMap, fileNameMap);
if(impPersonList == null || impPersonList.size() ==0) {
getRequest().setAttribute("err","导入文件为空或格式不正确!");
getRequest().setAttribute("rtnurl", "");
return ERROR;
}
if(flagMap != null && flagMap.size() > 0) {
errFlag = "1"; //有错
}
if(fileNameMap != null && fileNameMap.size() > 0) {
newFileName = fileNameMap.get("newFileName");
}

return "loadExcel";
}

/**
* 保存学员,绑定学习计划
* @return
*/
@Token
public String saveImpPerson(){
impPersonList = personService.loadImpFile(newFileName);
personService.impPersonAndPersonPlan(impPersonList, planIds);
return "saveImpPerson";
}

/**
* 进入打印页预览
* @author lengzl
* @create 2015年8月12日 下午8:32:35
* @return
*/
public String enterPrintAc(){
User curuser = (User)getSession().getAttribute("curuser");
if(null==curuser){
if (curuser == null) {
getRequest().setAttribute("err", "session信息丢失!");
getRequest().setAttribute("rtnurl", BaseConf.get().getString(BaseConf._ADMINX_NAMED_RESOURCES_LOGIN));
return ERROR;
}
}

try {
startDate = java.net.URLDecoder.decode(startDate,"utf-8");
endDate = java.net.URLDecoder.decode(endDate,"utf-8");
targetTime = java.net.URLDecoder.decode(targetTime,"utf-8");
courseName = java.net.URLDecoder.decode(courseName,"utf-8");
realName = java.net.URLDecoder.decode(realName,"utf-8");
idCard = java.net.URLDecoder.decode(idCard,"utf-8");
certificationNum = java.net.URLDecoder.decode(certificationNum,"utf-8");
// registerFaceImage = java.net.URLDecoder.decode(registerFaceImage,"utf-8"); //

/*
* 最后的四张照片.

Map<String,Object> map = new HashMap<String, Object>();
map.put("personId", id);
personFaceImages = personFaceImageService.getPersonFaceImageListByPid(map);
*/
currentDate = DateFormatUtil.formatCnYyyyMMdd(new Date());

} catch(UnsupportedEncodingException e) {
log.error("转码出现异常!");
ExceptionPrintUtil.PrintErrorMessage(e, log);
}
//getRequest().setAttribute("currentDate",currentDate);
return "printOne";
}

/**
* 批量打印学时证明,5s循环弹出窗口.废弃.C
* @author lengzl
* @create 2015年8月14日 下午1:40:18
*/
public void batchPrint(){
try {
String str = "";
//Cau:如果有且只有一个disabled的被选中,那么传到后台为null.
if (ids != null&&ids.length > 0) {
for (int i = 0, m = ids.length; i < m; i++) {
str = str + ids[i];
if (i < (m - 1)) {
str = str + ",";
}
}
}
viewList = personService.getPersonLearnTimeCertificate(str);
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < viewList.size(); i++) {
JSONObject jsonObject = new JSONObject();
/*
需要的人名,身份证号,开始,结束时间,目标学时,当前时间.id="+jsonarray[data_count].pId;
*/
jsonObject.put("realName", viewList.get(i).get("pRealName"));
jsonObject.put("idCard", viewList.get(i).get("pIdCard"));
jsonObject.put("startDate", viewList.get(i).get("ppStartDate").toString());
jsonObject.put("endDate", viewList.get(i).get("ppEndDate").toString());
jsonObject.put("courseName", viewList.get(i).get("planName"));
jsonObject.put("certificationNum", viewList.get(i).get("certificationNum"));
//jsonObject.put("registerFaceImage", viewList.get(i).get("ppRegisterFaceImage"));
jsonObject.put("targetTime", viewList.get(i).get("ppTargetStudyTime"));
jsonObject.put("pId", viewList.get(i).get("pId")); //person 的id.
/*不用传递,每次打开调用就行.
String currentDate = DateFormatUtil.formatCnYyyyMMdd(new Date());
jsonObject.put("currentDate", currentDate);*/
jsonArray.add(jsonObject);
jsonObject = null;
}
bm.setCode("00");
bm.setMessage(jsonArray.toString());
System.out.println(jsonArray.toString()+"←===============================================****");
printAjaxMessage(JSONObject.fromObject(bm).toString());
} catch(Exception e) {
log.error("批量打印异常!");
ExceptionPrintUtil.PrintErrorMessage(e, log);
}
}

/**
* 通过一个页面的分页 实现批量打印学时证明
* @author lengzl
* @create 2015年8月14日 下午1:40:18
*/
public String batchPrintByOnePage(){

String str = "";

str = idsString.substring(0,idsString.length()-1);

viewList = personService.getPersonLearnTimeCertificate(str);
//遍历,找到id,查一下,放到Map中科.
for (int i = 0; i < viewList.size(); i++) {
//Long ppId = (Long) viewList.get(i).get("ppPersonId");

//放置单个学员信息
Map<String,Object> personPlanCyMap = new HashMap<String, Object>();
/*
* 最后的四张照片
*/
/*Map<String,Object> map = new HashMap<String, Object>();
map.put("personId", ppId);
personFaceImages = personFaceImageService.getPersonFaceImageListByPid(map);*/

personPlanCyMap.put("ppInfo", viewList.get(i));
//personPlanCyMap.put("ppFaceImage", personFaceImages);

ppInfoAndImage.add(personPlanCyMap);
}
currentDate = DateFormatUtil.formatCnYyyyMMdd(new Date());
return "printAll";
/*
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < viewList.size(); i++) {
JSONObject jsonObject = new JSONObject();

需要的人名,身份证号,开始,结束时间,目标学时,当前时间.id="+jsonarray[data_count].pId;

//System.out.println("真实姓名:"+viewList.get(i).get("pRealName")+viewList.get(i).get("pIdCard")+viewList.get(i).get("ppStartDate"));
jsonObject.put("realName", viewList.get(i).get("pRealName"));
jsonObject.put("idCard", viewList.get(i).get("pIdCard"));
jsonObject.put("startDate", viewList.get(i).get("ppStartDate").toString());
jsonObject.put("endDate", viewList.get(i).get("ppEndDate").toString());
jsonObject.put("courseName", viewList.get(i).get("planName"));
jsonObject.put("certificationNum", viewList.get(i).get("certificationNum"));
jsonObject.put("registerFaceImage", viewList.get(i).get("ppRegisterFaceImage"));
jsonObject.put("targetTime", viewList.get(i).get("ppTargetStudyTime"));
jsonObject.put("pId", viewList.get(i).get("pId")); //person 的id.
不用传递,每次打开调用就行.
String currentDate = DateFormatUtil.formatCnYyyyMMdd(new Date());
jsonObject.put("currentDate", currentDate);
jsonArray.add(jsonObject);
jsonObject = null;
}
bm.setCode("00");
bm.setMessage(jsonArray.toString());
System.out.println(jsonArray.toString()+"←===============================================****");
printAjaxMessage(JSONObject.fromObject(bm).toString());
} catch(Exception e) {
log.error("批量打印异常!");
ExceptionPrintUtil.PrintErrorMessage(e, log);
}
*/
}

/**
* @return the personService
*/
public PersonService getPersonService() {
return personService;
}


/**
* @param personService the personService to set
*/
public void setPersonService(PersonService personService) {
this.personService = personService;
}


/**
* @return the person
*/
public Person getPerson() {
return person;
}


/**
* @param person the person to set
*/
public void setPerson(Person person) {
this.person = person;
}

/**
* @return the loginId
*/
public String getLoginId() {
return loginId;
}


/**
* @param loginId the loginId to set
*/
public void setLoginId(String loginId) {
this.loginId = loginId;
}


/**
* @return the realName
*/
public String getRealName() {
return realName;
}


/**
* @param realName the realName to set
*/
public void setRealName(String realName) {
this.realName = realName;
}

/**
* @return the personList
*/
public List<Map> getPersonList() {
return personList;
}


/**
* @param personList the personList to set
*/
public void setPersonList(List<Map> personList) {
this.personList = personList;
}


/**
* @return the qc
*/
public QueryCriterion getQc() {
return qc;
}


/**
* @param qc the qc to set
*/
public void setQc(QueryCriterion qc) {
this.qc = qc;
}


/**
* @return the bar
*/
public String getBar() {
return bar;
}


/**
* @param bar the bar to set
*/
public void setBar(String bar) {
this.bar = bar;
}


/**
* @return the planService
*/
public PlanService getPlanService() {
return planService;
}


/**
* @param planService the planService to set
*/
public void setPlanService(PlanService planService) {
this.planService = planService;
}


/**
* @return the planList
*/
public List<Plan> getPlanList() {
return planList;
}


/**
* @param planList the planList to set
*/
public void setPlanList(List<Plan> planList) {
this.planList = planList;
}


/**
* @return the planIds
*/
public String getPlanIds() {
return planIds;
}


/**
* @param planIds the planIds to set
*/
public void setPlanIds(String planIds) {
this.planIds = planIds;
}


/**
* @return the id
*/
public String getId() {
return id;
}


/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}


/**
* @return the personPlanService
*/
public PersonPlanService getPersonPlanService() {
return personPlanService;
}


/**
* @param personPlanService the personPlanService to set
*/
public void setPersonPlanService(PersonPlanService personPlanService) {
this.personPlanService = personPlanService;
}


/**
* @return the agentList
*/
public List getAgentList() {
return agentList;
}


/**
* @param agentList the agentList to set
*/
public void setAgentList(List agentList) {
this.agentList = agentList;
}


/**
* @return the agentService
*/
public AgentService getAgentService() {
return agentService;
}


/**
* @param agentService the agentService to set
*/
public void setAgentService(AgentService agentService) {
this.agentService = agentService;
}


/**
* @return the agentId
*/
public String getAgentId() {
return agentId;
}


/**
* @param agentId the agentId to set
*/
public void setAgentId(String agentId) {
this.agentId = agentId;
}

public File getImpPerson() {
return impPerson;
}

public void setImpPerson(File impPerson) {
this.impPerson = impPerson;
}

public String getImpPersonFileName() {
return impPersonFileName;
}

public void setImpPersonFileName(String impPersonFileName) {
this.impPersonFileName = impPersonFileName;
}


public String getErrFlag() {
return errFlag;
}

public void setErrFlag(String errFlag) {
this.errFlag = errFlag;
}

public List<Person> getImpPersonList() {
return impPersonList;
}

public void setImpPersonList(List<Person> impPersonList) {
this.impPersonList = impPersonList;
}

public String getNewFileName() {
return newFileName;
}

public void setNewFileName(String newFileName) {
this.newFileName = newFileName;
}

public String getPersonPlanStatus() {
return personPlanStatus;
}

public void setPersonPlanStatus(String personPlanStatus) {
this.personPlanStatus = personPlanStatus;
}


public String getResDatas_agent() {
return resDatas_agent;
}


public void setResDatas_agent(String resDatas_agent) {
this.resDatas_agent = resDatas_agent;
}


public String getStartDate() {
return startDate;
}


public void setStartDate(String startDate) {
this.startDate = startDate;
}


public String getEndDate() {
return endDate;
}


public void setEndDate(String endDate) {
this.endDate = endDate;
}


public String getTargetTime() {
return targetTime;
}


public void setTargetTime(String targetTime) {
this.targetTime = targetTime;
}


public String getCourseName() {
return courseName;
}


public void setCourseName(String courseName) {
this.courseName = courseName;
}


public String getIdCard() {
return idCard;
}


public void setIdCard(String idCard) {
this.idCard = idCard;
}


public String[] getIds() {
return ids;
}


public void setIds(String[] ids) {
this.ids = ids;
}


public List<Map<String, Object>> getViewList() {
return viewList;
}


public void setViewList(List<Map<String, Object>> viewList) {
this.viewList = viewList;
}


public AjaxHead getBm() {
return bm;
}


public void setBm(AjaxHead bm) {
this.bm = bm;
}


public String getCurrentDate() {
return currentDate;
}


public void setCurrentDate(String currentDate) {
this.currentDate = currentDate;
}


public String getAct() {
return act;
}


public void setAct(String act) {
this.act = act;
}


public String getCertificationNum() {
return certificationNum;
}


public void setCertificationNum(String certificationNum) {
this.certificationNum = certificationNum;
}


public String getRegisterFaceImage() {
return registerFaceImage;
}


public void setRegisterFaceImage(String registerFaceImage) {
this.registerFaceImage = registerFaceImage;
}


public PersonFaceImageService getPersonFaceImageService() {
return personFaceImageService;
}


public void setPersonFaceImageService(PersonFaceImageService personFaceImageService) {
this.personFaceImageService = personFaceImageService;
}


public List<PersonFaceImage> getPersonFaceImages() {
return personFaceImages;
}


public void setPersonFaceImages(List<PersonFaceImage> personFaceImages) {
this.personFaceImages = personFaceImages;
}


public String getIdsString() {
return idsString;
}


public void setIdsString(String idsString) {
this.idsString = idsString;
}


public List<Map<String, Object>> getPpInfoAndImage() {
return ppInfoAndImage;
}


public void setPpInfoAndImage(List<Map<String, Object>> ppInfoAndImage) {
this.ppInfoAndImage = ppInfoAndImage;
}


public String getIsIE() {
return isIE;
}


public void setIsIE(String isIE) {
this.isIE = isIE;
}


}



struts-adminx.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<!-- 去Struts2默认标签样式的. -->
<constant name="struts.ui.theme" value="simple" />
<constant name="struts.ui.templateDir" value="template" />
<constant name="struts.ui.templateSuffix" value="ftl" />

<!-- 后台管理员action配置 -->
<package name="adminx" extends="default" namespace="/adminx">
<!-- 后台管理员拦截器队列 -->
<interceptors>
<interceptor-stack name="adminxInterceptorStack">
<interceptor-ref name="myLandInterceptorStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="adminxInterceptorStack"/>

<!-- 后台用户登录action -->
<action name="adminLogin" class="com.myland.jp.adminx.login.action.AdminLoginAction">
<result name="success">/adminx/login/adminLogin.jsp</result>
<result name="home" type="redirect">/adminx/home/home.jsp</result>
</action>
<action name="menusAction" class="com.myland.jp.adminx.login.action.MenusAction">
</action>

<!-- 后台考题管理action -->
<action name="examAction" class="com.myland.jp.adminx.exam.action.ExamAction">
<result name="success">/adminx/exam/examList.jsp</result>
<result name="addexam">/adminx/exam/examAdd.jsp</result>
<result name="editexam">/adminx/exam/examUpdate.jsp</result>
<result name="batchAddExam">/adminx/exam/examBatchAdd.jsp</result>
<result name="examCheck">/adminx/exam/examCheckList.jsp</result>
<result name="viewexam">/adminx/exam/examView.jsp</result>
<result name="show">/adminx/common/examContentShow.jsp</result>
</action>
<action name="examQueryAction" class="com.myland.jp.adminx.exam.action.ExamAction" method="examQueryList">
<result name="examList">/adminx/exam/examQueryList.jsp</result>
</action>
<action name="examCheckQueryAction" class="com.myland.jp.adminx.exam.action.ExamAction" method="examCheckQueryList">
<result name="examCheckList">/adminx/exam/examCheckQueryList.jsp</result>
</action>
<!-- 后台试卷管理action -->
<action name="testPaperAction" class="com.myland.jp.adminx.testpaper.action.TestPaperAction">
<result name="success">/adminx/testpaper/testPaperList.jsp</result>
<result name="addtestpaper">/adminx/testpaper/testPaperAdd.jsp</result>
<result name="forupdatetestpaper">/adminx/testpaper/testPaperUpdate.jsp</result>
</action>
<action name="testPaperQueryAction" class="com.myland.jp.adminx.testpaper.action.TestPaperAction" method="testPaperQueryList">
<result name="testPaperList">/adminx/testpaper/testPaperQueryList.jsp</result>
</action>

<!-- 学习计划 -->
<action name="plan" class="com.myland.jp.adminx.plan.action.PlanAction">
<result name="success">/adminx/plan/planList.jsp</result>
<result name="conditionSearch">/adminx/plan/planList.jsp</result>
<result name="planNode">/adminx/plan/planList.jsp</result>
<result name="addPlan">/adminx/plan/planAdd.jsp</result>
<result name="modifyPlan">/adminx/plan/planModify.jsp</result>
<result name="planDetail">/adminx/plan/planDetail.jsp</result>
<result name="showImg">/adminx/plan/showImg.jsp</result>
</action>
<!-- 学习计划节点 -->
<action name="planNode" class="com.myland.jp.adminx.planNode.action.PlanNodeAction">
<result name="success">/adminx/plan/planNodeList.jsp</result>
<result name="planList" type="redirect">/adminx/plan.do</result>
<result name="planDetail">/adminx/plan/planNodeAdd.jsp</result>
<result name="planNodeInterface">/adminx/plan/interfaceList.jsp</result>
<result name="planNodeJsMethod">/adminx/plan/jsPlanNode.jsp</result>
<result name="orderPlanNode">/adminx/plan/orderPlanNode.jsp</result>
</action>
<action name="planNodeCourse" class="com.myland.jp.adminx.planNode.action.PlanNodeAction" method="showPlanCourse">
<result name="planNodeCourse">/adminx/plan/courseList.jsp</result>
</action>
<action name="planNodeExam" class="com.myland.jp.adminx.planNode.action.PlanNodeAction" method="showPlanExam">
<result name="planNodeExam">/adminx/plan/examList.jsp</result>
</action>
<!-- 代理商 -->
<action name="agent" class="com.myland.jp.adminx.agent.action.AgentAction">
<result name="success">/adminx/agent/agentList.jsp</result>
<result name="addAgent">/adminx/agent/agentAdd.jsp</result>
<result name="modifyAgent">/adminx/agent/agentModify.jsp</result>
<result name="detailAgent">/adminx/agent/agentDetail.jsp</result>
<result name="binded">/adminx/agent/bindedPlanAgent.jsp</result>
</action>
<!--获取学习计划 -->
<action name="bindAgent" class="com.myland.jp.adminx.agent.action.AgentAction" method="bindAgent">
<result name="bindAgent">/adminx/agent/bindAgent.jsp</result>
</action>
<!-- 已绑定学习计划 -->
<action name="bindedPlan" class="com.myland.jp.adminx.agent.action.AgentAction" method="bindedPlan">
<result name="binded">/adminx/agent/bindedPlanAgent.jsp</result>
</action>
<!-- 供应商 -->
<action name="cont" class="com.myland.jp.adminx.cont.action.ContAction">
<result name="success">/adminx/cont/contList.jsp</result>
<result name="addAgent">/adminx/cont/contAdd.jsp</result>
<result name="modifyAgent">/adminx/cont/contModify.jsp</result>
<result name="detailAgent">/adminx/cont/contDetail.jsp</result>
<result name="contView">/adminx/cont/contView.jsp</result>
</action>

<!-- 供应商审核 -->
<action name="contApplyReview" class="com.myland.jp.adminx.contApplyReview.action.contApplyReviewAction">
<result name="success">/adminx/cont/personDataSuccess.jsp</result>
<result name="viewDetailInfo">/adminx/cont/viewDetailInfo.jsp</result>
<result name="viewImageFile">/adminx/cont/showImage.jsp?fileName=${fileName}</result>
</action>

<!-- 账户信息 -->
<action name="payAccnt" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction">
<result name="success">/adminx/payAccnt/payAccntList.jsp</result>
<result name="addPayAccnt">/adminx/payAccnt/payAccntAdd.jsp</result>
<result name="modifyPayAccnt">/adminx/payAccnt/payAccntModify.jsp</result>
</action>
<!-- 账户明细 原payAccntFlow {1}-->
<action name="payAccntFlow_*" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="payAccntFlow">
<result name="payAccntFlow">/adminx/payAccnt/payAccntFlowList.jsp</result>
</action>
<!-- 统计账户信息 -->
<action name="payAccntFlowSum" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="payAccntFlowSum">
<result name="success">/adminx/payAccnt/payAccntFlowSum.jsp</result>
</action>

<!-- 课程销售量统计 -->
<action name="courseSaledSum" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="courseSaledSum">
<result name="success">/adminx/payAccnt/courseSaledSum.jsp</result>
</action>
<!-- 课程销售量统计图表展示 -->
<action name="showChartCourseSaledSum" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="showChartCourseSaledSum">
<result name="pie">/adminx/payAccnt/showPieChartCourseSaledSum.jsp</result>
<result name="column">/adminx/payAccnt/showColumnChartCourseSaledSum.jsp</result>
<result name="line">/adminx/payAccnt/showLineChartCourseSaledSum.jsp</result>
</action>


<action name="addPayAccntAction" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="addPayAccnt">
<result name="addPayAccnt">/adminx/payAccnt/payAccntAdd.jsp</result>
</action>

<action name="agentList" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="loadAgentList">
<result name="agentList">/adminx/payAccnt/agentList.jsp</result>
</action>
<action name="contList" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="loadContList">
<result name="contList">/adminx/payAccnt/contList.jsp</result>
</action>

<!-- 根据数据权限显示相应列表 -->
<action name="payAccntByDepIdList" class="com.myland.jp.adminx.payAccnt.action.PayAccntAction" method="payAccntByDepIdList">
<result name="payAccntByDepIdList">/adminx/payAccnt/payAccntByDeptIdList.jsp</result>
</action>

<!-- 代理商学员查询 -->
<action name="agentViewPerson" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction">
<result name="agentSuccess">/adminx/viewPerson/agentViewPersonList.jsp</result>
</action>

<!-- 组织者学员查询 -->
<action name="deptViewPerson" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="initViewPersonPerosnPlanForDept">
<result name="deptSuccess">/adminx/viewPerson/deptViewPersonList.jsp</result>
</action>
<!-- 组织者学员查询,市区及以下的. -->
<action name="deptViewPerson_sum" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="initViewPersonPerosnPlanForDept_sum">
<result name="deptSuccess">/adminx/viewPerson/deptViewPersonList_sum.jsp</result>
</action>
<!-- 客服学员查询 -->
<action name="deptViewPerson_cs" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="initViewPersonPersonPlanForDept_cs">
<result name="deptSuccess">/adminx/viewPerson/deptViewPersonList_cs.jsp</result>
</action>
<!-- 重置学员密码 -->
<action name="resetPersonPwd" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="resetPersonPwd">
</action>
<!-- 重置学员人脸 -->
<action name="resetPersonFace" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="resetPersonFace">
</action>
<!-- 关闭开启学员人脸识别 -->
<action name="effectIsFace" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="effectPersonPlanIsFace">
<result name="success" type="redirect">/adminx/deptViewPerson_cs.do</result>
</action>
<!-- 改变部门,改变计划. 其实不会改变页面的. -->
<action name="changePlanList" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction">
<result name="success">/adminx/viewPerson/deptViewPersonList_cs.jsp</result>
</action>

<!-- 学习记录查询 -->
<action name="personRecordAction" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPlanRecordList">
<result name="personPlanRecordList">/adminx/viewPerson/personPlanRecord.jsp</result>
</action>

<!--驾校学员退款申请查询 -->
<action name="agentRefundApplyPage" class="com.myland.jp.adminx.agentAccntRefund.action.AgentAccntRefundAction" method="agentRefundApplyPage">
<result name="agentRefundApplyPage">/adminx/agentRefund/agentRefundApplyPage.jsp</result>
</action>

<!--驾校学员退款申请 -->
<action name="saveAgentRefundApply" class="com.myland.jp.adminx.agentAccntRefund.action.AgentAccntRefundAction" method="saveAgentRefundApply">
</action>

<!--驾校学员退款审核列表-->
<action name="agentRefundAuditPage" class="com.myland.jp.adminx.agentAccntRefund.action.AgentAccntRefundAction" method="agentRefundAuditPage">
<result name="agentRefundAuditPage">/adminx/agentRefund/agentRefundAuditPage.jsp</result>
</action>

<!--驾校学员退款审核明细-->
<action name="agentRefundAuditDetail" class="com.myland.jp.adminx.agentAccntRefund.action.AgentAccntRefundAction" method="agentRefundAuditDetail">
<result name="agentRefundAuditDetail">/adminx/agentRefund/agentRefundAuditDetail.jsp</result>
</action>

<!--驾校学员退款审核-->
<action name="saveAgentRefundAudit" class="com.myland.jp.adminx.agentAccntRefund.action.AgentAccntRefundAction" method="saveAgentRefundAudit">
<result name="saveAgentRefundAudit" type="redirect">/adminx/agentRefundAuditPage.do</result>
</action>
<!-- 退款记录 -->
<action name="agentAccntRefundPage" class="com.myland.jp.adminx.agentAccntRefund.action.AgentAccntRefundAction" method="agentAccntRefundPage">
<result name="agentAccntRefundPage">/adminx/agentRefund/agentAccntRefundPage.jsp</result>
</action>

<!-- 考试记录查询 -->
<action name="personExamAction" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPlanExamList">
<result name="personPlanExamList">/adminx/viewPerson/personPlanExam.jsp</result>
</action>

<!-- 学习记录查询_客服 -->
<action name="personRecordAction_cs" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPlanRecordList">
<result name="personPlanRecordList">/adminx/viewPerson/personPlanRecord.jsp</result>
</action>

<!-- 考试记录查询_客服 -->
<action name="personExamAction_cs" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPlanExamList">
<result name="personPlanExamList">/adminx/viewPerson/personPlanExam.jsp</result>
</action>

<!-- 学习记录查询_数据统计的 -->
<action name="personRecordAction_sum" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPlanRecordList">
<result name="personPlanRecordList">/adminx/viewPerson/personPlanRecord.jsp</result>
</action>

<!-- 考试记录查询_数据统计的 -->
<action name="personExamAction_sum" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPlanExamList">
<result name="personPlanExamList">/adminx/viewPerson/personPlanExam.jsp</result>
</action>

<!-- 学员照片审核页面 -->
<action name="personPhotoCheckAction" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPhotoCheck">
<result name="personPhotoView">/adminx/viewPerson/personPhotoView.jsp</result>
</action>
<!-- 学员照片审核 -->
<action name="personPhotoToExamineAction" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="personPhotoToExamine">
<result name="success" type="redirect">/adminx/deptViewPerson.do</result>
</action>

<!--组织者 数据统计 针对 personPlan的./jpv2/WebContent/common/error.jsp 菜单使用-->
<action name="deptViewSummary" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="initViewPersonSummaryForDept">
<result name="list">/adminx/statisticalSummary/deptViewSummary.jsp</result>
<result name="noRight">/common/error.jsp</result>
<result name="listData">/adminx/statisticalSummary/deptViewSummary_list.jsp</result>
</action>
<!-- 通用数据统计 -->
<action name="dataStatistics" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction">
<result name="listData">/adminx/statisticalSummary/deptViewSummary_list.jsp</result>
<result name="listDataAgent">/adminx/statisticalSummary/agentViewSummary_list.jsp</result>
</action>
<!-- 下级明细,也要分页的. -->
<action name="deptViewSummary_subDetial" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="subDetial">
<result name="subList">/adminx/statisticalSummary/deptViewSummary.jsp</result>
<result name="listData">/adminx/statisticalSummary/deptViewSummary_list.jsp</result>
</action>

<!-- 不需要分页的统计汇总,图表显示 -->
<!-- 4.result柱状图显示的 -->
<action name="highcharts" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" >
<result name="success">/adminx/statisticalSummary/highcharts.jsp</result>
<result name="payAccntFlow">/adminx/payAccnt/payAccntFlowList.jsp</result>
<result name="subList">/adminx/statisticalSummary/deptViewSummary.jsp</result>
<result name="success_agentDetialForColumnChart">/adminx/statisticalSummary/highcharts_column.jsp</result>
<result name="success_columnChart">/adminx/statisticalSummary/deptColumnChart.jsp</result>
</action>

<!-- 代理明细. 考虑将来可能分页,so动态 -->
<action name="agentViewDetail" class="com.myland.jp.adminx.viewPerson.action.ViewPersonAction" method="queryAgentDetail">
<result name="success_agentDetial">/adminx/statisticalSummary/agentViewSummary.jsp</result>

</action>

<!-- 汇总统计 end -->

<!-- 银行信息 -->
<action name="payBank" class="com.myland.jp.adminx.payBank.action.PayBankAction">
<result name="success">/adminx/payBank/payBankList.jsp</result>
<result name="addPayBank">/adminx/payBank/payBankAdd.jsp</result>
<result name="modifyPayBank">/adminx/payBank/payBankModify.jsp</result>
<result name="backDetailed">/adminx/payBank/payBankDetailed.jsp</result>
</action>
<!-- 代理商充值 -->
<action name="agentChange" class="com.myland.jp.adminx.agentChange.action.AgentChangeAction">
<result name="success">/adminx/agentChange/agentList.jsp</result>
<result name="modifyAgent">/adminx/agentChange/agentModify.jsp</result>
<result name="angetChange">/adminx/agentChange/agentChangeList.jsp</result>
<result name="modifyAngetChagne">/adminx/agentChange/agentChangeModify.jsp</result>
<result name="modifyAgentChangeP">/adminx/agentChange/agentChangeModifyP.jsp</result>
<result name="payInvoice">/adminx/agentChange/agentInvoiceModify.jsp</result>
<result name="payInvoiceView">/adminx/agentChange/agentInvoiceView.jsp</result>
<result name="agentChangeConfirm" type="redirect">/adminx/agentChangeConfirmAction.do</result>
<result name="agentChangePage">/adminx/agentChange/agentChangePage.jsp</result>
<result name="payAccountSelect">/adminx/agentChange/payAccntListSelect.jsp</result>
<result name="viewAgentChangeDetail">/adminx/agentChange/viewAgentChangeDetail.jsp</result>
</action>
<action name="agentChangeLoad" class="com.myland.jp.adminx.agentChange.action.AgentChangeAction" method="loadAgentChange">
<result name="angetChange">/adminx/agentChange/agentChangeList.jsp</result>
</action>
<!-- 充值详情 -->
<action name="viewAgentChangeDetail" class="com.myland.jp.adminx.agentChange.action.AgentChangeAction" method="viewAgentChangeDetail">
<result name="viewAgentChangeDetail">/adminx/agentChange/viewAgentChangeDetail.jsp</result>
</action>

<action name="addAgentChangeAction" class="com.myland.jp.adminx.agentChange.action.AgentChangeAction" method="addAgentChange">
<result name="addAgentChange">/adminx/agentChange/agentChangeAdd.jsp</result>
</action>
<action name="agentChangeAccnt" class="com.myland.jp.adminx.agentChange.action.AgentChangeAction" method="initPayAccntList">
<result name="payAccntList">/adminx/agentChange/payAccntList.jsp</result>
</action>
<action name="agentChangeBank" class="com.myland.jp.adminx.agentChange.action.AgentChangeAction" method="initPayBankList">
<result name="payBankList">/adminx/agentChange/payBankListSelect.jsp</result>
</action>
<!-- 确认 -->
<action name="agentChangeConfirmAction" class="com.myland.jp.adminx.agentChange.action.AgentChangeAction" method="agentChangeConfirm">
<result name="agentChagneConfirm">/adminx/agentChange/agentChangeConfirm.jsp</result>
</action>
<!-- 部门操作 -->
<action name="deptAction" class="com.myland.jp.adminx.dept.action.DeptAction">
<result name="success">/adminx/dept/deptList.jsp</result>
<result name="open">/adminx/dept/deptUpdate.jsp?hotId=${hotId}&hotPid=${hotPid}</result>
<result name="add" type="redirect">/adminx/deptAction.do?hotId=${hotId}&hotPid=${hotPid}</result>
<result name="del" type="redirect">/adminx/deptAction.do?hotId=${hotPid}&hotPid=${hotPid}&delFlag=1</result>
<result name="update" type="redirect">/adminx/deptAction.do?hotId=${hotPid}</result>
</action>

<!-- 角色操作action -->
<action name="roleAction" class="com.myland.jp.adminx.role.action.RoleAction">
<result name="success">/adminx/role/roleList.jsp</result>
<result name="add" type="redirect">/adminx/roleAction.do?conditions=keep</result>
<result name="open">/adminx/role/roleUpdate.jsp</result>
<result name="update" type="redirect">/adminx/roleAction.do?conditions=keep</result>
<result name="del" type="redirect">/adminx/roleAction.do?conditions=keep</result>
<result name="detail">/adminx/role/roleDetail.jsp</result>
<result name="menuAllocate">/adminx/role/menuAllocate.jsp</result>
<result name="funcAllocate">/adminx/role/funcAllocate.jsp</result>
</action>

<!-- 系统用户操作action begin
原:update_myinfoSuccess =>/adminx/home/main.jsp //现在改为重定向可.
2.这个改为ajax的.
<result name="add" type="redirect">/adminx/getUsersInfo.do?conditions=keep</result>
-->
<action name="userAction" class="com.myland.jp.adminx.user.action.UserAction">
<result name="add" type="redirect">/adminx/getUsersInfo.do?conditions=keep</result>
<result name="view">/adminx/user/userView.jsp</result>
<result name="open">/adminx/user/userUpdate.jsp</result>
<result name="update" type="redirect">/adminx/getUsersInfo.do?conditions=keep</result>
<result name="del" type="redirect">/adminx/getUsersInfo.do?conditions=keep</result>
<result name="open_myInfo">/adminx/user/myInfoUpdate.jsp</result>
<result name="tools">/adminx/user/tools.jsp</result>

</action>

<!-- 个人设置部分 -->
<action name="editMyInfo" class="com.myland.jp.adminx.user.action.UserAction" method="openMyInfo">
<result name="open_myInfo">/adminx/user/myInfoUpdate.jsp</result>
</action>
<!-- editMyPass -->
<action name="editMyPass" class="com.myland.jp.adminx.user.action.UserAction" method="openMyPass">
<result name="openPwdSuccess">/adminx/user/myPassUpdate.jsp</result>
</action>
<!-- 个人设置 end -->
<action name="getUsersInfo" class="com.myland.jp.adminx.user.action.UserAction" method="getUsersInfo">
<result name="list">/adminx/user/userList.jsp</result>
</action>

<action name="openUserAdd" class="com.myland.jp.adminx.user.action.UserAction" method="openUserAdd">
<result name="openUserAdd">/adminx/user/userAdd.jsp</result>
</action>
<!-- 系统用户操作action end -->

<!-- 数据权限操作action -->
<action name="resDataAction" class="com.myland.jp.adminx.resdata.action.ResDataAction">
<result name="open">/adminx/resdata/resdataDetail.jsp</result>
<result>/adminx/resdata/resdataDetail.jsp</result>
</action>

<!-- 方法名直接指定action的方法 ok-->

<!-- 安全性,使用method,防止动态调用 为了以后 注释不要写到里面-->
<action name="simpleHelp" class="com.myland.jp.adminx.resdata.action.SimpleHelpAction" method="simpleHelp">
<result name="success">/adminx/resdata/simpleHelp.jsp</result>
</action>
<!-- 请求 一样.帮助页面 左边的请求 故意不写 与方法名相同,保证权限的. -->
<action name="searchData" class="com.myland.jp.adminx.resdata.action.SimpleHelpAction" method="resDataSearch">
<result name="list">/adminx/resdata/resDataList.jsp</result>
</action>

<!-- 数据权限操作 end -->



<!-- 后台订单相关操作 -->
<action name="queryPayOrderAction" class="com.myland.jp.adminx.pay.action.PayOrderAdminAction" method="queryPayOrderInfoByPage">
<result name="payOrderFlowList">/adminx/pay/payOrderListAdminx.jsp</result>
<result name="payOrdersFlowList">/adminx/pay/payOrdersListAdminx.jsp</result>
<result name="payResult">/web/pay/alipayapi.jsp</result>
<result name="payResults">/web/pay/alipayapi.jsp</result>
<result name="orderDetail">/adminx/pay/orderDetail.jsp</result>
<result name="detail">/adminx/pay/orderDetailInfo.jsp</result>
</action>

<action name="queryPayOrdersInfoByPage" class="com.myland.jp.adminx.pay.action.PayOrderAdminAction" method="queryPayOrdersInfoByPage">
<result name="payOrdersFlowList">/adminx/pay/payOrdersListAdminx.jsp</result>
</action>

<action name="examVersionAction" class="com.myland.jp.adminx.exam.action.ExamVersionAction">
<result name="success">/adminx/exam/appExamVersion.jsp</result>
</action>

<!-- 定单退款申请列表 -->
<action name="orderRefundApplyPage" class="com.myland.jp.adminx.pay.action.PayOrderAdminAction" method="orderRefundApplyPage">
<result name="success">/adminx/pay/orderRefundApplyPage.jsp</result>
</action>
<action name="orderRefundApply" class="com.myland.jp.adminx.pay.action.PayOrderAdminAction" method="orderRefundApply">
</action>
<action name="orderRefundApplyDetail" class="com.myland.jp.adminx.pay.action.PayOrderAdminAction" method="orderRefundApplyDetail">
<result name="success">/adminx/pay/orderRefundApplyDetailPage.jsp</result>
</action>
<action name="orderRefundAuditPage" class="com.myland.jp.adminx.pay.action.PayOrderAdminAction" method="orderRefundAuditPage">
<result name="success">/adminx/pay/orderRefundAuditPage.jsp</result>
</action>
<action name="saveOrderRefundAudit" class="com.myland.jp.adminx.pay.action.PayOrderAdminAction" method="saveOrderRefundAudit">
<result name="success" type="redirect">/adminx/orderRefundAuditPage.do</result>
</action>

<!-- 类别体系 begin -->
<action name="catTypeAction" class="com.myland.jp.adminx.catType.action.CatTypeAction">
<result>/adminx/catType/catTypeList.jsp</result>
<result name="insertCatType">/adminx/catType/catTypeAdd.jsp</result>
<result name="updateCatType">/adminx/catType/catTypeUpdate.jsp</result>
</action>
<!-- 类别体系end -->

<!-- 内容管理 begin -->
<action name="chapterAction" class="com.myland.jp.adminx.chapter.action.ChapterAction">
<result name="success">/adminx/chapter/chapterParentList.jsp</result>
<result name="insertChapterParent">/adminx/chapter/chapterParentAdd.jsp</result>
<result name="updateChapterParent">/adminx/chapter/chapterParentUpdate.jsp</result>
<result name="toWorks">/adminx/chapter/works.jsp</result>
<result name="chapterTopList">/adminx/chapter/chapterTopList.jsp</result>
<result name="chapterTree">/adminx/chapter/chapterTree.jsp</result>
<result name="chapterList">/adminx/chapter/chapterList.jsp</result>
<result name="insertChapter">/adminx/chapter/chapterAdd.jsp</result>
<result name="updateChapter">/adminx/chapter/chapterUpdate.jsp</result>
<result name="toChapterList" type="redirect">/adminx/chapterAction!getChapterList.do?id=${pid}</result>
<result name="uploadCCWareList">/adminx/chapter/uploadCCWareList.jsp</result>
<result name="refreshUploadCCList">/adminx/chapter/uploadCCWareList_list.jsp</result>
<result name="importExcel">/adminx/chapter/importExcel.jsp</result>
</action>
<action name="chapterQueryAction" class="com.myland.jp.adminx.chapter.action.ChapterAction" method="chapterQueryList">
<result name="chapterParentList">/adminx/chapter/chapterQueryList.jsp</result>
</action>

<!-- 内容管理end -->

<!-- 章节考题管理 begin -->
<action name="chapterExamAction" class="com.myland.jp.adminx.chapter.action.ChapterExamAction">
<result name="success">/adminx/chapter/examHelp.jsp</result>
<result name="chapterExamList">/adminx/chapter/chapterExamList.jsp</result>
<result name="insertChapterExam">/adminx/chapter/chapterExamAdd.jsp</result>
<result name="updateChapterExam">/adminx/chapter/chapterExamUpdate.jsp</result>
<result name="getChapterExamList" type="redirect">/adminx/chapterExamAction!getChapterExamList.do?id=${id}</result>
</action>

<action name="examListAction" class="com.myland.jp.adminx.chapter.action.ChapterExamAction" method="findExamList">
<result name="examList">/adminx/chapter/examList.jsp</result>
</action>

<!-- 章节考题管理end -->
<!-- 章节课件管理 begin -->
<action name="chapterWareAction" class="com.myland.jp.adminx.chapter.action.ChapterWareAction">
<result name="success">/adminx/chapter/chapterWareList.jsp</result>
<result name="insertChapterWare">/adminx/chapter/chapterWareAdd.jsp</result>
<result name="updateChapterWare">/adminx/chapter/chapterWareUpdate.jsp</result>
<result name="addChapterWare">/adminx/chapter/wareAdd.jsp </result>
<result name="viewChapterWare">/adminx/chapter/chapterWareView.jsp </result>
<result name="delCW" type="redirect">/adminx/chapterWareAction!getChapterWareList.do?chapterId=${chapterId} </result>
</action>
<!-- 章节课件管理 end -->

<!-- 课程管理 begin -->
<action name="courseAction" class="com.myland.jp.adminx.course.action.CourseAction">
<result name="success">/adminx/course/courseList.jsp</result>
<result name="insertCourse">/adminx/course/courseAdd.jsp</result>
<result name="updateCourse">/adminx/course/courseUpdate.jsp</result>
<result name="courseCheck">/adminx/course/courseCheckList.jsp</result>
<result name="works">/adminx/course/works.jsp</result>
<result name="courseTree">/adminx/course/courseTree.jsp</result>
<result name="chapterList">/adminx/course/chaptersList.jsp</result>
<result name="chapterWareList">/adminx/course/chapterWareList.jsp</result>
<result name="chapterExamList">/adminx/course/chapterExamList.jsp</result>
<result name="uploadCCWareList">/adminx/course/uploadCCWareList.jsp</result>
<result name="refreshUploadCCList">/adminx/course/uploadCCWareList_list.jsp</result>
<result name="viewCourse">/adminx/course/courseView.jsp</result>
</action>
<action name="courseQueryAction" class="com.myland.jp.adminx.course.action.CourseAction" method="courseQueryList">
<result name="success">/adminx/course/courseQueryList.jsp</result>
</action>
<!-- 课程审核 -->
<action name="courseCheckQueryAction" class="com.myland.jp.adminx.course.action.CourseAction" method="courseCheckQueryList">
<result name="success">/adminx/course/courseCheckQueryList.jsp</result>
</action>
<!-- 课程管理end -->

<!-- 课程配置章节begin -->
<action name="coursePowerAction" class="com.myland.jp.adminx.course.action.CoursePowerAction">
<result name="coursePower">/adminx/course/coursePower.jsp</result>
<result name="chapterSelList">/adminx/course/chapterSelectList.jsp</result>
<result name="insert" type="redirect">/adminx/chapterSelListAction.do?id=${id}</result>
<result name="del" type="redirect">/adminx/chapterSelListAction.do?id=${id}</result>
</action>

<action name="chapterListAction" class="com.myland.jp.adminx.course.action.CoursePowerAction" method="findChapterList">
<result name="chapterList">/adminx/course/chapterList.jsp</result>
</action>

<action name="chapterSelListAction" class="com.myland.jp.adminx.course.action.CoursePowerAction" method="findSelectChapterList">
<result name="chapterSelList">/adminx/course/chapterSelectList.jsp</result>
</action>

<action name="delCourseChapter" class="com.myland.jp.adminx.course.action.CoursePowerAction" method="delCourseChapter">
<result name="chapterSelList">/adminx/course/chapterSelectList.jsp</result>
</action>
<!-- 课程配置章节end -->

<!-- 发票管理 st--><!-- 针对代理商的操作 不可放里面?★$30min-->
<action name="payInvoiceAdmin" class="com.myland.jp.adminx.pay.action.PayInvoiceAdminAction">
<result name="payInvoiceList">/adminx/pay/payInvoiceListAdminx.jsp</result>
<result name="payInvoice" type="chain">
<param name="method">queryInvoice</param>
<param name="actionName">payInvoiceAdmin</param>
<param name="namespace">/adminx</param>
</result><!-- /adminx/pay/payInvoiceListAdminx_agent.jsp -->
<result name="payInvoice_agent" type="chain">
<param name="method">queryInvoice_agent</param>
<param name="actionName">payInvoiceAdmin_agent</param>
<param name="namespace">/adminx</param>
</result>
</action>

<!-- 驾校发票管理 st--><!-- 针对代理商的操作 不可放里面?★$30min-->
<action name="payInvoiceAdmin_a" class="com.myland.jp.adminx.pay.action.PayInvoiceAdminAction">
<result name="payInvoiceList">/adminx/pay/payInvoiceListAdminx.jsp</result>
<result name="payInvoice" type="chain">
<param name="method">queryInvoice</param>
<param name="actionName">payInvoiceAdmin</param>
<param name="namespace">/adminx</param>
</result><!-- /adminx/pay/payInvoiceListAdminx_agent.jsp -->
<result name="payInvoice_agent" type="chain">
<param name="method">queryInvoice_agent</param>
<param name="actionName">payInvoiceAdmin_agent</param>
<param name="namespace">/adminx</param>
</result>
</action>

<action name="payInvoiceConfirmAdmin" class="com.myland.jp.adminx.pay.action.PayInvoiceAdminAction" method="queryInvoice">
<result name="payInvoiceList">/adminx/pay/payInvoiceListAdminx.jsp</result>
</action>
<!-- 分页不能动态 ! -->
<action name="payInvoiceAdmin_agent" class="com.myland.jp.adminx.pay.action.PayInvoiceAdminAction" method="queryInvoice_agent">
<result>/adminx/pay/payInvoiceListAdminx_agent.jsp</result>
<result name="payInvoiceList_agent">/adminx/pay/payInvoiceListAdminx_agent.jsp</result> <!-- 专门用来分页显示的. -->
</action>
<!-- 发票管理 end -->

<!-- 字典维护 begin -->
<action name="dicAction" class="com.myland.jp.adminx.dic.action.DicAction">
<result name="success">/adminx/dic/dicMain.jsp</result> <!-- 默认的不想用,配上 -->
</action>
<!-- 分页一定不可动态代理 -->
<action name="queryCodeByTypeAction" class="com.myland.jp.adminx.dic.action.DicAction" method="queryCodeByType">
<result name="list">/adminx/dic/dicList.jsp</result>
</action>
<!-- 字典维护 end -->

<!-- 学员管理 -->
<action name="personAction" class="com.myland.jp.adminx.person.action.PersonAction">
<result name="success">/adminx/person/personList.jsp</result>
<result name="addPerson">/adminx/person/personAdd.jsp</result>
<result name="modifyPerson">/adminx/person/personModify.jsp</result>
<result name="impPerson">/adminx/person/impPerson.jsp</result>
<result name="loadExcel">/adminx/person/loadImpPerson.jsp</result>
<result name="saveImpPerson" type="redirect">/adminx/personAction.do</result>
<result name="printOne">/adminx/viewPerson/printAc.jsp</result>
<result name="printAll">/adminx/viewPerson/printAcBatch.jsp</result>
</action>
<!-- 学员管理end logOrderAction_queryLogOrder-->
<action name="logOrderAction_*" class="com.myland.jp.adminx.LogOrder.action.LogOrderAction" method="{1}">
<result>/adminx/pay/logOrderList.jsp</result>
</action>

<!-- 菜单管理 -->
<action name="menuAction" class="com.myland.jp.adminx.menu.action.MenuAction">
<result name="success">/adminx/menu/menuInfo.jsp</result>
<result name="addTopMenuInfo">/adminx/menu/menuTopAdd.jsp</result>
<result name="addSubMenuInfo">/adminx/menu/menuSubAdd.jsp</result>
<result name="editTopMenuInfo">/adminx/menu/menuTopUpdate.jsp</result>
<result name="editSubMenuInfo">/adminx/menu/menuSubUpdate.jsp</result>
<result name="menuList" type="redirect">/adminx/menuListAction.do?pid=${pid}</result>
</action>
<action name="menuTreeAction" class="com.myland.jp.adminx.menu.action.MenuAction" method="menuTreeShow">
<result name="success">/adminx/menu/menuTree.jsp</result>
</action>
<action name="menuListAction" class="com.myland.jp.adminx.menu.action.MenuAction" method="menuListByPid">
<result name="menuTopList">/adminx/menu/menuTopList.jsp</result>
<result name="menuSubList">/adminx/menu/menuSubList.jsp</result>
</action>

<!-- 功能权限管理 -->
<action name="funcInfoAction" class="com.myland.jp.adminx.funcInfo.action.FuncInfoAction">
<result name="funcInfoList" type="redirect">/adminx/funcInfoListAction.do?pid=${pid}</result>
<result name="funcUrlsList" type="redirect">/adminx/funcUrlsListAction.do?funcId=${funcId}</result>
<result name="addFuncInfo">/adminx/menu/funcInfoAdd.jsp</result>
<result name="editFuncInfo">/adminx/menu/funcInfoUpdate.jsp</result>
<result name="addFuncUrls">/adminx/menu/funcUrlsAdd.jsp</result>
<result name="editFuncUrls">/adminx/menu/funcUrlsUpdate.jsp</result>
</action>
<action name="funcInfoListAction" class="com.myland.jp.adminx.funcInfo.action.FuncInfoAction" method="funcInfoListByPid">
<result name="success">/adminx/menu/funcInfoList.jsp</result>
</action>
<action name="funcUrlsListAction" class="com.myland.jp.adminx.funcInfo.action.FuncInfoAction" method="funcUrlsListByFuncId">
<result name="success">/adminx/menu/funcUrlsList.jsp</result>
</action>

<!-- 考点管理 begin -->
<action name="examPointAction" class="com.myland.jp.adminx.examPoint.action.ExamPointAction">
<result name="success">/adminx/examPoint/examPointList.jsp</result>
<result name="insertExamPoint">/adminx/examPoint/examPointAdd.jsp</result>
<result name="updateExamPoint">/adminx/examPoint/examPointUpdate.jsp</result>
</action>
<action name="examPointQueryAction" class="com.myland.jp.adminx.examPoint.action.ExamPointAction" method="examPointQueryList">
<result name="examPointQueryList">/adminx/examPoint/examPointQueryList.jsp</result>
</action>
<!-- 考点管理 end -->


<!-- 问卷调查 -->
<action name="surveyAction" class="com.myland.jp.adminx.survey.action.surveyAction">
<result name="success">/adminx/survey/surveyList.jsp</result>
<result name="toAdd">/adminx/survey/questionAdd.jsp</result>
<result name="saveSurvey">/adminx/surveyAction.do</result>
<result name="toModifyQuestion">/adminx/survey/questionModify.jsp</result>
</action>
<!-- 问卷调查 -->

<!-- 打回信息管理begin -->
<action name="applyReplyAction" class="com.myland.jp.adminx.applyReply.action.ApplyReplyAction">
<result name="applyReplyList">/adminx/applyReply/applyReplyList.jsp</result>
</action>

<!-- 打回信息管理end -->
<!-- 接口管理 -->
<action name="interFaceAction" class="com.myland.jp.adminx.interfaces.action.InterFaceAction">
<result name="success">/adminx/interFace/interFaceList.jsp</result>
<result name="addInterFace">/adminx/interFace/interFaceAdd.jsp</result>
<result name="editInterFace">/adminx/interFace/interFaceEdit.jsp</result>
<result name="viewInterFace">/adminx/interFace/interFaceView.jsp</result>
</action>

<!-- 刷新缓存 -->
<action name="refreshCache_*" class="com.myland.framework.cache.action.RefreshCacheAction" method="{1}">
<result name="open">/adminx/cache/refreshCache.jsp</result>
</action>

<!-- 日志管理 begin -->
<action name="logAction" class="com.myland.jp.adminx.log.action.LogAction">
<result name="courseLogList">/adminx/log/LogList.jsp</result>
</action>
<!-- 后台日志集合 -->
<action name="LogQueryAction" class="com.myland.jp.adminx.log.action.LogAction" method="LogQueryList">
<result name="success">/adminx/log/LogQueryList.jsp</result>
</action>
<!-- 前台日志集合 -->
<action name="webLogQueryAction" class="com.myland.jp.adminx.log.action.LogAction" method="WebLogQueryList">
<result name="success">/adminx/log/WebLogQueryList.jsp</result>
</action>
<!-- 日志管理 end -->
<!-- 统计汇总 -->
<action name="summaryAction_*" class="com.myland.jp.adminx.summary.action.SummaryAction" method="{1}">
<result name="success">/adminx/summary/summaryMonthList.jsp</result>
<result name="{1}">/adminx/summary/summaryNumList.jsp</result>
</action>
<!-- 月度内每天学员汇总 -->
<action name="summaryDaysOfMonth" class="com.myland.jp.adminx.summary.action.SummaryAction" method="summaryDaysOfMonth">
<result name="summaryDay">/adminx/summary/summaryDayList.jsp</result>
</action>
<!-- 每天学习学员明细 -->
<action name="detailSummaryDay" class="com.myland.jp.adminx.summary.action.SummaryAction" method="detailSummaryDay">
<result name="detailSummary">/adminx/summary/detailDayList.jsp</result>
</action>
<!-- App问题查询 母页面 -->
<action name="messageAction" class="com.myland.jp.adminx.message.action.MessageAction">
<result name="messageList">/adminx/message/messageCheckList.jsp</result>
</action>
<!-- App问题查询 子页面 -->
<action name="messageActionQuery" class="com.myland.jp.adminx.message.action.MessageAction" method="messageQuery">
<result name="messageCheckList">/adminx/message/messageQueryList.jsp</result>
<!-- 动态调用,App问题审核 -->
</action>
<action name="messageCheckAction" class="com.myland.jp.adminx.message.action.MessageAction">
<result name="show">/adminx/message/messageContentShow.jsp</result>
<result name="detailList">/adminx/message/messageDetailList.jsp</result>
<result name="showDetail">/adminx/message/messageDetailContentShow.jsp</result>
</action>
<!-- 回复问题的审核 子页面 -->
<action name="messageDetailActionQuery" class="com.myland.jp.adminx.message.action.MessageAction" method="messageDetailQuery">
<result name="messageDetailQueryList">/adminx/message/messageDetailQueryList.jsp</result>
</action>
<!-- 订单汇总 -->
<action name="payOrderFlowTotalAction" class="com.myland.jp.adminx.payOrderFlowTotal.action.PayOrderFlowTotalAction">
<result name="summarizeList">/adminx/payOrderFlowTotal/orderTotalList.jsp</result>
</action>
</package>
</struts>
课程设计与要求: 实验18 手写数字识别程序设计与实现 实验类型:设计性实验 实验学时:8 涉及的知识点:SVM、决策树、随机森林、XGBoost和LightGBM机器学习算法的综合应用 一、 实验目的 1、 了解机器学习算法应用项目设计流程与基本方法。 2、 掌握SVM应用设计与K折交叉验证法获得测试数据。 3、 熟悉两种以上不同类型机器学习算法及应用。 4、 掌握各类机器学习算法的区别、优缺点;会应用网格搜索选择最优超参数。 5、 掌握分类任务的性能指标评价方法。 二、 实验要求 1、 使用anaconda集成开发环境完成课程设计,代码的可维护性好,有必要的注释和相应的文档。 2、 能够识别符合分辨率要求的手写数字。 3、 构建不同模型实现手写数字分类识别,至少要对比两种方法,如决策树、支持向量机、随机森林、XGBoost和LightGBM等。对比不同模型的分类性能报告,评价模型好坏。 4、 数据集采用sklearn.datasets中的digits,测试集数据可以用自己手写产生或者从digits中拆分。 三、 设计指标 1、 完整的设计文档 1) 系统的需求分析 2) 系统的概要设计 3) 详细设计与实现 4) 系统测试方法 2、 运行画面截图 3、 每一部分附上关键性代码 4、 项目总结 四、 预习与参考 1、 教材有关决策树、SVM(支持向量机)、随机森林、XGBoost和LightGBM有关章节。 2、 课程PPT有关内容。 3、 中国知网有关手写数字识别的文献资料。 五、 考核形式 根据提交的设计文档完成程度以及程序功能的实现情况(要求演示)进行考核:  无任何文档,无程序,得 0 分;  文档描述不清楚,思路混乱,程序不能运行,2分;  文档描述清晰,程序实现了基本功能,3.5分;  文档描述清晰准确,思路清晰,程序实现了要求的所有功能,4. 5分;  文档完备,设计合理有创新,报告清晰明确,深入分析了自己进行实验的体会感想,程序实现了全部功能,功能完善,并有其它的创新实现,5分。 六、 实验报告要求 1、 实验目的结合自己个人的实际情况书写,不要雷同。 2、 项目概要设计说明书(描述软件系统架构、逻辑架构、物理架构、部署结构、功能架构及关键技术,关键业务模块需通过UML图进行详细描述)、需求规格说明书(包括功能设计、非功能性设计、系统用例)。 3、 项目设计运行截图。 代码程序: # ======================== # 导入必要的库 # ======================== import numpy as np # 数值计算库 import matplotlib.pyplot as plt # 绘图库 import pandas as pd # 数据处理库 import tkinter as tk # GUI库 from tkinter import ttk, filedialog, messagebox # GUI组件 from PIL import Image, ImageDraw # 图像处理库 import cv2 # 计算机视觉库 import os # 操作系统接口 import csv # CSV文件处理 from sklearn.datasets import load_digits # 加载数字数据集 from sklearn.model_selection import train_test_split # 数据集划分 from sklearn.svm import SVC # 支持向量机模型 from sklearn.tree import DecisionTreeClassifier # 决策树模型 from sklearn.ensemble import RandomForestClassifier # 随机森林模型 from sklearn.neural_network import MLPClassifier # 多层感知机模型 from sklearn.neighbors import KNeighborsClassifier # K近邻模型 from sklearn.naive_bayes import GaussianNB # 朴素贝叶斯模型 from sklearn.metrics import accuracy_score # 准确率评估 from sklearn.preprocessing import StandardScaler # 数据标准化 # 设置中文字体和负号显示(解决中文乱码问题) plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei"] plt.rcParams["axes.unicode_minus"] = False # ======================== # 尝试导入可选模型库 # ======================== XGB_INSTALLED = False # 标记XGBoost是否安装 LGB_INSTALLED = False # 标记LightGBM是否安装 try: import xgboost as xgb # XGBoost模型 XGB_INSTALLED = True except ImportError: print("警告: 未安装XGBoost库,无法使用XGBoost模型") try: import lightgbm as lgb # LightGBM模型 LGB_INSTALLED = True except ImportError: print("警告: 未安装LightGBM库,无法使用LightGBM模型") # ======================== # 模型配置 # ======================== # 定义模型元数据(包含模型名称、类、标准化器和参数) MODEL_METADATA = { 'svm': ('支持向量机(SVM)', SVC, StandardScaler, {'probability': True, 'random_state': 42}), 'dt': ('决策树(DT)', DecisionTreeClassifier, None, {'random_state': 42}), 'rf': ('随机森林(RF)', RandomForestClassifier, None, {'n_estimators': 100, 'random_state': 42}), 'mlp': ('多层感知机(MLP)', MLPClassifier, StandardScaler, {'hidden_layer_sizes': (100, 50), 'max_iter': 500, 'random_state': 42}), 'knn': ('K最近邻(KNN)', KNeighborsClassifier, StandardScaler, {'n_neighbors': 5, 'weights': 'distance'}), 'nb': ('高斯朴素贝叶斯(NB)', GaussianNB, None, {}), } # 添加可选模型(如果已安装) if XGB_INSTALLED: MODEL_METADATA['xgb'] = ('XGBoost(XGB)', xgb.XGBClassifier, None, {'objective': 'multi:softmax', 'random_state': 42}) if LGB_INSTALLED: MODEL_METADATA['lgb'] = ('LightGBM(LGB)', lgb.LGBMClassifier, None, { 'objective': 'multiclass', 'random_state': 42, 'num_class': 10, 'max_depth': 5, 'min_child_samples': 10, 'learning_rate': 0.1, 'force_col_wise': True }) # ======================== # 模型工厂类 - 负责模型创建、训练和评估 # ======================== class ModelFactory: @staticmethod def get_split_data(digits_dataset): """数据集划分""" X, y = digits_dataset.data, digits_dataset.target # 获取特征和标签 # 划分训练集和测试集(70%训练,30%测试) return train_test_split(X, y, test_size=0.3, random_state=42) @classmethod def create_model(cls, model_type): """创建模型和数据标准化器""" # 检查模型类型是否有效 if model_type not in MODEL_METADATA: raise ValueError(f"未知模型类型: {model_type}") # 从配置中获取模型信息 name, model_cls, scaler_cls, params = MODEL_METADATA[model_type] # 创建模型实例和标准化器 model = model_cls(**params) scaler = scaler_cls() if scaler_cls else None return model, scaler @staticmethod def train_model(model, X_train, y_train, scaler=None, model_type=None): """训练模型""" # 数据标准化处理 if scaler: X_train = scaler.fit_transform(X_train) # LightGBM特殊处理(需要DataFrame格式) if model_type == 'lgb' and isinstance(X_train, np.ndarray): X_train = pd.DataFrame(X_train) # 训练模型 model.fit(X_train, y_train) return model @staticmethod def evaluate_model(model, X_test, y_test, scaler=None, model_type=None): """评估模型""" # 数据标准化处理 if scaler: X_test = scaler.transform(X_test) # LightGBM特殊处理 if model_type == 'lgb' and isinstance(X_test, np.ndarray) and hasattr(model, 'feature_name_'): X_test = pd.DataFrame(X_test, columns=model.feature_name_) # 预测并计算准确率 y_pred = model.predict(X_test) return accuracy_score(y_test, y_pred) @classmethod def train_and_evaluate(cls, model_type, X_train, y_train, X_test, y_test): """训练并评估模型""" try: # 创建模型 model, scaler = cls.create_model(model_type) # 训练模型 model = cls.train_model(model, X_train, y_train, scaler, model_type) # 评估模型 accuracy = cls.evaluate_model(model, X_test, y_test, scaler, model_type) return model, scaler, accuracy except Exception as e: print(f"模型 {model_type} 训练/评估错误: {str(e)}") raise @classmethod def evaluate_all_models(cls, digits_dataset): """评估所有可用模型""" print("\n=== 模型评估 ===") # 划分数据集 X_train, X_test, y_train, y_test = cls.get_split_data(digits_dataset) results = [] # 存储结果 # 遍历所有模型 for model_type in MODEL_METADATA: name = MODEL_METADATA[model_type][0] print(f"评估模型: {name} ({model_type})") # 检查模型是否可用 if not MODEL_METADATA[model_type][1]: results.append({"模型名称": name, "准确率": "N/A"}) continue try: # 训练并评估模型 _, _, accuracy = cls.train_and_evaluate( model_type, X_train, y_train, X_test, y_test ) results.append({"模型名称": name, "准确率": f"{accuracy:.4f}"}) except Exception as e: results.append({"模型名称": name, "准确率": f"错误: {str(e)}"}) # 按准确率排序 results.sort( key=lambda x: float(x["准确率"]) if isinstance(x["准确率"], str) and x["准确率"].replace('.', '', 1).isdigit() else -1, reverse=True ) # 打印结果 print(pd.DataFrame(results)) return results # ======================== # 手写板类 - GUI界面和绘图功能 # ======================== class HandwritingBoard: CANVAS_SIZE = 300 # 固定画布尺寸 BRUSH_SIZE = 12 # 画笔大小 def __init__(self, root, model_factory, digits): # 初始化主窗口 self.root = root self.root.title("手写数字识别系统") self.root.geometry("1000x700") # 设置窗口大小 # 模型和数据相关 self.model_factory = model_factory # 模型工厂 self.digits = digits # 数字数据集 self.model_cache = {} # 模型缓存(提高切换速度) self.current_model = None # 当前使用的模型 self.scaler = None # 数据标准化器 self.current_model_type = None # 当前模型类型 self.has_drawn = False # 标记是否已绘制数字 self.custom_data = [] # 存储自定义训练数据 # 绘图相关状态 self.drawing = False # 是否正在绘制 self.last_x = self.last_y = 0 # 上次绘制位置 # 创建自定义数据目录 self.data_dir = "custom_digits_data" os.makedirs(self.data_dir, exist_ok=True) # 初始化画布(PIL图像) self.image = Image.new("L", (self.CANVAS_SIZE, self.CANVAS_SIZE), 255) # 创建白色背景图像 self.draw_obj = ImageDraw.Draw(self.image) # 创建绘图对象 # 创建界面组件 self.create_widgets() # 初始化默认模型 self.init_default_model() def create_widgets(self): """创建界面组件""" # 创建主框架 main_frame = tk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 1. 模型选择区域 model_frame = tk.LabelFrame(main_frame, text="模型选择", font=("Arial", 10, "bold")) model_frame.grid(row=0, column=0, columnspan=2, sticky="ew", padx=5, pady=5) model_frame.grid_columnconfigure(1, weight=1) # 让模型标签可以扩展 # 模型选择标签 tk.Label(model_frame, text="选择模型:", font=("Arial", 10)).grid(row=0, column=0, padx=5, pady=5, sticky="w") # 获取可用模型列表 self.available_models = [] for model_type, (name, _, _, _) in MODEL_METADATA.items(): if MODEL_METADATA[model_type][1]: self.available_models.append((model_type, name)) # 模型选择下拉框 self.model_var = tk.StringVar() self.model_combobox = ttk.Combobox( model_frame, textvariable=self.model_var, values=[name for _, name in self.available_models], state="readonly", width=25, font=("Arial", 10) ) self.model_combobox.current(0) # 设置默认选项 self.model_combobox.bind("<<ComboboxSelected>>", self.on_model_select) # 绑定选择事件 self.model_combobox.grid(row=0, column=1, padx=5, pady=5, sticky="ew") # 模型信息标签(显示准确率) self.model_label = tk.Label( model_frame, text="", font=("Arial", 10), relief=tk.SUNKEN, padx=5, pady=2 ) self.model_label.grid(row=0, column=2, padx=5, pady=5, sticky="ew") # 2. 左侧绘图区域和右侧结果区域 # 左侧绘图区域 left_frame = tk.LabelFrame(main_frame, text="绘制区域", font=("Arial", 10, "bold")) left_frame.grid(row=1, column=0, padx=5, pady=5, sticky="nsew") # 绘图画布 self.canvas = tk.Canvas(left_frame, bg="white", width=self.CANVAS_SIZE, height=self.CANVAS_SIZE) self.canvas.pack(padx=10, pady=10) # 绑定绘图事件 self.canvas.bind("<Button-1>", self.start_draw) # 鼠标按下 self.canvas.bind("<B1-Motion>", self.draw) # 鼠标拖动 self.canvas.bind("<ButtonRelease-1>", self.stop_draw) # 鼠标释放 # 添加绘制提示 self.canvas.create_text( self.CANVAS_SIZE / 2, self.CANVAS_SIZE / 2, text="绘制数字", fill="gray", font=("Arial", 16) ) # 绘图控制按钮 btn_frame = tk.Frame(left_frame) btn_frame.pack(fill=tk.X, pady=(0, 10)) # 功能按钮 tk.Button(btn_frame, text="识别", command=self.recognize, width=8).pack(side=tk.LEFT, padx=5) tk.Button(btn_frame, text="清除", command=self.clear_canvas, width=8).pack(side=tk.LEFT, padx=5) tk.Button(btn_frame, text="样本", command=self.show_samples, width=8).pack(side=tk.LEFT, padx=5) # 右侧结果区域 right_frame = tk.Frame(main_frame) right_frame.grid(row=1, column=1, padx=5, pady=5, sticky="nsew") # 2.1 识别结果区域 result_frame = tk.LabelFrame(right_frame, text="识别结果", font=("Arial", 10, "bold")) result_frame.pack(fill=tk.X, padx=5, pady=5) # 结果显示标签 self.result_label = tk.Label( result_frame, text="请绘制数字", font=("Arial", 24), pady=10 ) self.result_label.pack() # 置信度显示标签 self.prob_label = tk.Label( result_frame, text="", font=("Arial", 12) ) self.prob_label.pack() # 2.2 置信度可视化区域 confidence_frame = tk.LabelFrame(right_frame, text="识别置信度", font=("Arial", 10, "bold")) confidence_frame.pack(fill=tk.X, padx=5, pady=5) # 置信度画布(条形图) self.confidence_canvas = tk.Canvas( confidence_frame, bg="white", height=50 ) self.confidence_canvas.pack(fill=tk.X, padx=10, pady=10) self.confidence_canvas.create_text( 150, 25, text="识别后显示置信度", fill="gray", font=("Arial", 10) ) # 2.3 候选数字区域 candidates_frame = tk.LabelFrame(right_frame, text="可能的数字", font=("Arial", 10, "bold")) candidates_frame.pack(fill=tk.X, padx=5, pady=5) # 候选数字表格 columns = ("数字", "概率") self.candidates_tree = ttk.Treeview( candidates_frame, columns=columns, show="headings", height=4 ) # 配置表格列 for col in columns: self.candidates_tree.heading(col, text=col) self.candidates_tree.column(col, width=80, anchor=tk.CENTER) # 添加滚动条 scrollbar = ttk.Scrollbar( candidates_frame, orient=tk.VERTICAL, command=self.candidates_tree.yview ) self.candidates_tree.configure(yscroll=scrollbar.set) self.candidates_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) scrollbar.pack(side=tk.RIGHT, fill=tk.Y, padx=5, pady=5) # 3. 模型性能对比和训练集管理区域 # 3.1 模型性能对比区域 performance_frame = tk.LabelFrame(main_frame, text="模型性能对比", font=("Arial", 10, "bold")) performance_frame.grid(row=2, column=0, padx=5, pady=5, sticky="nsew") # 性能表格 columns = ("模型名称", "准确率") self.performance_tree = ttk.Treeview( performance_frame, columns=columns, show="headings", height=8 ) # 配置表格列 for col in columns: self.performance_tree.heading(col, text=col) self.performance_tree.column(col, width=120, anchor=tk.CENTER) # 添加滚动条 scrollbar = ttk.Scrollbar( performance_frame, orient=tk.VERTICAL, command=self.performance_tree.yview ) self.performance_tree.configure(yscroll=scrollbar.set) self.performance_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) scrollbar.pack(side=tk.RIGHT, fill=tk.Y, padx=5, pady=5) # 3.2 训练集管理区域 train_frame = tk.LabelFrame(main_frame, text="训练集管理", font=("Arial", 10, "bold")) train_frame.grid(row=2, column=1, padx=5, pady=5, sticky="nsew") # 训练集管理按钮 tk.Button( train_frame, text="保存为训练样本", command=self.save_as_training_sample, width=18, height=2 ).grid(row=0, column=0, padx=5, pady=5, sticky="ew") tk.Button( train_frame, text="保存全部训练集", command=self.save_all_training_data, width=18, height=2 ).grid(row=0, column=1, padx=5, pady=5, sticky="ew") tk.Button( train_frame, text="加载训练集", command=self.load_training_data, width=18, height=2 ).grid(row=1, column=0, padx=5, pady=5, sticky="ew") tk.Button( train_frame, text="性能图表", command=self.show_performance_chart, width=18, height=2 ).grid(row=1, column=1, padx=5, pady=5, sticky="ew") # 4. 状态栏 self.status_var = tk.StringVar(value="就绪") status_bar = tk.Label( self.root, textvariable=self.status_var, bd=1, relief=tk.SUNKEN, anchor=tk.W, font=("Arial", 10) ) status_bar.pack(side=tk.BOTTOM, fill=tk.X) # 配置布局权重 main_frame.grid_columnconfigure(0, weight=1) main_frame.grid_columnconfigure(1, weight=1) main_frame.grid_rowconfigure(1, weight=1) main_frame.grid_rowconfigure(2, weight=1) # ======================== # 绘图功能 # ======================== def start_draw(self, event): """开始绘制""" self.drawing = True self.last_x, self.last_y = event.x, event.y def draw(self, event): """绘制""" if not self.drawing: return x, y = event.x, event.y # 在画布上绘制 self.canvas.create_line( self.last_x, self.last_y, x, y, fill="black", width=self.BRUSH_SIZE, capstyle=tk.ROUND, smooth=True ) # 在图像上绘制(用于后续处理) self.draw_obj.line( [self.last_x, self.last_y, x, y], fill=0, # 黑色 width=self.BRUSH_SIZE ) # 更新位置 self.last_x, self.last_y = x, y def stop_draw(self, event): """停止绘制""" self.drawing = False self.has_drawn = True self.status_var.set("已绘制数字,点击'识别'进行识别") def clear_canvas(self): """清除画布""" # 清除画布内容 self.canvas.delete("all") # 重置图像 self.image = Image.new("L", (self.CANVAS_SIZE, self.CANVAS_SIZE), 255) # 白色背景 self.draw_obj = ImageDraw.Draw(self.image) # 添加绘制提示 self.canvas.create_text( self.CANVAS_SIZE / 2, self.CANVAS_SIZE / 2, text="绘制数字", fill="gray", font=("Arial", 16) ) # 重置结果显示 self.result_label.config(text="请绘制数字") self.prob_label.config(text="") self.clear_confidence_display() self.has_drawn = False self.status_var.set("画布已清除") def clear_confidence_display(self): """清除置信度显示""" self.confidence_canvas.delete("all") self.confidence_canvas.create_text( 150, 25, text="识别后显示置信度", fill="gray", font=("Arial", 10) ) # 清空候选数字表格 for item in self.candidates_tree.get_children(): self.candidates_tree.delete(item) # ======================== # 图像处理功能 # ======================== def preprocess_image(self): """预处理手写数字图像""" # 将PIL图像转换为NumPy数组 img_array = np.array(self.image) # 1. 高斯模糊降噪 img_array = cv2.GaussianBlur(img_array, (5, 5), 0) # 2. 二值化(转换为黑白图像) _, img_array = cv2.threshold(img_array, 127, 255, cv2.THRESH_BINARY_INV) # 3. 轮廓检测(查找数字轮廓) contours, _ = cv2.findContours(img_array, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: self.status_var.set("未检测到有效数字,请重新绘制") return None # 4. 找到最大轮廓(即数字部分) c = max(contours, key=cv2.contourArea) x, y, w, h = cv2.boundingRect(c) # 5. 提取数字区域 digit = img_array[y:y+h, x:x+w] # 6. 填充为正方形(保持长宽比) size = max(w, h) padded = np.ones((size, size), dtype=np.uint8) * 255 # 白色背景 offset_x = (size - w) // 2 offset_y = (size - h) // 2 padded[offset_y:offset_y+h, offset_x:offset_x+w] = digit # 7. 缩放为8x8(匹配MNIST数据集格式) resized = cv2.resize(padded, (8, 8), interpolation=cv2.INTER_AREA) # 8. 归一化(将像素值从0-255映射到0-16) normalized = 16 - (resized / 255 * 16).astype(np.uint8) # 9. 展平为一维数组(64个特征) return normalized.flatten() # ======================== # 识别功能 # ======================== def recognize(self): """识别手写数字""" # 检查是否已绘制数字 if not self.has_drawn: self.status_var.set("请先绘制数字再识别") return # 检查模型是否已加载 if self.current_model is None: self.status_var.set("模型未加载,请选择模型") return # 预处理图像 img_array = self.preprocess_image() if img_array is None: return # 重塑为模型输入格式(1个样本,64个特征) img_input = img_array.reshape(1, -1) try: # 数据标准化 if self.scaler: img_input = self.scaler.transform(img_input) # LightGBM特殊处理(需要DataFrame格式) if self.current_model_type == 'lgb' and hasattr(self.current_model, 'feature_name_'): img_input = pd.DataFrame(img_input, columns=self.current_model.feature_name_) # 预测数字 pred = self.current_model.predict(img_input)[0] self.result_label.config(text=f"识别结果: {pred}") # 概率预测(如果模型支持) if hasattr(self.current_model, 'predict_proba'): probs = self.current_model.predict_proba(img_input)[0] confidence = probs[pred] # 预测结果的置信度 # 更新UI self.prob_label.config(text=f"置信度: {confidence:.2%}") self.update_confidence_display(confidence) # 更新置信度可视化 # 显示候选数字(概率最高的3个) top3 = sorted(enumerate(probs), key=lambda x: -x[1])[:3] self.update_candidates_display(top3) else: self.prob_label.config(text="该模型不支持概率输出") self.clear_confidence_display() self.status_var.set(f"识别完成: 数字 {pred}") except Exception as e: self.status_var.set(f"识别错误: {str(e)}") self.clear_confidence_display() # ======================== # UI更新功能 # ======================== def update_confidence_display(self, confidence): """更新置信度可视化""" self.confidence_canvas.delete("all") # 获取画布宽度 canvas_width = self.confidence_canvas.winfo_width() or 300 # 绘制背景 self.confidence_canvas.create_rectangle( 10, 10, canvas_width - 10, 40, fill="#f0f0f0", outline="#cccccc" ) # 绘制置信度条(根据置信度值) bar_width = int((canvas_width - 20) * confidence) color = self.get_confidence_color(confidence) # 根据置信度选择颜色 self.confidence_canvas.create_rectangle( 10, 10, 10 + bar_width, 40, fill=color, outline="" ) # 绘制文本(显示百分比) self.confidence_canvas.create_text( canvas_width / 2, 25, text=f"{confidence:.1%}", font=("Arial", 10, "bold") ) # 绘制刻度 for i in range(0, 11): x_pos = 10 + i * (canvas_width - 20) / 10 self.confidence_canvas.create_line(x_pos, 40, x_pos, 45, width=1) if i % 2 == 0: self.confidence_canvas.create_text(x_pos, 55, text=f"{i*10}%", font=("Arial", 8)) def get_confidence_color(self, confidence): """根据置信度获取颜色""" # 高置信度:绿色 if confidence >= 0.9: return "#4CAF50" # 中等置信度:黄色 elif confidence >= 0.7: return "#FFC107" # 低置信度:红色 else: return "#F44336" def update_candidates_display(self, candidates): """更新候选数字显示""" # 清空现有项 for item in self.candidates_tree.get_children(): self.candidates_tree.delete(item) # 添加新项(候选数字及其概率) for digit, prob in candidates: self.candidates_tree.insert( "", tk.END, values=(digit, f"{prob:.2%}") ) # ======================== # 样本显示功能 # ======================== def show_samples(self): """显示样本图像""" plt.figure(figsize=(10, 4)) # 显示0-9每个数字的一个样本 for i in range(10): plt.subplot(2, 5, i+1) sample_idx = np.where(self.digits.target == i)[0][0] plt.imshow(self.digits.images[sample_idx], cmap="gray") plt.title(f"数字 {i}", fontsize=9) plt.axis("off") plt.tight_layout() plt.show() # ======================== # 模型管理功能 # ======================== def on_model_select(self, event): """模型选择事件处理""" # 获取选中的模型名称 selected_name = self.model_var.get() # 查找对应的模型类型 model_type = next( (k for k, v in self.available_models if v == selected_name), None ) if model_type: # 切换模型 self.change_model(model_type) def change_model(self, model_type): """切换模型""" model_name = MODEL_METADATA[model_type][0] # 尝试从缓存加载模型 if model_type in self.model_cache: self.current_model, self.scaler, accuracy, self.current_model_type = self.model_cache[model_type] self.model_label.config(text=f"{model_name} (准确率:{accuracy:.4f})") self.status_var.set(f"已加载模型: {model_name}") return # 加载新模型 self.status_var.set(f"正在加载模型: {model_name}...") self.root.update() # 更新UI显示状态 try: # 获取数据集 X_train, X_test, y_train, y_test = self.model_factory.get_split_data(self.digits) # 训练并评估模型 self.current_model, self.scaler, accuracy = self.model_factory.train_and_evaluate( model_type, X_train, y_train, X_test, y_test ) # 缓存模型 self.current_model_type = model_type self.model_cache[model_type] = (self.current_model, self.scaler, accuracy, self.current_model_type) # 更新UI self.model_label.config(text=f"{model_name} (准确率:{accuracy:.4f})") self.status_var.set(f"模型加载完成: {model_name}, 准确率: {accuracy:.4f}") self.clear_canvas() # 更新性能表格 self.load_performance_data() except Exception as e: self.status_var.set(f"模型加载失败: {str(e)}") self.model_label.config(text="模型加载失败") def init_default_model(self): """初始化默认模型""" # 设置默认模型并加载 self.model_var.set(self.available_models[0][1]) self.change_model(self.available_models[0][0]) def load_performance_data(self): """加载性能数据""" # 评估所有模型 results = self.model_factory.evaluate_all_models(self.digits) # 清空表格 for item in self.performance_tree.get_children(): self.performance_tree.delete(item) # 添加数据到表格 for i, result in enumerate(results): tag = "highlight" if i == 0 else "" # 高亮显示性能最好的模型 self.performance_tree.insert( "", tk.END, values=(result["模型名称"], result["准确率"]), tags=(tag,) ) # 配置高亮样式 self.performance_tree.tag_configure("highlight", background="#e6f7ff") # ======================== # 性能可视化功能 # ======================== def show_performance_chart(self): """显示性能图表""" # 获取性能数据 results = self.model_factory.evaluate_all_models(self.digits) # 提取有效结果(过滤掉错误数据) valid_results = [] for result in results: try: accuracy = float(result["准确率"]) valid_results.append((result["模型名称"], accuracy)) except ValueError: continue if not valid_results: messagebox.showinfo("提示", "没有可用的性能数据") return # 按准确率排序 valid_results.sort(key=lambda x: x[1], reverse=True) models, accuracies = zip(*valid_results) # 创建水平条形图 plt.figure(figsize=(10, 5)) bars = plt.barh(models, accuracies, color='#2196F3') plt.xlabel('准确率', fontsize=10) plt.ylabel('模型', fontsize=10) plt.title('模型性能对比', fontsize=12) plt.xlim(0, 1.05) # 设置X轴范围 # 添加数值标签 for bar in bars: width = bar.get_width() plt.text( width + 0.01, bar.get_y() + bar.get_height()/2, f'{width:.4f}', ha='left', va='center', fontsize=8 ) plt.tight_layout() plt.show() # ======================== # 训练集管理功能 # ======================== def save_as_training_sample(self): """保存为训练样本""" # 检查是否已绘制数字 if not self.has_drawn: self.status_var.set("请先绘制数字再保存") return # 预处理图像 img_array = self.preprocess_image() if img_array is None: return # 弹出标签输入窗口 label_window = tk.Toplevel(self.root) label_window.title("输入标签") label_window.geometry("300x150") label_window.transient(self.root) label_window.grab_set() # 模态窗口 # 标签输入提示 tk.Label( label_window, text="请输入数字标签 (0-9):", font=("Arial", 10) ).pack(pady=10) # 输入框 entry = tk.Entry(label_window, font=("Arial", 12), width=5) entry.pack(pady=5) entry.focus_set() def save_with_label(): """保存带标签的样本""" try: # 验证标签 label = int(entry.get()) if label < 0 or label > 9: raise ValueError("标签必须是0-9的数字") # 添加到自定义数据集 self.custom_data.append((img_array.tolist(), label)) self.status_var.set(f"已保存数字 {label} (共 {len(self.custom_data)} 个样本)") label_window.destroy() except ValueError as e: self.status_var.set(f"保存错误: {str(e)}") # 保存按钮 tk.Button( label_window, text="保存", command=save_with_label, width=10 ).pack(pady=5) def save_all_training_data(self): """保存全部训练数据""" # 检查是否有数据可保存 if not self.custom_data: self.status_var.set("没有训练数据可保存") return # 弹出文件保存对话框 file_path = filedialog.asksaveasfilename( defaultextension=".csv", filetypes=[("CSV文件", "*.csv")], initialfile="custom_digits.csv", title="保存训练集" ) if not file_path: return try: # 写入CSV文件 with open(file_path, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) # 写入表头(64个像素+标签) writer.writerow([f'pixel{i}' for i in range(64)] + ['label']) # 写入数据 for img_data, label in self.custom_data: writer.writerow(img_data + [label]) self.status_var.set(f"已保存 {len(self.custom_data)} 个样本到 {os.path.basename(file_path)}") except Exception as e: self.status_var.set(f"保存失败: {str(e)}") def load_training_data(self): """加载训练数据""" # 弹出文件选择对话框 file_path = filedialog.askopenfilename( filetypes=[("CSV文件", "*.csv")], title="加载训练集" ) if not file_path: return try: self.custom_data = [] # 读取CSV文件 with open(file_path, 'r', newline='', encoding='utf-8') as f: reader = csv.reader(f) next(reader) # 跳过标题行 # 解析每一行数据 for row in reader: if len(row) != 65: # 64像素+1标签 continue # 提取像素数据和标签 img_data = [float(pixel) for pixel in row[:64]] label = int(row[64]) self.custom_data.append((img_data, label)) self.status_var.set(f"已加载 {len(self.custom_data)} 个样本") except Exception as e: self.status_var.set(f"加载失败: {str(e)}") # ======================== # 主程序入口 # ======================== def run(self): """运行应用""" self.root.mainloop() # ======================== # 程序入口 # ======================== if __name__ == "__main__": digits = load_digits() # 加载数字数据集 root = tk.Tk() # 创建主窗口 app = HandwritingBoard(root, ModelFactory, digits) # 创建应用实例 app.run() # 运行应用 请你根据上面的内容生成符合要求的课程设计:
最新发布
06-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值