Compare commits

...

44 Commits

Author SHA1 Message Date
pxrztuq3h 035176bb03 Merge pull request '访客管理系统' (#4) from branch_liu into develop
3 months ago
pxrztuq3h d2f8f08b4b Merge pull request 'Dorm' (#5) from branch_li into develop
3 months ago
LFF 2d171d28bb ygg
3 months ago
LFF bb9ac2ca94 ygg
3 months ago
LFF dc0e33233b ygg
3 months ago
LFF 246f2197b9 ygg
3 months ago
LFF 64c87e2d5c ygg
3 months ago
LFF ba64413ead ygg
3 months ago
LiuChang 708f126107 tijiao
3 months ago
LiuChang cedccae9d5 tijiao
3 months ago
pxrztuq3h 68d4ce068a Merge pull request 'smq' (#3) from branch_shen into develop
3 months ago
LiuChang affd83e652 tijiao
3 months ago
LiuChang 563386b450 8
3 months ago
shen 0e97a6ac63 5
3 months ago
shen 64d272d9a9 5
3 months ago
shen 2c7993443a 5
3 months ago
LFF 908c02403a ygg
3 months ago
shen 14d3410f7b 5
3 months ago
shen d9fe360dd9 4
3 months ago
LFF 2bbfdb4db2 ygg
3 months ago
pxrztuq3h 19e25b56bc Merge pull request 'wang' (#2) from branch_wang into develop
3 months ago
wang ziting bf9f1391f5 wang
3 months ago
shen 0d66630248 3
3 months ago
shen 30e89a98a7 2
3 months ago
LFF d1ae0ce251 ygg
3 months ago
shen 74a8a886b3 1
3 months ago
shen 582624afa9 ss
3 months ago
LFF acaa857369 ygg
3 months ago
shen f5fd8283b6 dd
3 months ago
shen d3c44841ef dd
3 months ago
shen 193fa5b67e dd
3 months ago
wang ziting ecaa541e38 wang
3 months ago
LFF fb6df5f224 ygg
3 months ago
pxrztuq3h e531e146f5 Merge pull request 'smq' (#1) from branch_shen into develop
3 months ago
LFF b18db0c6c4 ygg
3 months ago
wang ziting 28f99910d6 wang
3 months ago
shen e87530308b dd
3 months ago
wang ziting 66eefa2dab Merge remote-tracking branch 'origin/branch_wang' into branch_wang
3 months ago
wang ziting 0f8159e6dd wang
3 months ago
wang ziting 2e957a5782 wang
3 months ago
wang ziting b8bf02094c sdd
3 months ago
LFF 77255fd9b3 ygg
3 months ago
LiuChang 5e49b5cfdf tijiao
3 months ago
shen 7f3aa64603 dd
3 months ago

@ -26,7 +26,7 @@ import java.io.UnsupportedEncodingException;
import java.util.List;
/**
* Description:
* Description: AdminControllerWeb
*
* @Date: 2020/2/10 15:20
* @Author: PeiChen
@ -34,7 +34,10 @@ import java.util.List;
@Controller
public class AdminController {
// 依赖注入AdminService用于调用业务逻辑层相关方法来处理管理员数据
private AdminService adminService;
// 通过@Autowired注解让Spring框架自动注入AdminService的实现类实例
@Autowired
public void setAdminService(AdminService adminService) {
this.adminService = adminService;
@ -42,44 +45,66 @@ public class AdminController {
/**
*
* @param model
* @param admin
* @param session
* @param request
* @return
*
* @param model
* @param admin Admin
* @param session session
* @param request HTTP
* @param response HTTP
* @return "main""login"
* @throws Exception
*/
@RequestMapping(value = "/login")
public String login(Model model, Admin admin, HttpSession session, HttpServletRequest request,HttpServletResponse response) throws Exception {
public String login(Model model, Admin admin, HttpSession session, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置请求的字符编码为utf-8防止中文乱码等问题
request.setCharacterEncoding("utf-8");
// 设置响应的字符编码为utf-8确保返回给客户端的数据编码正确
response.setCharacterEncoding("utf-8");
// 获取响应的输出流对象,用于向客户端输出数据(这里主要用于输出错误提示等文本信息)
PrintWriter writer = response.getWriter();
// 如果传入的admin对象为空或者用户名、密码为空则直接返回登录页面
if (admin == null || admin.getUsername() == null || admin.getPassword() == null) {
return "login";
}
// 使用MD5Util工具类对用户输入的密码进行MD5加密以utf-8编码格式增强密码安全性
admin.setPassword(MD5Util.MD5EncodeUtf8(admin.getPassword()));
// 调用adminService的方法根据传入的admin对象包含加密后的密码去数据库查找对应的管理员信息
Admin ad = adminService.findAdmin(admin);
// 如果能查到对应的管理员信息,说明登录成功
if (ad != null) {
//登录信息存入session域
session.setAttribute("adminInfo",ad);
//System.out.println(ad);
//登录成功后的管理员信息存入session域,方便后续在其他请求中获取登录用户信息
session.setAttribute("adminInfo", ad);
// 返回主页面视图名称,通常对应着系统的主界面
return "main";
}
model.addAttribute("msg","用户名或密码错误,请重新输入!");
// 如果没查到,说明用户名或密码错误,向模型中添加错误提示信息
model.addAttribute("msg", "用户名或密码错误,请重新输入!");
// 返回登录页面视图名称,让用户重新输入登录信息
return "login";
}
//拦截后跳转至登录页
// 拦截后跳转至登录页,当用户未登录访问需要登录才能访问的资源时,可能会被拦截到此方法,然后跳转到登录页面
@RequestMapping("/to_login")
public String Login() {
return "login";
}
/**
* 退
n */
* 退使退
*
* @param admin 使Spring MVC
* @param model 使
* @param session invalidate
* @return 退
*/
@RequestMapping(value = "/loginOut")
public String loginOut(Admin admin,Model model,HttpSession session) {
//通过session.invalidate()方法来注销当前的session
public String loginOut(Admin admin, Model model, HttpSession session) {
// 通过session.invalidate()方法来注销当前的session,清除会话相关信息
session.invalidate();
return "login";
@ -87,121 +112,193 @@ public class AdminController {
/**
*
*
* @param page @RequestParam1使
* @param size @RequestParam5使
* @param request HTTP
* @param response HTTP
* @return ModelAndView
* @throws Exception
*/
@RequestMapping(value = "/findAllAdmin")
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1") int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size,HttpServletRequest request,HttpServletResponse response) throws Exception {
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1") int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置请求的字符编码为utf-8
request.setCharacterEncoding("utf-8");
// 设置响应的字符编码为utf-8
response.setCharacterEncoding("utf-8");
// 创建一个ModelAndView对象用于封装要返回给视图的数据以及视图名称
ModelAndView mv = new ModelAndView();
// 用于存放查询到的管理员列表数据初始化为null
List<Admin> admins = null;
// 从请求参数中获取查询关键字如果没有传递该参数则可能为null
String keyword = request.getParameter("keyword");
// 如果关键字为空包括null、空字符串、长度为0等情况则查询所有管理员信息按照分页条件
if (keyword == null || keyword.trim().equals("") || keyword.length() == 0) {
admins = adminService.findAll(page,size);
}else {
admins = adminService.serarchInfo(page,size,keyword);
admins = adminService.findAll(page, size);
} else {
// 如果有关键字,则根据关键字进行模糊查询管理员信息(按照分页条件)
admins = adminService.serarchInfo(page, size, keyword);
}
//PageInfo就是一个封装了分页数据的bean
// 使用PageInfo对查询到的管理员列表数据进行分页相关信息的封装方便在视图层展示分页导航等信息
PageInfo pageInfo = new PageInfo(admins);
mv.addObject("pageInfo",pageInfo);
// 将封装好分页数据的PageInfo对象添加到ModelAndView中以便在视图中可以获取并展示分页数据
mv.addObject("pageInfo", pageInfo);
// 设置要跳转的视图名称为"admin-list",通常对应着展示管理员列表的页面
mv.setViewName("admin-list");
return mv;
}
/**
*
* idadminService
*
* @param request HTTPid
* @throws Exception
*/
@ResponseBody
@RequestMapping(value = "/deleteAdmin")
public void deleteAdmin(HttpServletRequest request) throws Exception {
// 从请求参数中获取要删除的管理员的id
String id = request.getParameter("id");
// 调用adminService的方法根据解析后的管理员id转换为整数类型来删除对应的管理员记录
adminService.deleteAdminById(Integer.parseInt(id));
}
/**
*
* adminService
*
* @param request HTTP
* @param response
* @throws Exception
*/
@RequestMapping(value = "/checkUserName")
public void checkUserName(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置请求的字符编码为utf-8
request.setCharacterEncoding("utf-8");
// 设置响应的字符编码为utf-8
response.setCharacterEncoding("utf-8");
// 获取响应的输出流对象,用于向客户端输出校验结果信息
PrintWriter pw = response.getWriter();
//取值
// 从请求参数中获取要校验的用户名
String u_name = request.getParameter("u_name");
//调用service,用户名存在返回true不存在则返回false
// 调用adminService的方法校验用户名是否存在存在返回true不存在返回false
Boolean result = adminService.checkUserName(u_name);
//System.out.println(result);
//回调函数
// 根据校验结果,向客户端输出相应的提示信息
if (result) {
//pw.write("用户名已存在,请重新输入!");
pw.write("账号可用");
}else {
} else {
pw.write("账号不存在");
}
}
@RequestMapping(value = "/adminAdd")
public String adminAdd() {
// 返回添加管理员页面的视图名称,通常对应着展示添加管理员表单的页面
return "admin-add";
}
/**
*
* @param admin
* @param request
* @param response
* @throws Exception
* AdminadminService
*
* @param admin Admin
* @param request HTTP
* @param response
* @throws Exception
*/
@RequestMapping("/addAdmin")
public void addAdmin(Admin admin,HttpServletRequest request,HttpServletResponse response) throws Exception {
public void addAdmin(Admin admin, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取响应的输出流对象,用于向客户端输出添加操作的结果信息(成功或失败)
PrintWriter writer = response.getWriter();
// 调用adminService的方法校验用户名是否已存在已存在则check为true不存在为false
Boolean check = adminService.checkUserName(admin.getUsername());
//如果用户名已存在check为true不存在为false
// 如果用户名已存在,向客户端输出"false"表示添加失败,并结束方法执行
if (check) {
writer.write("false");
return;
}
// 如果传入的admin对象为空向客户端输出"false"表示添加失败,并结束方法执行
if (admin == null) {
writer.write("false");
return;
}else {
if(admin.getUsername() == null || "".trim().equals(admin.getUsername())
|| admin.getPassword() == null ||"".trim().equals(admin.getPassword())
} else {
// 进一步校验管理员对象的各个属性是否为空(去除两端空格后为空字符串也算空),只要有一个属性为空,就向客户端输出"false"表示添加失败,并结束方法执行
if (admin.getUsername() == null || "".trim().equals(admin.getUsername())
|| admin.getPassword() == null || "".trim().equals(admin.getPassword())
|| admin.getName() == null || "".trim().equals(admin.getName())
|| admin.getUid() == null || "".trim().equals(admin.getUid())
|| admin.getPhone() == null || "".trim().equals(admin.getPhone())
|| admin.getDescription() == null || "".trim().equals(admin.getDescription())) {
writer.write("false");
return;
writer.write("false");
return;
}
}
// 校验学工号是否已被注册若已被注册返回的Admin对象不为null向客户端输出"false"表示添加失败,并结束方法执行
Admin isNull = adminService.checkUid(admin.getUid());
if (isNull != null) {
writer.write("false");
return;
}
// 使用MD5Util工具类对管理员密码进行MD5加密以utf-8编码格式
admin.setPassword(MD5Util.MD5EncodeUtf8(admin.getPassword()));
// 调用adminService的方法将经过校验和加密密码后的管理员信息添加到数据库
adminService.addAdmin(admin);
// 添加成功后,向客户端输出"true"表示添加成功
writer.write("true");
}
//跳转管理员信息编辑页面,并回显信息
// 跳转管理员信息编辑页面并回显信息根据传入的管理员id从数据库查询对应的管理员信息然后将信息传递到编辑页面进行展示
@RequestMapping("/adminEdit")
public ModelAndView editAdmin(HttpServletRequest request) throws Exception {
// 创建一个ModelAndView对象用于封装要返回给视图的数据以及视图名称
ModelAndView mv = new ModelAndView();
// 从请求参数中获取要编辑的管理员的id
String id = request.getParameter("id");
// 调用adminService的方法根据管理员id查询对应的管理员信息
Admin ad = adminService.findAdminById(Integer.parseInt(id));
mv.addObject("ad",ad);
//mv.addObject("id",id);
// 将查询到的管理员信息添加到ModelAndView中以便在编辑页面可以获取并展示该信息
mv.addObject("ad", ad);
// 设置要跳转的视图名称为"admin-edit",通常对应着展示管理员信息编辑表单的页面
mv.setViewName("admin-edit");
return mv;
}
//修改管理员信息
// 修改管理员信息操作接收一个Admin对象包含修改后的管理员各项信息以及响应对象进行一系列校验后调用adminService的方法更新数据库中的管理员信息
@RequestMapping("/editAdmin")
public void editAdmin(Admin admin,HttpServletResponse response) throws Exception {
public void editAdmin(Admin admin, HttpServletResponse response) throws Exception {
// 获取响应的输出流对象,用于向客户端输出修改操作的结果信息(成功或失败)
PrintWriter writer = response.getWriter();
// 如果传入的admin对象为空向客户端输出"false"表示修改失败,并结束方法执行
if (admin == null) {
writer.write("false");
return;
}else {
if(admin.getUsername() == null || "".trim().equals(admin.getUsername())
} else {
// 校验管理员对象的各个属性是否为空(去除两端空格后为空字符串也算空),只要有一个属性为空,就向客户端输出"false"表示修改失败,并结束方法执行
if (admin.getUsername() == null || "".trim().equals(admin.getUsername())
|| admin.getName() == null || "".trim().equals(admin.getName())
|| admin.getUid() == null || "".trim().equals(admin.getUid())
|| admin.getPhone() == null || "".trim().equals(admin.getPhone())
@ -210,63 +307,46 @@ public class AdminController {
return;
}
}
// 此处注释掉了密码加密代码,可能根据业务需求,修改管理员信息时不一定需要重新加密密码(具体看实际情况)
//admin.setPassword(MD5Util.MD5EncodeUtf8(admin.getPassword()));
// 调用adminService的方法根据传入的修改后的管理员信息更新数据库中的对应记录
adminService.updateAdmin(admin);
//更新成功进行提示信息回显
// 更新成功后,向客户端输出"true"表示更新成功
writer.write("true");
}
/**
*
* AdminadminService
*
* @param admin Admin
* @param response
* @throws Exception
*/
@RequestMapping("/put_power")
public void put_power(Admin admin,HttpServletResponse response) throws Exception {
public void put_power(Admin admin, HttpServletResponse response) throws Exception {
// 获取响应的输出流对象,用于向客户端输出授权操作的结果信息(成功或失败)
PrintWriter writer = response.getWriter();
// 如果传入的admin对象为空向客户端输出"false"表示授权失败,并结束方法执行
if (admin == null) {
writer.write("false");
return;
}
// 校验授权级别是否在合法范围内0到4之间不在则向客户端输出"false"表示授权失败,并结束方法执行
if (admin.getPower() < 0 || admin.getPower() > 4) {
writer.write("false");
return;
}
adminService.put_power(admin);
writer.write("true");
}
/**
*
* @param response
* @throws Exception
*/
@RequestMapping("/exportAdminInfo")
public void exportAdminInfo(HttpServletResponse response) throws Exception {
InputStream is = adminService.getInputStream();
response.setContentType("application/vnd.ms-excel");
response.setHeader("contentDisposition", "attachment;filename=adminsInfo.xls");
ServletOutputStream outputStream = response.getOutputStream();
IOUtils.copy(is,outputStream);
}
/**
*
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("/checkUid")
public void checkUid(HttpServletRequest request,HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
String uid = request.getParameter("uid");
Admin admin = adminService.checkUid(uid);
if (admin != null) {
writer.write("true");//uid已被注册
return;
}
// 调用adminService的方法进行授权相关的数据库操作具体操作由service层实现
adminService.put_power(admin);
// 授权成功后,向客户端输出"true"表示授权成功
writer.write("true");
}
}

@ -8,12 +8,12 @@ import cn.ppdxzz.service.DormService;
import cn.ppdxzz.service.StudentService;
import com.github.pagehelper.PageInfo;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -21,110 +21,153 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
/**
* Description:
*
* @Date: 2020/2/19 21:01
* @Author: PeiChen
*/
@RequestMapping("/dorm")
@Controller
public class DormController {
public class DormController
{
// 定义宿舍服务、学生服务和管理员服务的私有成员变量
private DormService dormService;
private StudentService studentService;
private AdminService adminService;
// 使用@Autowired注解自动注入DormService实例
@Autowired
public void setStudentService(StudentService studentService) {
public void setStudentService(StudentService studentService)
{
this.studentService = studentService;
}
// 使用@Autowired注解自动注入StudentService实例
@Autowired
public void setDormService(DormService dormService) {
public void setDormService(DormService dormService)
{
this.dormService = dormService;
}
// 使用@Autowired注解自动注入AdminService实例
@Autowired
public void setAdminService(AdminService adminService) {
public void setAdminService(AdminService adminService)
{
this.adminService = adminService;
}
/**
* 宿
* @param page
* @param size
* @param request
* @param response
* @return
* @throws Exception
* @param page
* @param size
* @param request HTTP
* @param response HTTP
* @return ModelAndView
* @throws Exception
*/
@RequestMapping("/findAll")
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1")int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size, HttpServletRequest request, HttpServletResponse response) throws Exception {
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1"
)int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size,
HttpServletRequest request, HttpServletResponse response) throws Exception
{
// 设置请求和响应的字符编码为UTF-8
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
// 初始化宿舍列表
List<Dorm> dorms = null;
// 获取搜索关键字
String keyword = request.getParameter("keyword");
if (keyword == null || "".trim().equals(keyword)) {
if (keyword == null || "".trim().equals(keyword))
{
// 根据分页参数查询所有宿舍信息
dorms = dormService.findAll(page,size);
}else {
}
else
{
// 根据关键字进行搜索
dorms = dormService.search(page,size,keyword);
}
// 创建PageInfo对象封装分页信息
PageInfo pageInfo = new PageInfo(dorms);
// 将分页信息添加到ModelAndView对象中
mv.addObject("pageInfo",pageInfo);
// 设置视图名称为"dorm-list"
mv.setViewName("dorm-list");
//返回ModelAndView对象
return mv;
}
/**
* 宿
* @return
* @throws Exception
* @return
* @throws Exception
*/
@RequestMapping("/toAdd")
public String addDorm() throws Exception {
public String addDorm() throws Exception
{
// 返回宿舍添加页面的视图名称
return "dorm-add";
}
/**
* 宿
* @param dorm
* @param response
* @throws Exception
* 宿
* @param dorm 宿宿
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/add")
public void add(Dorm dorm,HttpServletResponse response) throws Exception {
public void add(Dorm dorm,HttpServletResponse response) throws Exception
{
response.setCharacterEncoding("utf-8");
// 获取PrintWriter对象用于向客户端输出内容
PrintWriter writer = response.getWriter();
// 检查宿舍对象及其必要属性是否为空
if (dorm == null || dorm.getDorm_id() == null || dorm.getDorm_intro() == null || dorm.getDorm_rps() == null
|| dorm.getDorm_leader() == null || dorm.getTeacher() == null) {
|| dorm.getDorm_leader() == null || dorm.getTeacher() == null)
{
writer.write("false");
return;
}
// 根据宿舍ID查询是否存在相同ID的宿舍
Dorm isNull = dormService.findByDormId(dorm.getDorm_id());
if (isNull != null) {
if (isNull != null)
{
writer.write("false");
return;
}
// 调用服务层方法添加宿舍信息
dormService.add(dorm);
writer.write("true");
}
/**
* 宿宿,true
* @param request
* @param response
* @throws Exception
* 宿宿true
* @param request HTTP
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/isExist")
public void isExist(HttpServletRequest request,HttpServletResponse response) throws Exception {
public void isExist(HttpServletRequest request,HttpServletResponse response) throws Exception
{
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
// 获取请求中的宿舍ID参数
String dorm_id = request.getParameter("dorm_id");
Dorm isNull = dormService.findByDormId(dorm_id);
if (isNull != null) {
if (isNull != null)
{
// 如果存在相同ID的宿舍则返回"true"
writer.write("true");
return;
}
@ -132,20 +175,26 @@ public class DormController {
/**
* id宿宿
* @param request
* @return
* @throws Exception
* @param request HTTP
* @return ModelAndView宿
* @throws Exception
*/
@RequestMapping("/toUpdate")
public ModelAndView toUpdate(HttpServletRequest request) throws Exception {
public ModelAndView toUpdate(HttpServletRequest request) throws Exception
{
request.setCharacterEncoding("utf-8");
ModelAndView mv = new ModelAndView();
String id = request.getParameter("id");
if (id == null) {
if (id == null)
{
return mv;
}
Dorm dorm = dormService.findById(id);
// 将宿舍信息添加到ModelAndView对象中
mv.addObject("dorm",dorm);
// 设置视图名称为"dorm-edit"
mv.setViewName("dorm-edit");
return mv;
@ -153,59 +202,85 @@ public class DormController {
/**
* 宿
* @param dorm
* @param response
* @throws Exception
* @param dorm 宿宿
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/update")
public void update(Dorm dorm,HttpServletResponse response) throws Exception {
public void update(Dorm dorm,HttpServletResponse response) throws Exception
{
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
if (dorm == null ||dorm.getId() == null || dorm.getDorm_id() == null || dorm.getDorm_intro() == null || dorm.getDorm_rps() == null
|| dorm.getDorm_leader() == null || dorm.getTeacher() == null) {
if (dorm == null ||dorm.getId() == null || dorm.getDorm_id() == null
|| dorm.getDorm_intro() == null || dorm.getDorm_rps() == null
|| dorm.getDorm_leader() == null || dorm.getTeacher() == null)
{
writer.write("false");
return;
}
// 调用服务层方法更新宿舍信息
dormService.update(dorm);
writer.write("true");
}
/**
* 宿
* @param response
* @throws Exception
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/export")
public void export(HttpServletResponse response) throws Exception {
public void export(HttpServletResponse response) throws Exception
{
// 获取宿舍信息的输入流
InputStream is = dormService.getInputStream();
// 设置响应的内容类型为Excel文件格式
response.setContentType("application/vnd.ms-excel");
// 设置响应头,指定下载的文件名
response.setHeader("contentDisposition","attachment;filename=dormInfo.xls");
// 获取ServletOutputStream对象用于向客户端输出二进制数据
ServletOutputStream outputStream = response.getOutputStream();
// 将输入流的数据复制到输出流中,实现文件下载
IOUtils.copy(is,outputStream);
}
/**
*
* @param request
* @return
* @throws Exception
* @param request HTTP
* @return ModelAndView宿
* @throws Exception
*/
@RequestMapping("/look")
public ModelAndView look(HttpServletRequest request) throws Exception {
public ModelAndView look(HttpServletRequest request) throws Exception
{
ModelAndView mv = new ModelAndView();
Dorm dorm = null;
String id = request.getParameter("id");
String uid = request.getParameter("uid");
if (id == null && uid != null) {
// 根据不同的参数情况查询宿舍信息
if (id == null && uid != null)
{
// 根据学生ID查询学生信息再根据学生的宿舍ID查询宿舍信息
Student stu = studentService.findBySno(uid);
dorm = dormService.findByDormId(stu.getDorm_id());
}else if (id != null) {
}
else if (id != null)
{
dorm = dormService.findById(id);
}else {
}
else
{
return mv;
}
mv.addObject("dorm",dorm);
// 设置视图名称为"look-dorm"
mv.setViewName("look-dorm");
return mv;
@ -217,18 +292,33 @@ public class DormController {
* @return
* @throws Exception
*/
@RequestMapping("/byDorm_leader")
public ModelAndView find(HttpServletRequest request) throws Exception {
//根据宿舍ID或学生ID查询宿舍学生信息
public ModelAndView find(HttpServletRequest request) throws Exception
{
request.setCharacterEncoding("utf-8");
// 创建ModelAndView对象用于返回视图和数据
ModelAndView mv = new ModelAndView();
// 从请求中获取参数uid
String uid = request.getParameter("uid");
String dorm_id = request.getParameter("dorm_id");
if (dorm_id != null) {
if (dorm_id != null)
{
// 根据dorm_id查询学生信息
List<Student> studentsInfo = studentService.findByDormId(dorm_id, 1);
// 将学生信息添加到ModelAndView对象中
mv.addObject("studentsInfo",studentsInfo);
// 设置视图名称为"dormStudentsInfo"
mv.setViewName("dormStudentsInfo");
return mv;
}
// 根据uid查询学生信息
Student stu = studentService.findBySno(uid);
// Dorm dormInfo = dormService.findByDormId(stu.getDorm_id());
List<Student> studentsInfo = studentService.findByDormId(stu.getDorm_id(), 1);
@ -239,12 +329,20 @@ public class DormController {
return mv;
}
//根据教师ID查询该教师管理的宿舍信息
@RequestMapping("/byTeacher")
public ModelAndView find1(HttpServletRequest request) throws Exception {
public ModelAndView find1(HttpServletRequest request) throws Exception
{
ModelAndView mv = new ModelAndView();
String uid = request.getParameter("uid");
// 根据uid查询管理员信息
Admin admin = adminService.checkUid(uid);
// 根据管理员姓名查询宿舍信息
List<Dorm> dorms = dormService.findByTeacher(admin.getName());
// 将宿舍信息添加到ModelAndView对象中
mv.addObject("dorms",dorms);
mv.setViewName("dormsTeacherInfo");
return mv;
@ -252,33 +350,47 @@ public class DormController {
/**
* teacher
* @param page
* @param size
* @param request
* @return
* @throws Exception
*/
@RequestMapping("/findStudent")
public ModelAndView findStudents(@RequestParam(name = "page", required = true, defaultValue = "1")int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size,HttpServletRequest request) throws Exception {
//根据教师姓名和关键词分页查询学生集合
public ModelAndView findStudents(@RequestParam(name = "page", required = true, defaultValue = "1")int page,
@RequestParam(name = "size", required = true, defaultValue = "5") int size,
HttpServletRequest request) throws Exception
{
request.setCharacterEncoding("utf-8");
ModelAndView mv = new ModelAndView();
// 初始化学生列表
List<Student> students = null;
// 从请求中获取参数name教师姓名、keyword搜索关键词
String teacher = request.getParameter("name");
String keyword = request.getParameter("keyword");
// 打印关键词到控制台
System.out.println(keyword);
if (keyword == null || "".trim().equals(keyword) || keyword.length() == 0) {
if (keyword == null || "".trim().equals(keyword) || keyword.length() == 0)
{
// 根据教师姓名分页查询学生信息
students = studentService.findByTeacher(page,size,teacher);
}
if (keyword != null){
if (keyword != null)
{
students = studentService.searchStudent(page,size,teacher,keyword);
}
PageInfo pageInfo = new PageInfo(students);
mv.addObject("pageInfo",pageInfo);
// 设置视图名称为"studentsTeacher"
mv.setViewName("studentsTeacher");
return mv;
}
}

@ -9,39 +9,80 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Description:
* Description: Web
* 访访
*
* @Date: 2020/2/14 16:50
* @Author: PeiChen
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
*
*
* @param request HTTPURL
* @param response HTTP
* @param handler Controller使
* @return true访false
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取请求的URL
// 获取请求的URL(统一资源标识符),用于判断当前请求的是哪个页面或者资源路径。
String url = request.getRequestURI();
// URL:除了login.jsp是可以公开访问的其它的URL都进行拦截控制
if(url.toLowerCase().indexOf("login")>=0){
// 进行URL判断这里设定的规则是除了包含"login"不区分大小写的URL是可以公开访问的比如登录页面本身其它的URL都要进行拦截控制。
// 如果URL中包含"login"则允许请求继续执行返回true。
if (url.toLowerCase().indexOf("login") >= 0) {
return true;
}
// 获取当前请求对应的HttpSession对象HttpSession用于在服务器端存储用户相关的会话信息比如用户登录后的身份信息等。
HttpSession session = request.getSession();
// 获取Session中的用户登录信息
// 尝试从Session中获取用户登录信息这里假设用户登录成功后将登录的管理员信息Admin对象存入了名为"adminInfo"的Session属性中。
// 通过强制类型转换获取存储在Session中的Admin对象如果不存在则返回null。
Admin admin = (Admin) session.getAttribute("adminInfo");
// 判断Session中是否有用户数据如果有则返回true,继续向下执行
if(admin != null){
// 判断Session中是否获取到了用户数据即Admin对象是否为null如果不为null说明用户已经登录允许请求继续向下执行返回true。
if (admin!= null) {
return true;
}
// 地址栏不符合条件的直接重定向到登录页面
// 如果经过前面的判断地址栏对应的URL不符合可直接访问的条件既不是登录相关页面且用户又未登录
// 则使用响应对象的sendRedirect方法将请求重定向到登录页面这里的"/hellossm/to_login"是登录页面的相对路径,根据实际项目配置可能会不同)。
// 并且返回false表示中断当前请求不再继续执行后续的处理器逻辑。
response.sendRedirect("/hellossm/to_login");
return false;
}
/**
*
*
*
* @param request HTTP
* @param response HTTP
* @param handler
* @param modelAndView
* @throws Exception ModelAndView
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
/**
*
*
*
* @param request HTTP
* @param response HTTP
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
}

@ -22,15 +22,14 @@ import java.util.List;
/**
* Description:
*
* @Date: 2020/2/17 14:17
* @Author: PeiChen
*/
@Controller
@RequestMapping("/student")
public class StudentController {
private StudentService studentService;
@Autowired
public void setStudentService(StudentService studentService) {
this.studentService = studentService;
@ -38,6 +37,7 @@ public class StudentController {
/**
*
*
* @param page
* @param size
* @param request
@ -46,160 +46,171 @@ public class StudentController {
* @throws Exception
*/
@RequestMapping("/findAll")
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1") int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size, HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
ModelAndView mv = new ModelAndView();
List<Student> list = null;
String keyword = request.getParameter("keyword");
if (keyword == null || keyword.trim().equals("") || keyword.length() == 0) {
list = studentService.findAll(page, size);
}else {
list = studentService.search(page,size,keyword);
}
//PageInfo就是一个封装了分页数据的bean
PageInfo pageInfo = new PageInfo(list);
mv.addObject("pageInfo",pageInfo);
mv.setViewName("student-list");
public class StudentController {
return mv;
}
private StudentService studentService;
/**
*
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("/delete")
public void delete(HttpServletRequest request,HttpServletResponse response) throws Exception {
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
String sno = request.getParameter("sno");
if (sno == null || "".equals(sno) || sno.length() == 0) {
writer.write("false");
return;
@Autowired
public void setStudentService(StudentService studentService) {
this.studentService = studentService;
}
studentService.delete(sno);
writer.write("true");
}
/**
*
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("/isExist")
public void isSnoExist(HttpServletRequest request,HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
String sno = request.getParameter("sno");
Student isExist = studentService.findBySno(sno);
if (isExist == null) {
return;
/**
*
*
* @param page
* @param size
* @param request HTTP
* @param response HTTP
* @return ModelAndView
* @throws Exception
*/
@RequestMapping("/findAll")
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1") int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size, HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
ModelAndView mv = new ModelAndView();
List<Student> list = null;
String keyword = request.getParameter("keyword");
if (keyword == null || keyword.trim().equals("") || keyword.length() == 0) {
list = studentService.findAll(page, size);
} else {
list = studentService.search(page, size, keyword);
}
PageInfo pageInfo = new PageInfo(list);
mv.addObject("pageInfo", pageInfo);
mv.setViewName("student-list");
return mv;
}
//如果isExist不为空说明学号已被注册
writer.write("true");
}
/**
*
*
* @param request HTTP
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/delete")
public void delete(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
String sno = request.getParameter("sno");
if (sno == null || "".equals(sno) || sno.length() == 0) {
writer.write("false");
return;
}
studentService.delete(sno);
writer.write("true");
}
@RequestMapping("/addStudent")
public ModelAndView addStudent(HttpServletRequest request) throws Exception {
request.setCharacterEncoding("utf-8");
ModelAndView mv = new ModelAndView();
String dorm_id = request.getParameter("dorm_id");
if (dorm_id != null) {
mv.addObject("dorm_id",dorm_id);
mv.setViewName("dormStudent-add");
/**
*
*
* @param request HTTP
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/isExist")
public void isSnoExist(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
String sno = request.getParameter("sno");
Student isExist = studentService.findBySno(sno);
if (isExist == null) {
return;
}
writer.write("true");
}
@RequestMapping("/addStudent")
public ModelAndView addStudent(HttpServletRequest request) throws Exception {
request.setCharacterEncoding("utf-8");
ModelAndView mv = new ModelAndView();
String dorm_id = request.getParameter("dorm_id");
if (dorm_id != null) {
mv.addObject("dorm_id", dorm_id);
mv.setViewName("dormStudent-add");
return mv;
}
mv.setViewName("student-add");
return mv;
}
mv.setViewName("student-add");
return mv;
}
/**
*
* @param student
* @param response
* @throws Exception
*/
@RequestMapping("/add")
public void add(Student student,HttpServletResponse response) throws Exception {
PrintWriter writer = response.getWriter();
if (student == null || studentService.findBySno(student.getSno()) != null) {
writer.write("false");
return;
/**
*
*
* @param student
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/add")
public void add(Student student, HttpServletResponse response) throws Exception {
PrintWriter writer = response.getWriter();
if (student == null || studentService.findBySno(student.getSno()) != null) {
writer.write("false");
return;
}
Student s = studentService.findBySno(student.getSno());
if (s != null) {
writer.write("false");
return;
}
boolean isAdd = studentService.add(student);
if (isAdd) {
writer.write("true");
} else {
writer.write("false");
}
}
Student s = studentService.findBySno(student.getSno());
if (s != null) {
writer.write("false");
return;
@RequestMapping("/editStudent")
public ModelAndView editStudent(HttpServletRequest request) throws Exception {
ModelAndView mv = new ModelAndView();
request.setCharacterEncoding("utf-8");
String sno = request.getParameter("sno");
Student stu = studentService.findBySno(sno);
mv.addObject("stu", stu);
mv.setViewName("student-edit");
return mv;
}
boolean isAdd = studentService.add(student);
if (isAdd) {
/**
*
*
* @param student
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/update")
public void update(Student student, HttpServletResponse response) throws Exception {
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
if (student == null || student.getId() == null) {
return;
}
if (student.getName() == null || "".equals(student.getName()) || student.getName().length() == 0 || student.getSex() == null || student.getSex().length() == 0 || "".equals(student.getSex()) || student.getSno() == null || "".equals(student.getSno()) || student.getSno().length() == 0 || student.getPhone() == null || "".equals(student.getPhone()) || student.getPhone().length() == 0 || student.getStu_class() == null || "".equals(student.getStu_class()) || student.getStu_class().length() == 0 || student.getPlace() == null || "".equals(student.getPlace()) || student.getPlace().length() == 0 || student.getDorm_id() == null || "".equals(student.getDorm_id()) || student.getDorm_id().length() == 0 || student.getTeacher() == null || "".equals(student.getTeacher()) || student.getTeacher().length() == 0) {
return;
}
studentService.update(student);
writer.write("true");
}else {
writer.write("false");
}
}
@RequestMapping("/editStudent")
public ModelAndView editStudent(HttpServletRequest request) throws Exception {
ModelAndView mv = new ModelAndView();
request.setCharacterEncoding("utf-8");
String sno = request.getParameter("sno");
Student stu = studentService.findBySno(sno);
mv.addObject("stu",stu);
mv.setViewName("student-edit");
return mv;
}
/**
*
* @param student
* @param response
* @throws Exception
*/
@RequestMapping("/update")
public void update(Student student,HttpServletResponse response) throws Exception {
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
if (student == null || student.getId() == null) {
return;
}
if (student.getName() == null || "".equals(student.getName()) || student.getName().length() == 0
|| student.getSex() == null || student.getSex().length() == 0 || "".equals(student.getSex())
|| student.getSno() == null || "".equals(student.getSno()) || student.getSno().length() == 0
|| student.getPhone() == null || "".equals(student.getPhone()) || student.getPhone().length() == 0
|| student.getStu_class() == null || "".equals(student.getStu_class()) || student.getStu_class().length() == 0
|| student.getPlace() == null || "".equals(student.getPlace()) || student.getPlace().length() == 0
|| student.getDorm_id() == null || "".equals(student.getDorm_id()) || student.getDorm_id().length() == 0
|| student.getTeacher() == null || "".equals(student.getTeacher()) || student.getTeacher().length() == 0 ) {
return;
/**
* Excel
*
* @param response HTTP
* @throws Exception
*/
@RequestMapping("/export")
public void export(HttpServletResponse response) throws Exception {
InputStream is = studentService.getInputStream();
response.setContentType("application/vnd.ms-excel");
response.setHeader("contentDisposition", "attachment;filename=studentsInfo.xls");
ServletOutputStream outputStream = response.getOutputStream();
IOUtils.copy(is, outputStream);
}
studentService.update(student);
writer.write("true");
}
/**
* Excel
* @param response
* @throws Exception
*/
@RequestMapping("/export")
public void export(HttpServletResponse response) throws Exception {
InputStream is = studentService.getInputStream();
response.setContentType("application/vnd.ms-excel");
response.setHeader("contentDisposition", "attachment;filename=studentsInfo.xls");
ServletOutputStream outputStream = response.getOutputStream();
IOUtils.copy(is,outputStream);
}
}

@ -24,154 +24,216 @@ import java.util.List;
import java.util.UUID;
/**
* Description:
* Description: 访访访
*
* @Date: 2020/2/18 16:26
* @Author: PeiChen
*/
// 声明这是一个Spring框架中的控制器表明该类可以处理HTTP请求并返回相应的视图或数据
@Controller
// 映射访问路径为/visitor意味着所有以/visitor开头的请求都会被该控制器处理
@RequestMapping("/visitor")
public class VisitorController {
// 自动注入VisitorService服务类通过依赖注入的方式获取VisitorService的实例以便调用其中的业务逻辑方法
private VisitorService visitorService;
// 通过Autowired注解自动注入VisitorService这里是设置属性注入的方法Spring会自动找到VisitorService的实现类并注入进来
@Autowired
public void setVisitorService(VisitorService visitorService) {
this.visitorService = visitorService;
}
// 访问路径为/visitor/login的请求处理方法该方法返回注册页面的视图名称通常Spring会根据这个名称去查找对应的视图文件进行渲染展示
@RequestMapping("/login")
public String register() {
return "regist_visitor";
}
} // 返回regist_visitor视图此视图应该是用于展示访客注册相关页面内容的具体的页面解析和渲染由Spring的视图解析器根据配置来完成
/**
* 访C
* @param visitor
* @return
* @throws Exception
* 访访Visitor访
*
* @param visitor 访访访
* @return ModelAndView 便Spring
* @throws Exception
*/
@RequestMapping("/addLogin")
public ModelAndView addVisitor(Visitor visitor) throws Exception {
ModelAndView mv = new ModelAndView();
// 参数校验,如果访客信息不完整(访客对象为空或者关键属性如姓名、学号、电话、访问地点等为空),则返回错误信息页面
if (visitor == null || visitor.getName() == null || visitor.getSno() == null || visitor.getPhone() == null || visitor.getPlace() == null) {
mv.addObject("error_msg","来访登记失败,请重新登记!");
mv.addObject("error_msg", "来访登记失败,请重新登记!");
mv.setViewName("regist_visitor");
return mv;
}
// 生成访客ID使用UUID通用唯一识别码来生成一个唯一的标识符作为访客的ID如果原访客对象中的ID为空或者是空白字符串则进行生成操作
if (visitor.getId() == null || "".trim().equals(visitor.getId())) {
String uuid = UUID.randomUUID().toString().replace("-", "");
visitor.setId(uuid);
}
// 设置来访时间为当前系统时间通过SimpleDateFormat格式化当前的日期和时间格式为"yyyy-MM-dd HH:mm:ss"),并设置到访客对象的来访时间属性中
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
visitor.setBegin_date(date);//设置来访时间为提交来访登记时间
//先设置离开时间为空串,后续注销时再修改为注销时系统时间
// 先设置离开时间为空串,后续注销时再修改为注销时系统时间,初始化访客的离开时间为空字符串,表示访客尚未离开
if (visitor.getEnd_date() == null || "".trim().equals(visitor.getEnd_date())) {
visitor.setEnd_date("");
}
// 添加访客信息到数据库调用VisitorService中的add方法将完整的访客信息保存到数据库中
visitorService.add(visitor);
mv.addObject("id",visitor.getId());
mv.setViewName("visitor-success");
// 添加访客ID到模型用于页面显示将生成的访客ID添加到ModelAndView对象中以便在后续的视图中可以获取并展示给用户
mv.addObject("id", visitor.getId());
mv.setViewName("visitor-success"); // 设置成功页面视图,指定成功登记后要展示的视图名称,通常会显示登记成功的相关提示信息
return mv;
}
/**
* 访
* @param request
* @return
* @throws Exception
* 访HttpServletRequest访ID
*
* @param request HttpServletRequest访ID
* @return ModelAndView
* @throws Exception
*/
@RequestMapping("/login_out")
public ModelAndView logout(HttpServletRequest request) throws Exception {
ModelAndView mv = new ModelAndView();
// 获取访客ID从HttpServletRequest对象中获取名为"id"的参数值,该参数值代表要注销的访客的唯一标识
String id = request.getParameter("id");
// 如果ID为空则返回错误信息页面提示系统繁忙让用户稍后再试
if (id == null || "".trim().equals(id)) {
mv.addObject("logout_msg","系统繁忙,请稍后再试!");
mv.addObject("logout_msg", "系统繁忙,请稍后再试!");
mv.setViewName("regist_visitor");
}
// 获取当前系统时间通过SimpleDateFormat格式化当前的日期和时间格式为"yyyy-MM-dd HH:mm:ss"),用于更新访客记录的注销时间
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
visitorService.logout(id,date);
mv.addObject("logout_msg","注销成功");
// 注销访客记录调用VisitorService中的logout方法传入访客ID和当前时间完成在数据库中对访客记录的注销操作可能是更新离开时间等相关操作
visitorService.logout(id, date);
mv.addObject("logout_msg", "注销成功");
mv.setViewName("regist_visitor");
return mv;
}
/**
* 访
* @param request
* @param response
* @throws Exception
* 访HttpServletRequestHttpServletResponse访IDtruefalse
*
* @param request HttpServletRequest访ID
* @param response HttpServletResponse
* @throws Exception
*/
@RequestMapping("/updateStatus")
public void updateStatus(HttpServletRequest request,HttpServletResponse response) throws Exception {
public void updateStatus(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
// 设置请求的字符编码为UTF-8确保能正确接收和处理包含中文等特殊字符的请求参数
response.setCharacterEncoding("utf-8");
// 设置响应的字符编码为UTF-8保证返回给客户端的数据能正确显示避免出现乱码问题
PrintWriter writer = response.getWriter();
// 获取响应的输出流的PrintWriter对象用于向客户端发送文本数据这里用于写入操作结果
// 获取访客ID从HttpServletRequest对象中获取名为"id"的参数值,该参数值是要注销的访客记录的标识
String id = request.getParameter("id");
// 如果ID为空则返回错误信息向客户端写入"false"表示注销操作失败
if (id == null || "".trim().equals(id)) {
writer.write("false");
return;
}
// 获取当前系统时间通过SimpleDateFormat格式化当前的日期和时间格式为"yyyy-MM-dd HH:mm:ss"),用于更新访客记录的注销时间
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
visitorService.logout(id,date);
// 注销访客记录调用VisitorService中的logout方法传入访客ID和当前时间在数据库中执行注销操作比如更新离开时间等相关字段
visitorService.logout(id, date);
writer.write("true");
// 向客户端写入"true"表示注销操作成功,客户端可以根据接收到的这个结果进行相应的提示或后续处理
}
/**
* 访
* @param page
* @param size
* @param request
* @param response
* @return
* @throws Exception
* 访HttpServletRequestHttpServletResponse
*
* @param page 1使
* @param size 访5使
* @param request HttpServletRequest
* @param response HttpServletResponse
* @return ModelAndView 访便Spring
* @throws Exception
*/
@RequestMapping("/findAll")
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1") int page, @RequestParam(name = "size", required = true, defaultValue = "5") int size,HttpServletRequest request,HttpServletResponse response) throws Exception {
public ModelAndView findAll(@RequestParam(name = "page", required = true, defaultValue = "1") int page,
@RequestParam(name = "page", required = true, defaultValue = "5") int size,
HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置请求的字符编码为UTF-8确保能正确处理包含中文等特殊字符的请求参数
request.setCharacterEncoding("utf-8");
// 设置响应的字符编码为UTF-8保证返回给客户端的数据能正确显示避免出现乱码情况
response.setCharacterEncoding("utf-8");
// 创建ModelAndView对象用于返回视图和数据该对象可以携带数据并指定要展示的视图名称方便Spring进行后续的视图渲染操作
ModelAndView mv = new ModelAndView();
List<Visitor> visitors = null;
// 获取请求中的keyword参数该参数用于根据关键词进行访客记录的搜索如果没有该参数则查询所有记录
String keyword = request.getParameter("keyword");
// 如果keyword为空或为空字符串或者长度为0进一步确保为空的情况则查询所有访客记录调用VisitorService的findAll方法获取所有访客信息分页查询
if (keyword == null || "".trim().equals(keyword) || keyword.length() == 0) {
visitors = visitorService.findAll(page,size);
}else {
visitors = visitorService.search(page,size,keyword);
visitors = visitorService.findAll(page, size);
} else {
// 否则根据keyword进行搜索调用VisitorService的search方法传入当前页码、每页显示数量以及关键词进行带关键词的分页搜索操作
visitors = visitorService.search(page, size, keyword);
}
// 创建分页信息对象通过PageInfo对查询到的访客列表进行分页相关信息的封装如总页数、总记录数等信息都会被自动计算并封装在该对象中
PageInfo pageInfo = new PageInfo(visitors);
mv.addObject("pageInfo",pageInfo);
// 将分页信息添加到ModelAndView对象中这样在视图中就可以获取并展示分页相关的信息如页码导航、总记录数等内容
mv.addObject("pageInfo", pageInfo);
// 设置视图名称为"visitor-list"指定要返回的视图名称Spring会根据配置找到对应的视图文件进行渲染展示该视图可能用于展示访客记录列表信息
mv.setViewName("visitor-list");
// 返回ModelAndView对象将携带数据的视图模型返回给Spring框架由框架进行后续的视图渲染和响应返回操作
return mv;
}
/**
* 访`
* @return
* @throws Exception
* 访
* 访访
*
* @return ModelAndView 访
* @throws Exception
*/
@RequestMapping("/log")
public ModelAndView log(@RequestParam(name = "page", required = true, defaultValue = "1") int page, @RequestParam(name = "size", required = true, defaultValue = "10") int size) throws Exception {
public ModelAndView log(@RequestParam(name = "page", required = true, defaultValue = "1") int page,
@RequestParam(name = "size", required = true, defaultValue = "10") int size) throws Exception {
// 创建ModelAndView对象用于返回视图和数据该对象可以携带数据并指定要展示的视图名称方便Spring进行后续的视图渲染操作
ModelAndView mv = new ModelAndView();
List<Visitor> logs = visitorService.log(page,size);
// 获取访客日志列表调用VisitorService的log方法传入当前页码和每页显示数量获取相应分页的访客日志信息
List<Visitor> logs = visitorService.log(page, size);
// 创建分页信息对象通过PageInfo对获取到的访客日志列表进行分页相关信息的封装方便在视图中展示分页相关的内容
PageInfo pageInfo = new PageInfo(logs);
mv.addObject("pageInfo",pageInfo);
// 将分页信息添加到ModelAndView对象中使得视图可以获取并展示如总页数、当前页码等分页相关信息
mv.addObject("pageInfo", pageInfo);
// 设置视图名称为"visitor-log"指定要返回的视图名称Spring会根据配置找到对应的视图文件进行渲染展示该视图用于展示访客日志相关信息
mv.setViewName("visitor-log");
// 返回ModelAndView对象将携带访客日志数据和分页信息的视图模型返回给Spring框架由框架进行后续的视图渲染和响应返回操作
return mv;
}
/**
* 访
* @param response
* @throws Exception
* 访ExcelHttpServletResponseExcel
*
* @param response HttpServletResponseExcel
* @throws Exception
*/
@RequestMapping("/visitorInfo")
public void export(HttpServletResponse response) throws Exception {
// 获取Excel文件的输入流调用VisitorService的getInputStream方法获取访客信息对应的Excel文件的输入流以便后续将文件内容发送给客户端
InputStream is = visitorService.getInputStream();
// 设置响应的内容类型为Excel文件指定响应的内容类型为"application/vnd.ms-excel"告诉客户端返回的数据是Excel格式的文件以便客户端进行正确的处理如下载或打开操作
response.setContentType("application/vnd.ms-excel");
response.setHeader("contentDisposition","attachment;filename=visitorInfo.xls");
// 设置响应头指示浏览器以附件形式下载文件并设置文件名为visitorInfo.xls通过设置"contentDisposition"头信息,让浏览器以附件形式下载文件,并指定文件名,方便用户保存文件
response.setHeader("contentDisposition", "attachment;filename=visitorInfo.xls");
// 获取响应的输出流用于将Excel文件的内容写入到响应中发送给客户端
ServletOutputStream outputStream = response.getOutputStream();
IOUtils.copy(is,outputStream);
// 使用IOUtils工具类将输入流的内容复制到输出流借助Apache Commons IO库提供的IOUtils工具类方便地将Excel文件的输入流内容复制到响应的输出流中实现文件的发送
IOUtils.copy(is, outputStream);
}
}
}

@ -8,6 +8,7 @@ import java.util.List;
/**
* Description:
* 访使MyBatisSQLadmins
*
* @Date: 2020/2/10 15:33
* @Author: PeiChen
@ -16,93 +17,142 @@ import java.util.List;
public interface AdminDao {
/**
*
* @param admin
* @return
* @throws Exception
*
* 使MyBatis@SelectSQL"admins"Admin
*
* @param admin AdminMyBatis#{username}#{password}SQL
* @return AdminnullMyBatis
* @throws Exception SQL
*/
@Select("select * from admins where username = #{username} and password = #{password}")
Admin findAdmin(Admin admin) throws Exception;
/**
* id
* 使@SelectSQL"admins"idAdmin
* #{id}idSQLid
*
* @param id
* @return Adminnull
* @throws Exception
*/
@Select("select * from admins where id = #{id}")
Admin findAdminById(Integer id) throws Exception;
/**
*
* 使@SelectSQL"admins"
* MyBatisPageHelper
*
* @return List<Admin>
* @throws Exception
*/
@Select("select * from admins")
List<Admin> findAll() throws Exception;
/**
*
* @return
* @throws Exception
* 使@SelectSQL"admins"便Excel
*
* @return List<Admin>
* @throws Exception 访
*/
@Select("select * from admins")
List<Admin> exportAdminInfo() throws Exception;
/**
* id
* @param id
* @throws Exception
* 使@DeleteSQLid"admins"
* #{id}idSQL
*
* @param id
* @throws Exception
*/
@Delete("delete from admins where id = #{id}")
void deleteAdminById(Integer id) throws Exception;
/**
*
* @param admin
* @throws Exception
* @UpdateSQLAdmin"admins"id
* 使#{}AdminSQL
*
* @param admin Admin
* @throws Exception
*/
@Update("update admins set username= #{username},name = #{name},uid = #{uid}, phone = #{phone}, description = #{description} where id = #{id}")
void updateAdmin(Admin admin) throws Exception;
/**
*
* @param admin
* @throws Exception
* @InsertSQLAdmin"admins"
* #{}AdminSQL
*
* @param admin Admin
* @throws Exception
*/
@Insert("insert into admins(username,password,name,uid,phone,power,description) values (#{username},#{password},#{name},#{uid},#{phone},#{power},#{description})")
void addAdmin(Admin admin) throws Exception;
/**
*
* 使@SelectSQL"admins"使
* truefalseMyBatis
*
* @param u_name
* @return truefalse
* @throws Exception
*/
@Select("select * from admins where username = #{u_name}")
Boolean checkUserName(String u_name) throws Exception;
/**
* /
* @param uid
* @return
* @throws Exception
* @SelectSQL"admins"/uid/使
* Adminnull/null
*
* @param uid /
* @return /Adminnull
* @throws Exception 访
*/
@Select("select * from admins where uid = #{uid}")
Admin checkUid(String uid) throws Exception;
/**
*
* @param password
* @param id
* @throws Exception
* 使@UpdateSQLid"admins"
* #{password}#{id}SQL
*
* @param password
* @param id
* @throws Exception
*/
@Update("update admins set password = #{password} where id = #{id}")
void updatePassword(String password,Integer id) throws Exception;
void updatePassword(String password, Integer id) throws Exception;
//select * from admins where username like '%p%' or name like '%万%' or power like '%1%' or description like '%管理员%';
//模糊搜索管理员信息查询结果返回一个list集合
/**
*
* 使@SelectLIKESQL"admins"/keyword
* ${keyword}SQL#{keyword}${}#{}SQLList<Admin>
* 使${}SQL
*
* @param keyword
* @return List<Admin>
* @throws Exception
*/
@Select("select * from admins where username like '%${keyword}%' or name like '%${keyword}%' or uid like '%${keyword}%' or phone like '%${keyword}%' or power like '%${keyword}%' or description like '%${keyword}%' ")
List<Admin> serarchInfo(@Param(value="keyword") String keyword) throws Exception;
/**
*
* 0 1 2 3
* @param admin
* @throws Exception
* @UpdateSQLAdminidpower"admins"
* #{power}#{id}AdminSQL
*
* @param admin idpowerAdmin
* @throws Exception
*/
@Update("update admins set power = #{power} where id = #{id} ")
void put_power(Admin admin) throws Exception;
}
}

@ -3,49 +3,50 @@ package cn.ppdxzz.dao;
import cn.ppdxzz.domain.Dorm;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* Description:
*
* @Date: 2020/2/19 18:28
* @Author: PeiChen
*/
@Repository
public interface DormDao {
public interface DormDao //DormDao 的接口,用于操作宿舍信息
{
/**
* 宿
* @return
* @throws Exception
*/
@Select("select * from dorms")
List<Dorm> findAll() throws Exception;
@Select("select * from dorms")//使用 @Select 注解指定 SQL 查询语句
List<Dorm> findAll() throws Exception;//返回包含所有宿舍信息的一个列表
/**
* 宿
* 宿
* @param keyword
* @return
* @throws Exception
*/
@Select("select * from dorms where dorm_id like '%${keyword}%' or dorm_intro like '%${keyword}%' or dorm_rps like '%${keyword}%' or dorm_leader like '%${keyword}%' or teacher like '%${keyword}%' ")
List<Dorm> search(@Param(value = "keyword") String keyword) throws Exception;
@Select("select * from dorms where dorm_id like '%${keyword}%' or dorm_intro " +
"like '%${keyword}%' or dorm_rps like '%${keyword}%' or dorm_leader " +
"like '%${keyword}%' or teacher like '%${keyword}%' ")
//返回一个包含匹配条件的宿舍信息的列表
List<Dorm> search(@Param(value = "keyword") String keyword) throws Exception;//将方法参数 keyword 绑定到 SQL 语句中的占位符
/**
* 宿
* 宿
* @param dorm
* @throws Exception
*/
@Insert("insert into dorms(dorm_id,dorm_intro,dorm_rps,dorm_leader,teacher) values(#{dorm_id},#{dorm_intro},#{dorm_rps},#{dorm_leader},#{teacher})")
//注解指定 SQL 插入语句,占位符#{dorm_id}、#{dorm_intro}、#{dorm_rps}、#{dorm_leader} 和 #{teacher}表示 Dorm 对象的属性值
@Insert("insert into dorms(dorm_id,dorm_intro,dorm_rps,dorm_leader,teacher) " +
"values(#{dorm_id},#{dorm_intro},#{dorm_rps},#{dorm_leader},#{teacher})")
void add(Dorm dorm) throws Exception;
/**
* 宿
* 宿
* @param dorm
* @throws Exception
*/
@Update("update dorms set dorm_id = #{dorm_id},dorm_intro = #{dorm_intro},dorm_rps = #{dorm_rps},dorm_leader = #{dorm_leader},teacher = #{teacher} where id = #{id}")
//注解指定了SQL 更新语句,
@Update("update dorms set dorm_id = #{dorm_id},dorm_intro = #{dorm_intro}," +
"dorm_rps = #{dorm_rps},dorm_leader = #{dorm_leader},teacher = #{teacher} where id = #{id}")
void update(Dorm dorm) throws Exception;
/**
@ -53,16 +54,19 @@ public interface DormDao {
* @param id
* @throws Exception
*/
@Delete("delete from dorms where id = #{id}")
@Delete("delete from dorms where id = #{id}")//占位符#{id} 表示要删除的宿舍记录的ID。
void delete(String id) throws Exception;
//根据宿舍ID查询宿舍信息
@Select("select * from dorms where dorm_id = #{dorm_id}")
Dorm findByDormId(String dorm_id) throws Exception;
Dorm findByDormId(String dorm_id) throws Exception;//返回一个 Dorm 对象
//根据记录ID查询宿舍信息
@Select("select * from dorms where id = #{id}")
Dorm findById(String id) throws Exception;
Dorm findById(String id) throws Exception;//返回一个 Dorm 对象
//根据教师姓名查询宿舍信息
@Select("select * from dorms where teacher = #{teacher}")
List<Dorm> findByTeacher(String teacher) throws Exception;
List<Dorm> findByTeacher(String teacher) throws Exception;//返回一个包含匹配条件的宿舍信息的列表
}

@ -7,88 +7,88 @@ import org.springframework.stereotype.Repository;
import java.util.List;
/**
* Description:
*
* @Date: 2020/2/17 14:19
* @Author: PeiChen
* Description:
*/
@Repository
public interface StudentDao {
/**
*
* @return
* @throws Exception
* @return
* @throws Exception
*/
@Select("select * from students")
List<Student> findAll() throws Exception;
/**
* sno
* @return
* @throws Exception
* @param sno
* @return
* @throws Exception
*/
@Select("select * from students where sno = #{sno}")
Student findBySno(String sno) throws Exception;
/**
*
* @return
* @throws Exception
* @param keyword
* @return
* @throws Exception
*/
@Select("select * from students where name like '%${keyword}%' or sex like '%${keyword}%' or sno like '%${keyword}%' or stu_class like '%${keyword}%' or phone like '%${keyword}%' or place like '%${keyword}%' or dorm_id like '%${keyword}%' or teacher like '%${keyword}%' ")
List<Student> search(@Param(value = "keyword") String keyword) throws Exception;
/**
*
* @param student
* @throws Exception
* @param student
* @throws Exception
*/
@Insert("insert into students(name, sex, sno, stu_class, phone, place, dorm_id, teacher, status) values(#{name},#{sex},#{sno},#{stu_class},#{phone},#{place},#{dorm_id},#{teacher},#{status})")
void add(Student student) throws Exception;
/**
* id
* @param sno
* @throws Exception
*
* @param sno
* @throws Exception
*/
@Delete("delete from students where sno = #{sno}")
void delete(String sno) throws Exception;
/**
* id
* @param student
* @throws Exception
*
* @param student
* @throws Exception
*/
@Update("update students set name = #{name},sex = #{sex},sno = #{sno},stu_class = #{stu_class},phone = #{phone},place = #{place},dorm_id = #{dorm_id},teacher = #{teacher},status = #{status} where id = #{id}")
void update(Student student) throws Exception;
/**
* 宿status宿
* @param dorm_id
* @return
* @throws Exception
* 宿
* @param dorm_id 宿
* @param status
* @return
* @throws Exception
*/
@Select("select * from students where dorm_id = #{dorm_id} and status = #{status}")
List<Student> findByDormId(@Param(value = "dorm_id") String dorm_id,@Param(value = "status") Integer status) throws Exception;
/**
* teacher
* @param teacher
* @return
* @throws Exception
*
* @param teacher
* @return
* @throws Exception
*/
@Select("select * from students where teacher = #{teacher}")
List<Student> findByTeacher(String teacher) throws Exception;
/**
*
* @param teacher
* @param keyword
* @return
* @throws Exception
*
* @param teacher
* @param keyword
* @return
* @throws Exception
*/
@Select("select * from students where teacher = #{teacher} and sno = #{keyword} ")
List<Student> searchStudent(@Param(value = "teacher") String teacher,@Param(value = "keyword") String keyword) throws Exception;
}

@ -11,45 +11,62 @@ import java.util.List;
/**
* Description:访
* 访访MyBatisSQL
* 访visitors
*
* @Date: 2020/2/18 16:27
* @Author: PeiChen
*/
// 声明这是一个数据访问对象接口在Spring框架中使用 @Repository 注解标记该接口为数据访问层组件,便于进行依赖注入和管理
@Repository
public interface VisitorDao {
/**
* 访
* @param visitor
* @throws Exception
* 访访MyBatis @Insert SQL
* 访
*
* @param visitor 访访ID访访访
* SQLvisitors
* @throws Exception SQL
*/
@Insert("insert into visitors(id,name,sno,phone,place,begin_date,end_date,visit_result) values(#{id},#{name},#{sno},#{phone},#{place},#{begin_date},#{end_date},#{visit_result})")
void add(Visitor visitor) throws Exception;
/**
* 访
* @return
* @throws Exception
* 访访begin_date访
* MyBatis @Select SQL访
*
* @return 访Visitor访
* @throws Exception
*/
@Select("select * from visitors order by begin_date desc")
List<Visitor> findAll() throws Exception;
/**
* 访访
* @param id
* @param end_date
* @throws Exception
* 访访MyBatis @Update SQL
* 访IDend_date
*
* @param id 访访visitorsid
* @param end_date 访访end_date
* @throws Exception
*/
@Update("update visitors set end_date = #{end_date} where id = #{id}")
void logout(@Param(value = "id") String id,@Param(value = "end_date") String end_date) throws Exception;
void logout(@Param(value = "id") String id, @Param(value = "end_date") String end_date) throws Exception;
/**
* 访
* @param keyword
* @return
* @throws Exception
* 访访
* 访begin_date
* MyBatis @Select SQL访
*
* @param keyword 访
* @return 访Visitor访
* @throws Exception
*/
@Select("select * from visitors where name like '%${keyword}%' or sno like '%${keyword}%' or phone like '%${keyword}%' or place like '%${keyword}%' or begin_date like '%${keyword}%' or end_date like '%${keyword}%' or visit_result like '%${keyword}%' order by begin_date desc ")
List<Visitor> search(@Param(value = "keyword") String keyword) throws Exception;
}
}

@ -4,23 +4,54 @@ import java.io.Serializable;
/**
* Description:
* Java
* Serializable便使
*
* @Date: 2020/2/10 15:13
* @Author: PeiChen
*/
public class Admin implements Serializable {
private Integer id; //id 主键自增
private String username; //用户名
private String password; //密码
private String name; //姓名
private String uid; //学/工号
private String phone; //手机号
private int power; //是否开启权限
private String description; //描述
// 管理员的唯一标识,通常对应数据库表中的主键字段,设置为自增类型,用于唯一确定一条管理员记录。
private Integer id;
// 管理员的用户名,用于登录系统等操作,存储用户名相关的字符串信息。
private String username;
// 管理员的密码,用于验证登录身份,存储密码相关的字符串信息,在实际应用中应进行加密存储等安全处理。
private String password;
// 管理员的真实姓名,用于展示和区分不同的管理员个体,存储姓名相关的字符串信息。
private String name;
// 学/工号,用于唯一标识管理员在学校或单位内的身份编号,存储相应的字符串信息。
private String uid;
// 管理员的手机号码,可用于联系管理员等相关用途,存储手机号码的字符串信息。
private String phone;
// 表示管理员是否开启权限的标识,整型变量,具体含义根据业务逻辑确定(例如不同数值对应不同权限级别等)。
private int power;
// 对管理员的相关描述信息,比如岗位描述、职责范围等,存储对应的字符串信息。
private String description;
// 默认的无参构造函数,在一些框架进行对象实例化等操作时可能会用到,例如通过反射机制创建对象时需要默认构造函数。
public Admin() {
}
/**
* Admin便
*
* @param id
* @param username
* @param password
* @param name
* @param uid /
* @param phone
* @param power
* @param description
*/
public Admin(Integer id, String username, String password, String name, String uid, String phone, int power, String description) {
this.id = id;
this.username = username;
@ -32,70 +63,92 @@ public class Admin implements Serializable {
this.description = description;
}
// 获取管理员的唯一标识id的方法供外部类访问该对象的id属性值。
public Integer getId() {
return id;
}
// 设置管理员的唯一标识id的方法供外部类修改该对象的id属性值。
public void setId(Integer id) {
this.id = id;
}
// 获取管理员用户名的方法供外部类访问该对象的username属性值。
public String getUsername() {
return username;
}
// 设置管理员用户名的方法供外部类修改该对象的username属性值。
public void setUsername(String username) {
this.username = username;
}
// 获取管理员密码的方法供外部类访问该对象的password属性值。
public String getPassword() {
return password;
}
// 设置管理员密码的方法供外部类修改该对象的password属性值。
public void setPassword(String password) {
this.password = password;
}
// 获取管理员真实姓名的方法供外部类访问该对象的name属性值。
public String getName() {
return name;
}
// 设置管理员真实姓名的方法供外部类修改该对象的name属性值。
public void setName(String name) {
this.name = name;
}
// 获取管理员学/工号的方法供外部类访问该对象的uid属性值。
public String getUid() {
return uid;
}
// 设置管理员学/工号的方法供外部类修改该对象的uid属性值。
public void setUid(String uid) {
this.uid = uid;
}
// 获取管理员手机号码的方法供外部类访问该对象的phone属性值。
public String getPhone() {
return phone;
}
// 设置管理员手机号码的方法供外部类修改该对象的phone属性值。
public void setPhone(String phone) {
this.phone = phone;
}
// 获取管理员权限标识的方法供外部类访问该对象的power属性值。
public int getPower() {
return power;
}
// 设置管理员权限标识的方法供外部类修改该对象的power属性值。
public void setPower(int power) {
this.power = power;
}
// 获取管理员描述信息的方法供外部类访问该对象的description属性值。
public String getDescription() {
return description;
}
// 设置管理员描述信息的方法供外部类修改该对象的description属性值。
public void setDescription(String description) {
this.description = description;
}
/**
* toString便Admin便
* "Admin{" + = + '}'
*
* @return Admin
*/
@Override
public String toString() {
return "Admin{" +
@ -109,4 +162,4 @@ public class Admin implements Serializable {
", description='" + description + '\'' +
'}';
}
}
}

@ -2,13 +2,8 @@ package cn.ppdxzz.domain;
import java.io.Serializable;
/**
* Description:宿
*
* @Date: 2020/2/19 17:51
* @Author: PeiChen
*/
public class Dorm implements Serializable {
public class Dorm implements Serializable //该类的实例可以被序列化,可以将其转换为字节流以便存储、传输
{
private Integer id;//ID
private String dorm_id;//宿舍号
private String dorm_intro;//宿舍简介
@ -16,68 +11,88 @@ public class Dorm implements Serializable {
private String dorm_leader;//宿舍长
private String teacher;//管辖育人导师
public Dorm() {
//构造方法
public Dorm()
{
}
public Dorm(Integer id, String dorm_id, String dorm_intro, String dorm_rps, String dorm_leader, String teacher) {
public Dorm(Integer id, String dorm_id, String dorm_intro, String dorm_rps,
String dorm_leader, String teacher) {
this.id = id;
this.dorm_id = dorm_id;
this.dorm_intro = dorm_intro;
this.dorm_rps = dorm_rps;
this.dorm_leader = dorm_leader;
this.teacher = teacher;
}
public Integer getId() {
//Getter 和 Setter 方法
public Integer getId()
{
return id;
}
public void setId(Integer id) {
public void setId(Integer id)
{
this.id = id;
}
public String getDorm_id() {
public String getDorm_id()
{
return dorm_id;
}
public void setDorm_id(String dorm_id) {
public void setDorm_id(String dorm_id)
{
this.dorm_id = dorm_id;
}
public String getDorm_intro() {
public String getDorm_intro()
{
return dorm_intro;
}
public void setDorm_intro(String dorm_intro) {
public void setDorm_intro(String dorm_intro)
{
this.dorm_intro = dorm_intro;
}
public String getDorm_rps() {
public String getDorm_rps()
{
return dorm_rps;
}
public void setDorm_rps(String dorm_rps) {
public void setDorm_rps(String dorm_rps)
{
this.dorm_rps = dorm_rps;
}
public String getDorm_leader() {
public String getDorm_leader()
{
return dorm_leader;
}
public void setDorm_leader(String dorm_leader) {
public void setDorm_leader(String dorm_leader)
{
this.dorm_leader = dorm_leader;
}
public String getTeacher() {
public String getTeacher()
{
return teacher;
}
public void setTeacher(String teacher) {
public void setTeacher(String teacher)
{
this.teacher = teacher;
}
//重写toString() 方法,返回一个描述 Dorm 对象的字符串
@Override
public String toString() {
public String toString()
{
return "Dorm{" +
"id=" + id +
", dorm_id='" + dorm_id + '\'' +

@ -3,26 +3,26 @@ package cn.ppdxzz.domain;
import java.io.Serializable;
/**
* Description:
*
* @Date: 2020/2/17 14:08
* @Author: PeiChen
* Student
* Serializable
*/
public class Student implements Serializable {
private Integer id;
private String name;//姓名
private String sex;//性别
private String sno;//学号
private String stu_class;//班级
private String phone;//联系方式
private String place;//家庭住址
private String dorm_id;//宿舍号
private String teacher;//育人导师
private Integer status;//学生状态是否激活1 激活 0 禁用
private Integer id; // 学生的唯一标识符
private String name; // 学生的姓名
private String sex; // 学生的性别
private String sno; // 学生的学号
private String stu_class; // 学生所在的班级
private String phone; // 学生的联系电话
private String place; // 学生的家庭住址
private String dorm_id; // 学生宿舍的编号
private String teacher; // 负责学生育人导师的名字
private Integer status; // 学生的状态1表示激活0表示禁用
// 无参构造函数
public Student() {
}
// 全参构造函数,用于创建具有所有属性的学生对象
public Student(Integer id, String name, String sex, String sno, String stu_class, String phone, String place, String dorm_id, String teacher, Integer status) {
this.id = id;
this.name = name;
@ -36,6 +36,7 @@ public class Student implements Serializable {
this.status = status;
}
// Getter和Setter方法用于访问和修改私有属性
public Integer getId() {
return id;
}
@ -116,6 +117,7 @@ public class Student implements Serializable {
this.status = status;
}
// toString方法用于返回对象的字符串表示形式便于调试和日志记录
@Override
public String toString() {
return "Student{" +

@ -4,23 +4,49 @@ import java.io.Serializable;
/**
* Description:访
*
* 访Serializable便
* @Date: 2020/2/18 16:29
* @Author: PeiChen
*/
public class Visitor implements Serializable {
private String id;//uuid 全球唯一id
private String name;//访客姓名
private String sno;//访客学号
private String phone;//联系方式
private String place;//访问地址
private String begin_date;//来访时间
private String end_date;//离开时间
private String visit_result;//到访原因
// uuid 全球唯一id用于唯一标识每个访客记录在数据库操作等场景中可作为主键来区分不同访客
private String id;
// 访客姓名,用于记录访客的具体称呼,方便后续识别和查询访客相关信息
private String name;
// 访客学号,若访客是学生等有学号标识的群体,可通过该字段存储学号信息,便于按学号进行相关业务操作(如查询、统计等)
private String sno;
// 联系方式,存储访客的电话号码等联系信息,方便在需要时与访客进行沟通联系
private String phone;
// 访问地址,记录访客访问的具体地点,例如访问的具体校区、办公楼、房间号等信息
private String place;
// 来访时间,用于记录访客到达访问地点的具体时间,格式通常遵循一定的日期时间格式(如 yyyy-MM-dd HH:mm:ss
private String begin_date;
// 离开时间,记录访客离开访问地点的时间,初始可能为空字符串,在访客离开时更新为实际离开时间,同样一般遵循日期时间格式
private String end_date;
// 到访原因,用于描述访客前来访问的事由,例如参加会议、拜访某人等具体原因说明
private String visit_result;
/**
*
* Visitor
*
*/
public Visitor() {
}
/**
* 访
* 访便访
*
* @param id 访ID访IDid访
* @param name 访访name访
* @param sno 访访sno便
* @param phone 访访phone便
* @param place 访访访访place访
* @param begin_date 访访访begin_date访
* @param end_date 访访end_date
* @param visit_result 访访访访visit_result便访
*/
public Visitor(String id, String name, String sno, String phone, String place, String begin_date, String end_date, String visit_result) {
this.id = id;
this.name = name;
@ -32,70 +58,159 @@ public class Visitor implements Serializable {
this.visit_result = visit_result;
}
// 以下是属性的getter和setter方法用于获取和设置对象的各个属性值遵循JavaBean规范方便外部类对对象属性进行访问和修改操作。
/**
* 访ID
*
* @return 访ID访
*/
public String getId() {
return id;
}
/**
* 访ID
*
* @param id 访ID访id
*/
public void setId(String id) {
this.id = id;
}
/**
* 访
*
* @return 访访
*/
public String getName() {
return name;
}
/**
* 访
*
* @param name 访访name
*/
public void setName(String name) {
this.name = name;
}
/**
* 访
*
* @return 访访
*/
public String getSno() {
return sno;
}
/**
* 访
*
* @param sno 访访sno
*/
public void setSno(String sno) {
this.sno = sno;
}
/**
* 访
*
* @return 访访
*/
public String getPhone() {
return phone;
}
/**
* 访
*
* @param phone 访访phone
*/
public void setPhone(String phone) {
this.phone = phone;
}
/**
* 访访
*
* @return 访访访访
*/
public String getPlace() {
return place;
}
/**
* 访访
*
* @param place 访访访place访
*/
public void setPlace(String place) {
this.place = place;
}
/**
* 访访
*
* @return 访访访访
*/
public String getBegin_date() {
return begin_date;
}
/**
* 访访
*
* @param begin_date 访访访begin_date访
*/
public void setBegin_date(String begin_date) {
this.begin_date = begin_date;
}
/**
* 访
*
* @return 访访
*/
public String getEnd_date() {
return end_date;
}
/**
* 访
*
* @param end_date 访访end_date
*/
public void setEnd_date(String end_date) {
this.end_date = end_date;
}
/**
* 访访
*
* @return 访访访访
*/
public String getVisit_result() {
return visit_result;
}
/**
* 访访
*
* @param visit_result 访访访visit_result访
*/
public void setVisit_result(String visit_result) {
this.visit_result = visit_result;
}
/**
* toString访
* 使System.out.println访访
* 便访
*
* @return 访 "Visitor{" + + '}'访
*/
@Override
public String toString() {
return "Visitor{" +
@ -109,4 +224,4 @@ public class Visitor implements Serializable {
", visit_result='" + visit_result + '\'' +
'}';
}
}
}

@ -2,188 +2,237 @@ package cn.ppdxzz.poi;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* Description:Excel
* ExcelExcel便Web
*
* @Date: 2020/2/16 15:17
* @Author: PeiChen
*/
public class WriteExcel {
//导出表的列名
// 导出表的列名数组用于存储Excel表格每列的标题名称。
private String[] rowName;
//每行作为一个Object对象
private List<Object[]> dataList = new ArrayList<Object[]>();
//构造方法,传入要导出的数据:第一个参数传入一个列名数组第二个参数传入一个list集合Object对象数组
public WriteExcel(String[] rowName,List<Object[]> dataList){
// 每行作为一个Object对象这里使用List来存储多个Object数组每个Object数组代表Excel表格中的一行数据除去列名那一行
private List<Object[]> dataList = new ArrayList<Object[]>();
// 构造方法,传入要导出的数据
// 第一个参数传入一个列名数组用于设置Excel表格的列标题。
// 第二个参数传入一个list集合Object对象数组集合中的每个Object数组对应Excel表格中的一行具体数据。
public WriteExcel(String[] rowName, List<Object[]> dataList) {
this.dataList = dataList;
this.rowName = rowName;
}
/*
*
* */
public InputStream export() throws Exception{
HSSFWorkbook workbook = new HSSFWorkbook(); // 创建工作簿对象
HSSFSheet sheet = workbook.createSheet("sheet1"); // 创建工作表
/**
*
* Excel簿Excel便
*
* @return InputStreamExcel
* @throws Exception 簿IO
*/
public InputStream export() throws Exception {
// 创建工作簿对象这是整个Excel文件的基础容器后续的工作表、单元格等都将添加到这个工作簿中。
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建工作表,这里创建了一个名为"sheet1"的工作表,一个工作簿可以包含多个工作表,此处只创建了一个。
HSSFSheet sheet = workbook.createSheet("sheet1");
// 设置sheet表样式
HSSFCellStyle columnTopStyle = this.getColumnTopStyle(workbook);//获取列头样式对象
HSSFCellStyle style = this.getColumnStyle(workbook); //单元格样式对象
// 获取列头样式对象用于设置Excel表格中列标题那一行单元格的样式。
HSSFCellStyle columnTopStyle = this.getColumnTopStyle(workbook);
// 获取单元格样式对象用于设置Excel表格中除列标题外其他数据单元格的样式。
HSSFCellStyle style = this.getColumnStyle(workbook);
// 定义所需列数
// 定义所需列数通过传入的列名数组长度来确定Excel表格的列数。
int columnNum = rowName.length;
HSSFRow rowRowName = sheet.createRow(0); // 在索引2的位置创建行(最顶端的行开始的第二行)
// 在索引0的位置创建行Excel表格中最顶端的行用于设置列头信息。
HSSFRow rowRowName = sheet.createRow(0);
// 将列头设置到sheet的单元格中
for(int n=0;n<columnNum;n++){
HSSFCell cellRowName = rowRowName.createCell(n); //创建列头对应个数的单元格
cellRowName.setCellType(HSSFCell.CELL_TYPE_STRING); //设置列头单元格的数据类型
// 循环遍历每一列,创建对应的单元格并设置相关属性,包括数据类型、值以及样式等。
for (int n = 0; n < columnNum; n++) {
// 创建列头对应个数的单元格每个单元格对应Excel表格中的一列标题。
HSSFCell cellRowName = rowRowName.createCell(n);
// 设置列头单元格的数据类型为字符串类型,以便后续正确设置列头的文本内容。
cellRowName.setCellType(HSSFCell.CELL_TYPE_STRING);
// 创建一个富文本字符串对象,将列名数组中的对应列名作为文本内容传入,用于设置单元格的值。
HSSFRichTextString text = new HSSFRichTextString(rowName[n]);
cellRowName.setCellValue(text); //设置列头单元格的值
cellRowName.setCellStyle(columnTopStyle); //设置列头单元格样式
// 设置列头单元格的值,即将列名填充到对应的单元格中。
cellRowName.setCellValue(text);
// 设置列头单元格样式,应用之前获取的列头样式对象,使列头具有统一的样式外观。
cellRowName.setCellStyle(columnTopStyle);
}
//将查询出的数据设置到sheet对应的单元格中
for(int i=0;i<dataList.size();i++){
Object[] obj = dataList.get(i); //遍历每个对象
HSSFRow row = sheet.createRow(i+1); //创建所需的行数
for(int j=0; j<obj.length; j++){
HSSFCell cell = null; //设置单元格的数据类型
cell = row.createCell(j,HSSFCell.CELL_TYPE_STRING);
if(!"".equals(obj[j]) && obj[j] != null){
cell.setCellValue(obj[j].toString()); //设置单元格的值
// 将查询出的数据设置到sheet对应的单元格中
// 遍历数据列表将每一行数据填充到Excel表格对应的行和列的单元格中。
for (int i = 0; i < dataList.size(); i++) {
// 取出每一行数据即一个Object数组数组中的每个元素对应Excel表格该行中的一个单元格数据。
Object[] obj = dataList.get(i);
// 创建所需的行数索引从1开始因为0行已经用于列头了每循环一次创建一行对应数据列表中的一行数据。
HSSFRow row = sheet.createRow(i + 1);
// 循环遍历该行数据中的每个元素,将其填充到对应的单元格中。
for (int j = 0; j < obj.length; j++) {
HSSFCell cell = null;
// 设置单元格的数据类型为字符串类型,方便处理各种类型的数据转换为字符串后填充到单元格。
cell = row.createCell(j, HSSFCell.CELL_TYPE_STRING);
if (!"".equals(obj[j]) && obj[j]!= null) {
// 如果数据不为空且不为空字符串,则将其转换为字符串后设置为单元格的值。
cell.setCellValue(obj[j].toString());
}
cell.setCellStyle(style); //设置单元格样式
// 设置单元格样式,应用之前获取的普通单元格样式对象,使数据单元格具有统一的样式。
cell.setCellStyle(style);
}
}
//让列宽随着导出的列长自动适应
// 让列宽随着导出的列长自动适应
// 通过遍历每一列以及每一行中的单元格内容长度,来动态调整每列的宽度,使表格内容能更好地展示。
for (int colNum = 0; colNum < columnNum; colNum++) {
// 先获取当前列的初始宽度并将其转换为以字符为单位除以256方便后续比较和调整。
int columnWidth = sheet.getColumnWidth(colNum) / 256;
// 遍历工作表中的每一行从第0行开始到最后一行查找当前列中最长的单元格内容长度以此来确定该列合适的宽度。
for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
HSSFRow currentRow;
//如若当前行未被使用过,则新建一行
// 如若当前行未被使用过即为null,则新建一行,以便后续获取单元格进行操作。
if (sheet.getRow(rowNum) == null) {
currentRow = sheet.createRow(rowNum);
} else {
currentRow = sheet.getRow(rowNum);
}
if (currentRow.getCell(colNum) != null) {
if (currentRow.getCell(colNum)!= null) {
HSSFCell currentCell = currentRow.getCell(colNum);
if (currentCell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
// 如果当前单元格的数据类型是字符串类型,则获取其字符串内容的字节长度,以此来衡量其显示宽度。
int length = currentCell.getStringCellValue().getBytes().length;
if (columnWidth < length) {
// 如果当前列宽小于该单元格内容长度对应的宽度,则更新列宽为该单元格内容长度对应的宽度,确保能完整显示内容。
columnWidth = length;
}
}
}
}
if(colNum == 0){
sheet.setColumnWidth(colNum, (columnWidth-2) * 256);
}else{
sheet.setColumnWidth(colNum, (columnWidth+4) * 256);
// 根据列的索引位置,对列宽进行适当的调整(减去或加上一定的偏移量,使表格看起来更美观、合适),然后设置为最终的列宽。
if (colNum == 0) {
sheet.setColumnWidth(colNum, (columnWidth - 2) * 256);
} else {
sheet.setColumnWidth(colNum, (columnWidth + 4) * 256);
}
}
// 生成一个文件名,文件名包含当前时间戳信息(取其中一部分),后缀为".xls"表示生成的是Excel 2003格式的文件。
String fileName = "Excel-" + String.valueOf(System.currentTimeMillis()).substring(4, 13) + ".xls";
// 设置响应头中的文件信息,指定文件名以及表示这是一个附件(用于文件下载场景),告知浏览器以附件形式处理该文件并显示给定的文件名。
String headStr = "attachment; filename=\"" + fileName + "\"";
ByteArrayOutputStream os=new ByteArrayOutputStream();
// 创建一个字节数组输出流对象用于临时存储Excel工作簿写入的文件内容后续将其转换为字节数组再转换为输入流返回。
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
// 将工作簿的内容写入到字节数组输出流中即将Excel文件内容以字节形式存储到内存中的输出流里。
workbook.write(os);
} catch (IOException e) {
e.printStackTrace();
}
byte[] content=os.toByteArray();
InputStream is=new ByteArrayInputStream(content);
// 将字节数组输出流中的内容转换为字节数组,以便后续创建输入流。
byte[] content = os.toByteArray();
// 根据字节数组创建一个字节输入流对象该输入流指向的内容就是生成的Excel文件内容最终将其返回供外部使用如文件下载等操作
InputStream is = new ByteArrayInputStream(content);
return is;
}
/*
*
/**
*
* Excel
*
* @param workbook 簿簿
* @return HSSFCellStyle
*/
public HSSFCellStyle getColumnTopStyle(HSSFWorkbook workbook) {
// 设置字体
HSSFFont font = workbook.createFont();
//设置字体大小
font.setFontHeightInPoints((short)11);
//字体加粗
// 设置字体大小为11号以指定列头字体的显示大小。
font.setFontHeightInPoints((short) 11);
// 设置字体加粗,使列头文字更加突出、醒目。
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
//设置字体名字
// 设置字体名字为"Courier New",指定列头文字使用的字体类型。
font.setFontName("Courier New");
//设置样式;
// 设置样式
HSSFCellStyle style = workbook.createCellStyle();
//设置底边框;
// 设置底边框为细边框,定义了单元格底部边框的样式为细线类型。
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//设置底边框颜色;
// 设置底边框颜色为黑色,指定了单元格底部边框的颜色。
style.setBottomBorderColor(HSSFColor.BLACK.index);
//设置左边框;
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
//设置左边框颜色;
// 设置左边框为细边框,确定单元格左边框的样式。
style.setBorderLeft(HSSFColor.BLACK.index);
// 设置左边框颜色为黑色,设定单元格左边框的颜色。
style.setLeftBorderColor(HSSFColor.BLACK.index);
//设置右边框;
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
//设置右边框颜色;
// 设置右边框为细边框,定义单元格右边框的样式。
style.setBorderRight(HSSFColor.BLACK.index);
// 设置右边框颜色为黑色,指定单元格右边框的颜色。
style.setRightBorderColor(HSSFColor.BLACK.index);
//设置顶边框;
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
//设置顶边框颜色;
// 设置顶边框为细边框,确定单元格顶部边框的样式。
style.setBorderTop(HSSFColor.BLACK.index);
// 设置顶边框颜色为黑色,设定单元格顶部边框的颜色。
style.setTopBorderColor(HSSFColor.BLACK.index);
//在样式用应用设置的字体;
// 在样式中应用设置的字体,将之前创建的字体对象应用到该单元格样式中,使字体设置生效。
style.setFont(font);
//设置自动换行;
// 设置自动换行属性为false即单元格内容超过列宽时不自动换行显示根据实际需求可调整
style.setWrapText(false);
//设置水平对齐的样式为居中对齐;
// 设置水平对齐的样式为居中对齐,使列头内容在水平方向上居中显示,看起来更美观。
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//设置垂直对齐的样式为居中对齐;
// 设置垂直对齐的样式为居中对齐,让列头内容在垂直方向上也居中显示,整体排版更整齐。
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
return style;
}
/*
*
/**
*
* Excel
*
* @param workbook 簿簿
* @return HSSFCellStyle
*/
public HSSFCellStyle getColumnStyle(HSSFWorkbook workbook) {
// 设置字体
HSSFFont font = workbook.createFont();
//设置字体名字
// 设置字体名字为"Courier New",指定数据单元格文字使用的字体类型。
font.setFontName("Courier New");
//设置样式;
// 设置样式
HSSFCellStyle style = workbook.createCellStyle();
//设置底边框;
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//设置底边框颜色;
// 设置底边框为细边框,定义了单元格底部边框的样式为细线类型。
style.setBorderBottom(HSSFColor.BLACK.index);
// 设置底边框颜色为黑色,指定了单元格底部边框的颜色。
style.setBottomBorderColor(HSSFColor.BLACK.index);
//设置左边框;
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
//设置左边框颜色;
// 设置左边框为细边框,确定单元格左边框的样式。
style.setBorderLeft(HSSFColor.BLACK.index);
// 设置左边框颜色为黑色,设定单元格左边框的颜色。
style.setLeftBorderColor(HSSFColor.BLACK.index);
//设置右边框;
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
//设置右边框颜色;
// 设置右边框为细边框,定义单元格右边框的样式。
style.setBorderRight(HSSFColor.BLACK.index);
// 设置右边框颜色为黑色,指定单元格右边框的颜色。
style.setRightBorderColor(HSSFColor.BLACK.index);
//设置顶边框;
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
//设置顶边框颜色;
// 设置顶边框为细边框,确定单元格顶部边框的样式。
style.setBorderTop(HSSFColor.BLACK.index);
// 设置顶边框颜色为黑色,设定单元格顶部边框的颜色。
style.setTopBorderColor(HSSFColor.BLACK.index);
//在样式用应用设置的字体;
// 在样式中应用设置的字体,将之前创建的字体对象应用到该单元格样式中,使字体设置生效。
style.setFont(font);
//设置自动换行;
// 设置自动换行属性为false即单元格内容超过列宽时不自动换行显示根据实际需求可调整
style.setWrapText(false);
//设置水平对齐的样式为居中对齐;
// 设置水平对齐的样式为居中对齐,使数据内容在水平方向上居中显示,看起来更美观。
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//设置垂直对齐的样式为居中对齐;
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 设置垂直对齐的样式为居中对齐,让数据内容在垂直方向上也居中显示,整体排版更整齐。
style.setVerticalAlignment(HSSFColor.BLACK.index);
return style;
}
}
}

@ -1,43 +1,139 @@
package cn.ppdxzz.service;
import cn.ppdxzz.domain.Admin;
import java.io.InputStream;
import java.util.List;
/**
* Description:
* Description:
* AdminServiceImplControllerDao
* 使便
*
* @Date: 2020/2/10 15:27
* @Author: PeiChen
*/
public interface AdminService {
/**
*
* Admin
* Adminnull
*
* @param admin Admin
* @return Adminnull
* @throws Exception
*/
Admin findAdmin(Admin admin) throws Exception;
//通过id查询管理员信息
// 通过id查询管理员信息
/**
* id
* idAdminnull
*
* @param id
* @return Adminnull
* @throws Exception
*/
Admin findAdminById(Integer id) throws Exception;
List<Admin> findAll(int page,int size) throws Exception;
/**
*
* pagesize
*
*
* @param page 1
* @param size
* @return List<Admin>
* @throws Exception 使
*/
List<Admin> findAll(int page, int size) throws Exception;
/**
* id
* idid
*
* @param id
* @throws Exception
*/
void deleteAdminById(Integer id) throws Exception;
/**
*
* Admin
*
*
* @param admin Admin
* @throws Exception
*/
void updateAdmin(Admin admin) throws Exception;
/**
*
* Admin
*
*
* @param admin Admin
* @throws Exception
*/
void addAdmin(Admin admin) throws Exception;
/**
*
* 使
* truefalse
*
* @param u_name
* @return truefalse
* @throws Exception
*/
Boolean checkUserName(String u_name) throws Exception;
//模糊搜索管理员信息查询结果返回一个list集合
List<Admin> serarchInfo(int page,int size,String keyword) throws Exception;
//授权
// 模糊搜索管理员信息查询结果返回一个list集合
/**
*
* pagesizekeyword
* 便
*
* @param page 1
* @param size
* @param keyword
* @return List<Admin>
* @throws Exception 使
*/
List<Admin> serarchInfo(int page, int size, String keyword) throws Exception;
// 授权
/**
*
* Admin
*
*
* @param admin Admin
* @throws Exception
*/
void put_power(Admin admin) throws Exception;
//返回一个携带所有管理员信息数据的InputStream输入流
// 返回一个携带所有管理员信息数据的InputStream输入流
/**
*
* Excel
* InputStream
*
* @return InputStream
* @throws Exception
*/
InputStream getInputStream() throws Exception;
//校验学工号是否被注册
// 校验学工号是否被注册
/**
* /
* ///使
* Adminnullnull/
*
* @param uid /
* @return /Adminnull
* @throws Exception
*/
Admin checkUid(String uid) throws Exception;
}
}

@ -1,31 +1,33 @@
package cn.ppdxzz.service;
import cn.ppdxzz.domain.Dorm;
import java.io.InputStream;
import java.util.List;
/**
* Description:
*
* @Date: 2020/2/19 19:52
* @Author: PeiChen
*/
public interface DormService {
public interface DormService
{
List<Dorm> findAll(int page,int size) throws Exception;
//分页查询所有宿舍信息参数page 当前页码参数size (每页显示的记录数)
List<Dorm> findAll(int page,int size) throws Exception;//返回一个包含宿舍信息的列表List<Dorm>
List<Dorm> search(int page,int size,String keyword) throws Exception;
//根据关键字进行分页模糊查询宿舍信息参数keyword (查询的关键字)
List<Dorm> search(int page,int size,String keyword) throws Exception;//返回一个包含匹配关键字的宿舍信息的列表List<Dorm>
//添加新的宿舍信息参数dorm包含宿舍信息的对象
void add(Dorm dorm) throws Exception;
//更新已有的宿舍信息参数dorm包含更新后宿舍信息的对象
void update(Dorm dorm) throws Exception;
InputStream getInputStream() throws Exception;
//导出宿舍信息为Excel文件
InputStream getInputStream() throws Exception;//返回一个输入流InputStream用于读取生成的Excel文件
//根据宿舍号查找宿舍信息,参数 dorm_id (宿舍号)
Dorm findByDormId(String dorm_id) throws Exception;
//根据ID查找宿舍信息参数 id宿舍的唯一标识符
Dorm findById(String id) throws Exception;
List<Dorm> findByTeacher(String teacher) throws Exception;
//根据导师查找宿舍信息,参数 teacher导师的名字或标识
List<Dorm> findByTeacher(String teacher) throws Exception;//返回一个包含匹配导师的宿舍信息的列表List<Dorm>
}

@ -6,31 +6,92 @@ import java.io.InputStream;
import java.util.List;
/**
* Description:
*
* @Date: 2020/2/17 14:21
* @Author: PeiChen
* Description:
*/
public interface StudentService {
/**
*
* @param page
* @param size
* @return
* @throws Exception
*/
List<Student> findAll(int page, int size) throws Exception; // 定义分页查询所有学生信息的方法
List<Student> findAll(int page,int size) throws Exception;
/**
*
* @param sno
* @return
* @throws Exception
*/
Student findBySno(String sno) throws Exception; // 定义根据学号查询学生信息的方法
Student findBySno(String sno) throws Exception;
/**
*
* @param page
* @param size
* @param keyword
* @return
* @throws Exception
*/
List<Student> search(int page, int size, String keyword) throws Exception; // 定义分页搜索学生信息的方法
List<Student> search(int page, int size, String keyword) throws Exception;
/**
*
* @param student
* @return truefalse
* @throws Exception
*/
boolean add(Student student) throws Exception; // 定义添加新学生信息的方法
boolean add(Student student) throws Exception;
/**
*
* @param sno
* @throws Exception
*/
void delete(String sno) throws Exception; // 定义根据学号删除学生信息的方法
void delete(String sno) throws Exception;
/**
*
* @param student
* @throws Exception
*/
void update(Student student) throws Exception; // 定义更新学生信息的方法
void update(Student student) throws Exception;
/**
*
* @return InputStream
* @throws Exception
*/
InputStream getInputStream() throws Exception; // 定义获取所有学生信息输入流的方法
//返回一个携带所有学生信息数据的InputStream输入流
InputStream getInputStream() throws Exception;
/**
* 宿ID
* @param dorm_id 宿ID
* @param status
* @return
* @throws Exception
*/
List<Student> findByDormId(String dorm_id, Integer status) throws Exception; // 定义根据宿舍ID和状态查询学生信息的方法
List<Student> findByDormId(String dorm_id,Integer status) throws Exception;
/**
*
* @param page
* @param size
* @param teacher
* @return
* @throws Exception
*/
List<Student> findByTeacher(int page, int size, String teacher) throws Exception; // 定义根据教师姓名分页查询学生信息的方法
List<Student> findByTeacher(int page,int size,String teacher) throws Exception;
List<Student> searchStudent(int page,int size,String teacher,String keyword) throws Exception;
/**
*
* @param page
* @param size
* @param teacher
* @param keyword
* @return
* @throws Exception
*/
List<Student> searchStudent(int page, int size, String teacher, String keyword) throws Exception; // 定义根据教师姓名和搜索关键字分页查询学生信息的方法
}

@ -6,23 +6,103 @@ import java.io.InputStream;
import java.util.List;
/**
* Description:
* Description:访访
* 访
* 访
* 访
*
* @Date: 2020/2/18 18:27
* @Author: PeiChen
*/
public interface VisitorService {
/**
* 访
* 访访Visitor
*
*
* @param visitor 访访访访访访
* 访
* @throws Exception
* 便
*/
void add(Visitor visitor) throws Exception;
List<Visitor> findAll(int page,int size) throws Exception;
/**
* 访
* 访访
*
*
* @param page
* page1
* @param size 访size1010访
* 访
* @return 访Visitor访访
* 访访访
* @throws Exception
*
*/
List<Visitor> findAll(int page, int size) throws Exception;
List<Visitor> search(int page,int size,String keyword) throws Exception;
/**
*
* 访访
*
*
* @param page
*
* @param size 访
* 2020访
* @param keyword 访访
* 访"张三""张三"访
* @return 访Visitor访
* 访便访
* @throws Exception
*
*/
List<Visitor> search(int page, int size, String keyword) throws Exception;
void logout(String id,String end_date) throws Exception;
/**
* 访
* 访访
*
*
* @param id 访访访
* 使UUID访
* @param end_date 访 "yyyy-MM-dd HH:mm:ss"
* 访访访
* @throws Exception
*
*/
void logout(String id, String end_date) throws Exception;
/**
* 访
* 访访Excel
*
*
* @return 访访
* 访访
*
* @throws Exception 访
*
*/
InputStream getInputStream() throws Exception;
List<Visitor> log(int page,int size) throws Exception;
/**
* 访
* 访访
*
*
* @param page 访
* page2访
* @param size 访访
* size1515访
* @return 访Visitor访访访
* 访访访便访访
* @throws Exception
*
*/
List<Visitor> log(int page, int size) throws Exception;
}
}

@ -18,7 +18,8 @@ import java.util.ArrayList;
import java.util.List;
/**
* Description:
* Description: AdminService
* AdminDao
*
* @Date: 2020/2/10 15:30
* @Author: PeiChen
@ -26,7 +27,10 @@ import java.util.List;
@Service("adminService")
public class AdminServiceImpl implements AdminService {
// 依赖注入AdminDao接口用于调用持久层的数据库操作方法。
private AdminDao adminDao;
// 通过@Autowired注解让Spring框架自动注入AdminDao的实现类实例实现依赖注入。
@Autowired
public void setAdminDao(AdminDao adminDao) {
this.adminDao = adminDao;
@ -34,9 +38,11 @@ public class AdminServiceImpl implements AdminService {
/**
* findAdmin()
* @param admin
* @return
* @throws Exception
* Admin
*
* @param admin Admin
* @return Adminnull
* @throws Exception
*/
@Override
public Admin findAdmin(Admin admin) throws Exception {
@ -45,9 +51,11 @@ public class AdminServiceImpl implements AdminService {
/**
* id
* @param id
* @return Admin
* @throws Exception
* id
*
* @param id
* @return Adminnull
* @throws Exception
*/
@Override
public Admin findAdminById(Integer id) throws Exception {
@ -56,19 +64,26 @@ public class AdminServiceImpl implements AdminService {
/**
*
* @return
* @throws Exception
* PageHelper
*
* @param page
* @param size
* @return List<Admin>
* @throws Exception 使
*/
@Override
public List<Admin> findAll(int page,int size) throws Exception {
PageHelper.startPage(page,size);
public List<Admin> findAll(int page, int size) throws Exception {
// 启动PageHelper分页功能设置当前页码和每页显示的记录数后续调用持久层查询方法时会自动应用分页逻辑。
PageHelper.startPage(page, size);
return adminDao.findAll();
}
/**
* id
* @param id
* @throws Exception
* idid
*
* @param id
* @throws Exception
*/
@Override
public void deleteAdminById(Integer id) throws Exception {
@ -77,8 +92,10 @@ public class AdminServiceImpl implements AdminService {
/**
*
* @param admin
* @throws Exception
* Admin
*
* @param admin Admin
* @throws Exception
*/
@Override
public void updateAdmin(Admin admin) throws Exception {
@ -87,8 +104,11 @@ public class AdminServiceImpl implements AdminService {
/**
*
* @param admin
* @throws Exception
* 使Spring@Transactional
* Admin
*
* @param admin Admin
* @throws Exception
*/
@Transactional
@Override
@ -96,11 +116,20 @@ public class AdminServiceImpl implements AdminService {
adminDao.addAdmin(admin);
}
/**
*
* 使
* nulltruefalse
*
* @param u_name
* @return truefalse
* @throws Exception
*/
@Override
public Boolean checkUserName(String u_name) throws Exception {
//System.out.println(adminDao.checkUserName(u_name));
//用户名不存在则返回空直接false
if (adminDao.checkUserName(u_name) != null) {
// 用户名不存在则返回空直接false
if (adminDao.checkUserName(u_name)!= null) {
return true;
}
return false;
@ -108,21 +137,28 @@ public class AdminServiceImpl implements AdminService {
/**
*
* @param keyword
* @return
* @throws Exception
* PageHelper
*
* @param page
* @param size
* @param keyword
* @return List<Admin>
* @throws Exception 使
*/
@Override
public List<Admin> serarchInfo(int page,int size,String keyword) throws Exception {
PageHelper.startPage(page,size);
public List<Admin> serarchInfo(int page, int size, String keyword) throws Exception {
// 启动PageHelper分页功能设置当前页码和每页显示的记录数后续调用持久层模糊查询方法时会自动应用分页逻辑。
PageHelper.startPage(page, size);
List<Admin> list = adminDao.serarchInfo(keyword);
return list;
}
/**
*
* @param admin
* @throws Exception
* Admin
*
* @param admin Admin
* @throws Exception
*/
@Override
public void put_power(Admin admin) throws Exception {
@ -131,17 +167,23 @@ public class AdminServiceImpl implements AdminService {
/**
*
* @return
* @throws Exception
* Excel
* WriteExcelExcelWeb
*
* @return InputStreamExcel
* @throws Exception Excel
*/
@Override
public InputStream getInputStream() throws Exception {
//Excel中的每列列名依次对应数据库的字段
String[] title = new String[]{"ID","用户名","密码","姓名","学/工号","手机号","权限","描述"};
// Excel中的每列列名依次对应数据库的字段用于设置导出的Excel表格的列标题。
String[] title = new String[]{"ID", "用户名", "密码", "姓名", "学/工号", "手机号", "权限", "描述"};
// 调用持久层的方法获取数据库中所有管理员的信息得到一个List<Admin>集合集合中的每个Admin对象代表一条管理员记录。
List<Admin> admins = adminDao.exportAdminInfo();
List<Object[]> dataList = new ArrayList<Object[]>();
// 创建一个用于存储每行数据的列表每个元素是一个Object数组代表Excel表格中的一行数据除去列标题行初始化为空列表。
List<Object[]> dataList = new ArrayList<Object[]>();
// 遍历从数据库获取的管理员信息列表将每条管理员记录的各个字段值提取出来整理成Object数组形式添加到数据列表中以便后续生成Excel文件。
for (int i = 0; i < admins.size(); i++) {
Object[] obj = new Object[7];
Object[] obj = new Object[8];
obj[0] = admins.get(i).getId();
obj[1] = admins.get(i).getUsername();
obj[2] = admins.get(i).getPassword();
@ -152,20 +194,25 @@ public class AdminServiceImpl implements AdminService {
obj[7] = admins.get(i).getDescription();
dataList.add(obj);
}
// 创建WriteExcel类的实例传入列名数组和整理好的数据列表用于生成Excel文件。
WriteExcel ex = new WriteExcel(title, dataList);
InputStream in;
// 调用WriteExcel类的export方法生成包含管理员信息的Excel文件对应的输入流将其赋值给变量in。
in = ex.export();
return in;
}
/**
* /
* @param uid
* @return
* @throws Exception
* //使
* Adminnull/null
*
* @param uid /
* @return /Adminnull
* @throws Exception
*/
@Override
public Admin checkUid(String uid) throws Exception {
return adminDao.checkUid(uid);
}
}
}

@ -8,25 +8,22 @@ import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
*
* @Date: 2020/2/19 20:22
* @Author: PeiChen
*/
@Transactional
@Service("dormService")
public class DormServiceImpl implements DormService {
//基于Spring框架的Java服务类用于管理宿舍信息
@Transactional//该类中的所有方法都支持事务管理,这些方法在执行过程中如果出现异常,将进行回滚操作
@Service("dormService")//将这个类标记为一个Spring的服务组件并指定其名称为"dormService",可以通过依赖注入的方式在其他类中使用它
public class DormServiceImpl implements DormService
{
//用于访问数据层DAO
private DormDao dormDao;
@Autowired
public void setDormDao(DormDao dormDao) {
@Autowired//通过自动装配机制将DormDao类型的Bean注入到dormDao变量中
public void setDormDao(DormDao dormDao)
{
this.dormDao = dormDao;
}
@ -38,8 +35,11 @@ public class DormServiceImpl implements DormService {
* @throws Exception
*/
@Override
public List<Dorm> findAll(int page, int size) throws Exception {
public List<Dorm> findAll(int page, int size) throws Exception
{
//使用MyBatis的分页插件进行分页设置
PageHelper.startPage(page,size);
//调用DAO层的findAll方法获取数据
return dormDao.findAll();
}
@ -52,8 +52,11 @@ public class DormServiceImpl implements DormService {
* @throws Exception
*/
@Override
public List<Dorm> search(int page, int size, String keyword) throws Exception {
public List<Dorm> search(int page, int size, String keyword) throws Exception
{
//设置分页参数
PageHelper.startPage(page,size);
//调用DAO层的search方法进行模糊查询
return dormDao.search(keyword);
}
@ -63,7 +66,9 @@ public class DormServiceImpl implements DormService {
* @throws Exception
*/
@Override
public void add(Dorm dorm) throws Exception {
public void add(Dorm dorm) throws Exception
{
//调用DAO层的add方法保存数据
dormDao.add(dorm);
}
@ -73,7 +78,9 @@ public class DormServiceImpl implements DormService {
* @throws Exception
*/
@Override
public void update(Dorm dorm) throws Exception {
public void update(Dorm dorm) throws Exception
{
//调用DAO层的update方法更新数据
dormDao.update(dorm);
}
@ -83,12 +90,18 @@ public class DormServiceImpl implements DormService {
* @throws Exception
*/
@Override
public InputStream getInputStream() throws Exception {
public InputStream getInputStream() throws Exception
{
//Excel中的每列列名依次对应数据库的字段
String[] title = new String[]{"ID","宿舍号","宿舍简介","宿舍荣誉","宿舍长","育人导师"};
//获取所有宿舍信息
List<Dorm> dorms = dormDao.findAll();
// 创建一个列表存储数据
List<Object[]> datalist = new ArrayList<>();
for (int i = 0; i < dorms.size(); i++) {
//循环遍历宿舍信息将每个宿舍的信息存入datalist中
for (int i = 0; i < dorms.size(); i++)
{
Object[] obj = new Object[6];
obj[0] = dorms.get(i).getId();
obj[1] = dorms.get(i).getDorm_id();
@ -98,22 +111,27 @@ public class DormServiceImpl implements DormService {
obj[5] = dorms.get(i).getTeacher();
datalist.add(obj);
}
//创建Excel对象
WriteExcel excel = new WriteExcel(title,datalist);
//返回生成的Excel文件流
return excel.export();
}
@Override
public Dorm findByDormId(String dorm_id) throws Exception {
@Override//根据宿舍号查找宿舍信息
public Dorm findByDormId(String dorm_id) throws Exception
{
return dormDao.findByDormId(dorm_id);
}
@Override
public Dorm findById(String id) throws Exception {
@Override//根据ID查找宿舍信息
public Dorm findById(String id) throws Exception
{
return dormDao.findById(id);
}
@Override
public List<Dorm> findByTeacher(String teacher) throws Exception {
@Override//根据导师查找宿舍信息
public List<Dorm> findByTeacher(String teacher) throws Exception
{
return dormDao.findByTeacher(teacher);
}
}

@ -13,10 +13,7 @@ import java.util.ArrayList;
import java.util.List;
/**
* Description:
*
* @Date: 2020/2/17 14:22
* @Author: PeiChen
* StudentServiceImplStudentService
*/
@Service("studentService")
public class StudentServiceImpl implements StudentService {
@ -29,20 +26,23 @@ public class StudentServiceImpl implements StudentService {
}
/**
*
* @return
* @throws Exception
*
* @param page
* @param size
* @return
* @throws Exception
*/
@Override
public List<Student> findAll(int page,int size) throws Exception {
PageHelper.startPage(page,size);
public List<Student> findAll(int page, int size) throws Exception {
PageHelper.startPage(page, size);
return studentDao.findAll();
}
/**
* sno
* @return
* @throws Exception
*
* @param sno
* @return
* @throws Exception
*/
@Override
public Student findBySno(String sno) throws Exception {
@ -50,26 +50,30 @@ public class StudentServiceImpl implements StudentService {
}
/**
*
* @return
* @throws Exception
*
* @param page
* @param size
* @param keyword
* @return
* @throws Exception
*/
@Override
public List<Student> search(int page, int size, String keyword) throws Exception {
PageHelper.startPage(page,size);
PageHelper.startPage(page, size);
return studentDao.search(keyword);
}
/**
*
* @param student
* @throws Exception
*
* @param student
* @return
* @throws Exception
*/
@Override
public boolean add(Student student) throws Exception {
if (student == null || student.getName() == null || student.getSex() == null || student.getSno() == null
|| student.getPhone() == null || student.getPlace() == null || student.getDorm_id() == null
|| student.getTeacher() == null || student.getStu_class() == null || student.getStatus() == null) {
|| student.getTeacher() == null || student.getStu_class() == null || student.getStatus() == null) {
return false;
}
studentDao.add(student);
@ -77,9 +81,9 @@ public class StudentServiceImpl implements StudentService {
}
/**
*
* @param sno
* @throws Exception
*
* @param sno
* @throws Exception
*/
@Override
public void delete(String sno) throws Exception {
@ -87,9 +91,9 @@ public class StudentServiceImpl implements StudentService {
}
/**
*
* @param student
* @throws Exception
*
* @param student
* @throws Exception
*/
@Override
public void update(Student student) throws Exception {
@ -97,14 +101,14 @@ public class StudentServiceImpl implements StudentService {
}
/**
*
* @return
* @throws Exception
* Excel
* @return Excel
* @throws Exception
*/
@Override
public InputStream getInputStream() throws Exception {
//Excel中的每列列名依次对应数据库的字段
String[] title = new String[]{"姓名","性别","学号","班级","联系方式","家庭住址","宿舍号","育人导师","状态"};
// Excel中的每列列名依次对应数据库的字段
String[] title = new String[]{"姓名", "性别", "学号", "班级", "联系方式", "家庭住址", "宿舍号", "育人导师", "状态"};
List<Student> students = studentDao.findAll();
List<Object[]> datalist = new ArrayList<>();
for (int i = 0; i < students.size(); i++) {
@ -120,17 +124,16 @@ public class StudentServiceImpl implements StudentService {
obj[8] = students.get(i).getStatus();
datalist.add(obj);
}
WriteExcel excel = new WriteExcel(title,datalist);
WriteExcel excel = new WriteExcel(title, datalist);
return excel.export();
}
/**
* 宿status
* @param dorm_id
* @param status
* @return
* @throws Exception
* 宿status
* @param dorm_id 宿
* @param status
* @return
* @throws Exception
*/
@Override
public List<Student> findByDormId(String dorm_id, Integer status) throws Exception {
@ -138,20 +141,31 @@ public class StudentServiceImpl implements StudentService {
}
/**
* teacher
* @param teacher
* @return
* @throws Exception
* teacher
* @param page
* @param size
* @param teacher
* @return
* @throws Exception
*/
@Override
public List<Student> findByTeacher(int page,int size,String teacher) throws Exception {
PageHelper.startPage(page,size);
public List<Student> findByTeacher(int page, int size, String teacher) throws Exception {
PageHelper.startPage(page, size);
return studentDao.findByTeacher(teacher);
}
/**
*
* @param page
* @param size
* @param teacher
* @param keyword
* @return
* @throws Exception
*/
@Override
public List<Student> searchStudent(int page, int size, String teacher, String keyword) throws Exception {
PageHelper.startPage(page,size);
return studentDao.searchStudent(teacher,keyword);
PageHelper.startPage(page, size);
return studentDao.searchStudent(teacher, keyword);
}
}

@ -13,16 +13,26 @@ import java.util.ArrayList;
import java.util.List;
/**
* Description:
* Description:访VisitorService
* 访VisitorDao访
* PageHelperWriteExcelExcel
*
* @Date: 2020/2/18 18:50
* @Author: PeiChen
*/
// 使用 @Service 注解将该类标记为Spring框架中的服务层组件并指定了组件的名称为 "visitorService",方便在依赖注入时使用
@Service("visitorService")
public class VisitorServiceImpl implements VisitorService {
// 定义一个VisitorDao类型的成员变量用于后续调用数据访问层的方法来操作数据库中的访客数据
private VisitorDao visitorDao;
/**
* AutowiredVisitorDao
* @AutowiredSpringVisitorDao
* 使便访
* @param visitorDao 访访SpringVisitorDao
*/
@Autowired
public void setVisitorDao(VisitorDao visitorDao) {
this.visitorDao = visitorDao;
@ -30,59 +40,95 @@ public class VisitorServiceImpl implements VisitorService {
/**
* 访
* @param visitor
* @throws Exception
* VisitorService访Visitor
* VisitorDao访
*
* @param visitor 访访访访
* @throws Exception
*/
@Override
public void add(Visitor visitor) throws Exception {
// 调用VisitorDao的add方法将传入的访客对象visitor的信息插入到数据库中实现来访登记功能将访客信息持久化
visitorDao.add(visitor);
}
/**
* 访
* @return
* @throws Exception
* 访
* VisitorService访访
* PageHelperVisitorDao访
*
* @return 访Visitor访访
* @throws Exception
*/
@Override
public List<Visitor> findAll(int page, int size) throws Exception {
PageHelper.startPage(page,size);
// 使用PageHelper插件进行分页传入当前页码page和每页显示的记录数size参数该插件会自动拦截后续的数据库查询操作
// 根据设置的分页参数对查询结果进行分页处理,使得返回的结果是符合分页要求的访客记录列表
PageHelper.startPage(page, size);
// 调用VisitorDao的findAll方法从数据库中查询所有访客记录由于前面已经设置了分页这里返回的结果将是分页后的访客记录列表
// 按照来访时间降序排列由VisitorDao的findAll方法中的SQL语句决定排序方式
return visitorDao.findAll();
}
/**
* 访
* @param keyword
* @return
* @throws Exception
* 访
* VisitorService访访
* PageHelperVisitorDao访
*
* @param page
* @param size 访
* @param keyword 访
* @return 访Visitor访访
* @throws Exception
*/
@Override
public List<Visitor> search(int page, int size, String keyword) throws Exception {
PageHelper.startPage(page,size);
// 使用PageHelper插件进行分页传入当前页码page和每页显示的记录数size参数让插件为后续的数据库查询操作添加分页逻辑
// 确保返回符合分页要求的查询结果
PageHelper.startPage(page, size);
// 调用VisitorDao的search方法传入搜索关键字keyword从数据库中查询所有符合关键字模糊匹配条件的访客记录
// 并且按照来访时间降序排列由VisitorDao的search方法中的SQL语句决定排序方式最终返回分页后的符合条件的访客记录列表
return visitorDao.search(keyword);
}
/**
* 访访
* @param id
* @param end_date
* @throws Exception
* VisitorService访访
* VisitorDao访访
*
* @param id 访访UUID
* @param end_date 访 yyyy-MM-dd HH:mm:ss
* 访访
* @throws Exception
*/
@Override
public void logout(String id, String end_date) throws Exception {
visitorDao.logout(id,end_date);
// 调用VisitorDao的logout方法传入访客的唯一标识符id和离开时间end_date在数据库中执行更新操作
// 将对应访客记录的离开时间字段更新为传入的end_date值实现访客记录的注销功能即标记访客已经离开
visitorDao.logout(id, end_date);
}
/**
* 访
* @return
* @throws Exception
* 访Excel
* VisitorService访Excel访
* WriteExcelExcelExcel便
*
* @return 访访ExcelExcel
* 访Excel
* @throws Exception Excel
*
*/
@Override
public InputStream getInputStream() throws Exception {
//Excel中的每列列名依次对应数据库的字段
String[] title = new String[]{"ID","姓名","学号","联系方式","访问地址","来访时间","离开时间","来访原因"};
// Excel中的每列列名依次对应数据库的字段定义一个字符串数组用于指定要导出到Excel文件中的列标题
// 这些标题与数据库中访客表的字段名相对应方便在Excel文件中清晰展示访客记录的各项信息
String[] title = new String[]{"ID", "姓名", "学号", "联系方式", "访问地址", "来访时间", "离开时间", "来访原因"};
// 调用VisitorDao的findAll方法从数据库中获取所有访客记录得到一个包含所有访客信息的列表后续将基于这些数据来填充Excel文件内容
List<Visitor> visitors = visitorDao.findAll();
// 创建一个List<Object[]>类型的列表用于存储整理后的访客数据每个Object[]数组代表一行数据,
// 数组中的元素依次对应Excel文件中的每列数据与前面定义的title列名顺序对应方便后续将数据批量写入Excel文件
List<Object[]> datalist = new ArrayList<>();
// 遍历从数据库中获取到的所有访客记录列表visitors将每条访客记录的数据按照指定顺序整理到Object[]数组中并添加到datalist列表中
for (int i = 0; i < visitors.size(); i++) {
Object[] obj = new Object[8];
obj[0] = visitors.get(i).getId();
@ -95,20 +141,32 @@ public class VisitorServiceImpl implements VisitorService {
obj[7] = visitors.get(i).getVisit_result();
datalist.add(obj);
}
WriteExcel excel = new WriteExcel(title,datalist);
// 使用WriteExcel类将数据写入Excel文件创建一个WriteExcel类的实例传入列标题title和整理好的数据列表datalist
// 该类内部会实现将数据按照指定格式写入到Excel文件的逻辑并返回该Excel文件对应的输入流
WriteExcel excel = new WriteExcel(title, datalist);
// 调用WriteExcel类实例的export方法获取包含访客记录数据的Excel文件的输入流以便后续在控制器层将该输入流通过响应流发送给客户端
// 实现访客记录的导出功能客户端可以将接收到的输入流保存为本地的Excel文件进行查看和分析
return excel.export();
}
/**
* 访
* @param page
* @param size
* @return
* @throws Exception
* 访
* VisitorService访访
* PageHelperVisitorDao访
*
* @param page 访
* @param size 访
* @return 访Visitor访访
* 访访访访
* @throws Exception
*/
@Override
public List<Visitor> log(int page,int size) throws Exception {
PageHelper.startPage(page,size);
public List<Visitor> log(int page, int size) throws Exception {
// 使用PageHelper插件进行分页传入当前页码page和每页显示的记录数size参数该插件会自动拦截后续的数据库查询操作
// 根据设置的分页参数对查询结果进行分页处理,使得返回的结果是符合分页要求的访客日志记录列表
PageHelper.startPage(page, size);
// 调用VisitorDao的findAll方法从数据库中查询所有访客日志记录由于前面已经设置了分页这里返回的结果将是分页后的访客日志记录列表
// 按照来访时间降序排列由VisitorDao的findAll方法中的SQL语句决定排序方式
return visitorDao.findAll();
}
}
}

@ -4,59 +4,112 @@ import java.security.MessageDigest;
/**
* MD5
* MD5
* UTF-8MD5便
*/
public class MD5Util {
/**
*
*
*
* @param b MD5
* @return
*/
private static String byteArrayToHexString(byte b[]) {
// 创建一个StringBuffer对象用于高效地拼接字符串存储最终转换后的十六进制字符串结果。
StringBuffer resultSb = new StringBuffer();
// 遍历字节数组中的每个字节
for (int i = 0; i < b.length; i++)
// 调用byteToHexString方法将每个字节转换为十六进制字符串并添加到resultSb中
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
/**
*
* 44
*
*
* @param b
* @return 2
*/
private static String byteToHexString(byte b) {
// 将字节转换为整数如果字节值是负数Java中字节是有符号的范围是 -128 到 127则通过加上256将其转换为正数范围0 到 255便于后续计算。
int n = b;
if (n < 0)
n += 256;
// 获取该整数的高4位用于对应十六进制的高位数字通过除以16来得到十六进制中每一位代表16的幂次高4位对应的幂次为1
int d1 = n / 16;
// 获取该整数的低4位用于对应十六进制的低位数字通过取模16来得到。
int d2 = n % 16;
// 从预定义的十六进制字符数组中查找对应的字符拼接成十六进制字符串返回高4位在前低4位在后。
return hexDigits[d1] + hexDigits[d2];
}
/**
* MD5
* MD5
* MessageDigestMD5
*
* @param origin MD5
* @param charsetname 使null使
* @return MD5null
*/
private static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
// 先将传入的原始字符串赋值给结果字符串变量,这里可以根据实际需求考虑是否进行深拷贝等更严谨的处理(当前代码只是简单赋值)。
resultString = new String(origin);
// 获取MD5算法的MessageDigest实例用于进行MD5摘要计算通过传入"MD5"字符串指定使用MD5算法。
MessageDigest md = MessageDigest.getInstance("MD5");
// 如果未指定字符编码或者字符编码为空字符串则使用默认方式将字符串转换为字节数组后进行MD5摘要计算再将摘要结果转换为十六进制字符串。
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
else
// 如果指定了字符编码则按照指定的字符编码将字符串转换为字节数组然后进行MD5摘要计算并转换为十六进制字符串。
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
} catch (Exception exception) {
// 当前代码只是简单捕获异常,未做详细的异常处理(如记录日志、抛出更具体的异常等),实际应用中可根据需求完善此处逻辑。
}
return resultString.toUpperCase();
}
/**
* UTF-8MD5
* 便使UTF-8MD5Encode
* SaltMD5
*
* @param origin MD5
* @return UTF-8MD5
*/
public static String MD5EncodeUtf8(String origin) {
//盐值Salt加密
//origin = origin + PropertiesUtil.getProperty("password.salt", "");
// 盐值Salt加密
// 以下代码是预留的盐值加密逻辑通过从配置文件PropertiesUtil.getProperty方法调用此处未展示该类的实现中获取盐值
// 将盐值添加到原始字符串后面再进行MD5加密可以使相同的原始字符串在不同的盐值情况下加密结果不同增强安全性。
// 当前代码将其注释掉了,如果需要启用盐值加密,可取消注释并确保配置文件读取等相关逻辑正确实现。
// origin = origin + PropertiesUtil.getProperty("password.salt", "");
return MD5Encode(origin, "utf-8");
}
// 预定义的十六进制字符数组用于在字节转换十六进制字符串时查找对应的字符表示按照十六进制的顺序排列从0到f。
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
/**
* MD5
* MD5Util
* MD5EncodeUtf8"123456"MD5便
*
* @param args 使
*/
public static void main(String[] args) {
MD5Util md = new MD5Util();
String psd = md.MD5EncodeUtf8("123456");
System.out.println(psd);
}
}
}

@ -5,22 +5,32 @@
Date: 2020/2/12
Time: 13:06
To change this template use File | Settings | File Templates.
上面这部分是JSP页面的头部注释说明了该文件创建时的相关信息如创建者、创建日期、时间以及提示如何修改模板等内容
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<!-- 引入Bootstrap的CSS样式文件路径通过表达式语言获取当前页面上下文请求路径拼接而成用于实现页面的基本布局和样式美化 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<!-- 引入layer组件的CSS样式文件用于实现一些弹出层等样式效果 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layer.css">
<!-- 引入jQuery库的JavaScript文件这是一个常用的JavaScript库用于简化DOM操作、事件处理等功能 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!-- 引入layer组件的JavaScript文件用于在页面中实现弹出层提示等交互功能 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/layer/layer.js"></script>
</head>
<body background="${pageContext.request.contextPath}/images/01.jpg">
<!-- 添加两个换行,用于页面布局上的间隔 -->
<br><br>
<!-- 创建一个水平布局的表单行使用Bootstrap的row和form-horizontal类用于放置各种表单元素 -->
<div class="row form-horizontal">
<!-- 创建一个表单组,用于对一组相关的表单元素进行分组,方便布局和样式设置 -->
<div class="form-group">
<!-- 创建一个用于显示标签的元素设置其占2列宽度基于Bootstrap的网格系统添加控制标签的类以及自定义的form-label类用于显示用户名的文本标签 -->
<label class="col-sm-2 control-label form-label">用户名:</label>
<div class="col-sm-8">
<!-- 创建一个文本输入框添加form-control类用于应用Bootstrap的输入框样式设置name和id属性方便后续通过JavaScript等操作该元素以及提交表单时传递对应的值 -->
<input type="text" class="form-control" name="username" id="username">
</div>
</div>
@ -51,8 +61,11 @@
<div class="form-group">
<label class="col-sm-2 control-label form-label">权限:</label>
<div class="col-sm-8">
<!-- 创建一个下拉选择框添加form-control类应用样式设置name和id属性用于选择用户的权限 -->
<select class="form-control" name="power" id="power">
<!-- 设置默认选中的选项值为0显示文本为“访客” -->
<option value="0" selected>访客</option>
<!-- 使用JSTL标签进行条件判断如果在会话范围sessionScope中的adminInfo对象的power属性大于0则显示宿舍长这个选项 -->
<c:if test="${sessionScope.adminInfo.power > 0}">
<option value="1">宿舍长</option>
</c:if>
@ -75,35 +88,47 @@
</div>
</div>
</div>
<!-- 创建一个新的行,用于放置按钮等操作元素 -->
<div class="row">
<!-- 创建一个表单组并设置按钮组的样式通过col-md-offset-5类设置偏移量使其在页面中水平居中显示基于Bootstrap的列偏移功能 -->
<div class="form-group btn-group col-md-offset-5">
<!-- 创建一个按钮添加btn和btn-primary类用于应用Bootstrap的按钮主色调样式设置点击事件点击时调用toValidate()函数 -->
<button class="btn btn-primary" onclick="toValidate()">确认添加</button>
<!-- 创建一个链接按钮添加btn和btn-default类用于应用Bootstrap的默认按钮样式点击时跳转到查找所有管理员的页面路径通过表达式语言拼接而成 -->
<a type="button" class="btn btn-default" href="${pageContext.request.contextPath}/findAllAdmin">返回列表</a>
</div>
</div>
</body>
<script src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<script src="${pageContext.request.contextPath}/js/validate.js"></script>
<script>
$(function () {
//ajax校验用户名是否存在
// 在文档加载完成后执行以下代码这是jQuery的就绪函数确保DOM元素都已加载完毕再执行相关操作
// 当用户名输入框的值发生改变时change事件执行以下函数
$("#username").change(function () {
//取username的值
//用户名输入框id为username)中的值通过jQuery的val()方法获取
var u_name = $(this).val();
//ajax异步请求
// 使用jQuery的$.get()方法发起一个GET类型的Ajax异步请求
// 请求的URL是通过表达式语言拼接而成的路径传递的参数是一个包含用户名u_name的对象请求成功后会执行回调函数
$.get("${pageContext.request.contextPath}/checkUserName",{"u_name":u_name},function (msg) {
//$(".error").html(msg);
// 根据服务器返回的消息msg进行判断如果消息是“账号可用”说明用户名已存在弹出相应提示信息
if (msg == "账号可用") {
layer.msg('用户名已存在');
}else {
} else {
// 否则说明用户名可用,弹出相应提示信息
layer.msg('用户名可用');
}
});
});
});
// 当学/工号输入框的值发生改变时change事件执行以下函数
$("#uid").change(function () {
// 获取学/工号输入框id为uid中的值并去除前后空格trim()方法)
var uid = $("#uid").val().trim();
// 使用jQuery的$.get()方法发起一个GET类型的Ajax异步请求请求的URL是检查学/工号是否已注册的接口(通过表达式语言拼接路径),传递学/工号参数
// 请求成功后会执行回调函数根据返回的数据data进行判断如果data为真说明学/工号已被注册),则弹出相应提示信息
$.get("${pageContext.request.contextPath}/checkUid",{"uid":uid},function (data) {
if (data) {
layer.msg('该学/工号已被注册,请重新输入');
@ -111,12 +136,14 @@
});
});
function toValidate(){
// 创建一个validate对象实例用于对表单进行验证传入一个配置对象
var val = new validate({
/*rules里面是检验规则
*key为需要检验的input的id,
*value为此input对应的检验规则
* key为需要检验的input的id,
* value为此input对应的检验规则
*/
rules:{
// 设置用户名输入框id为username的验证规则为不能为空notEmpty
username:"notEmpty",
name:"notEmpty",
uid:"notEmpty",
@ -126,12 +153,15 @@
},
/*submitFun里面为检验成功后要执行的方法*/
submitFun:function(){
// 如果验证成功调用toSubmit()函数,该函数用于提交表单数据等后续操作
toSubmit();
}
})
}
function toSubmit(){
//增加管理员,异步提交管理员表单
// 以下是用于向服务器提交添加管理员表单数据的函数
// 获取用户名输入框的值,并去除前后空格
var username = $("#username").val().trim();
var password = $("#password").val().trim();
var name = $("#name").val().trim();
@ -139,10 +169,11 @@
var phone = $("#phone").val().trim();
var power = $("#power").val().trim();
var description = $("#description").val().trim();
// 使用jQuery的$.ajax()方法发起一个POST类型的Ajax异步请求
$.ajax({
url: "${pageContext.request.contextPath}/addAdmin",//要请求的服务器url
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
//data:{method:"ajaxTest",val:value},
// 设置请求的URL指向添加管理员的接口通过表达式语言拼接路径
url: "${pageContext.request.contextPath}/addAdmin",
// 设置请求的数据,将各个表单字段的值组成一个对象传递给服务器,服务器可以通过相应的方式获取这些参数
data: {
username:username,
password:password,
@ -152,13 +183,16 @@
power: power,
description: description
},
type: "POST", //请求方式为POST
dataType: "json", //服务器返回的数据是什么类型
success: function(result){ //这个方法会在服务器执行成功时被调用 参数result就是服务器返回的值(现在是json类型)
type: "POST", // 设置请求方式为POST
dataType: "json", // 期望服务器返回的数据类型为JSON格式
success: function(result){ // 当服务器成功处理请求并返回数据时会执行这个回调函数参数result就是服务器返回的值现在是JSON类型
if(result){
// 如果服务器返回的结果为真(通常表示添加成功),弹出添加成功的提示信息
layer.msg('添加成功');
// 使用setTimeout()函数设置一个定时器2秒后执行函数这里是跳转到查找所有管理员的页面通过修改浏览器的当前地址实现
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}else {
// 如果服务器返回的结果为假(通常表示添加失败),弹出添加失败的提示信息,并提示联系管理员
layer.msg('添加失败,请联系管理员');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}
@ -166,5 +200,4 @@
});
}
</script>
</body>
</html>
</html>

@ -4,120 +4,153 @@
Date: 2020/2/12
Time: 13:08
To change this template use File | Settings | File Templates.
这部分是JSP页面的头部注释说明了该文件创建时的相关信息如创建者、创建日期、时间以及提示如何修改模板等内容
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<!-- 引入Bootstrap的CSS样式文件路径通过表达式语言获取当前页面上下文请求路径拼接而成用于实现页面的基本布局和样式美化 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<!-- 引入layer组件的CSS样式文件用于实现一些弹出层等样式效果 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layer.css">
<!-- 引入jQuery库的JavaScript文件这是一个常用的JavaScript库用于简化DOM操作、事件处理等功能 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!-- 引入layer组件的JavaScript文件用于在页面中实现弹出层提示等交互功能 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/layer/layer.js"></script>
</head>
<body background="${pageContext.request.contextPath}/images/01.jpg">
<!-- 添加两个换行,用于页面布局上的间隔 -->
<br><br>
<!-- 创建一个隐藏的输入框设置id和name属性为“id”通过表达式语言获取并设置其值为“ad.id”推测“ad”是某个从后台传递过来的管理员对象相关的数据这个输入框可能用于存储要编辑的管理员记录的唯一标识方便后续提交表单时传递给服务器 -->
<input type="hidden" id="id" name="id" value="${ad.id}">
<!-- 创建一个水平布局的表单行使用Bootstrap的row和form-horizontal类用于放置各种表单元素 -->
<div class="row form-horizontal">
<!-- 创建一个表单组,用于对一组相关的表单元素进行分组,方便布局和样式设置 -->
<div class="form-group">
<!-- 创建一个用于显示标签的元素设置其占2列宽度基于Bootstrap的网格系统添加控制标签的类以及自定义的form-label类用于显示用户名的文本标签 -->
<label class="col-sm-2 control-label form-label">用户名:</label>
<div class="col-sm-8">
<!-- 创建一个文本输入框设置为只读readonly通过表达式语言获取并设置其值为“ad.username”添加form-control类用于应用Bootstrap的输入框样式设置name和id属性方便后续通过JavaScript等操作该元素以及提交表单时传递对应的值此处设置只读可能表示该用户名不允许在此处修改 -->
<input type="text" readonly value="${ad.username}" class="form-control" name="username" id="username">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label form-label">姓名:</label>
<div class="col-sm-8">
<!-- 创建一个文本输入框设置为只读通过表达式语言获取并设置其值为“ad.name”添加form-control类用于应用Bootstrap的输入框样式设置name和id属性此处设置只读可能有相应业务逻辑决定暂不允许修改 -->
<input type="text" readonly value="${ad.name}" class="form-control" name="name" id="name">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label form-label">学/工号:</label>
<div class="col-sm-8">
<!-- 创建一个文本输入框添加form-control类应用样式通过表达式语言获取并设置其值为“ad.uid”设置name和id属性用于输入或显示学/工号,从此处未设置只读来看可能是允许修改该字段内容 -->
<input type="text" class="form-control" value="${ad.uid}" name="uid" id="uid">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label form-label">手机号:</label>
<div class="col-sm-8">
<!-- 创建一个文本输入框通过表达式语言获取并设置其值为“ad.phone”添加form-control类应用样式设置name和id属性用于输入或显示手机号 -->
<input type="text" value="${ad.phone}" class="form-control" name="phone" id="phone">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label form-label">描述:</label>
<div class="col-sm-8">
<!-- 创建一个文本输入框通过表达式语言获取并设置其值为“ad.description”添加form-control类应用样式设置name和id属性用于输入或显示管理员相关的描述信息 -->
<input type="text" class="form-control" value="${ad.description}" name="description" id="description">
</div>
</div>
</div>
<!-- 创建一个新的行,用于放置按钮等操作元素 -->
<div class="row">
<!-- 创建一个表单组并设置按钮组的样式通过col-md-offset-5类设置偏移量使其在页面中水平居中显示基于Bootstrap的列偏移功能 -->
<div class="form-group btn-group col-md-offset-5">
<!-- 创建一个按钮添加btn和btn-warning类用于应用Bootstrap的警告色调样式设置点击事件点击时调用toValidate()函数,该按钮用于触发确认修改的操作 -->
<button class="btn btn-warning" onclick="toValidate()">确认修改</button>
<!-- 创建一个链接按钮添加btn和btn-primary类用于应用Bootstrap的主色调样式点击时跳转到查找所有管理员的页面路径通过表达式语言拼接而成用于返回管理员列表页面 -->
<a type="button" href="${pageContext.request.contextPath}/findAllAdmin" class="btn btn-primary">返回列表</a>
</div>
</div>
</body>
<script src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<script src="${pageContext.request.contextPath}/js/validate.js"></script>
<script>
function toValidate(){
// 创建一个validate对象实例用于对表单进行验证传入一个配置对象
var val = new validate({
/*rules里面是检验规则
*key为需要检验的input的id,
*value为此input对应的检验规则
* key为需要检验的input的id,
* value为此input对应的检验规则
*/
rules:{
// 设置姓名输入框id为name的验证规则为不能为空notEmpty
name:"notEmpty",
// 设置学/工号输入框id为uid的验证规则为不能为空notEmpty
uid:"notEmpty",
// 设置描述输入框id为description的验证规则为不能为空notEmpty
description:"notEmpty",
// 设置手机号输入框id为phone的验证规则为符合手机号码格式mobile这里应该是在validate.js中自定义的验证规则用于校验手机号合法性
phone:"mobile",
},
/*submitFun里面为检验成功后要执行的方法*/
submitFun:function(){
// 如果验证成功调用toSubmit()函数,该函数用于提交表单数据等后续操作
toSubmit();
}
})
}
function toSubmit(){
//增加管理员,异步提交管理员表单
// 以下是用于向服务器提交修改管理员表单数据的函数
// 获取隐藏输入框id为id中的值并去除前后空格trim()方法),该值是要修改的管理员记录的唯一标识
var id = $("#id").val().trim();
var username = $("#username").val().trim();
var name = $("#name").val().trim();
var uid = $("#uid").val().trim();
var phone = $("#phone").val().trim();
var description = $("#description").val().trim();
// 使用layer组件弹出一个确认框提示用户是否确定要修改当用户点击确认按钮“确定”执行回调函数中的代码回调函数接收一个参数index用于后续操作该弹出层如关闭它
layer.confirm('确定要修改吗',function (index) {
// 判断当前用户的权限通过表达式语言从会话范围获取adminInfo对象的power属性如果小于3推测3及以上为有足够权限修改管理员信息的级别则提示用户权限不足关闭弹出层并且终止后续操作返回false
if (${sessionScope.adminInfo.power < 3}) {//非超级管理员不能修改管理员信息
layer.msg('对不起,您权限不足');
layer.close(index);
return false;
}
$.ajax({
url: "${pageContext.request.contextPath}/editAdmin",//要请求的服务器url
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
//data:{method:"ajaxTest",val:value},
data: {
id:id,
username:username,
name:name,
uid:uid,
phone: phone,
description: description
},
type: "POST", //请求方式为POST
dataType: "json", //服务器返回的数据是什么类型
success: function(result){ //这个方法会在服务器执行成功时被调用 参数result就是服务器返回的值(现在是json类型)
if(result){
layer.msg('修改成功');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}else {
layer.msg('修改失败,请联系管理员');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
// 使用jQuery的$.ajax()方法发起一个POST类型的Ajax异步请求
$.ajax({
// 设置请求的URL指向修改管理员信息的接口通过表达式语言拼接路径
url: "${pageContext.request.contextPath}/editAdmin",
// 设置请求的数据,将各个表单字段的值组成一个对象传递给服务器,服务器可以通过相应的方式获取这些参数
data: {
id:id,
username:username,
name:name,
uid:uid,
phone: phone,
description: description
},
type: "POST", // 设置请求方式为POST
dataType: "json", // 期望服务器返回的数据类型为JSON格式
success: function(result){ // 当服务器成功处理请求并返回数据时会执行这个回调函数参数result就是服务器返回的值现在是JSON类型
if(result){
// 如果服务器返回的结果为真(通常表示修改成功),弹出修改成功的提示信息
layer.msg('修改成功');
// 使用setTimeout()函数设置一个定时器2秒后执行函数这里是跳转到查找所有管理员的页面通过修改浏览器的当前地址实现
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}else {
// 如果服务器返回的结果为假(通常表示修改失败),弹出修改失败的提示信息,并提示联系管理员
layer.msg('修改失败,请联系管理员');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}
}
}
});
});
});
}
</script>
</body>
</html>
</html>

@ -4,6 +4,7 @@
Date: 2020/2/10
Time: 21:45
To change this template use File | Settings | File Templates.
这部分是JSP页面的头部注释说明了该文件创建时的相关信息如创建者、创建日期、时间以及提示如何修改模板等内容
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
@ -11,38 +12,59 @@
<head>
<meta charset="UTF-8">
<title></title>
<!-- 设置页面渲染引擎为webkit用于在一些浏览器中更好地渲染页面样式等 -->
<meta name="renderer" content="webkit">
<!-- 配置页面兼容模式使其在IE浏览器下以最高级别的标准模式IE=edge以及启用Chrome Framechrome=1来渲染页面以提高兼容性 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- 引入字体相关的CSS样式文件路径通过表达式语言获取当前页面上下文请求路径拼接而成用于页面中字体的显示样式设置 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/font.css">
<!-- 引入xadmin框架的CSS样式文件用于实现该框架下特定的页面布局和样式效果 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/xadmin.css">
<!-- 引入Bootstrap的CSS样式文件用于实现页面基本的布局和样式美化 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<!-- 引入jQuery库的JavaScript文件这是一个常用的JavaScript库用于简化DOM操作、事件处理等功能 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!-- 引入layui框架的JavaScript核心文件layui是一个用于构建页面交互界面的前端框架 -->
<script src="${pageContext.request.contextPath}/lib/layui/layui.js" charset="utf-8"></script>
<!-- 引入xadmin框架的JavaScript文件用于实现该框架相关的功能和交互效果 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/xadmin.js"></script>
<!-- 引入Bootstrap的JavaScript文件用于实现Bootstrap框架相关的交互功能比如一些组件的动态效果等 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script>
<!-- 再次引入jQuery库的JavaScript文件此处可能存在重复引入问题可根据实际情况进行优化 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!-- 以下是针对IE浏览器版本小于9的情况引入html5shiv库的JavaScript文件用于让IE低版本支持HTML5标签 -->
<!-- 以及引入respond.js库的JavaScript文件用于让IE低版本支持CSS3的媒体查询功能提升页面在低版本IE浏览器下的兼容性 -->
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
function changePageSize() {
//获取下拉框的值
// 获取下拉框id为changePageSize中用户选择的值,该下拉框通常用于选择每页显示的数据条数
var pageSize = $("#changePageSize").val();
//向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/findAllAdmin?page=1&size="+ pageSize;
// 通过修改浏览器地址栏的URLlocation.href向服务器发送请求,传递新的每页显示条数参数pageSize同时设置当前页码为1用于改变每页显示条数后刷新页面数据展示
location.href = "${pageContext.request.contextPath}/findAllAdmin?page=1&size=" + pageSize;
}
// 当搜索按钮id为serarch_btn被点击时执行以下函数
$("#serarch_btn").click(function () {
// 获取输入框id为keyword中的用户输入的关键字内容该关键字通常用于在查找管理员数据时进行筛选
var keyword = $("#keyword").val();
location.href="${pageContext.request.contextPath}/findAllAdmin?page=1&size=5&keyword="+keyword;
// 通过修改浏览器地址栏的URL向服务器发送请求传递关键字参数、设置当前页码为1以及每页显示条数为5用于根据关键字进行搜索并刷新页面展示搜索结果
location.href = "${pageContext.request.contextPath}/findAllAdmin?page=1&size=5&keyword=" + keyword;
});
// 当刷新按钮id为refresh代码中未展示该按钮的HTML部分但推测存在此功能按钮被点击时执行以下函数
$("#refresh").click(function () {
// 重置表单id为myform将表单中的输入框等元素的值恢复到初始状态此处假设表单中各元素有相应的重置逻辑实现
$("#myform").reset();
location.href="${pageContext.request.contextPath}/findAllAdmin?page=1&size=5";
// 通过修改浏览器地址栏的URL向服务器发送请求设置当前页码为1以及每页显示条数为5用于刷新页面展示初始的数据列表
location.href = "${pageContext.request.contextPath}/findAllAdmin?page=1&size=5";
});
</script>
</head>
<body>
<%-- 以下这部分代码被注释掉了,原本可能是用于页面导航栏的展示,包含了面包屑导航以及一个刷新按钮,点击刷新按钮可重新加载当前页面 --%>
<%--<div class="x-nav">
<span class="layui-breadcrumb">
<a href="">首页</a>
@ -53,32 +75,46 @@
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" onclick="location.reload()" title="刷新">
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
</div>--%>
<!-- 使用layui的流体布局容器类layui-fluid使内部元素能自适应页面宽度 -->
<div class="layui-fluid">
<!-- 创建一个layui的行元素并设置列间距为15px用于放置页面中的各种模块 -->
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-body ">
<!-- 创建一个表单设置id为myform应用layui的表单样式以及列间距样式用于放置搜索等相关的表单元素 -->
<form id="myform" class="layui-form layui-col-space5">
<!-- 创建一个内联的表单元素块在小屏幕xs尺寸下显示用于放置一个文本输入框 -->
<div class="layui-inline layui-show-xs-block">
<!-- 创建一个文本输入框设置自动补全关闭添加占位提示文字设置name和id属性方便后续传递参数以及操作该元素同时通过表达式语言获取并设置输入框的值如果存在相应参数传入的话 -->
<input class="layui-input" type="text" autocomplete="off" placeholder="请输入关键字" name="keyword" id="keyword" value="${param.keyword}">
</div>
<!-- 创建一个内联的表单元素块在小屏幕xs尺寸下显示用于放置一个搜索按钮 -->
<div class="layui-inline layui-show-xs-block">
<!-- 创建一个layui的按钮设置id为serarch_btn添加相应的提交和过滤属性lay-submit和lay-filter按钮内部通过图标展示搜索的图标样式 -->
<button class="layui-btn" id="serarch_btn" lay-submit="" lay-filter="sreach"><i class="layui-icon">&#xe615;</i></button>
</div>
<!-- 创建一个内联的表单元素块在小屏幕xs尺寸下显示并且设置靠右对齐x-right类推测是自定义的样式类用于控制布局用于放置一个链接按钮 -->
<div class="layui-inline layui-show-xs-block x-right">
<!-- 创建一个layui的常规按钮样式的链接按钮点击可跳转到默认的管理员列表页面设置了固定的每页显示5条数据按钮内部通过图标展示相应的图标样式 -->
<a class="layui-btn layui-btn-normal" href="${pageContext.request.contextPath}/findAllAdmin?page=1&size=5"><i class="layui-icon">&#xe669;</i></a>
</div>
</form>
</div>
<xblock>
<!-- 创建一个添加按钮点击可跳转到添加管理员的页面按钮应用layui的常规按钮样式按钮内部通过图标展示添加的图标样式 -->
<a href="${pageContext.request.contextPath}/adminAdd" class="layui-btn layui-btn-normal"><i class="layui-icon">&#xe654;</i>添加</a>
<!-- 创建一个导出按钮点击时调用exportInfo函数会根据权限判断是否能导出按钮应用layui的暖色调按钮样式按钮内部通过图标展示导出的图标样式 -->
<a onclick="exportInfo(${sessionScope.adminInfo.power})" class="layui-btn layui-btn-warm" href="javascript:;"><i class="layui-icon">&#xe67c;</i>导出</a>
<!-- 创建一个靠右对齐的文本元素用于展示总的数据条数信息通过表达式语言获取并展示总数据条数pageInfo.total -->
<span class="x-right" style="line-height:40px">共有数据:${pageInfo.total} 条</span>
</xblock>
<div class="layui-card-body">
<!-- 创建一个layui的表格应用layui的表格和表单样式用于展示管理员数据列表 -->
<table class="layui-table layui-form">
<thead>
<tr style="text-align: center">
<!-- 表格表头部分分别设置各列的标题如ID、用户名等并且设置文本居中对齐 -->
<th style="text-align: center">ID</th>
<th style="text-align: center">用户名</th>
<th style="text-align: center">姓名</th>
@ -92,35 +128,43 @@
<%
int j = 1;
%>
<!-- 使用JSTL的<>标签循环遍历从服务器端获取的管理员数据列表pageInfo.list每次循环将一个管理员对象赋值给admin变量 -->
<c:forEach items="${pageInfo.list}" var="admin">
<tr id="light" style="text-align: center">
<td><%=j++%></td>
<td>${admin.username}</td>
<td>${admin.name}</td>
<td>${admin.uid}</td>
<td>${admin.phone}</td>
<td>${admin.power}</td>
<td>${admin.description}</td>
<td class="td-manage">
<a title="编辑" href="${pageContext.request.contextPath}/adminEdit?id=${admin.id}">
<i class="layui-icon">&#xe642;</i>
</a>
<a title="授权" onclick="put_power(this,${admin.id},${sessionScope.adminInfo.power})" href="javascript:;">
<i class="layui-icon">&#xe672;</i>
</a>
<a title="删除" onclick="member_del(this,${admin.id},${sessionScope.adminInfo.power})" href="javascript:;">
<i class="layui-icon">&#xe640;</i>
</a>
</td>
</c:forEach>
</tr>
<tr id="light" style="text-align: center">
<!-- 在表格行中展示数据ID列通过Java代码片段<%=j++%>)自增序号来显示序号,其他列通过表达式语言展示管理员对象的各个属性值,如用户名、姓名等 -->
<td><%=j++%></td>
<td>${admin.username}</td>
<td>${admin.name}</td>
<td>${admin.uid}</td>
<td>${admin.phone}</td>
<td>${admin.power}</td>
<td>${admin.description}</td>
<td class="td-manage">
<!-- 创建一个编辑操作的链接按钮点击可跳转到编辑管理员信息的页面通过传递管理员的id参数来指定要编辑的对象按钮内部通过图标展示编辑的图标样式 -->
<a title="编辑" href="${pageContext.request.contextPath}/adminEdit?id=${admin.id}">
<i class="layui-icon">&#xe642;</i>
</a>
<!-- 创建一个授权操作的链接按钮点击时调用put_power函数并传递当前管理员的id以及当前用户的权限信息用于判断是否有权限进行授权操作按钮内部通过图标展示授权的图标样式 -->
<a title="授权" onclick="put_power(this,${admin.id},${sessionScope.adminInfo.power})" href="javascript:;">
<i class="layui-icon">&#xe672;</i>
</a>
<!-- 创建一个删除操作的链接按钮点击时调用member_del函数并传递当前管理员的id以及当前用户的权限信息用于判断是否有权限进行删除操作按钮内部通过图标展示删除的图标样式 -->
<a title="删除" onclick="member_del(this,${admin.id},${sessionScope.adminInfo.power})" href="javascript:;">
<i class="layui-icon">&#xe640;</i>
</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<div class="pull-left">
<div class="form-group form-inline">
<!-- 展示分页相关信息,如总页数、当前页码等文本信息,并且通过表达式语言获取相应的数据进行展示 -->
共&nbsp;${pageInfo.pages}&nbsp;页&emsp;当前页:${pageInfo.pageNum}&nbsp;/&nbsp;${pageInfo.pages}&emsp; 每页
<!-- 创建一个下拉框用于选择每页显示的条数添加表单控制类样式设置id属性当下拉框的值改变时调用changePageSize函数来改变每页显示条数 -->
<select class="form-control" id="changePageSize" onchange="changePageSize()">
<!-- 下拉框中的各个选项,通过表达式语言获取当前每页显示条数作为默认选中项,并设置其他可选的每页显示条数选项 -->
<option value="1">${pageInfo.size}</option>
<option value="5">5</option>
<option value="10">10</option>
@ -130,129 +174,42 @@
</div>
</div>
<c:choose>
<c:when test="${pageInfo.pages < 5}">
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
</c:when>
<c:when test="${pageInfo.pageNum <= 3}">
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="5">
</c:set>
</c:when>
<c:when test="${pageInfo.pageNum > 3 and pageInfo.pageNum <= pageInfo.pages-2}">
<c:set var="begin" value="${pageInfo.pageNum - 2}">
</c:set>
<c:set var="end" value="${pageInfo.pageNum + 2}">
</c:set>
</c:when>
<c:otherwise>
<c:set var="begin" value="${pageInfo.pages - 4}">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
</c:otherwise>
<c:when test="${pageInfo.pages < 5}">
<!-- 当总页数小于5时设置分页导航的起始页码begin和结束页码end都为1到总页数用于展示所有页码链接 -->
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
</c:when>
<c:when test="${pageInfo.pageNum <= 3}">
<!-- 当当前页码小于等于3时设置分页导航的起始页码为1结束页码为5通常用于在前面几页时展示固定范围的页码链接 -->
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="5">
</c:set>
</c:when>
<c:when test="${pageInfo.pageNum > 3 and pageInfo.pageNum <= pageInfo.pages-2}">
<!-- 当当前页码大于3且小于等于总页数减2时设置分页导航的起始页码为当前页码减2结束页码为当前页码加2用于在中间页码范围时动态展示周边的页码链接 -->
<c:set var="begin" value="${pageInfo.pageNum - 2}">
</c:set>
<c:set var="end" value="${pageInfo.pageNum + 2}">
</c:set>
</c:when>
<c:otherwise>
<!-- 当当前页码大于总页数减2时即接近尾页时设置分页导航的起始页码为总页数减4结束页码为总页数用于展示尾页附近的页码链接 -->
<c:set var="begin" value="${pageInfo.pages - 4}">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
</c:otherwise>
</c:choose>
<div class="layui-card-body x-right" style="height: min-content">
<div class="page">
<div>
<!-- 创建一个首页链接按钮,点击可跳转到第一页,传递每页显示条数以及关键字参数(如果有),按钮应用相应的样式类 -->
<a class="next" href="${pageContext.request.contextPath}/findAllAdmin?page=1&size=${pageInfo.pageSize}&keyword=${param.keyword}">首页</a>
<!-- 当当前页码大于1时创建一个上一页链接按钮点击可跳转到上一页传递相应的参数按钮应用相应的样式类 -->
<c:if test="${pageInfo.pageNum > 1}">
<a class="prev" href="${pageContext.request.contextPath}/findAllAdmin?page=${pageInfo.pageNum-1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">上一页</a>
<a class="prev" href="${pageContext.request.contextPath}/findAllAdmin?page=${pageInfo.pageNum-1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">上一页</a>
</c:if>
<c:forEach var="i" begin="${begin}" end="${end}" step="1">
<c:if test="${pageInfo.pageNum == i}">
<span class="current">${i}</span>
</c:if>
<c:if test="${pageInfo.pageNum != i}">
<a class="num" href="${pageContext.request.contextPath}/findAllAdmin?page=${i}&size=${pageInfo.pageSize}&keyword=${param.keyword}">${i}</a>
</c:if>
</c:forEach>
<c:if test="${pageInfo.pageNum < pageInfo.pages}">
<a class="next" href="${pageContext.request.contextPath}/findAllAdmin?page=${pageInfo.pageNum+1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">下一页</a>
</c:if>
<a class="next" href="${pageContext.request.contextPath}/findAllAdmin?page=${pageInfo.pages}&size=${pageInfo.pageSize}&keyword=${param.keyword}">尾页</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
//删除操作
function member_del(obj,id,power){
layer.confirm('确认要删除吗?',function(index){
if ( power < 3){
layer.msg('对不起,您没有权限!');
return false;
}
//发异步删除数据
$.get("${pageContext.request.contextPath}/deleteAdmin",{"id":id},function (data) {
if(data = true){
layer.msg('删除成功!',{icon:1,time:2000});
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}else {
layer.msg('删除失败!',{icon:1,time:2000});
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}
});
});
}
//授权操作
function put_power(obj,id,power) {
//验证是否拥有权限
if (power < 3) {
layer.msg('对不起,您没有权限!');
return false;
}
//prompt层
layer.prompt({title: '输入授权密码,完成身份校验', formType: 1}, function(password, index){
if (password != 123) {
layer.msg('授权密码有误,身份验证失败');
layer.close(index);
return false;
}
layer.close(index);
layer.prompt({title: '输入权限级别,并确认授权', formType: 1}, function(level, index){
if (level < 0 || level > 4) {
layer.msg('授权等级输入有误,请重新输入!')
return false;
}
if (level > power) {
layer.msg('对不起,您权限不足!')
layer.close(index);
return false;
}
$.get("${pageContext.request.contextPath}/put_power",{"id":id,"power":level},function (data) {
if(data){
layer.msg('授权成功!');
layer.close(index);
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/findAllAdmin';},2000);
}else {
layer.msg('授权失败,请联系管理员!');
layer.close(index);
}
});
layer.close(index);
});
});
}
//导出Excel操作
function exportInfo(power) {
if (power < 3) {
layer.msg('对不起,您权限不足!');
return false;
}
layer.confirm('确定导出管理员数据吗?',function (index) {
location.href="${pageContext.request.contextPath}/exportAdminInfo";
layer.close(index);
});
}
</script>
</body>
</html>
<!-- 使用JSTL的标签循环生成页码链接按钮根据前面设置的起始页码begin

@ -1,10 +1,3 @@
<%--
Created by IntelliJ IDEA.
User: user
Date: 2020/2/19
Time: 21:16
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
@ -22,6 +15,7 @@
<tr>
<td><label for="dorm3">宿舍号</label></td>
<td>
<!-- 下拉选择框,用于选择宿舍楼 -->
<select class="form-control" name="dorm1" id="dorm1">
<option value="西六" selected>西六</option>
<option value="西七">西七</option>
@ -29,12 +23,17 @@
<option value="西十三">西十三</option>
</select>
</td>
<td><select class="form-control" name="dorm2" id="dorm2">
<td>
<!-- 下拉选择框,用于选择宿舍层 -->
<select class="form-control" name="dorm2" id="dorm2">
<option value="A" selected>A</option>
<option value="B">B</option>
</select></td>
</select>
</td>
<td>
<!-- 输入框,用于直接输入宿舍号 -->
<input type="text" name="dorm3" placeholder="请直接输入宿舍号" class="form-control" id="dorm3" list="did" required>
<!-- 数据列表,提供预定义的宿舍号选项 -->
<datalist id="did">
<option value="101" />
<option value="102" />
@ -66,9 +65,15 @@
</td>
</tr>
<tr>
<td><label for="dorm_intro">宿舍简介</label></td>
<td>
<label for="dorm_intro">宿舍简介</label>
</td>
<td colspan="3">
<textarea class="form-control" id="dorm_intro" name="dorm_intro" cols="2" maxlength="80" placeholder="请输入宿舍简介" required="required"></textarea>
<!-- 文本区域,用于输入宿舍简介 -->
<textarea class="form-control" id="dorm_intro" name="dorm_intro" cols="2"
maxlength="80" placeholder="请输入宿舍简介" required="required">
</textarea>
</td>
</tr>
<tr>
@ -76,7 +81,10 @@
<label for="dorm_rps">宿舍奖惩</label>
</td>
<td colspan="3">
<input type="text" name="dorm_rps" class="form-control" id="dorm_rps" value="无" placeholder="" list="rpsList" required>
<!-- 输入框,用于输入宿舍奖惩信息 -->
<input type="text" name="dorm_rps" class="form-control" id="dorm_rps" value="无"
placeholder="" list="rpsList" required>
<!-- 数据列表,提供预定义的宿舍奖惩选项 -->
<datalist id="rpsList">
<option value="年度最佳宿舍" />
<option value="年度活跃宿舍" />
@ -92,12 +100,14 @@
<label for="dorm_leader">宿舍长</label>
</td>
<td colspan="3">
<!-- 输入框,用于输入宿舍长姓名 -->
<input type="text" name="dorm_leader" class="form-control" id="dorm_leader" required>
</td>
</tr>
<tr>
<td><label for="teacher">育人导师</label></td>
<td colspan="3">
<!-- 下拉选择框,用于选择导师 -->
<select class="form-control" name="teacher" id="teacher">
<option value="小李" selected>小李</option>
<option value="小王">小王</option>
@ -109,7 +119,9 @@
</tr>
<tr>
<td colspan="4">
<!-- 确认添加按钮 -->
<button type="button" id="add-dorm" class="btn btn-primary">确认添加</button>
<!-- 返回列表按钮 -->
<a href="javascript:window.history.back(-1)" target="_self" class="btn btn-default">返回列表</a>
</td>
</tr>
@ -117,75 +129,133 @@
</table>
</form>
<script>
$("#dorm3").change(function () {
// 当宿舍号输入框的值发生变化时触发
$("#dorm3").change(function ()
{
// 获取楼栋选择框的值
var d1 = $("#dorm1").val();
// 获取楼层选择框的值
var d2 = $("#dorm2").val();
// 获取宿舍号输入框的值并去除两端空格
var dorm3 = $("#dorm3").val().trim();
// 拼接成完整的宿舍ID
var dorm_id = d1+""+d2+""+dorm3;
$.ajax({
url: "${pageContext.request.contextPath}/dorm/isExist",//要请求的服务器url
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
//data:{method:"ajaxTest",val:value},
data: {
// 发送的数据
dorm_id:dorm_id
},
type: "POST", //请求方式为POST
//请求方式为POST
type: "POST",
// 期望服务器返回JSON格式的数据
dataType: "json",
success:function(result){ //这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
success:function(result)//这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
{
//alert(result);
if(result){
if(result)
{// 如果返回结果为真,表示宿舍已存在
// 弹出提示信息
layer.msg('该宿舍已存在,请重新注册!');
}
}
});
});
$("#add-dorm").click(function () {
// 当点击“确认添加”按钮时触发
$("#add-dorm").click(function ()
{
// 获取宿舍号输入框的值并去除两端空格
var dorm3 = $("#dorm3").val().trim();
// 获取宿舍简介输入框的值并去除两端空格
var dorm_intro = $("#dorm_intro").val().trim();
// 获取宿舍奖惩输入框的值并去除两端空格
var dorm_rps = $("#dorm_rps").val().trim();
// 获取宿舍长输入框的值并去除两端空格
var dorm_leader = $("#dorm_leader").val().trim();
// 获取导师选择框的值并去除两端空格
var teacher = $("#teacher").val().trim();
if (dorm3.length == 0 || dorm_intro.length == 0 || dorm_rps.length == 0 || dorm_leader == 0 || teacher.length == 0) {
// 检查所有字段是否为空
if (dorm3.length == 0 || dorm_intro.length == 0 || dorm_rps.length == 0
|| dorm_leader == 0 || teacher.length == 0)
{
// 如果有任意一个字段为空,弹出提示信息
layer.msg('字段不能为空');
// 终止函数执行
return false;
}
if (${sessionScope.adminInfo.power < 2}) {
// 检查用户权限是否足够
if (${sessionScope.adminInfo.power < 2})
{
// 如果权限不足,弹出提示信息
layer.msg('权限不足');
return false;
}
// 获取楼栋选择框的值
var d1 = $("#dorm1").val();
// 获取楼层选择框的值
var d2 = $("#dorm2").val();
// 拼接成完整的宿舍ID
var dorm_id = d1+""+d2+""+dorm3;
//alert(dorm_id);
$.ajax({
$.ajax({// 发送AJAX请求到服务器进行添加操作
url: "${pageContext.request.contextPath}/dorm/add",//要请求的服务器url
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
//data:{method:"ajaxTest",val:value},
data: {
// 发送的宿舍ID
dorm_id:dorm_id,
// 发送的宿舍简介
dorm_intro:dorm_intro,
// 发送的宿舍奖惩
dorm_rps: dorm_rps,
// 发送的宿舍长
dorm_leader:dorm_leader,
// 发送的导师
teacher: teacher,
},
type: "POST", //请求方式为POST
dataType: "json",
success:function(result){ //这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
success:function(result)//这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
{
//alert(result);
if(result){
if(result)
{
// 弹出提示信息
layer.msg('添加成功');
if (${sessionScope.adminInfo.power == 2}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byTeacher?uid=${sessionScope.adminInfo.uid}';},2000);
// 如果用户权限为2跳转到教师管理的页面
if (${sessionScope.adminInfo.power == 2})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath
}/dorm/byTeacher?uid=${sessionScope.adminInfo.uid}';},2000);
// 终止函数执行
return flase;
}
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findAll';},2000);
}else {
// 否则跳转到宿舍列表页面
setTimeout(function () {window.location.href='${pageContext.request.contextPath
}/dorm/findAll';},2000);
}
else
{// 如果返回结果为假,表示添加失败
layer.msg('添加失败,请重新添加');
if (${sessionScope.adminInfo.power == 2}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byTeacher?uid=${sessionScope.adminInfo.uid}';},2000);
// 如果用户权限为2跳转到教师管理的页面
if (${sessionScope.adminInfo.power == 2})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath
}/dorm/byTeacher?uid=${sessionScope.adminInfo.uid}';},2000);
return flase;
}
// 否则跳转到宿舍列表页面
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findAll';},2000);
}
}

@ -1,16 +1,16 @@
<!-- 生成一个宿舍信息管理页面-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: user
Date: 2020/2/19
Time: 21:16
To change this template use File | Settings | File Templates.
--%>
<!-- 引入JSTL标签库并定义前缀c-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 设置页面内容类型为HTML字符编码为UTF-8使用的编程语言为Java-->
<html>
<!-- 定义HTML文档的根元素-->
<head>
<!-- 包含文档的头部信息-->
<title>Title</title>
<!-- 设置网页标题为“Title”-->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<!-- 引入Bootstrap样式表路径是相对于当前请求上下文的CSS文件夹下的bootstrap.css-->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/layer/layer.js"></script>
@ -18,31 +18,45 @@
<body>
<br />
<form>
<!-- 表格用于显示和编辑宿舍信息 -->
<table class="table" style="width: 100%;text-align: center;">
<tbody>
<!-- 宿舍号输入框 -->
<tr>
<td><label for="dorm_id">宿舍号</label></td>
<td>
<label for="dorm_id">宿舍号</label>
</td>
<td>
<!-- 隐藏的输入框用于存储宿舍ID -->
<input type="hidden" id="id" name="id" value="${dorm.id}">
<!-- 根据管理员权限判断是否可编辑宿舍号 -->
<c:if test="${sessionScope.adminInfo.power > 3}">
<input type="text" name="dorm_id" placeholder="例:西七B209" value="${dorm.dorm_id}" class="form-control" id="dorm_id" required>
<input type="text" name="dorm_id" placeholder="例:西七B209" value="${dorm.dorm_id}" class="form-control"
id="dorm_id" required>
</c:if>
<c:if test="${sessionScope.adminInfo.power <= 3}">
<input type="text" name="dorm_id" placeholder="" value="${dorm.dorm_id}" readonly class="form-control" id="dorm_id" required>
<input type="text" name="dorm_id" placeholder="" value="${dorm.dorm_id}" readonly class="form-control"
id="dorm_id" required>
</c:if>
</td>
</tr>
<!-- 宿舍简介输入框 -->
<tr>
<td><label for="dorm_intro">宿舍简介</label></td>
<td>
<label for="dorm_intro">宿舍简介</label>
</td>
<td colspan="3">
<input class="form-control" id="dorm_intro" value="${dorm.dorm_intro}" name="dorm_intro" cols="2" maxlength="80" placeholder="请输入宿舍简介" required="required">
<input class="form-control" id="dorm_intro" value="${dorm.dorm_intro}" name="dorm_intro" cols="2"
maxlength="80" placeholder="请输入宿舍简介" required="required">
</td>
</tr>
<!-- 宿舍奖惩选择框 -->
<tr>
<td>
<label for="dorm_rps">宿舍奖惩</label>
</td>
<td colspan="3">
<!-- 根据当前宿舍的奖惩类型,动态生成下拉菜单选项 -->
<c:if test="${dorm.dorm_rps == '年度最佳宿舍'}">
<select class="form-control" name="dorm_rps" id="dorm_rps">
<option value="无" selected>无</option>
@ -122,6 +136,7 @@
</c:if>
</td>
</tr>
<!-- 宿舍长输入框 -->
<tr>
<td>
<label for="dorm_leader">宿舍长</label>
@ -130,9 +145,13 @@
<input type="text" name="dorm_leader" value="${dorm.dorm_leader}" class="form-control" id="dorm_leader" required>
</td>
</tr>
<!-- 育人导师选择框 -->
<tr>
<td><label for="teacher">育人导师</label></td>
<td>
<label for="teacher">育人导师</label>
</td>
<td colspan="3">
<!-- 根据当前宿舍的育人导师,动态生成下拉菜单选项 -->
<c:if test="${dorm.teacher == '小李'}">
<select class="form-control" name="teacher" id="teacher">
<option value="小李" selected>小李</option>
@ -190,7 +209,10 @@
</table>
</form>
<script>
$("#update-dorm").click(function () {
// 当点击id为"update-dorm"的元素时,执行以下函数
$("#update-dorm").click(function ()
{
// 获取并去除输入框中id、dorm_id、dorm_intro、dorm_rps、dorm_leader和teacher的值的前后空格
var id = $("#id").val().trim();
var dorm_id = $("#dorm_id").val().trim();
var dorm_intro = $("#dorm_intro").val().trim();
@ -198,14 +220,22 @@
var dorm_leader = $("#dorm_leader").val().trim();
var teacher = $("#teacher").val().trim();
if (id.length == 0 || dorm_id.length == 0 || dorm_intro.length == 0 || dorm_rps.length == 0 || dorm_leader == 0 || teacher.length == 0) {
// 检查是否有任何一个字段为空如果有则弹出提示信息并返回false阻止后续代码执行
if (id.length == 0 || dorm_id.length == 0 || dorm_intro.length == 0 || dorm_rps.length == 0
|| dorm_leader == 0 || teacher.length == 0)
{
layer.msg('字段不能为空');
return false;
}
if (${sessionScope.adminInfo.power < 1}) {
// 检查当前用户的权限是否小于1如果是则弹出提示信息并返回false阻止后续代码执行
if (${sessionScope.adminInfo.power < 1})
{
layer.msg('权限不足');
return false;
}
// 使用AJAX发送POST请求到服务器进行数据更新操作
$.ajax({
url: "${pageContext.request.contextPath}/dorm/update",//要请求的服务器url
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
@ -218,34 +248,53 @@
dorm_leader:dorm_leader,
teacher: teacher,
},
type: "POST", //请求方式为POST
dataType: "json",
success:function(result){ //这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
type: "POST", // 请求方式为POST
dataType: "json",// 预期服务器返回的数据类型为JSON
success:function(result)// 请求成功时的回调函数参数result是服务器返回的数据
{
//alert(result);
if(result){
if(result)
{
layer.msg('修改成功!');
if (${sessionScope.adminInfo.power == 1}) {
// 根据用户权限不同,跳转到不同的页面
if (${sessionScope.adminInfo.power == 1})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/look?uid=${sessionScope.adminInfo.uid}';},2000);
}
if (${sessionScope.adminInfo.power == 2}) {
if (${sessionScope.adminInfo.power == 2})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byTeacher?uid=${sessionScope.adminInfo.uid}';},2000);
return flase;
}
if (${sessionScope.adminInfo.power > 2}) {
if (${sessionScope.adminInfo.power > 2})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findAll';},2000);
}
}else {
}
else
{
// 如果服务器返回的结果为假(即修改失败)
layer.msg('修改失败,请联系管理员');
if (${sessionScope.adminInfo.power == 1}) {
if (${sessionScope.adminInfo.power == 1})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/look?uid=${sessionScope.adminInfo.uid}';},2000);
}
if (${sessionScope.adminInfo.power == 2}) {
if (${sessionScope.adminInfo.power == 2})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byTeacher?uid=${sessionScope.adminInfo.uid}';},2000);
return flase;
}
if (${sessionScope.adminInfo.power > 2}) {
if (${sessionScope.adminInfo.power > 2})
{
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findAll';},2000);
}
}
}
});

@ -26,17 +26,22 @@
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
function changePageSize() {
function changePageSize()
{
//获取下拉框的值
var pageSize = $("#changePageSize").val();
//向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/dorm/findAll?page=1&size="+ pageSize;
}
$("#serarch_btn").click(function () {
$("#serarch_btn").click(function ()
{
var keyword = $("#keyword").val();
location.href="${pageContext.request.contextPath}/dorm/findAll?page=1&size=5&keyword="+keyword;
});
$("#refresh").click(function () {
$("#refresh").click(function ()
{
$("#myform").reset();
location.href="${pageContext.request.contextPath}/dorm/findAll?page=1&size=5";
});
@ -85,6 +90,7 @@
<th style="text-align: center">宿舍奖惩</th>
<th style="text-align: center">宿舍长</th>
<th style="text-align: center">育人导师</th>
<!--当前用户的权限大于2则显示“操作”列-->
<c:if test="${sessionScope.adminInfo.power > 2}">
<th style="text-align: center">操作</th>
</c:if>
@ -93,6 +99,8 @@
<%
int j = 1;
%>
<!--通过JSTL标签<c:forEach>循环遍历pageInfo.list中的每个宿舍对象dorm-->
<c:forEach items="${pageInfo.list}" var="dorm">
<tr id="light" style="text-align: center">
<td><%=j++%></td>
@ -118,6 +126,7 @@
</tr>
</tbody>
</table>
<!--关闭表格和外层容器的标签-->
</div>
<div class="pull-left">
<div class="form-group form-inline">
@ -186,7 +195,8 @@
<script>
//查看详情
function look(id) {
function look(id)
{
layer.open({
type: 2,
title:'宿舍详情',
@ -194,14 +204,20 @@
area: ['800px', '430px'], //宽高
content: '${pageContext.request.contextPath}/dorm/look?id='+id
});
}
//导出Excel操作
function exportInfo(power) {
if (power < 3) {
function exportInfo(power)
{
if (power < 3)
{
layer.msg('对不起,您没有权限导出宿舍信息');
return false;
}
layer.confirm('确定导出所有宿舍数据吗?',function (index) {
layer.confirm('确定导出所有宿舍数据吗?',function (index)
{
location.href="${pageContext.request.contextPath}/dorm/export";
layer.close(index);
});

@ -96,21 +96,25 @@
</table>
</form>
<script>
$(function () {
$(function ()
{
//ajax校验学号已被注册
$("#sno").change(function () {
$("#sno").change(function ()
{
//取sno的值
var sno = $(this).val();
//ajax异步请求
$.get("${pageContext.request.contextPath}/student/isExist",{"sno":sno},function (date) {
//$(".error").html(msg);
if (date) {
if (date)
{
layer.msg('学号已被注册,请重新输入!');
return false;
}
});
});
});
$("#add-student").click(function () {
var name = $("#name").val().trim();
var sex = $("#sex").val().trim();
@ -122,10 +126,12 @@
var teacher = $("#teacher").val().trim();
var status = $("#status").val().trim();
if (name == 0 || sex == 0 || sno == 0 || stu_class == 0 || phone == 0 || place == 0 || teacher == 0) {
if (name == 0 || sex == 0 || sno == 0 || stu_class == 0 || phone == 0 || place == 0 || teacher == 0)
{
layer.msg('字段不能为空');
return false;
}
$.ajax({
url: "${pageContext.request.contextPath}/student/add",//要请求的服务器url
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
@ -141,14 +147,19 @@
teacher:teacher,
status:status
},
type: "POST", //请求方式为POST
dataType: "json",
success:function(result){ //这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
success:function(result)
{ //这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
//alert(result);
if(result){
if(result)
{
layer.msg('添加成功!');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';},2000);
}else {
}
else
{
layer.msg('添加失败,请联系管理员');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';},2000);
}

@ -26,17 +26,22 @@
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
function changePageSize() {
function changePageSize()
{
//获取下拉框的值
var pageSize = $("#changePageSize").val();
//向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/student/findAll?page=1&size="+ pageSize;
}
$("#serarch_btn").click(function () {
$("#serarch_btn").click(function ()
{
var keyword = $("#keyword").val();
location.href="${pageContext.request.contextPath}/student/findAll?page=1&size=5&keyword="+keyword;
});
$("#refresh").click(function () {
$("#refresh").click(function ()
{
$("#myform").reset();
location.href="${pageContext.request.contextPath}/student/findAll?page=1&size=5";
});

@ -26,20 +26,26 @@
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
function changePageSize() {
function changePageSize()
{
//获取下拉框的值
var pageSize = $("#changePageSize").val();
//向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/dorm/findAll?page=1&size="+ pageSize;
}
$("#serarch_btn").click(function () {
$("#serarch_btn").click(function ()
{
var keyword = $("#keyword").val();
location.href="${pageContext.request.contextPath}/dorm/findAll?page=1&size=5&keyword="+keyword;
});
$("#refresh").click(function () {
$("#refresh").click(function ()
{
$("#myform").reset();
location.href="${pageContext.request.contextPath}/dorm/findAll?page=1&size=5";
});
</script>
</head>
<body>
@ -107,8 +113,8 @@
</div>
<script>
//查看详情
function look(id) {
function look(id) //查看详情
{
layer.open({
type: 2,
title:'宿舍详情',

@ -4,20 +4,29 @@
Date: 2020/2/10
Time: 10:32
To change this template use File | Settings | File Templates.
这部分是JSP页面头部的注释主要说明了该文件创建时相关信息例如创建者、创建日期、时间以及提示如何修改模板等内容方便后续对代码来源及修改情况进行追溯。
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<!-- 引入自定义的用于用户登录页面的CSS样式文件路径通过JSP表达式语言${pageContext.request.contextPath})获取当前页面上下文请求路径后拼接而成,目的是为登录页面设置特定的样式风格,使其符合设计要求。 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/usersLogin.css">
<!-- 引入页面图标文件指定图标大小为32x32像素用于在浏览器的标签页等位置显示特定的图标增强页面的辨识度和品牌性如果是对应特定项目的话。 -->
<link rel="icon" href="${pageContext.request.contextPath}/images/favicon.ico" sizes="32x32" />
<!-- 引入自定义的通用样式文件根据media属性中指定的“screen”可知主要用于屏幕显示相关的样式设置同样通过页面请求路径拼接来获取样式文件位置用于页面整体通用样式的规范和美化。 -->
<link rel="stylesheet" media="screen" href="${pageContext.request.contextPath}/css/style.css">
<!-- 引入用于重置页面默认样式的CSS文件类型声明为“text/css”路径也是基于请求路径拼接它能清除浏览器自带的一些默认样式让页面在不同浏览器下展示效果更趋一致。 -->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/reset.css"/>
<!-- 引入jQuery库的JavaScript文件jQuery是一个广泛使用的JavaScript库能极大地简化DOM操作、事件处理等常见的前端开发任务方便后续编写交互逻辑。 -->
<script src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!-- 引入layer组件的JavaScript文件layer组件常用于在页面中弹出提示框、模态框等交互效果这里引入是为了后续展示如登录验证提示等相关信息。 -->
<script src="${pageContext.request.contextPath}/layer/layer.js" type="text/javascript"></script>
<!-- 引入自定义的与登录相关的JavaScript文件可能包含一些登录业务特有的逻辑处理代码等通过请求路径拼接来定位文件辅助实现登录页面的各种功能。 -->
<script src="${pageContext.request.contextPath}/js/login.js"></script>
<title>登录页面--LOGIN</title>
<%--<script type="text/javascript">
<%-- 以下这段JavaScript代码被注释掉了原本的功能是在页面加载完成通过$(function () {...}) 这种jQuery的就绪函数来确保DOM加载完毕监听用户名输入框id为“username”的内容变化事件change事件。当用户名输入框的值改变时会获取输入框的值通过$(this).val()获取然后发起一个GET类型的Ajax异步请求到服务器端的“checkUserName”接口路径通过表达式语言拼接而成传递用户名参数{"u_name":u_name}并根据服务器返回的消息msg进行判断如果消息不是“账号可用”就弹出提示“账号不存在”的信息框。不过当前处于注释状态未生效。 --%>
<%--<script type="text/javascript">
$(function () {
//ajax校验用户名是否存在
$("#username").change(function () {
@ -26,64 +35,88 @@
//ajax异步请求
$.get("${pageContext.request.contextPath}/checkUserName",{"u_name":u_name},function (msg) {
//$(".error").html(msg);
if (msg != "账号可用") {
if (msg!= "账号可用") {
layer.msg('账号不存在');
}
});
});
});
</script>--%>
</script>--%>
</head>
<body>
<!-- 创建一个HTML表单通过action属性指定表单提交的目标URL这里使用表达式语言拼接出指向登录处理的后端接口路径设置表单名称为“myform”提交方法为“post”用于将用户输入的登录信息发送到服务器端进行验证处理。 -->
<form action="${pageContext.request.contextPath}/login" name="myform" method="post">
<div id="particles-js">
<div class="login">
<div class="login-top">
后台登录
</div>
<div class="login-center clearfix">
<div class="login-center-img"><img src="${pageContext.request.contextPath}/images/name.png"/></div>
<div class="login-center-input">
<input type="text" id="username" name="username" placeholder="请输入您的用户名" onfocus="this.placeholder=''" onblur="this.placeholder='请输入您的用户名'"/>
<div class="login-center-input-text">用户名</div>
<!-- 创建一个具有特定效果可能与粒子特效相关需结合引入的js文件进一步确定一般用于页面背景装饰等的容器id为“particles-js”作为登录相关元素的父容器营造出独特的页面视觉效果。 -->
<div id="particles-js">
<!-- 创建一个登录框相关的容器应用了“login”类推测在对应的CSS文件中有对这个类定义的样式规则用于包裹登录框内的各个部分如标题、输入框、按钮等来实现登录框整体的布局和样式呈现。 -->
<div class="login">
<!-- 登录框顶部区域的容器,用于显示如“后台登录”这样的标题文本,给用户明确提示当前登录的是后台系统。 -->
<div class="login-top">
后台登录
</div>
</div>
<div class="login-center clearfix">
<div class="login-center-img"><img src="${pageContext.request.contextPath}/images/password.png"/></div>
<div class="login-center-input">
<input type="password" id="password" name="password" placeholder="请输入您的密码" onfocus="this.placeholder=''" onblur="this.placeholder='请输入您的密码'"/>
<div class="login-center-input-text">密码</div>
<!-- 创建登录框中间区域的容器并应用“clearfix”类用于清除浮动在CSS中通过这个类设置相关样式确保内部的浮动元素布局正常避免出现排版混乱问题用于放置用户名相关的输入框等元素使其在水平方向上合理排列。 -->
<div class="login-center clearfix">
<!-- 创建一个用于放置用户名图标的容器,里面嵌入一个图片元素,通过指定的路径(使用表达式语言拼接获取)加载用户名对应的图标图片,用于在视觉上标识这是用户名输入的区域。 -->
<div class="login-center-img"><img src="${pageContext.request.contextPath}/images/name.png"/></div>
<!-- 创建一个用于放置用户名输入框的容器,包含实际的输入框元素和相关提示文本元素,用于用户输入用户名以及显示相应提示信息。 -->
<div class="login-center-input">
<!-- 创建一个文本输入框设置id为“username”方便后续通过JavaScript代码获取其值和操作设置name属性为“username”用于在表单提交时作为参数名传递给服务器添加占位提示文字“请输入您的用户名”并且通过onfocus和onblur事件来控制当输入框获取焦点用户点击输入框准备输入时和失去焦点用户鼠标离开输入框后时占位文字的显示和隐藏提升用户体验。 -->
<input type="text" id="username" name="username" placeholder="请输入您的用户名" onfocus="this.placeholder=''" onblur="this.placeholder='请输入您的用户名'"/>
<!-- 创建一个用于显示用户名提示文本的容器初始显示“用户名”字样可能通过后续的JavaScript交互逻辑比如输入框获取焦点时隐藏等来改变其显示状态进一步辅助用户了解该输入框的用途。 -->
<div class="login-center-input-text">用户名</div>
</div>
</div>
<!-- 再次创建登录框中间区域的容器(结构与上面用户名部分类似),用于放置密码相关的输入框等元素,将密码相关的输入和提示信息组织在一起,方便用户操作和查看。 -->
<div class="login-center clearfix">
<!-- 创建一个用于放置密码图标的容器,嵌入对应的密码图标图片,从指定路径(通过表达式语言获取)加载,用于直观地提示用户此处是输入密码的地方。 -->
<div class="login-center-img"><img src="${pageContext.request.contextPath}/images/password.png"/></div>
<!-- 创建一个用于放置密码输入框的容器,同样包含实际输入框和提示文本元素,用于密码的输入及相关提示展示。 -->
<div class="login-center-input">
<!-- 创建一个密码输入框设置id为“password”方便操作name为“password”用于表单提交传参添加占位提示文字“请输入您的密码”通过onfocus和onblur事件控制占位文字的显示和隐藏与用户名输入框的交互方式类似符合常规的用户输入习惯。 -->
<input type="password" id="password" name="password" placeholder="请输入您的密码" onfocus="this.placeholder=''" onblur="this.placeholder='请输入您的密码'"/>
<!-- 创建一个用于显示密码提示文本的容器,初始显示“密码”字样,后续可根据交互逻辑改变显示状态,辅助用户识别该输入框功能。 -->
<div class="login-center-input-text">密码</div>
</div>
</div>
<!-- 创建一个登录按钮相关的容器应用“login-button”类在CSS中有对应的样式定义用于设置按钮的外观样式如颜色、大小、边框等设置点击事件点击时调用“check()”函数,通过这个函数来进行登录前的输入信息验证等操作,决定是否能提交表单。 -->
<div class="login-button" onclick="check()">
登录
</div>
<!-- 创建一个用于显示提示信息的文本元素设置文本居中对齐、颜色为红色通过表达式语言获取并显示“msg”变量的值推测是后端传递过来的错误提示等信息比如登录失败原因等并且添加一些空格用于排版让提示信息在页面上展示更清晰美观方便用户查看。 -->
<span style="text-align: center;color: red;"><br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;${msg}</span>
</div>
<div class="login-button" onclick="check()">
登录
</div>
<span style="text-align: center;color: red;"><br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;${msg}</span>
<!-- 创建一个用于显示特定动画效果的元素比如旋转平面动画效果需结合相关CSS和JavaScript代码来看具体效果可能是作为页面的一个加载动画或者装饰性动画元素目前为空的div其具体显示内容和动画效果由对应的样式和脚本控制。 -->
<div class="sk-rotating-plane"></div>
</div>
<div class="sk-rotating-plane"></div>
</div>
</form>
<!-- 引入用于实现粒子效果的JavaScript库文件路径通过表达式语言获取当前页面上下文请求路径拼接而成它负责在页面中展示出粒子相关的特效为登录页面营造出独特的视觉氛围增强页面的观赏性和交互感。 -->
<script src="${pageContext.request.contextPath}/js/particles.min.js"></script>
<!-- 引入用于初始化页面相关功能可能与粒子效果以及登录页面整体功能结合相关比如初始化粒子效果的参数、绑定页面元素的一些交互事件等的JavaScript文件同样通过请求路径拼接来定位文件保障页面各项功能正常运行。 -->
<script src="${pageContext.request.contextPath}/js/app.js"></script>
<script type="text/javascript">
function check() {
// 获取用户名输入框id为“username”中的值并使用trim()方法去除前后空格,确保获取到的用户名数据干净、规范,便于后续验证和使用。
var username = $("#username").val().trim();
// 获取密码输入框id为“password”中的值同样使用trim()方法去除前后空格,得到准确的密码输入内容,准备进行密码相关的格式等验证。
var password = $("#password").val().trim();
// 判断用户名是否为空null、空字符串或者长度为0都视为空如果是这种情况就使用layer组件弹出提示信息“请输入用户帐号”并且终止后续表单提交操作通过返回false来阻止表单提交提醒用户必须输入用户名才能进行登录。
if (username == null || username == "" || username.length == 0) {
layer.msg('请输入用户帐号');
return false;
}
// 判断密码是否为空如果为空同样使用layer组件弹出提示“请输入登录密码”并终止表单提交要求用户输入密码才能继续登录流程。
if (password == null || password == "" || password.length == 0) {
layer.msg('请输入登录密码');
return false;
}
// 判断密码长度是否小于4或者大于20如果满足这个条件说明密码格式不符合要求这里限定密码长度在4 - 20位字符之间则使用layer组件弹出提示信息“密码格式有误4 - 20位字符同时终止表单提交引导用户输入符合格式规范的密码。
if (password.length < 4 || password.length > 20) {
layer.msg('密码格式有误4-20位字符');
layer.msg('密码格式有误4 - 20位字符');
return false;
}
// 如果前面的所有验证都通过用户名和密码都不为空且密码长度符合要求就提交表单通过表单对象的submit()方法将用户在表单中输入的用户名和密码等数据发送到后端的登录处理接口由表单的action属性指定的路径进行后续的登录验证操作。
document.myform.submit();
}
</script>
</body>
</html>
</html>

@ -6,53 +6,136 @@
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!--
设置该JSP页面的相关属性。
contentType属性指定了页面响应的内容类型为"text/html"即HTML格式同时将字符编码设置为UTF-8这样能保证页面中的中文等特殊字符可以正确显示避免出现乱码情况。
language属性表明该页面使用Java语言来编写服务器端的代码逻辑例如使用Java代码片段或者基于Java的标签库等
-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<!--
引入JSTLJavaServer Pages Standard Tag Library的核心标签库设置前缀为“c”。通过这个标签库我们可以在JSP页面中方便地使用如条件判断、循环遍历等功能实现更灵活的页面逻辑控制。
-->
<html>
<head>
<!--
设置页面的标题这个标题通常会显示在浏览器的标签页上用于标识当前页面的主题内容此处标题暂设置为“Title”实际应用中可根据具体需求修改为更有意义的标题内容。
-->
<title>Title</title>
<!--
引入Bootstrap框架的CSS样式文件通过EL表达式 "${pageContext.request.contextPath}/css/bootstrap.css" 来指定样式文件的路径。
"${pageContext.request.contextPath}" 会获取当前Web应用的上下文路径即项目部署后的根路径部分然后拼接上相对路径 "/css/bootstrap.css"这样就能准确地找到并应用Bootstrap框架提供的样式使页面具有相应的布局和外观效果。
-->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<!--
引入jQuery库的JavaScript文件路径同样通过EL表达式 "${pageContext.request.contextPath}/js/jquery-3.1.1.js" 来确定将其引入到页面中使得可以使用jQuery提供的各种强大的DOM操作、事件处理、AJAX等功能方便开发页面交互效果。
-->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!--
引入Bootstrap框架配套的JavaScript文件通过 "${pageContext.request.contextPath}/js/bootstrap.js" 路径进行引入这个文件包含了Bootstrap框架中各种组件如模态框、下拉菜单等所依赖的JavaScript交互逻辑与前面引入的Bootstrap的CSS样式文件配合使用让页面能完整地展现出Bootstrap框架的功能和效果。
-->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script>
<!--
引入layer弹出层插件的JavaScript文件其路径为 "${pageContext.request.contextPath}/layer/layer.js"layer插件常用于在页面中创建各种美观且交互友好的弹出层效果比如提示框、确认框、加载层等增强页面的用户交互体验。
-->
<script type="text/javascript" src="${pageContext.request.contextPath}/layer/layer.js"></script>
</head>
<body>
<br />
<form>
</head>
<body>
<!--
HTML中的换行标签在这里单纯起到在页面内容开始处添加一个空行的作用使页面布局看起来更加清晰避免内容过于紧凑在顶部主要是从视觉美观角度考虑的一个简单元素。
-->
<br />
<!--
创建一个HTML的表单form元素表单常用于收集用户输入的数据并提交到服务器端进行处理不过在当前代码中暂时未看到设置表单提交相关的属性如action属性指定提交的URL等可能后续根据具体需求还会完善这部分功能或者仅用于展示已有数据的布局结构。
-->
<form>
<!--
创建一个表格table元素并应用Bootstrap框架的 "table" 样式类,通过设置 "style="width: 100%;text-align: center;" 内联样式,将表格宽度设置为占满整个父容器(一般就是页面宽度),同时让表格内的文本内容在水平方向上居中显示,使表格呈现出整齐、美观的布局效果,用于展示宿舍相关信息。
-->
<table class="table" style="width: 100%;text-align: center;">
<tbody>
<tr>
<td style="text-align: center"><label>宿舍号</label></td>
<td colspan="3" style="text-align: center">${dorm.dorm_id}</td>
</tr>
<tr>
<td style="text-align: center"><label>宿舍简介</label></td>
<td colspan="3" style="text-align: center">${dorm.dorm_intro}</td>
</tr>
<tr>
<td style="text-align: center">
<label>宿舍奖惩</label>
</td>
<td colspan="3" style="text-align: center">${dorm.dorm_rps}</td>
</tr>
<tr>
<td style="text-align: center">
<label>宿舍长</label>
</td>
<td colspan="3" style="text-align: center">${dorm.dorm_leader}</td>
</tr>
<tr>
<td style="text-align: center"><label>育人导师</label></td>
<td colspan="3" style="text-align: center">${dorm.teacher}</td>
</tr>
<tbody>
<!--
创建表格中的一行tr元素用于放置宿舍号相关的信息单元格。
-->
<tr>
<!--
创建一个单元格td元素设置样式 "text-align: center" 使其内部文本在水平方向上居中显示,在这个单元格内放置一个<label>标签用于显示“宿舍号”的文本提示信息,告知用户该列对应的内容含义。
-->
<td style="text-align: center"><label>宿舍号</label></td>
<!--
创建一个跨3列的单元格通过设置 "colspan="3"" 属性用于显示宿舍号的具体值这里通过EL表达式 "${dorm.dorm_id}" 从服务器端传递过来的数据模型(名为 "dorm" 的对象)中获取宿舍号属性的值并展示在页面上,让用户可以看到具体的宿舍号信息。
-->
<td colspan="3" style="text-align: center">${dorm.dorm_id}</td>
</tr>
<!--
创建表格中的另一行tr元素用于放置宿舍简介相关的信息单元格。
-->
<tr>
<!--
创建一个单元格td元素设置样式使其内部文本居中放置一个<label>标签显示“宿舍简介”的提示文本,用于说明该列展示的内容是宿舍的简介信息。
-->
<td style="text-align: center"><label>宿舍简介</label></td>
<!--
创建一个跨3列的单元格通过EL表达式 "${dorm.dorm_intro}" 从服务器端数据模型中获取宿舍简介的内容并展示出来,让用户了解该宿舍的相关介绍信息,同样设置文本居中显示的样式。
-->
<td colspan="3" style="text-align: center">${dorm.dorm_intro}</td>
</tr>
<!--
创建表格中的又一行tr元素用于放置宿舍奖惩相关的信息单元格。
-->
<tr>
<!--
创建一个单元格td元素设置文本居中样式放置一个<label>标签显示“宿舍奖惩”的提示文本,表明该列展示的是宿舍在奖惩方面的情况。
-->
<td style="text-align: center">
<label>宿舍奖惩</label>
</td>
<!--
创建一个跨3列的单元格通过EL表达式 "${dorm.dorm_rps}" 从服务器端数据模型获取宿舍奖惩的相关内容并展示在页面上,方便用户知晓该宿舍在奖惩方面的记录情况,设置文本居中样式。
-->
<td colspan="3" style="text-align: center">${dorm.dorm_rps}</td>
</tr>
<!--
创建表格中的一行tr元素用于放置宿舍长相关的信息单元格。
-->
<tr>
<!--
创建一个单元格td元素设置文本居中样式放置一个<label>标签显示“宿舍长”的提示文本,用于提示该列展示的是宿舍长的相关信息。
-->
<td style="text-align: center">
<label>宿舍长</label>
</td>
<!--
创建一个跨3列的单元格通过EL表达式 "${dorm.dorm_leader}" 从服务器端数据模型获取宿舍长的相关信息(可能是姓名等具体内容)并展示出来,让用户知道该宿舍的宿舍长是谁,设置文本居中样式。
-->
<td colspan="3" style="text-align: center">${dorm.dorm_leader}</td>
</tr>
<!--
创建表格中的一行tr元素用于放置育人导师相关的信息单元格。
-->
<tr>
<!--
创建一个单元格td元素设置文本居中样式放置一个<label>标签显示“育人导师”的提示文本,表明该列展示的是育人导师的相关信息。
-->
<td style="text-align: center"><label>育人导师</label></td>
<!--
创建一个跨3列的单元格通过EL表达式 "${dorm.teacher}" 从服务器端数据模型获取育人导师的相关信息(比如姓名等)并展示出来,方便用户了解该宿舍对应的育人导师是谁,设置文本居中样式。
-->
<td colspan="3" style="text-align: center">${dorm.teacher}</td>
</tr>
<!--
使用JSTL的<if条件判断标签判断当前会话session范围中名为 "adminInfo" 的对象的 "power" 属性值是否等于1可能表示管理员具备某种特定权限如果满足条件则执行标签内部的代码展示一个“去修改”的按钮链接用于跳转到修改宿舍信息的页面。
-->
<c:if test="${sessionScope.adminInfo.power == 1}">
<tr>
<!--
创建一个跨4列的单元格通过设置 "colspan="4"" 属性在这个单元格内创建一个超链接a元素并应用Bootstrap框架的 "btn btn-warning" 样式类,使其显示为一个具有警告颜色(通常是黄色等醒目颜色)的按钮样式,
href属性通过EL表达式 "${pageContext.request.contextPath}/dorm/toUpdate?id=${dorm.id}" 设置链接的目标URL其中 "${pageContext.request.contextPath}/dorm/toUpdate" 指向用于进入修改宿舍信息页面的服务器端接口路径,"id=${dorm.id}" 表示将当前宿舍的ID作为参数传递过去方便服务器端根据这个ID获取对应的宿舍信息进行修改操作整体实现点击按钮跳转到修改页面的功能。
-->
<td colspan="4"><a class="btn btn-warning" href="${pageContext.request.contextPath}/dorm/toUpdate?id=${dorm.id}">去修改</a></td>
</tr>
</c:if>
</tbody>
</table>
</form>
</body>
</html>
</table>
</form>
</body>
</html>

@ -5,32 +5,44 @@
Date: 2020/2/10
Time: 15:58
To change this template use File | Settings | File Templates.
这部分是JSP页面头部的注释说明了该文件创建时的相关信息如创建者、创建日期、时间以及提示如何修改模板等内容。
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<!doctype html>
<html>
<head>
<title>管理员端平台</title>
<!-- 引入字体相关的CSS样式文件路径通过表达式语言获取当前页面上下文请求路径拼接而成用于页面中字体的显示样式设置。 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/font.css">
<!-- 引入xadmin框架的CSS样式文件用于实现该框架下特定的页面布局和样式效果。 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/xadmin.css">
<!-- 引入特定的灰色管理员主题的CSS样式文件从文件名推测是主题相关样式用于设置页面整体的主题风格使其呈现出灰色调的管理员界面风格这是一条注释对引入的这个文件作用做了简单说明。 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/theme2571.min.css"><%--灰色管理员主题 --%>
<!-- 引入jQuery库的JavaScript文件这是一个常用的JavaScript库用于简化DOM操作、事件处理等功能。 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!-- 引入layui框架的JavaScript核心文件layui是一个用于构建页面交互界面的前端框架。 -->
<script src="${pageContext.request.contextPath}/lib/layui/layui.js" charset="utf-8"></script>
<!-- 引入xadmin框架的JavaScript文件用于实现该框架相关的功能和交互效果。 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/xadmin.js"></script>
<script>
// 是否开启刷新记忆tab功能
// var is_remember = false;
// 上面这行代码定义了一个变量is_remember用于控制是否开启刷新记忆tab的功能但目前被注释掉了可能后续根据需求决定是否启用这个功能若启用则需要去掉注释并进行相应的逻辑实现。
</script>
</head>
<body class="index">
<!-- 顶部开始 -->
<div class="container">
<!-- 页面左上角的logo部分点击链接可以跳转到指定的网址这里是"http://ppdxzz.cn"),显示的文本是"皮皮的小猪仔",用于品牌展示或者作为返回首页等功能的入口(取决于具体业务逻辑)。 -->
<div class="logo">
<a href="http://ppdxzz.cn">皮皮的小猪仔</a></div>
<!-- 用于展开左侧栏的按钮部分,点击按钮(<a>标签包裹),图标(<i>标签应用特定的图标字体类,这里是"iconfont"并通过Unicode编码指定具体图标样式"&#xe699;"来显示展开图标会触发相应的展开左侧栏的操作具体操作可能在相关的JavaScript代码中实现比如显示隐藏左侧菜单的DOM元素等标题属性"展开左侧栏"用于鼠标悬停时提示用户该按钮的功能。 -->
<div class="left_open">
<a><i title="展开左侧栏" class="iconfont">&#xe699;</i></a>
</div>
<!-- 页面右上角的导航栏部分使用layui的导航组件layui-nav类lay-filter属性用于后续对导航栏进行一些筛选、事件绑定等操作虽然这里为空字符串但按照layui框架规范预留了该属性里面包含多个菜单项<li>标签表示一个菜单项)。 -->
<ul class="layui-nav right" lay-filter="">
<!-- 第一个菜单项,显示文本为"我的消息",点击后会展开二级菜单(通过<dl>和<dd>标签构建二级菜单结构),用于展示不同类型的消息相关选项。 -->
<li class="layui-nav-item">
<a href="javascript:;">我的消息</a>
<dl class="layui-nav-child">
@ -46,6 +58,7 @@
</dd>
</dl>
</li>
<!-- 第二个菜单项显示当前登录管理员的姓名通过表达式语言从会话范围获取adminInfo对象的name属性来展示点击后同样展开二级菜单提供个人信息查看、切换帐号、退出等功能选项。 -->
<li class="layui-nav-item">
<a href="javascript:;">${sessionScope.adminInfo.name}</a>
<dl class="layui-nav-child">
@ -58,6 +71,7 @@
<a href="${pageContext.request.contextPath}/loginOut">退出</a></dd>
</dl>
</li>
<!-- 第三个菜单项显示文本包含一个友情链接的图标通过layui-icon类以及特定的Unicode编码"&#xe64c;"来显示图标样式)和"友情链接"文字,点击后可跳转到指定的网址(这里是"http://ppdxzz.cn"),用于引导用户访问相关的友情链接页面。 -->
<li class="layui-nav-item to-index">
<a href="http://ppdxzz.cn"><i class="layui-icon">&#xe64c;</i>友情链接</a>
</li>
@ -69,22 +83,26 @@
<div class="left-nav">
<div id="side-nav">
<ul id="nav">
<!-- 使用JSTL的标签进行条件判断如果管理员的权限通过表达式语言从会话范围获取adminInfo对象的power属性大于2推测权限值越大权限越高大于2表示有较高权限比如超级管理员等则显示以下菜单项用于学生管理相关功能入口。 -->
<c:if test="${sessionScope.adminInfo.power > 2}">
<li>
<a href="javascript:;">
<i class="iconfont left-nav-li" lay-tips="学生管理">&#xe6b8;</i>
<cite>学生管理</cite>
<i class="iconfont nav_right">&#xe697;</i>
</a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('学生信息','${pageContext.request.contextPath}/student/findAll')">
<i class="iconfont">&#xe6a7;</i>
<cite>学生信息</cite></a>
</li>
</ul>
</li>
<li>
<a href="javascript:;">
<!-- 使用特定的图标字体类iconfont并通过Unicode编码指定图标样式"&#xe6b8;"来显示一个图标lay-tips属性用于鼠标悬停时提示用户该菜单项对应的功能是"学生管理"<cite>标签内显示菜单项的文本名称"学生管理",另一个图标("&#xe697;")可能用于表示展开收起子菜单等操作(具体由样式控制)。 -->
<i class="iconfont left-nav-li" lay-tips="学生管理">&#xe6b8;</i>
<cite>学生管理</cite>
<i class="iconfont nav_right">&#xe697;</i>
</a>
<ul class="sub-menu">
<li>
<!-- 通过调用xadmin框架提供的add_tab函数在xadmin.js中应该有定义添加一个名为"学生信息"的tab页点击该菜单项后会跳转到对应的URL通过表达式语言拼接出查找所有学生信息的接口路径"${pageContext.request.contextPath}/student/findAll"),用于展示学生信息列表等相关功能。 -->
<a onclick="xadmin.add_tab('学生信息','${pageContext.request.contextPath}/student/findAll')">
<i class="iconfont">&#xe6a7;</i>
<cite>学生信息</cite></a>
</li>
</ul>
</li>
</c:if>
<!-- 再次使用标签判断如果管理员权限等于2推测是普通管理员之类的角色则显示以下不同的学生管理相关菜单项其URL拼接了根据当前管理员姓名查找学生信息的参数可能用于普通管理员查看其负责管理的学生信息。 -->
<c:if test="${sessionScope.adminInfo.power == 2}">
<li>
<a href="javascript:;">
@ -101,25 +119,26 @@
</ul>
</li>
</c:if>
<!-- 类似前面的权限判断如果管理员权限大于2显示以下管理员管理相关的菜单项包含管理员列表查看以及权限管理目前权限管理点击调用power函数从后面定义的函数来看是提示功能暂未开放等功能入口。 -->
<c:if test="${sessionScope.adminInfo.power > 2}">
<li>
<a href="javascript:;">
<i class="iconfont left-nav-li" lay-tips="管理员管理">&#xe726;</i>
<cite>管理员管理</cite>
<i class="iconfont nav_right">&#xe697;</i></a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('管理员列表','${pageContext.request.contextPath}/findAllAdmin')">
<i class="iconfont">&#xe6a7;</i>
<cite>管理员列表</cite></a>
</li>
<li>
<a onclick="power()">
<i class="iconfont">&#xe6a7;</i>
<cite>权限管理</cite></a>
</li>
</ul>
</li>
<li>
<a href="javascript:;">
<i class="iconfont left-nav-li" lay-tips="管理员管理">&#xe726;</i>
<cite>管理员管理</cite>
<i class="iconfont nav_right">&#xe697;</i></a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('管理员列表','${pageContext.request.contextPath}/findAllAdmin')">
<i class="iconfont">&#xe6a7;</i>
<cite>管理员列表</cite></a>
</li>
<li>
<a onclick="power()">
<i class="iconfont">&#xe6a7;</i>
<cite>权限管理</cite></a>
</li>
</ul>
</li>
</c:if>
<li>
<a href="javascript:;">
@ -127,6 +146,7 @@
<cite>宿舍管理</cite>
<i class="iconfont nav_right">&#xe697;</i></a>
<ul class="sub-menu">
<!-- 根据不同的管理员权限显示不同的宿舍管理相关菜单项。如果权限大于2高权限可以查看所有宿舍列表点击后通过xadmin框架的add_tab函数添加名为"宿舍列表"的tab页并跳转到查找所有宿舍信息的接口路径。 -->
<c:if test="${sessionScope.adminInfo.power > 2}">
<li>
<a onclick="xadmin.add_tab('宿舍列表','${pageContext.request.contextPath}/dorm/findAll')">
@ -134,7 +154,8 @@
<cite>宿舍列表</cite></a>
</li>
</c:if>
<%--普通管理员只能看到自己所带宿舍的人员信息--%>
<!-- 如果权限等于2普通管理员则查看自己所带宿舍的人员信息URL中拼接了根据当前管理员的唯一标识uid查找宿舍信息的参数通过add_tab函数添加tab页来展示相关信息。 -->
<%--普通管理员只能看到自己所带宿舍的人员信息--%>
<c:if test="${sessionScope.adminInfo.power == 2}">
<li>
<a onclick="xadmin.add_tab('宿舍列表','${pageContext.request.contextPath}/dorm/byTeacher?uid=${sessionScope.adminInfo.uid}')">
@ -142,7 +163,8 @@
<cite>宿舍列表</cite></a>
</li>
</c:if>
<%--宿舍长只能看到自己所在宿舍的人员信息--%>
<!-- 如果权限等于1宿舍长则只能看到自己所在宿舍的人员信息以及宿舍信息分别通过不同的URL拼接了管理员的uid参数和add_tab函数来添加相应的tab页展示对应信息。 -->
<%--宿舍长只能看到自己所在宿舍的人员信息--%>
<c:if test="${sessionScope.adminInfo.power == 1}">
<li>
<a onclick="xadmin.add_tab('宿舍信息','${pageContext.request.contextPath}/dorm/look?uid=${sessionScope.adminInfo.uid}')">
@ -157,51 +179,52 @@
</c:if>
</ul>
</li>
<!-- 如果管理员权限大于2显示以下访客管理相关的菜单项包含访客信息查看、来访登记目前点击提示暂不支持网页端登记通过tip函数实现提示功能、访客日志查看等功能入口每个功能通过add_tab函数添加相应的tab页并跳转到对应的接口路径有的还拼接了分页等参数。 -->
<c:if test="${sessionScope.adminInfo.power > 2}">
<li>
<a href="javascript:;">
<i class="iconfont left-nav-li" lay-tips="访客管理">&#xe6f5;</i>
<cite>访客管理</cite>
<i class="iconfont nav_right">&#xe6f5;</i></a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('访客信息','${pageContext.request.contextPath}/visitor/findAll')">
<i class="iconfont">&#xe6a7;</i>
<cite>访客信息</cite>
</a>
</li>
<li>
<a onclick="tip()" href="javascript:;">
<i class="iconfont">&#xe6a7;</i>
<cite>来访登记(手机端)</cite>
</a>
</li>
<li>
<a onclick="xadmin.add_tab('访客日志','${pageContext.request.contextPath}/visitor/log?page=1&size=10')">
<i class="iconfont">&#xe6a7;</i>
<cite>访客日志</cite>
</a>
</li>
</ul>
</li>
<li>
<a href="javascript:;">
<i class="iconfont left-nav-li" lay-tips="系统统计">&#xe6ce;</i>
<cite>系统统计</cite>
<i class="iconfont nav_right">&#xe697;</i></a>
<ul class="sub-menu">
<li>
<a onclick="power()">
<i class="iconfont">&#xe6a7;</i>
<cite>曲线统计</cite></a>
</li>
<li>
<a onclick="power()">
<i class="iconfont">&#xe6a7;</i>
<cite>实时流量统计</cite></a>
</li>
</ul>
</li>
<li>
<a href="javascript:;">
<i class="iconfont left-nav-li" lay-tips="访客管理">&#xe6f5;</i>
<cite>访客管理</cite>
<i class="iconfont nav_right">&#xe6f5;</i></a>
<ul class="sub-menu">
<li>
<a onclick="xadmin.add_tab('访客信息','${pageContext.request.contextPath}/visitor/findAll')">
<i class="iconfont">&#xe6a7;</i>
<cite>访客信息</cite>
</a>
</li>
<li>
<a onclick="tip()" href="javascript:;">
<i class="iconfont">&#xe6a7;</i>
<cite>来访登记(手机端)</cite>
</a>
</li>
<li>
<a onclick="xadmin.add_tab('访客日志','${pageContext.request.contextPath}/visitor/log?page=1&size=10')">
<i class="iconfont">&#xe6a7;</i>
<cite>访客日志</cite>
</a>
</li>
</ul>
</li>
<li>
<a href="javascript:;">
<i class="iconfont left-nav-li" lay-tips="系统统计">&#xe6ce;</i>
<cite>系统统计</cite>
<i class="iconfont nav_right">&#xe697;</i></a>
<ul class="sub-menu">
<li>
<a onclick="power()">
<i class="iconfont">&#xe6a7;</i>
<cite>曲线统计</cite></a>
</li>
<li>
<a onclick="power()">
<i class="iconfont">&#xe6a7;</i>
<cite>实时流量统计</cite></a>
</li>
</ul>
</li>
</c:if>
</ul>
</div>
@ -218,6 +241,7 @@
</ul>
<div class="layui-tab-content"><%--中间的空白面板--%>
<div class="layui-tab-item layui-show o_div" >
<!-- 根据管理员权限判断如果权限大于2通过>标签引入名为"welcome.jsp"的页面,可能用于展示高权限管理员登录后的欢迎页面或者一些重要信息等内容,具体取决于"welcome.jsp"页面的实现。 -->
<c:if test="${sessionScope.adminInfo.power > 2}">
<jsp:include page="welcome.jsp"></jsp:include>
</c:if>
@ -234,13 +258,5 @@
<!-- 底部结束 -->
</body>
<script>
function tip() {
layer.msg('目前暂不支持网页端登记');
return false;
}
function power() {
layer.msg('该功能暂未开放');
return false;
}
</script>
</html>
function tip() {}
</script>

@ -6,74 +6,191 @@
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!--
设置该JSP页面的相关属性。
contentType属性指定了页面响应的内容类型为"text/html"即HTML格式同时将字符编码设置为UTF-8这样能保证页面中的中文等特殊字符可以正确显示避免出现乱码情况。
language属性表明该页面使用Java语言来编写服务器端的代码逻辑例如使用Java代码片段或者基于Java的标签库等
-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<!--
引入JSTLJavaServer Pages Standard Tag Library的核心标签库设置前缀为“c”。通过这个标签库我们可以在JSP页面中方便地使用如条件判断、循环遍历等功能实现更灵活的页面逻辑控制。
-->
<html>
<head>
<!--
设置页面的字符编码为UTF-8确保浏览器能正确解析并显示页面中的各种字符防止出现乱码现象虽然在上面的page指令中已经设置了字符编码但这里再次明确一下也是一种良好的习惯保证兼容性。
-->
<meta charset="UTF-8" />
<!--
设置页面渲染所使用的引擎为webkit让页面在支持webkit的浏览器中按照该引擎的规则进行渲染有助于呈现出期望的页面样式和交互效果针对移动端页面webkit引擎能提供较好的兼容性和性能表现。
-->
<meta name="renderer" content="webkit" />
<!--
设置页面的视口viewport属性用于控制页面在移动端设备上的显示效果。
width=device-width表示页面宽度跟随设备宽度自适应initial-scale=1.0设置初始缩放比例为1.0maximum-scale=1.0限制最大缩放比例为1.0user-scalable=0表示禁止用户手动缩放页面uc-fitscreen=yes用于适配UC浏览器的屏幕显示特定浏览器相关设置这些设置可以让页面在移动端有合适的展示效果适配不同屏幕尺寸的设备。
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0,uc-fitscreen=yes" />
<!--
设置页面在iOS系统下的Web应用相关属性content="yes"表示该网页可以作为一个独立的Web应用在iOS设备的主屏幕上以全屏模式运行提供类似原生应用的体验。
-->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!--
设置iOS系统下Web应用状态栏的样式为黑色用于统一页面在iOS设备上的显示风格使其更加美观和符合视觉习惯。
-->
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<!--
设置禁止页面自动识别电话号码,避免页面中的数字被误识别为电话号码并添加点击拨号的链接等情况,保持页面内容的原始展示意图。
-->
<meta name="format-detection" content="telephone=no" />
<!--
设置页面的标题,这个标题通常会显示在浏览器的标签页上,用于标识当前页面的主题内容,此处标题设置为“来访登记”,清晰地表明了该页面的主要功能是进行来访登记操作。
-->
<title>来访登记</title>
<!-- miniMObile.css、js -->
<!--
引入miniMObile框架的CSS样式文件通过EL表达式 "${pageContext.request.contextPath}/css/miniMobile.css" 来指定样式文件的路径。
"${pageContext.request.contextPath}" 会获取当前Web应用的上下文路径即项目部署后的根路径部分然后拼接上相对路径 "/css/miniMobile.css"这样就能准确地找到并应用miniMObile框架提供的样式使页面具有相应的布局和外观效果。
-->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/miniMobile.css"/>
<!--
引入jQuery库的JavaScript文件路径同样通过EL表达式 "${pageContext.request.contextPath}/js/jquery-3.1.1.js" 来确定将其引入到页面中使得可以使用jQuery提供的各种强大的DOM操作、事件处理、AJAX等功能方便开发页面交互效果。
-->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!--
引入layer弹出层插件的JavaScript文件其路径为 "${pageContext.request.contextPath}/layer/layer.js"layer插件常用于在页面中创建各种美观且交互友好的弹出层效果比如提示框、确认框、加载层等增强页面的用户交互体验这里主要用于显示一些提示信息给用户。
-->
<script type="text/javascript" src="${pageContext.request.contextPath}/layer/layer.js"></script>
<!--
引入zepto.min.js文件zepto是一个轻量级的JavaScript库与jQuery类似提供了简洁易用的DOM操作、事件处理等功能常用于移动端页面开发它在文件大小上相对更轻量适合移动端对性能和资源占用有要求的场景这里引入可能是为了在页面中使用它的一些特性来实现交互功能。
-->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/zepto.min.js"></script>
<!--
引入miniMobile.js文件这应该是与前面引入的miniMobile.css配套的JavaScript文件可能包含了miniMObile框架中各种组件或功能所依赖的交互逻辑用于实现页面中基于该框架的一些特定交互效果或业务逻辑。
-->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/miniMobile.js"></script>
<!-- mobileSelect -->
<!--
引入mobileSelect组件的CSS样式文件用于为页面中的下拉选择组件可能是自定义的具有更丰富功能的选择器提供样式使其在页面上呈现出特定的外观风格通过指定路径 "${pageContext.request.contextPath}/css/mobileSelect.css" 来准确引入该样式文件。
-->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/mobileSelect.css">
<!--
引入mobileSelect组件的JavaScript文件该文件包含了mobileSelect组件实现下拉选择等交互功能的具体逻辑代码路径为 "${pageContext.request.contextPath}/js/mobileSelect.js",引入后可在页面中使用该组件来实现更友好的选择操作界面。
-->
<script src="${pageContext.request.contextPath}/js/mobileSelect.js" type="text/javascript"></script>
<!-- noUiSlider -->
<!--
引入noUiSlider组件的CSS样式文件noUiSlider通常用于在页面中创建滑块组件用于选择数值范围等交互操作这里引入其样式文件 "${pageContext.request.contextPath}/css/nouislider.css" 是为了给该组件应用相应的样式,使其在页面上正确显示外观。
-->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/nouislider.css" />
<!-- switchery -->
<!--
引入switchery组件的CSS样式文件switchery一般用于创建开关样式的交互组件通过引入 "${pageContext.request.contextPath}/css/switchery.css" 样式文件,能让该组件在页面上呈现出对应的样式效果,方便用户进行开关操作等交互。
-->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/switchery.css"/>
<!-- iconfont -->
<!--
引入iconfont.css文件这通常是用于引入自定义的图标字体文件通过字体文件来展示各种图标相比于传统的图片图标字体图标在缩放、修改颜色等方面更方便灵活且能减少页面加载的图片资源数量提高性能这里通过指定路径 "${pageContext.request.contextPath}/css/iconfont.css" 来引入对应的图标字体样式文件。
-->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/iconfont.css" />
<!-- animate.css -->
<!--
引入animate.css文件这是一个非常流行的CSS动画库通过链接 "https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.css" 从CDN内容分发网络引入该文件它提供了大量预定义的CSS动画类可以方便地应用到页面元素上实现各种酷炫的动画效果增强页面的视觉吸引力。
-->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.css" />
</head>
<body class="pb12 fadeIn animated">
<header class="formheader w75 h8 f30 color6 bg-color-info" style="text-align: center;">
</head>
<body class="pb12 fadeIn animated">
<!--
创建一个页面头部header元素应用了多个样式类如 "formheader" 应该是自定义的用于头部样式的类,"w75" 可能表示宽度占父容器的75%(具体取决于样式定义),"h8" 可能表示高度相关的设置(同样依赖具体样式定义),"f30" 大概率是设置字体大小为30单位可能是像素等由样式决定"color6" 和 "bg-color-info" 分别用于设置文本颜色和背景颜色这些颜色类的具体颜色值由对应的CSS文件定义同时通过内联样式 "text-align: center;" 设置文本在头部元素内水平居中显示,该头部元素用于展示页面的主要标题“学生来访登记”。
-->
<header class="formheader w75 h8 f30 color6 bg-color-info" style="text-align: center;">
学生来访登记
</header>
<style>
</header>
<style>
.formheader {
line-height: 0.7rem;
line-height: 0.7rem;
/*
设置头部元素(.formheader类的行高为0.7rem行高用于控制文本行之间的垂直间距合理设置行高可以让文本在元素内看起来更加整齐、美观这里使用相对单位rem能更好地根据页面根元素的字体大小进行自适应调整。
*/
}
.formheader span {
display: inline-block;
display: inline-block;
/*
设置头部元素内的<span>子元素以行内块级元素inline-block方式显示这样既可以像行内元素一样在一行内排列又能像块级元素一样设置宽度、高度等样式属性方便对头部内的特定元素进行布局和样式调整。
*/
}
.formheader input {
border: none;
border: none;
/*
设置头部元素内的<input>输入框元素去除边框样式,使其外观更加简洁,可能是为了符合页面整体的设计风格,避免输入框的边框影响视觉效果。
*/
}
</style>
<div class="p3 f30 f30 w75">
</style>
<!--
创建一个包含内容的容器div元素应用了多个样式类"p3" 可能表示该元素具有一定的内边距padding设置具体数值由样式定义"f30" 大概率是设置字体大小为30"w75" 可能表示宽度占父容器的75%,用于在页面中划分出一块用于放置来访登记表单内容的区域,使其在页面上有合适的布局位置和大小。
-->
<div class="p3 f30 f30 w75">
<!--
创建一个HTML的表单form元素用于收集用户输入的来访登记相关信息并将这些信息提交到服务器端进行处理。
action属性通过EL表达式 "${pageContext.request.contextPath}/visitor/addLogin" 指定了表单提交的目标URL即当用户点击提交按钮后表单数据将被发送到该路径对应的服务器端接口进行处理这里应该是处理来访登记的业务逻辑接口
method属性设置为"post"表示使用POST方法提交表单数据相对GET方法POST更适合用于提交包含敏感信息或者大量数据的表单因为数据会放在请求体中而不是URL上更加安全且数据量限制相对较小。
name属性设置为"myform"用于在JavaScript等代码中可以通过这个名称来引用该表单元素方便进行一些表单相关的操作如提交表单等
-->
<form action="${pageContext.request.contextPath}/visitor/addLogin" method="post" name="myform">
<div class="pt2 pb2">
姓名:
<input type="text" class="w59 form-control" name="name" id="name" placeholder="输入姓名" maxlength="10" />
</div>
<div>
学号:
<input type="text" class="w59 form-control" name="sno" id="sno" min="5" max="20" placeholder="输入学号" />
</div>
<div class="pt2 pb2">
手机:
<input type="text" class="w59 form-control" name="phone" id="phone" placeholder="输入联系方式" />
</div>
<div class="pt2 pb2">
楼宇:
<!--
创建一个包含内容的容器div元素应用了 "pt2 pb2" 样式类(可能表示有顶部和底部的内边距设置,具体由样式定义),用于在表单内划分出一个区域来放置姓名相关的输入框和提示文本,使页面布局更加清晰、有条理。
-->
<div class="pt2 pb2">
姓名:
<!--
创建一个文本输入框input元素类型type设置为"text",表示这是一个普通的文本输入框,用户可以在里面输入文字信息。
class属性应用了 "w59 form-control" 样式类,"w59" 可能用于设置输入框的宽度(具体由样式定义),"form-control" 通常是一些框架如Bootstrap等类似框架风格中用于统一输入框样式的类使其具有一定的外观风格如边框、圆角等效果。
name属性设置为"name",这个名称会作为表单数据提交到服务器端时的参数名,服务器端可以通过这个参数名获取用户输入的姓名信息。
id属性设置为"name"用于在JavaScript代码中通过该ID来唯一标识这个输入框元素方便获取其输入的值或者进行其他操作如验证输入内容等
placeholder属性设置为"输入姓名",用于在输入框内显示一个提示性的文本,当输入框为空时,提示用户应该输入什么内容,提高用户体验。
maxlength属性设置为"10"用于限制用户输入的字符长度最多为10个字符避免用户输入过长的姓名导致数据不符合要求或者页面显示异常等情况。
-->
<input type="text" class="w59 form-control" name="name" id="name" placeholder="输入姓名" maxlength="10" />
</div>
<!--
创建一个包含内容的容器div元素用于在表单内划分出一个区域来放置学号相关的输入框和提示文本使页面布局清晰方便用户区分不同的输入项。
-->
<div>
学号:
<!--
创建一个文本输入框input元素类型为"text",表示用于输入文本内容。
应用 "w59 form-control" 样式类来设置输入框的外观样式和宽度等属性,使其与页面整体风格统一。
name属性设置为"sno",作为提交到服务器端的参数名,方便服务器获取用户输入的学号信息。
id属性设置为"sno"用于在JavaScript代码中通过该ID来操作这个输入框元素比如获取输入的值进行验证等操作。
min和max属性分别设置为"5"和"20"这里可能是用于限制学号的长度范围不过在HTML5中对于普通文本输入框这种限制的实际效果可能有限更多的是一种提示作用真正的验证通常还需要在JavaScript或者服务器端进一步处理表示学号的长度应该在5到20个字符之间。
placeholder属性设置为"输入学号",在输入框为空时显示提示文本,引导用户输入正确的内容。
-->
<input type="text" class="w59 form-control" name="sno" id="sno" min="5" max="20" placeholder="输入学号" />
</div>
<!--
创建一个包含内容的容器div元素应用 "pt2 pb2" 样式类,在表单内划分出一个区域来放置手机号码相关的输入框和提示文本,使页面布局更加合理,便于用户操作和查看。
-->
<div class="pt2 pb2">
手机:
<!--
创建一个文本输入框input元素类型为"text",用于输入手机号码信息。
应用 "w59 form-control" 样式类来设置输入框的样式和宽度等,使其符合页面整体的视觉风格。
name属性设置为"phone",作为提交到服务器端的参数名,以便服务器获取用户输入的手机号码内容。
id属性设置为"phone"方便在JavaScript代码中通过该ID对这个输入框进行操作比如获取输入的值进行合法性验证等操作。
placeholder属性设置为"输入联系方式",在输入框为空时显示提示文本,引导用户输入手机号码信息。
-->
<input type="text" class="w59 form-control" name="phone" id="phone" placeholder="输入联系方式" />
</div>
<!--
创建一个包含内容的容器div元素应用 "pt2 pb2" 样式类在表单内划分出一个区域来放置楼宇相关的下拉选择框select和提示文本使用下拉选择框可以提供预定义的选项供用户选择方便用户操作且能保证输入数据的规范性。
-->
<div class="pt2 pb2">
楼宇:
<!-- 显示“楼宇”字样作为提示文本,告知用户接下来的选择框对应的内容含义 -->
<select class="w59 form-control" id="place" name="place">
<!-- 创建一个下拉选择框select元素应用 "w59 form-control" 样式类来控制其宽度及样式外观使其符合页面整体风格id 设置为 "place" 用于在 JavaScript 中通过该 ID 来获取其选中的值name 同样为 "place",以便表单提交时以此作为参数名向服务器端传递用户选择的楼宇信息 -->
<option value="西六一楼">西六一楼</option>
<!-- 创建一个下拉选项option元素其 value 属性值为 "西六一楼",表示当用户选择该项时,实际传递给服务器端的值就是 "西六一楼",显示的文本内容为 "西六一楼",供用户直观看到可选择的具体楼宇名称 -->
<option value="西六二楼">西六二楼</option>
<option value="西六三楼">西六三楼</option>
<option value="西七一楼">西七一楼</option>
<option value="西七二楼" selected="selected">西七二楼</option>
<!-- 此选项设置了 "selected" 属性,表示该选项在页面加载时默认被选中,即初始状态下用户看到的已选中的楼宇是 "西七二楼" -->
<option value="西七三楼">西七三楼</option>
<option value="西十二一楼">西十二一楼</option>
<option value="西十二二楼">西十二二楼</option>
@ -84,34 +201,53 @@
</select>
</div>
<div class="mt4 mb4">
<!-- 创建一个带有类名 "mt4 mb4" 的 div 容器推测可能是设置了顶部mt4和底部mb4的外边距用于在页面中进一步划分布局区域此处用于放置“备注”相关的输入框 -->
备注:
<!-- 显示“备注”字样作为提示文本,提示用户接下来的输入框用于填写访问原因等备注信息 -->
<input class="w59 h20 form-control" value="公事" id="visit_result" name="visit_result" placeholder="访问原因" />
<!-- 创建一个文本输入框input元素应用 "w59 h20 form-control" 样式类来控制其宽度、高度及样式外观使其与页面整体风格统一初始值value设置为 "公事"id 设置为 "visit_result" 用于在 JavaScript 中通过该 ID 操作该输入框name 为 "visit_result" 以便表单提交时以此作为参数名向服务器端传递用户输入的备注信息placeholder 属性设置为 "访问原因",当输入框为空时显示此提示文本引导用户输入内容 -->
</div>
<div class="t-c mt5">
<!-- 创建一个带有类名 "t-c mt5" 的 div 容器,推测 "t-c" 可能表示文本居中text-align: center样式相关设置"mt5" 可能是设置了顶部外边距,用于在页面中定位放置提交按钮的位置,使其在页面上有合适的布局呈现 -->
<input type="button" onclick="toCheck()" id="sub-btn" class="btn f30 btn-primary radius10 p2 w50" value="提交登记" />
<!-- 创建一个按钮类型type 为 "button")的输入框元素,点击时会触发名为 "toCheck" 的 JavaScript 函数(通过 onclick 属性指定),设置了 id 为 "sub-btn" 方便在 JavaScript 或 CSS 中对该按钮进行样式控制或操作,应用 "btn f30 btn-primary radius10 p2 w50" 样式类来赋予其按钮外观样式(比如颜色、圆角、内边距、宽度等样式效果),按钮显示的文本内容为 "提交登记",告知用户点击该按钮的作用 -->
</div>
</form>
</div>
<script>
function toCheck() {
var name = $("#name").val().trim();
var sno = $("#sno").val().trim();
var phone = $("#phone").val().trim();
var place = $("#place").val().trim();
var visit_result = $("#visit_result").val().trim();
if (name == null || sno == null || phone == null || place == null || visit_result == null
|| name.length == 0 || sno.length == 0 || phone.length == 0 || place.length == 0 || visit_result.length == 0) {
layer.msg('不能为空,请输入信息...');
return false;
</div>
<script>
function toCheck() {
// 定义一个名为 toCheck 的 JavaScript 函数,用于在点击提交按钮时进行表单数据的验证以及提交操作
var name = $("#name").val().trim();
// 通过 jQuery 选择器($)选取 id 为 "name" 的元素即前面的姓名输入框获取其输入的值val 方法),并使用 trim 方法去除输入值前后可能存在的空白字符,将处理后的结果存储在变量 name 中
var sno = $("#sno").val().trim();
// 同理,获取 id 为 "sno" 的学号输入框的值,去除空白字符后存储在变量 sno 中
var phone = $("#phone").val().trim();
// 获取 id 为 "phone" 的手机号码输入框的值,去除空白字符后存储在变量 phone 中
var place = $("#place").val().trim();
// 获取 id 为 "place" 的楼宇选择框选中项的值(即用户选择的楼宇名称),去除空白字符后存储在变量 place 中
var visit_result = $("#visit_result").val().trim();
// 获取 id 为 "visit_result" 的备注输入框的值,去除空白字符后存储在变量 visit_result 中
if (name == null || sno == null || phone == null || place == null || visit_result == null
|| name.length == 0 || sno.length == 0 || phone.length == 0 || place.length == 0 || visit_result.length == 0) {
// 进行条件判断,如果获取到的任何一个输入框的值为 null可能是未获取到元素等情况或者长度为 0即用户未输入任何内容则执行以下代码块
layer.msg('不能为空,请输入信息...');
// 使用 layer 插件弹出一个提示框,显示提示信息 "不能为空,请输入信息...",告知用户需要填写完整表单信息
return false;
// 返回 false阻止表单的提交操作因为此时表单数据不完整不符合提交要求
}
document.myform.submit();
// 如果所有输入框都有值(通过前面的条件判断),则通过 JavaScript 的原生方式获取名为 "myform" 的表单元素(前面在 form 标签中设置了 name 属性为 "myform"),并调用其 submit 方法来提交表单数据到服务器端,触发服务器端对应的处理逻辑(由 form 表单的 action 属性指定的 URL 对应的接口来处理)
}
document.myform.submit();
}
if (${logout_msg != null && !(logout_msg.trim().equals(""))}) {
layer.msg(${logout_msg});
}
if (${error_msg != null && !("".trim().equals(error_msg))}) {
layer.msg(${error_msg});
}
</script>
</body>
</html>
if (${logout_msg!= null &&!(logout_msg.trim().equals(""))}) {
// 使用 JSP 表达式语言EL进行条件判断判断名为 logout_msg 的变量是否不为 null 并且去除两端空白字符后不为空字符串,如果满足该条件,则执行以下代码块,此处可能是用于处理注销相关的提示信息显示逻辑
layer.msg(${logout_msg});
// 使用 layer 插件弹出提示框,显示 logout_msg 变量对应的消息内容,向用户展示相关提示信息(例如注销成功或失败等提示)
}
if (${error_msg!= null &&!("".trim().equals(error_msg))}) {
// 同样使用 EL 表达式进行条件判断,判断名为 error_msg 的变量是否不为 null 并且去除两端空白字符后不为空字符串,如果满足条件,则执行以下代码块,此处可能是用于处理其他错误相关的提示信息显示逻辑
layer.msg(${error_msg});
// 使用 layer 插件弹出提示框,显示 error_msg 变量对应的消息内容,向用户展示相应的错误提示信息(例如表单提交失败等错误提示)
}
</script>
</body>
</html>

@ -1,33 +1,19 @@
<%--
Created by IntelliJ IDEA.
User: user
Date: 2020/2/17
Time: 12:33
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<!-- 引入Bootstrap样式表 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/layer/layer.js"></script>
</head>
<body>
<form>
<!-- 创建一个表格,用于输入学生信息 -->
<table class="table" style="width: 100%;text-align: center;">
<tbody>
<tr>
<td>
<label for="name">姓名</label>
</td>
<td>
<input type="text" class="form-control" id="name" name="name" maxlength="10" required>
</td>
<td>
<label for="sex">性别</label>
</td>
<td><label for="name">姓名</label></td>
<td><input type="text" class="form-control" id="name" name="name" maxlength="10" required></td>
<td><label for="sex">性别</label></td>
<td>
<select class="form-control" name="sex" id="sex">
<option value="男" selected>男</option>
@ -36,28 +22,16 @@
</td>
</tr>
<tr>
<td>
<label for="sno">学号</label>
</td>
<td>
<input type="text" name="sno" class="form-control" id="sno" aria-describedby="textHelp" maxlength="20" required>
</td>
<td>
<label for="stu_class">班级</label>
</td>
<td>
<input type="text" name="stu_class" class="form-control" id="stu_class" maxlength="30" required>
</td>
<td><label for="sno">学号</label></td>
<td><input type="text" name="sno" class="form-control" id="sno" aria-describedby="textHelp" maxlength="20" required></td>
<td><label for="stu_class">班级</label></td>
<td><input type="text" name="stu_class" class="form-control" id="stu_class" maxlength="30" required></td>
</tr>
<tr>
<td><label for="phone">联系方式</label></td>
<td>
<input type="text" name="phone" class="form-control" id="phone" minlength="11" maxlength="11" required>
</td>
<td><input type="text" name="phone" class="form-control" id="phone" minlength="11" maxlength="11" required></td>
<td><label for="place">家庭住址</label></td>
<td>
<input type="text" placeholder="请输入家庭详细地址" name="place" class="form-control" id="place" maxlength="30" required>
</td>
<td><input type="text" placeholder="请输入家庭详细地址" name="place" class="form-control" id="place" maxlength="30" required></td>
</tr>
<tr>
<td><label for="dorm1">宿舍号</label></td>
@ -73,49 +47,46 @@
<option value="A" selected>A</option>
<option value="B">B</option>
</select></td>
<td>
<input type="text" name="dorm3" placeholder="请直接输入宿舍号" maxlength="3" class="form-control" id="dorm3" required>
</td>
<td><input type="text" name="dorm3" placeholder="请直接输入宿舍号" maxlength="3" class="form-control" id="dorm3" required></td>
</tr>
<tr>
<td><label for="teacher">育人导师</label></td>
<td>
<select class="form-control" name="teacher" id="teacher">
<option value="小李" selected>小李</option>
<option value="小王">小王</option>
<option value="小赵">小赵</option>
<option value="小飞">小飞</option>
<option value="小张">小张</option>
</select>
</td>
<td><select class="form-control" name="teacher" id="teacher">
<option value="小李" selected>小李</option>
<option value="小王">小王</option>
<option value="小赵">小赵</option>
<option value="小飞">小飞</option>
<option value="小张">小张</option>
</select></td>
<td><label for="status">状态</label></td>
<td>
<select class="form-control" name="status" id="status">
<option value="0" selected>禁用</option>
<option value="1">激活</option>
</select>
</td>
<td><select class="form-control" name="status" id="status">
<option value="0" selected>禁用</option>
<option value="1">激活</option>
</select></td>
</tr>
<tr>
<td colspan="4">
<!-- 确认添加按钮 -->
<button type="button" id="add-student" class="btn btn-primary">确认添加</button>
<a href="javascript:window.history.back(-1)" target="_self" class="btn btn-default">返回列表</a>
<!-- 返回列表链接 -->
<a href="window.history.back(-1)" target="_self" class="btn btn-default">返回列表</a>
</td>
</tr>
</tbody>
</table>
</form>
<!-- jQuery脚本 -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(function () {
//ajax校验学号已被注册
// ajax校验学号已被注册
$("#sno").change(function () {
//取sno的值
var sno = $(this).val();
//ajax异步请求
var sno = $(this).val(); // 获取学号的值
$.get("${pageContext.request.contextPath}/student/isExist",{"sno":sno},function (date) {
//$(".error").html(msg);
if (date) {
layer.msg('学号已被注册,请重新输入!');
layer.msg('学号已被注册,请重新输入!'); // 提示学号已被注册
return false;
}
});
@ -133,21 +104,18 @@
var status = $("#status").val().trim();
if (name == 0 || sex == 0 || sno == 0 || stu_class == 0 || phone == 0 || place == 0 || dorm3 == 0 || teacher == 0) {
layer.msg('字段不能为空');
layer.msg('字段不能为空'); // 提示字段不能为空
return false;
}
if (${sessionScope.adminInfo.power < 1}) {
layer.msg('对不起,您权限不足');
layer.msg('对不起,您权限不足'); // 提示权限不足
return false;
}
var d1 = $("#dorm1").val();
var d2 = $("#dorm2").val();
var dorm_id = d1+""+d2+""+dorm3;
//alert(dorm_id);
var dorm_id = d1+""+d2+""+dorm3; // 拼接宿舍ID
$.ajax({
url: "${pageContext.request.contextPath}/student/add",//要请求的服务器url
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
//data:{method:"ajaxTest",val:value},
url: "${pageContext.request.contextPath}/student/add", // 请求的URL
data: {
name:name,
sex:sex,
@ -159,33 +127,34 @@
teacher:teacher,
status:status
},
type: "POST", //请求方式为POST
dataType: "json",
success:function(result){ //这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
//alert(result);
type: "POST", // 请求方式为POST
dataType: "json", // 数据类型为JSON
success:function(result){ // 成功回调函数
if(result){
layer.msg('添加成功!');
layer.msg('添加成功!'); // 提示添加成功
if (${sessionScope.adminInfo.power == 1}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';},2000);
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';},2000); // 跳转到宿舍管理员页面
return false;
}
if (${sessionScope.adminInfo.power == 2}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';},2000);
return flase;
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';},2000); // 跳转到学生查询页面
return false;
}
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/student/findAll';},2000);
}else {
layer.msg('添加失败,请联系管理员');
if (${sessionScope.adminInfo.power == 1}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';},2000);
layer.msg('添加失败,请联系管理员'); // 如果操作失败,显示错误消息
if (${sessionScope.adminInfo.power == 1}) { // 根据用户权限不同,跳转到不同的页面
// 宿舍管理员权限2秒后跳转到宿舍管理员页面
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';}, 2000);
return false;
}
if (${sessionScope.adminInfo.power == 2}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';},2000);
return flase;
if (${sessionScope.adminInfo.power == 2}) { // 学生权限2秒后跳转到学生查询页面
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';}, 2000);
return false; //
}
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/student/findAll';},2000);
}
// 默认情况下2秒后跳转到学生列表页面
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/student/findAll';}, 2000);}
}
});
});

@ -1,11 +1,4 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: user
Date: 2020/2/17
Time: 12:34
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
@ -159,48 +152,49 @@
//这是一个对象表示请求的参数两个参数method=ajax&val=xxx服务器可以通过request.getParameter()来获取
//data:{method:"ajaxTest",val:value},
data: {
id:id,
name:name,
sex:sex,
id: id,
name: name,
sex: sex,
sno: sno,
stu_class:stu_class,
stu_class: stu_class,
phone: phone,
place: place,
dorm_id:dorm_id,
teacher:teacher,
status:status
dorm_id: dorm_id,
teacher: teacher,
status: status
},
type: "POST", //请求方式为POST
dataType: "json",
success:function(result){ //这个方法会在服务器执行成功时被调用 参数data就是服务器返回的值(现在是json类型)
//alert(result);
if(result){
layer.msg('修改成功');
type: "POST", // 请求方式为POST
dataType: "json", // 期望从服务器接收的数据类型为JSON
success: function(result) { // 成功回调函数参数result是服务器返回的数据
if (result) {
layer.msg('修改成功'); // 显示修改成功的提示消息
// 根据用户权限重定向到不同的页面
if (${sessionScope.adminInfo.power == 1}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';},2000);
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';}, 2000);
return false;
}
if (${sessionScope.adminInfo.power == 2}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';},2000);
return flase;
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';}, 2000);
return false; // 注意这里应该是 return false; 而不是 return flase;
}
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/student/findAll';},2000);
}else {
layer.msg('修改失败,请联系管理员');
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/student/findAll';}, 2000);
} else {
layer.msg('修改失败,请联系管理员'); // 显示修改失败的提示消息
// 根据用户权限重定向到不同的页面
if (${sessionScope.adminInfo.power == 1}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';},2000);
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/dorm/byDorm_leader?uid=${sessionScope.adminInfo.uid}';}, 2000);
return false;
}
if (${sessionScope.adminInfo.power == 2}) {
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';},2000);
return flase;
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}';}, 2000);
return false; // 注意这里应该是 return false; 而不是 return flase;
}
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/student/findAll';},2000);
}
setTimeout(function () {window.location.href = '${pageContext.request.contextPath}/student/findAll';}, 2000);}
}
});
});
});
</script>
</body>
</html>

@ -1,10 +1,3 @@
<%--
Created by IntelliJ IDEA.
User: user
Date: 2020/2/10
Time: 21:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html class="x-admin-sm">
@ -13,36 +6,37 @@
<title></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- 引入外部CSS文件 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/font.css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/xadmin.css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<script src="${pageContext.request.contextPath}/lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/xadmin.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
<script type="text/javascript">
// 定义一个函数用于改变每页显示条数
function changePageSize() {
//获取下拉框的值
// 获取下拉框的值
var pageSize = $("#changePageSize").val();
//向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/student/findAll?page=1&size="+ pageSize;
// 向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/student/findAll?page=1&size=" + pageSize;
}
// 绑定搜索按钮点击事件
$("#serarch_btn").click(function () {
var keyword = $("#keyword").val();
location.href="${pageContext.request.contextPath}/student/findAll?page=1&size=5&keyword="+keyword;
var keyword = $("#keyword").val(); // 获取输入框中的关键字
location.href = "${pageContext.request.contextPath}/student/findAll?page=1&size=5&keyword=" + keyword; // 向服务器发送请求,根据关键字搜索
});
// 绑定刷新按钮点击事件
$("#refresh").click(function () {
$("#myform").reset();
location.href="${pageContext.request.contextPath}/student/findAll?page=1&size=5";
$("#myform").reset(); // 重置表单
location.href = "${pageContext.request.contextPath}/student/findAll?page=1&size=5"; // 重新加载页面
});
</script>
</head>
<body>
<%-- 导航栏部分被注释掉了 --%>
<%--<div class="x-nav">
<span class="layui-breadcrumb">
<a href="">首页</a>
@ -50,7 +44,7 @@
<a>
<cite>导航元素</cite></a>
</span>
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" onclick="location.reload()" title="刷新">
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" "location.reload()" title="刷新">
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
</div>--%>
<div class="layui-fluid">
@ -58,24 +52,29 @@
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-body ">
<!-- 搜索表单 -->
<form id="myform" class="layui-form layui-col-space5">
<div class="layui-inline layui-show-xs-block">
<input class="layui-input" type="text" autocomplete="off" placeholder="请输入关键字" name="keyword" id="keyword" value="${param.keyword}">
</div>
<div class="layui-inline layui-show-xs-block">
<button class="layui-btn" id="serarch_btn" lay-submit="" lay-filter="sreach"><i class="layui-icon">&#xe615;</i></button>
<button class="layui-btn" id="serarch_btn" lay-submit="" lay-filter="sreach"><i class="layui-icon">&#xe615;</i></button>
</div>
<div class="layui-inline layui-show-xs-block x-right">
<a class="layui-btn layui-btn-normal" href="${pageContext.request.contextPath}/student/findAll?page=1&size=5"><i class="layui-icon">&#xe669;</i></a>
<a class="layui-btn layui-btn-normal" href="${pageContext.request.contextPath}/student/findAll?page=1&size=5"><i class="layui-icon">&#xe669;</i>全部</a>
</div>
</form>
</div>
<xblock>
<!-- 添加学生按钮 -->
<a href="${pageContext.request.contextPath}/student/addStudent" class="layui-btn layui-btn-normal"><i class="layui-icon">&#xe654;</i>添加</a>
<a onclick="exportInfo()" class="layui-btn layui-btn-warm" href="javascript:;"><i class="layui-icon">&#xe67c;</i>导出</a>
<!-- 导出信息按钮(功能未实现) -->
<a "exportInfo()" class="layui-btn layui-btn-warm" href=";"><i class="layui-icon">&#xe67c;</i>导出</a>
<!-- 显示数据总数 -->
<span class="x-right" style="line-height:40px">共有数据:${pageInfo.total} 条</span>
</xblock>
<div class="layui-card-body">
<!-- 表格展示学生信息 -->
<table class="layui-table layui-form">
<thead>
<tr style="text-align: center">
@ -94,38 +93,45 @@
</thead>
<tbody>
<%
int j = 1;
int j = 1; // 初始化行号计数器
%>
<!-- 遍历学生列表并生成表格行 -->
<c:forEach items="${pageInfo.list}" var="student">
<tr id="light" style="text-align: center">
<td><%=j++%></td>
<td>${student.name}</td>
<td>${student.sex}</td>
<td>${student.sno}</td>
<td>${student.stu_class}</td>
<td>${student.phone}</td>
<td>${student.dorm_id}</td>
<td>${student.teacher}</td>
<c:if test="${student.status == 1}">
<td><button class="layui-btn layui-btn-normal layui-btn-sm">已激活</button></td>
</c:if>
<c:if test="${student.status == 0}">
<td><button class="layui-btn layui-btn-danger layui-btn-sm">禁用</button></td>
</c:if>
<c:if test="${sessionScope.adminInfo.power > 1}">
<td class="td-manage">
<a title="编辑" href="${pageContext.request.contextPath}/student/editStudent?sno=${student.sno}">
<i class="layui-icon">&#xe642;</i>
</a>
<a title="删除" onclick="member_del(this,${student.sno},${sessionScope.adminInfo.power})" href="javascript:;">
<i class="layui-icon">&#xe640;</i>
</a>
</td>
</c:if>
</c:forEach>
</tr>
<tr id="light" style="text-align: center">
<td><%=j++%></td> <!-- 显示行号 -->
<td>${student.name}</td> <!-- 显示学生姓名 -->
<td>${student.sex}</td> <!-- 显示学生性别 -->
<td>${student.sno}</td> <!-- 显示学生学号 -->
<td>${student.stu_class}</td> <!-- 显示学生班级 -->
<td>${student.phone}</td> <!-- 显示学生联系方式 -->
<td>${student.dorm_id}</td> <!-- 显示学生宿舍号 -->
<td>${student.teacher}</td> <!-- 显示学生育人导师 -->
<c:if test="${student.status == 1}">
<!-- 显示已激活状态 -->
<td><button class="layui-btn layui-btn-normal layui-btn-sm">已激活</button></td>
</c:if>
<c:if test="${student.status == 0}">
<!-- 显示禁用状态 -->
<td><button class="layui-btn layui-btn-danger layui-btn-sm">禁用</button></td>
</c:if>
<c:if test="${sessionScope.adminInfo.power > 1}">
<td class="td-manage">
<!-- 编辑按钮 -->
<a title="编辑" href="${pageContext.request.contextPath}/student/editStudent?sno=${student.sno}">
<i class="layui-icon">&#xe642;</i>
</a>
<!-- 删除按钮(功能未实现) -->
<a title="删除" href=";" onclick="member_del(this,${student.sno},${sessionScope.adminInfo.power})">
<i class="layui-icon">&#xe640;</i>
</a>
</td>
</c:if>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<div class="pull-left">
<div class="form-group form-inline">
@ -139,32 +145,28 @@
</select> 条
</div>
</div>
// 根据总页数和当前页码,动态设置分页导航的起始和结束页码
<c:choose>
<c:when test="${pageInfo.pages < 5}">
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
<c:set var="begin" value="1"/>
<c:set var="end" value="${pageInfo.pages}"/>
</c:when>
<c:when test="${pageInfo.pageNum <= 3}">
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="5">
</c:set>
<c:set var="begin" value="1"/>
<c:set var="end" value="5"/>
</c:when>
<c:when test="${pageInfo.pageNum > 3 and pageInfo.pageNum <= pageInfo.pages-2}">
<c:set var="begin" value="${pageInfo.pageNum - 2}">
</c:set>
<c:set var="end" value="${pageInfo.pageNum + 2}">
</c:set>
<c:set var="begin" value="${pageInfo.pageNum - 2}"/>
<c:set var="end" value="${pageInfo.pageNum + 2}"/>
</c:when>
<c:otherwise>
<c:set var="begin" value="${pageInfo.pages - 4}">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
<c:set var="begin" value="${pageInfo.pages - 4}"/>
<c:set var="end" value="${pageInfo.pages}"/>
</c:otherwise>
</c:choose>
// 分页导航按钮部分
<div class="layui-card-body x-right" style="height: min-content">
<div class="page">
<div>
@ -183,8 +185,7 @@
<c:if test="${pageInfo.pageNum < pageInfo.pages}">
<a class="next" href="${pageContext.request.contextPath}/student/findAll?page=${pageInfo.pageNum+1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">下一页</a>
</c:if>
<a class="next" href="${pageContext.request.contextPath}/student/findAll?page=${pageInfo.pages}&size=${pageInfo.pageSize}&keyword=${param.keyword}">尾页</a>
</div>
<a class="next" href="${pageContext.request.contextPath}/student/findAll?page=${pageInfo.pages}&size=${pageInfo.pageSize}&keyword=${param.keyword}">尾页</a></div>
</div>
</div>
</div>
@ -224,6 +225,7 @@
layer.close(index);
});
}
</script>
</body>
</html>

@ -1,10 +1,3 @@
<%--
Created by IntelliJ IDEA.
User: user
Date: 2020/2/10
Time: 21:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html class="x-admin-sm">
@ -13,21 +6,16 @@
<title></title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- 引入外部CSS文件 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/font.css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/xadmin.css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<script src="${pageContext.request.contextPath}/lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/xadmin.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<%-- 注释掉的导航栏代码 --%>
<%--<div class="x-nav">
<span class="layui-breadcrumb">
<a href="">首页</a>
@ -35,14 +23,16 @@
<a>
<cite>导航元素</cite></a>
</span>
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" onclick="location.reload()" title="刷新">
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" "location.reload()" title="刷新">
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
</div>--%>
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-body ">
<!-- 注释掉的搜索表单代码 -->
<%--<form id="myform" class="layui-form layui-col-space5">
<div class="layui-inline layui-show-xs-block">
<input class="layui-input" type="text" autocomplete="off" placeholder="请输入关键字" name="keyword" id="keyword" value="${param.keyword}">
@ -56,10 +46,13 @@
</form>--%>
</div>
<xblock>
<!-- 添加学生按钮 -->
<a href="${pageContext.request.contextPath}/student/addStudent" class="layui-btn layui-btn-normal"><i class="layui-icon">&#xe654;</i>添加</a>
<!-- 显示总数据条数 -->
<span class="x-right" style="line-height:40px">共有数据:${pageInfo.total} 条</span>
</xblock>
<div class="layui-card-body">
<!-- 表格展示学生信息 -->
<table class="layui-table layui-form">
<thead>
<tr style="text-align: center">
@ -73,40 +66,47 @@
<th style="text-align: center">育人导师</th>
<th style="text-align: center">状态</th>
<th style="text-align: center">操作</th>
</tr>
</thead>
<tbody>
<%
int j = 1;
int j = 1; // 初始化行号计数器
%>
<!-- 遍历学生列表并生成表格行 -->
<c:forEach items="${pageInfo.list}" var="student">
<tr id="light" style="text-align: center">
<td><%=j++%></td>
<td>${student.name}</td>
<td>${student.sex}</td>
<td>${student.sno}</td>
<td>${student.stu_class}</td>
<td>${student.phone}</td>
<td>${student.dorm_id}</td>
<td>${student.teacher}</td>
<c:if test="${student.status == 1}">
<td><button class="layui-btn layui-btn-normal layui-btn-sm">已激活</button></td>
</c:if>
<c:if test="${student.status == 0}">
<td><button class="layui-btn layui-btn-danger layui-btn-sm">禁用</button></td>
</c:if>
<tr id="light" style="text-align: center">
<td><%=j++%></td> <!-- 显示行号 -->
<td>${student.name}</td> <!-- 显示学生姓名 -->
<td>${student.sex}</td> <!-- 显示学生性别 -->
<td>${student.sno}</td> <!-- 显示学生学号 -->
<td>${student.stu_class}</td> <!-- 显示学生班级 -->
<td>${student.phone}</td> <!-- 显示学生联系方式 -->
<td>${student.dorm_id}</td> <!-- 显示学生宿舍号 -->
<td>${student.teacher}</td> <!-- 显示学生育人导师 -->
<!-- 根据学生状态显示不同按钮 -->
<c:if test="${student.status == 1}">
<td><button class="layui-btn layui-btn-normal layui-btn-sm">已激活</button></td>
</c:if>
<c:if test="${student.status == 0}">
<td><button class="layui-btn layui-btn-danger layui-btn-sm">禁用</button></td>
</c:if>
<!-- 编辑按钮 -->
<td class="td-manage">
<a title="编辑" href="${pageContext.request.contextPath}/student/editStudent?sno=${student.sno}">
<i class="layui-icon">&#xe642;</i>
</a>
</td>
</c:forEach>
</tr>
</c:forEach>
</tr>
</tbody>
</table>
</div>
<div class="pull-left">
<!-- 左侧浮动的分页信息 -->
<div class="form-group form-inline">
共&nbsp;${pageInfo.pages}&nbsp;页&emsp;当前页:${pageInfo.pageNum}&nbsp;/&nbsp;${pageInfo.pages}&emsp; 每页
<!-- 下拉框用于选择每页显示的条数 -->
<select class="form-control" id="changePageSize" onchange="changePageSize()">
<option value="1">${pageInfo.size}</option>
<option value="5">5</option>
@ -116,50 +116,58 @@
</select> 条
</div>
</div>
<c:choose>
<!-- 根据总页数和当前页码设置分页按钮的范围 -->
<c:when test="${pageInfo.pages < 5}">
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
<!-- 如果总页数小于5则显示所有页码 -->
<c:set var="begin" value="1"></c:set>
<c:set var="end" value="${pageInfo.pages}"></c:set>
</c:when>
<c:when test="${pageInfo.pageNum <= 3}">
<c:set var="begin" value="1">
</c:set>
<c:set var="end" value="5">
</c:set>
<!-- 如果当前页码小于等于3则显示前5页 -->
<c:set var="begin" value="1"></c:set>
<c:set var="end" value="5"></c:set>
</c:when>
<c:when test="${pageInfo.pageNum > 3 and pageInfo.pageNum <= pageInfo.pages-2}">
<c:set var="begin" value="${pageInfo.pageNum - 2}">
</c:set>
<c:set var="end" value="${pageInfo.pageNum + 2}">
</c:set>
<!-- 如果当前页码大于3且小于总页数减2则显示当前页码前后各两页 -->
<c:set var="begin" value="${pageInfo.pageNum - 2}"></c:set>
<c:set var="end" value="${pageInfo.pageNum + 2}"></c:set>
</c:when>
<c:otherwise>
<c:set var="begin" value="${pageInfo.pages - 4}">
</c:set>
<c:set var="end" value="${pageInfo.pages}">
</c:set>
<!-- 其他情况显示最后4页 -->
<c:set var="begin" value="${pageInfo.pages - 4}"></c:set>
<c:set var="end" value="${pageInfo.pages}"></c:set>
</c:otherwise>
</c:choose>
<div class="layui-card-body x-right" style="height: min-content">
<!-- 右侧浮动的分页导航 -->
<div class="page">
<div>
<!-- 首页链接 -->
<a class="next" href="${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size=${pageInfo.pageSize}&keyword=${param.keyword}">首页</a>
<!-- 上一页链接如果当前页码大于1 -->
<c:if test="${pageInfo.pageNum > 1}">
<a class="prev" href="${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=${pageInfo.pageNum-1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">上一页</a>
</c:if>
<!-- 循环生成页码链接 -->
<c:forEach var="i" begin="${begin}" end="${end}" step="1">
<!-- 当前页码高亮显示 -->
<c:if test="${pageInfo.pageNum == i}">
<span class="current">${i}</span>
</c:if>
<!-- 非当前页码的普通链接 -->
<c:if test="${pageInfo.pageNum != i}">
<a class="num" href="${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=${i}&size=${pageInfo.pageSize}&keyword=${param.keyword}">${i}</a>
</c:if>
</c:forEach>
<!-- 下一页链接,如果当前页码小于总页数 -->
<c:if test="${pageInfo.pageNum < pageInfo.pages}">
<a class="next" href="${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=${pageInfo.pageNum+1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">下一页</a>
</c:if>
<!-- 尾页链接 -->
<a class="next" href="${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=${pageInfo.pages}&size=${pageInfo.pageSize}&keyword=${param.keyword}">尾页</a>
</div>
</div>
@ -168,24 +176,28 @@
</div>
</div>
</div>
<script>
function changePageSize() {
//获取下拉框的值
var pageSize = $("#changePageSize").val();
//向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size="+ pageSize;
}
$("#search_btn").click(function () {
alert(1234);
var keyword = $("#keyword").val();
alert(keyword);
alert("${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size=5&keyword="+keyword);
location.href="${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size=5&keyword="+keyword;
});
$("#refresh").click(function () {
$("#myform").reset();
location.href="${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size=5";
});
</script>
<script>
function changePageSize() {
// 获取下拉框的值
var pageSize = $("#changePageSize").val();
// 向服务器发送请求,改变每页显示条数
location.href = "${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size=" + pageSize;
}
$("#search_btn").click(function () {
// 获取搜索关键字
var keyword = $("#keyword").val();
// 向服务器发送请求,进行搜索
location.href = "${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size=5&keyword=" + keyword;
});
$("#refresh").click(function () {
// 重置表单并刷新页面
$("#myform").reset();
location.href = "${pageContext.request.contextPath}/dorm/findStudent?name=${sessionScope.adminInfo.name}&page=1&size=5";
});
</script>
</body>
</html>

@ -6,78 +6,135 @@
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 声明该JSP页面的内容类型是HTML格式字符编码采用UTF-8表明页面中使用Java语言编写服务器端逻辑 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 引入JSTLJavaServer Pages Standard Tag Library的核心标签库设置前缀为“c”方便后续在JSP页面中使用其提供的各种标签进行逻辑判断、循环遍历等操作 -->
<html class="x-admin-sm">
<head>
<!-- 设置页面的字符编码为UTF-8确保页面在浏览器中能正确显示各种字符避免出现乱码情况 -->
<meta charset="UTF-8">
<title></title>
<!-- 设置页面渲染所使用的引擎为webkit它能让页面在支持webkit的浏览器中以相应的渲染方式呈现提供较好的页面展示效果 -->
<meta name="renderer" content="webkit">
<!-- 声明页面在IE浏览器中的兼容模式使页面在IE浏览器中以其最高版本的模式进行渲染若安装了Chrome Frame则优先使用Chrome Frame来渲染以增强兼容性和展示效果 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- 引入自定义的字体样式表路径通过EL表达式结合pageContext对象获取项目相对路径用于设置页面中文字的字体、字号、颜色等样式相关属性 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/font.css">
<!-- 引入自定义的xadmin样式表通过EL表达式结合pageContext获取相对路径用于构建页面整体的xadmin风格布局与样式比如页面的整体色调、各组件的样式等 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/xadmin.css">
<!-- 引入Bootstrap框架的样式表同样借助EL表达式结合pageContext获取路径Bootstrap可以帮助快速搭建页面的响应式布局以及提供各种常用的UI组件样式 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.css">
<!-- 引入jQuery库其路径通过EL表达式结合pageContext获取项目相对路径jQuery是一个常用的JavaScript库方便在页面中操作DOM元素、处理事件、发起AJAX请求等 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
<!-- 引入layui框架的JavaScript文件指定字符编码为utf-8layui用于构建页面交互效果提供了丰富的UI组件和交互功能便于开发者打造具有良好用户体验的页面 -->
<script src="${pageContext.request.contextPath}/lib/layui/layui.js" charset="utf-8"></script>
<!-- 引入自定义的xadmin相关的JavaScript文件通过EL表达式结合pageContext获取路径这个文件可能包含了针对xadmin页面特有的交互逻辑和功能实现 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/xadmin.js"></script>
<!-- 引入Bootstrap的JavaScript文件通过EL表达式结合pageContext获取路径用于实现Bootstrap框架相关的交互功能例如一些组件的动态效果等 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script>
<!-- 引入layer弹窗插件的JavaScript文件通过EL表达式结合pageContext获取路径layer插件常用于在页面中弹出提示框、确认框、加载层等交互效果增强用户与页面的交互性 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/layer/layer.js"></script>
<!--[if lt IE 9]>
<!--[if lt IE 9] -->
<!-- 条件注释针对IE浏览器版本小于9的情况引入html5shiv库其作用是让旧版本的IE浏览器能够支持HTML5的新标签使得页面在这些旧浏览器中能正常解析HTML5相关的结构 -->
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<!-- 引入respond.js库用于让旧版本IE浏览器支持CSS3媒体查询确保页面在不同设备尺寸下的样式适配能在旧IE浏览器中正常工作 -->
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
function changePageSize() {
//获取下拉框的值
// 获取id为changePageSize的下拉框元素的值这个值代表了用户期望设置的每页显示数据的条数
// 通过jQuery选择器$("#changePageSize")选中该下拉框元素,再使用.val()方法获取其当前选中的值
var pageSize = $("#changePageSize").val();
//向服务器发送请求,改变每页显示条数
// 通过修改浏览器地址栏的URL向服务器发送请求请求的路径是/visitor/findAll传递参数page=1表示显示第一页
// size为获取到的下拉框的值以此改变每页显示的条数实现用户切换每页显示数据量的功能
// 这里利用了location.href属性来重定向页面到指定的URL
location.href = "${pageContext.request.contextPath}/visitor/findAll?page=1&size="+ pageSize;
}
$("#serarch_btn").click(function () {
// 获取id为keyword的输入框元素的值通常这个值是用户输入的用于搜索的关键词例如访客姓名、学号等
// 通过jQuery选择器$("#keyword")选中该输入框元素,再使用.val()方法获取其当前输入的值
var keyword = $("#keyword").val();
// 通过修改浏览器地址栏的URL向服务器发送请求请求的路径是/visitor/findAll传递参数page=1表示显示第一页
// size=5表示每页显示5条记录keyword为获取到的搜索关键词用于根据用户输入的关键词进行搜索并展示相应的访客信息
// 同样利用location.href属性来重定向页面到指定的带有搜索参数的URL
location.href="${pageContext.request.contextPath}/visitor/findAll?page=1&size=5&keyword="+keyword;
});
$("#refresh").click(function () {
// 尝试重置id为myform的表单元素此处重置方式可能不准确更准确的写法可能是$("#myform")[0].reset(); ),目的是将表单内的输入框等元素的值重置为初始状态,
// 例如清空用户输入的搜索关键词等内容不过当前写法依赖于具体的表单库是否支持这样直接调用reset方法可能存在兼容性问题
$("#myform").reset();
// 通过修改浏览器地址栏的URL向服务器发送请求请求的路径是/visitor/findAll传递参数page=1表示显示第一页
// size=5表示每页显示5条记录达到刷新页面数据的效果即将页面恢复到初始的显示状态展示第一页且每页显示5条记录的数据情况
// 借助location.href属性来实现页面重定向到相应的URL
location.href="${pageContext.request.contextPath}/visitor/findAll?page=1&size=5";
});
</script>
</head>
<body>
<%-- 以下这部分代码被注释掉了,原本可能是用于展示页面导航相关元素,包含面包屑导航以及一个刷新按钮,点击按钮可刷新页面,但当前处于注释状态,不会在页面中显示生效 --%>
<%--<div class="x-nav">
<span class="layui-breadcrumb">
<a href="">首页</a>
<a href="">演示</a>
<a>
<cite>导航元素</cite></a>
</span>
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" onclick="location.reload()" title="刷新">
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
<span class="layui-breadcrumb">
<a href="">首页</a>
<a href="">演示</a>
<a>
<cite>导航元素</cite></a>
</span>
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" onclick="location.reload()" title="刷新">
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
</div>--%>
<!-- 使用layui-fluid类创建一个流体布局容器使得内部的元素可以根据页面宽度自适应排列常用于实现响应式布局 -->
<div class="layui-fluid">
<!-- 创建一个layui的行元素layui-col-space15表示设置列间距为15像素用于对内部的列元素进行布局管理 -->
<div class="layui-row layui-col-space15">
<!-- 创建一个占12列的layui列元素在layui的栅格系统中一行默认分为12列这里表示占满一整行 -->
<div class="layui-col-md12">
<!-- 创建一个layui卡片组件用于将内部的内容以卡片的形式展示通常有边框、阴影等样式效果使页面结构更清晰美观 -->
<div class="layui-card">
<!-- 创建卡片的主体内容区域,用于放置表单相关元素 -->
<div class="layui-card-body ">
<!-- 创建一个id为myform的表单应用layui的表单样式类layui-form并且设置列间距为5像素用于布局表单内的各个元素 -->
<form id="myform" class="layui-form layui-col-space5">
<!-- 创建一个行内块元素layui-show-xs-block表示在小屏幕如手机端下显示该元素方便在不同屏幕尺寸下进行布局控制 -->
<div class="layui-inline layui-show-xs-block">
<!-- 创建一个文本输入框设置自动补全关闭autocomplete="off"添加提示占位文本“请输入关键字”指定name和id属性
并且其值通过EL表达式从请求参数中获取名为keyword的值如果有的话方便实现根据用户输入的关键字进行搜索功能 -->
<input class="layui-input" type="text" autocomplete="off" placeholder="请输入关键字" name="keyword" id="keyword" value="${param.keyword}">
</div>
<!-- 创建一个按钮应用layui的按钮样式类layui-btn指定id为serarch_btn此处可能有拼写错误正确应为search_btn
并设置了layui表单相关的提交和过滤属性lay-submit和lay-filter按钮内包含一个layui图标点击该按钮可能触发表单提交或者搜索操作 -->
<div class="layui-inline layui-show-xs-block">
<button class="layui-btn" id="serarch_btn" lay-submit="" lay-filter="sreach"><i class="layui-icon">&#xe615;</i></button>
</div>
<!-- 创建一个链接样式的按钮应用layui的正常样式类layui-btn-normal点击后跳转到指定路径路径通过EL表达式结合pageContext生成
用于获取所有访客信息并设置每页显示5条数据按钮内包含一个layui图标可能用于实现回到第一页且每页显示固定条数数据的功能通常作为重置按钮的一种体现 -->
<div class="layui-inline layui-show-xs-block x-right">
<a class="layui-btn layui-btn-normal" href="${pageContext.request.contextPath}/visitor/findAll?page=1&size=5"><i class="layui-icon">&#xe669;</i></a>
</div>
</form>
</div>
<!-- 自定义的<xblock>标签具体功能可能由相关的CSS或JavaScript根据业务逻辑来定义在这里用于包裹导出按钮和总数据条数显示相关的元素 -->
<xblock>
<a onclick="exportInfo(${sessionScope.adminInfo.power})" class="layui-btn layui-btn-warm" href="javascript:;"><i class="layui-icon">&#xe67c;</i>导出</a>
<!-- 创建一个链接样式按钮点击时调用exportInfo函数并传入管理员权限值从会话中获取按钮显示为“导出”包含一个layui图标用于触发导出访客数据的相关操作 -->
<a onclick="exportInfo(${sessionScope.adminInfo.power})" class="layui-btn layui-btn-warm" href="javascript:;"><i class="layui-icon">&#xe67c;</i>导出</a>
<!-- 显示总的访客数据条数信息设置了行高为40px的样式靠右对齐通过x-right类实现用于向用户展示当前访客数据的总量情况 -->
<span class="x-right" style="line-height:40px">共有数据:${pageInfo.total} 条</span>
</xblock>
<!-- 创建另一个卡片主体内容区域,可能用于展示不同部分的内容,这里用于放置访客信息表格 -->
<div class="layui-card-body">
<!-- 创建一个使用layui样式的表格同时应用layui的表单样式方便后续可能的表单相关交互操作比如行内编辑等 -->
<table class="layui-table layui-form">
<thead>
<tr style="text-align: center">
<!-- 创建表格的表头行,设置文本居中显示 -->
<th style="text-align: center">ID</th>
<th style="text-align: center">姓名</th>
<th style="text-align: center">学号</th>
@ -86,29 +143,41 @@
<th style="text-align: center">来访时间</th>
<th style="text-align: center">离开时间</th>
<th style="text-align: center">到访原因</th>
<!-- 通过JSTL的条件判断如果管理员权限大于2则显示操作列用于放置针对访客记录的操作按钮比如删除、修改等操作 -->
<c:if test="${sessionScope.adminInfo.power > 2}">
<th style="text-align: center">操作</th>
<th style="text-align: center">操作</th>
</c:if>
</tr>
</thead>
<tbody>
<%
// 在JSP脚本片段中定义一个局部变量j并初始化为1用于给表格中的数据行编号混合使用了JSP脚本片段和JSTL标签库来构建表格数据展示
int j = 1;
%>
<!-- 使用JSTL的forEach标签循环遍历pageInfo.list中的数据通常是分页后的访客列表集合每次循环将当前元素赋值给visitor变量方便在表格中展示各个访客的详细信息 -->
<c:forEach items="${pageInfo.list}" var="visitor">
<tr id="light" style="text-align: center">
<!-- 在表格行数据中第一列显示行号通过JSP脚本片段输出变量j的值并在每次循环后自增1实现逐行编号的效果 -->
<td><%=j++%></td>
<!-- 通过EL表达式从名为visitor的对象中获取姓名属性值展示访客的姓名信息 -->
<td>${visitor.name}</td>
<!-- 通过EL表达式从名为visitor的对象中获取学号属性值展示访客的学号信息 -->
<td>${visitor.sno}</td>
<td>${visitor.phone}</td>
<!-- 通过EL表达式从名为visitor的对象中获取联系方式属性值展示访客的联系方式信息 -->
<td>${visitor.place}</td>
<!-- 通过EL表达式从名为visitor的对象中获取来访时间属性值展示访客的来访时间信息 -->
<td>${visitor.begin_date}</td>
<!-- 通过JSTL的条件判断访客的离开时间是否为空如果为空则显示“尚未离开”用于提示访客当前是否还在访问中 -->
<c:if test="${visitor.end_date == null || visitor.end_date == ''}">
<td>尚未离开</td>
</c:if>
<c:if test="${visitor.end_date != ''}">
<!-- 如果离开时间不为空则通过EL表达式获取并显示具体的离开时间 -->
<c:if test="${visitor.end_date!= ''}">
<td>${visitor.end_date}</td>
</c:if>
<td>${visitor.visit_result}</td>
<!-- 通过JSTL的条件判断如果管理员权限大于2则显示操作列中的具体操作按钮这里定义一个链接点击时调用toUpdate函数并传入访客的id
按钮显示为一个图标,提示文本为“注销访客”,用于触发注销访客记录的相关操作 -->
<c:if test="${sessionScope.adminInfo.power > 2}">
<td class="td-manage">
<a title="注销访客" onclick="toUpdate('${visitor.id}');" href="javascript:;">
@ -121,97 +190,283 @@
</tbody>
</table>
</div>
<!-- 设置该元素向左浮动,常用于布局排版,使其在页面中向左对齐排列 -->
<div class="pull-left">
<!-- 创建一个表单组,设置为行内表单样式,方便在一行内展示多个表单相关元素 -->
<div class="form-group form-inline">
<!-- 显示分页相关信息,如总页数、当前页码等,告知用户当前的分页情况 -->
共&nbsp;${pageInfo.pages}&nbsp;页&emsp;当前页:${pageInfo.pageNum}&nbsp;/&nbsp;${pageInfo.pages}&emsp; 每页
<!-- 创建一个下拉菜单应用表单控件的样式类form-control绑定了id为changePageSize当下拉框选项改变时会调用changePageSize函数来改变每页显示条数 -->
<select class="form-control" id="changePageSize" onchange="changePageSize()">
<!-- 为下拉菜单添加各个选项,每个<option>标签代表一个可选择的每页显示条数的值,
初始显示的值通过EL表达式从pageInfo对象中获取相关属性值用户可选择不同的选项来改变每页显示的数据量 -->
<option value="1">${pageInfo.size}</option>
<option value="5">5</option>
<option value="10">10</option>
// 这是一个下拉菜单中的选项(<option>)标签,表示当用户选择该项时,
// 对应的值为10意味着每页显示10条数据用于设置每页显示数据量的可选项之一
<option value="15">15</option>
// 同样是下拉菜单中的选项标签选择该项则表示每页显示15条数据是提供给用户选择每页数据条数的一个选项
<option value="20">20</option>
// 下拉菜单中的选项标签若用户选择此项每页将显示20条数据作为可配置每页显示数量的一个选项
</select> 条
<!-- 结束下拉菜单标签,“条”字可能是用于在页面上更友好地提示用户该下拉菜单是用于选择每页显示数据的条数 -->
</div>
// 结束一个外层的div容器这个div可能用于布局包裹与每页显示条数选择相关的元素等
</div>
// 结束另一个外层的div容器可能在页面布局层级中处于更上层具体作用需结合整体页面结构来看
<!-- 分页按钮逻辑控制 -->
// 这是一个HTML注释用于说明下面的代码块主要是用于控制分页按钮的显示逻辑方便后续阅读和维护代码
<c:choose>
// 使用JSTLJavaServer Pages Standard Tag Library的标签开始一个条件选择结构
// 类似于Java中的switch语句用于根据不同条件执行不同的逻辑分支
<c:when test="${pageInfo.pages < 5}">
// 标签表示一个具体的条件分支这里的条件是判断pageInfo对象中的pages属性通常表示总页数是否小于5
// 如果满足该条件,则执行此分支内的代码
<c:set var="begin" value="1">
// 使用标签在JSP页面中设置一个名为“begin”的变量值设置为1
// 这个变量可能后续用于确定分页页码显示的起始范围等相关逻辑
</c:set>
<c:set var="end" value="${pageInfo.pages}">
// 同样使用标签设置一个名为“end”的变量其值设置为pageInfo对象中的pages属性值即总页数
// 用于配合“begin”变量来确定分页页码显示的范围
</c:set>
</c:when>
<c:when test="${pageInfo.pageNum <= 3}">
// 另一个条件分支判断pageInfo对象中的pageNum属性通常表示当前页码是否小于等于3
// 如果满足该条件,则执行此分支内的代码,用于设置不同情况下分页页码显示的范围
<c:set var="begin" value="1">
// 设置名为“begin”的变量值为1为后续确定分页页码显示范围做准备
</c:set>
<c:set var="end" value="5">
// 设置名为“end”的变量值为5结合“begin”变量来确定在当前页码小于等于3这种情况下分页页码显示的范围
</c:set>
</c:when>
<c:when test="${pageInfo.pageNum > 3 and pageInfo.pageNum <= pageInfo.pages-2}">
<c:when test="${pageInfo.pageNum > 3 and pageInfo.pageNum <= pageInfo.pages - 2}">
// 又一个条件分支判断当前页码pageInfo.pageNum大于3并且小于等于总页数减2时执行此分支内的代码
// 用于根据当前页码在特定区间时设置分页页码显示的范围
<c:set var="begin" value="${pageInfo.pageNum - 2}">
// 根据当前页码动态计算“begin”变量的值将其设置为当前页码减2以此来确定合适的分页页码显示起始范围
</c:set>
<c:set var="end" value="${pageInfo.pageNum + 2}">
// 根据当前页码动态计算“end”变量的值设置为当前页码加2与“begin”变量配合确定分页页码显示的范围
</c:set>
</c:when>
<c:otherwise>
// otherwise标签表示当上述所有条件都不满足时执行的代码分支相当于Java中switch语句的default分支
<c:set var="begin" value="${pageInfo.pages - 4}">
// 设置名为“begin”的变量值为总页数减4用于确定在其他情况之外的分页页码显示起始范围
</c:set>
<c:set var="end" value="${pageInfo.pages}">
// 设置名为“end”的变量值为总页数与“begin”变量配合确定分页页码显示的范围
</c:set>
</c:otherwise>
</c:choose>
<div class="layui-card-body x-right" style="height: min-content">
<div class="page">
<div>
<a class="next" href="${pageContext.request.contextPath}/visitor/findAll?page=1&size=${pageInfo.pageSize}&keyword=${param.keyword}">首页</a>
<c:if test="${pageInfo.pageNum > 1}">
<a class="prev" href="${pageContext.request.contextPath}/visitor/findAll?page=${pageInfo.pageNum-1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">上一页</a>
</c:if>
<c:forEach var="i" begin="${begin}" end="${end}" step="1">
<c:if test="${pageInfo.pageNum == i}">
<span class="current">${i}</span>
</c:if>
<c:if test="${pageInfo.pageNum != i}">
<a class="num" href="${pageContext.request.contextPath}/visitor/findAll?page=${i}&size=${pageInfo.pageSize}&keyword=${param.keyword}">${i}</a>
</c:if>
</c:forEach>
<c:if test="${pageInfo.pageNum < pageInfo.pages}">
<a class="next" href="${pageContext.request.contextPath}/visitor/findAll?page=${pageInfo.pageNum+1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">下一页</a>
</c:if>
<a class="next" href="${pageContext.request.contextPath}/visitor/findAll?page=${pageInfo.pages}&size=${pageInfo.pageSize}&keyword=${param.keyword}">尾页</a>
</div>
</div>
<div class="layui-card-body x-right" style="height: min-content">
// 创建一个使用layui样式的卡片主体内容区域layui-card-body并应用了x-right类可能用于控制布局靠右显示等
// 设置了高度样式为min-content使该区域的高度根据其内部内容自适应最小化高度占用
<div class="page">
// 创建一个自定义类名为“page”的<div>容器,可能用于专门放置分页相关的按钮等元素,进行布局分组
<div>
// 再创建一个内层的<div>容器,用于进一步细化分页按钮等元素的布局
<a class="next" href="${pageContext.request.contextPath}/visitor/findAll?page=1&size=${pageInfo.pageSize}&keyword=${param.keyword}">首页</a>
// 创建一个链接应用了名为“next”的类可能有对应的CSS样式用于外观控制
// href属性通过EL表达式拼接出具体的URL路径用于跳转到访客信息列表的第一页同时传递了每页显示条数pageInfo.pageSize和搜索关键词param.keyword等参数
// 链接显示的文本为“首页”,方便用户点击回到第一页
<c:if test="${pageInfo.pageNum > 1}">
// 使用JSTL的条件判断标签判断pageInfo对象中的pageNum属性当前页码是否大于1
// 如果满足该条件,则执行此标签内包含的代码,用于判断是否显示上一页按钮
<a class="prev" href="${pageContext.request.contextPath}/visitor/findAll?page=${pageInfo.pageNum - 1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">上一页</a>
// 创建一个链接应用“prev”类可能对应特定样式href属性通过EL表达式拼接出URL路径
// 用于跳转到上一页当前页码减1同时传递每页显示条数和搜索关键词等参数链接显示文本为“上一页”方便用户进行翻页操作
</c:if>
<c:forEach var="i" begin="${begin}" end="${end}" step="1">
// 使用JSTL的forEach循环标签开始一个循环循环变量为“i”循环的起始值为之前设置的“begin”变量的值
// 结束值为“end”变量的值步长为1即依次遍历从“begin”到“end”范围的每一个值用于生成分页页码链接
<c:if test="${pageInfo.pageNum == i}">
// 在循环内部再次使用条件判断标签判断当前页码pageInfo.pageNum是否等于循环变量“i”的值
// 如果相等,则执行此标签内的代码,用于对当前页码进行特殊样式显示等处理
<span class="current">${i}</span>
// 创建一个span标签应用了“current”类可能有对应的突出显示当前页码的样式并通过EL表达式显示循环变量“i”的值
// 用于将当前页码以特定样式展示出来,与其他页码区分开
</c:if>
<c:if test="${pageInfo.pageNum!= i}">
// 另一个条件判断标签判断当前页码是否不等于循环变量“i”的值如果不相等则执行此标签内的代码
// 用于生成普通的页码链接(非当前页码的情况)
<a class="num" href="${pageContext.request.contextPath}/visitor/findAll?page=${i}&size=${pageInfo.pageSize}&keyword=${param.keyword}">${i}</a>
// 创建一个链接应用“num”类可能对应普通页码链接的样式href属性通过EL表达式拼接出URL路径
// 用于跳转到对应页码循环变量“i”表示的页码同时传递每页显示条数和搜索关键词等参数链接内通过EL表达式显示循环变量“i”的值作为页码显示内容方便用户点击跳转到相应页码
</c:if>
</c:forEach>
<!-- 下一页链接,当不是最后一页时显示 -->
// 这是一个HTML注释说明下面的代码是用于在不是最后一页的情况下显示下一页的链接
<c:if test="${pageInfo.pageNum < pageInfo.pages}">
// 使用JSTL的条件判断标签判断当前页码pageInfo.pageNum是否小于总页数pageInfo.pages
// 如果满足该条件,则执行此标签内的代码,用于判断是否显示下一页链接
<a class="next" href="${pageContext.request.contextPath}/visitor/findAll?page=${pageInfo.pageNum + 1}&size=${pageInfo.pageSize}&keyword=${param.keyword}">下一页</a>
// 创建一个链接(<a>标签应用“next”类href属性通过EL表达式拼接出URL路径用于跳转到下一页当前页码加1
// 同时传递每页显示条数和搜索关键词等参数,链接显示文本为“下一页”,方便用户进行翻页操作
</c:if>
<!-- 尾页链接 -->
// 这是一个HTML注释说明下面的代码是用于显示尾页的链接
<a class="next" href="${pageContext.request.contextPath}/visitor/findAll?page=${pageInfo.pages}&size=${pageInfo.pageSize}&keyword=${param.keyword}">尾页</a>
// 创建一个链接应用“next”类href属性通过EL表达式拼接出URL路径用于跳转到最后一页总页数对应的页码
// 同时传递每页显示条数和搜索关键词等参数,链接显示文本为“尾页”,方便用户直接跳转到最后一页
</div>
</div>
</div>
</div>
</div>
<script>
//导出Excel操作
function exportInfo(power) {
if (power < 3) {
layer.msg('对不起,您没有权限导出访客记录');
return false;
}
layer.confirm('确定导出所有访客数据吗?',function (index) {
location.href="${pageContext.request.contextPath}/visitor/visitorInfo";
layer.close(index);
});
// 结束内层的<div>容器,该容器用于放置分页相关的各个链接按钮等元素
</div>
// 结束类名为“page”的<div>容器,其整体用于对分页相关元素进行布局分组
</div>
// 结束应用了layui样式和特定布局类x-right等的卡片主体内容区域的<div>容器
</div>
// 结束外层的一个<div>容器,其在页面布局层级中有相应的位置和作用(结合整体结构确定)
</div>
// 结束另一个外层的<div>容器,同样在页面布局中处于一定层级,与整体页面结构相关
</div>
// 结束可能是更外层的一个<div>容器,是页面布局中的一部分
</div>
// 结束最外层的一个div容器完成整个页面主体部分的布局结构
</div>
// 结束包含页面主体流体布局layui-fluid的div容器该容器实现了页面的整体流体布局效果
</div>
// 结束包含页面主体行布局layui-row的div容器该行布局内设置了列间距等用于管理列元素的布局
</div>
// 结束包含页面主体列布局layui-col-md12的div容器该列布局占满中等屏幕及以上尺寸下的一行
</div>
// 结束layui卡片layui-card组件的div容器卡片组件用于以卡片形式展示内部内容使页面结构更清晰美观
</body>
// 结束HTML页面的body部分body内包含了页面实际展示的所有内容元素
<script>
// 开始JavaScript代码块用于定义在页面中可执行的客户端脚本逻辑
//导出Excel操作
// 这是一个JavaScript函数的注释说明下面定义的函数主要用于处理导出Excel相关的操作
function exportInfo(power) {
// 定义一个名为exportInfo的JavaScript函数接收一个名为power的参数该参数可能用于表示用户权限等相关信息
// 用于在函数内部根据权限判断是否允许执行导出操作
// 检查当前用户的权限等级如果权限小于3则没有导出权限
if (power < 3) {
// 使用if条件语句判断传入的权限值power是否小于3如果小于3则表示用户没有导出权限执行下面的代码块
// 使用layer插件显示提示信息告知用户没有权限
layer.msg('对不起,您没有权限导出访客记录');
// 调用layer插件提供的msg方法弹出一个提示框显示“对不起您没有权限导出访客记录”的提示信息告知用户当前操作权限不足
return false;
// 函数执行到此处直接返回false表示导出操作不被允许终止函数后续的执行
}
function toUpdate(id) {
layer.confirm('确定要注销此访客记录吗',function (index) {
layer.close(index);
$.get("${pageContext.request.contextPath}/visitor/updateStatus",{"id":id},function (data) {
if (data) {
layer.msg('注销成功');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/visitor/findAll';},2000);
}else {
layer.msg('系统繁忙,请联系系统管理员');
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/visitor/findAll';},2000);
}
});
// 弹出确认框询问用户是否确定要导出所有访客数据
layer.confirm('确定导出所有访客数据吗?',function (index) {
// 调用layer插件提供的confirm方法弹出一个确认框显示“确定导出所有访客数据吗”的提示信息
// 同时传入一个回调函数当用户点击确认框上的按钮时会执行该回调函数回调函数接收一个参数index用于后续操作确认框如关闭等
// 当用户点击确定时重定向到导出访客信息的URL
location.href="${pageContext.request.contextPath}/visitor/visitorInfo";
// 当用户在确认框中点击确定按钮后通过修改浏览器的location.href属性重定向到指定的URL路径
// 该路径通过EL表达式拼接出用于导出访客信息的具体地址触发实际的导出操作具体由服务器端逻辑处理
layer.close(index); // 关闭确认框
// 调用layer插件提供的close方法传入之前接收的index参数用于关闭弹出的确认框完成导出操作相关的交互流程
});
}
// 注销访客记录
// 这是一个JavaScript函数的注释说明下面定义的函数主要用于处理注销访客记录相关的操作
function toUpdate(id) {
// 定义一个名为toUpdate的JavaScript函数接收一个名为id的参数该参数通常用于表示要注销的访客记录的唯一标识
// 用于在函数内部向服务器发送请求来更新对应访客记录的状态
// 使用layer组件的confirm方法弹出确认框询问用户是否确定要注销此访客记录
layer.confirm('确定要注销此访客记录吗',function (index) {
// 调用layer插件提供的confirm方法弹出一个确认框显示“确定要注销此访客记录吗”的提示信息
// 同时传入一个回调函数当用户点击确认框上的按钮时会执行该回调函数回调函数接收一个参数index用于后续操作确认框如关闭等
// 用户点击确定后关闭确认框
layer.close(index);
// 当用户在确认框中点击确定按钮后调用layer插件提供的close方法传入之前接收的index参数关闭弹出的确认框
// 发送异步请求到服务器端更新访客状态
$.get("${pageContext.request.contextPath}/visitor/updateStatus",{"id":id},function (data) {
// 使用jQuery库提供的$.get方法发送一个GET类型的异步请求请求的URL地址通过EL表达式拼接出指向用于更新访客状态的服务器端接口/visitor/updateStatus
// 同时传递一个名为“id”的参数其值为传入函数的id参数表示要更新状态的访客记录的标识
// 并传入一个回调函数当服务器端返回响应数据后会执行该回调函数回调函数接收一个参数data代表服务器返回的数据
// 根据服务器返回的数据判断操作是否成功
if (data) {
// 使用if条件语句判断服务器返回的数据data是否为真值具体真值的判断依据由服务器端返回的数据格式和逻辑决定
// 如果为真值,则表示更新操作成功,执行下面的代码块
// 成功时显示成功消息并在2秒后刷新页面
layer.msg('注销成功');
// 调用layer插件提供的msg方法弹出一个提示框显示“注销成功”的提示信息告知用户操作已成功
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/visitor/findAll';},2000);
// 使用JavaScript的setTimeout函数设置一个定时器在2000毫秒2秒后执行传入的回调函数
// 回调函数内通过修改浏览器的window.location.href属性重定向到指定的URL路径/visitor/findAll实现刷新页面的效果
// 重新加载访客信息列表页面,展示更新后的访客数据情况
}else {
// 如果服务器返回的数据为假值(不符合成功的判断条件),则表示更新操作失败,执行下面的代码块
// 失败时显示错误消息并在2秒后刷新页面
layer.msg('系统繁忙,请联系系统管理员');
// 调用layer插件提供的msg方法弹出一个提示框显示“系统繁忙请联系系统管理员”的提示信息告知用户操作失败及相应的解决建议
setTimeout(function () {window.location.href='${pageContext.request.contextPath}/visitor/findAll';},2000);
// 同样使用setTimeout函数设置定时器在2秒后重定向到访客信息列表页面/visitor/findAll刷新页面
// 以便用户可以查看操作失败后的当前访客数据情况,或者再次尝试操作
}
});
}
});
}
</script>
</body>
</html>

@ -6,65 +6,108 @@
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 声明该JSP页面的内容类型为text/html即HTML格式字符编码采用UTF-8表明页面将以HTML格式展示并且在服务器端使用Java语言编写相关逻辑 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 引入JSTLJavaServer Pages Standard Tag Library的核心标签库设置前缀为“c”方便后续在JSP页面中使用其提供的各种标签进行如条件判断、循环遍历等操作 -->
<html>
<head>
<!-- 设置页面的字符编码为utf-8确保浏览器能正确解析并显示页面中的各种字符防止出现乱码现象 -->
<meta charset="utf-8">
<!-- 设置页面渲染所使用的引擎为webkit让页面在支持webkit的浏览器中按照该引擎的规则进行渲染有助于呈现出期望的页面样式和交互效果 -->
<meta name="renderer" content="webkit">
<!-- 声明页面在IE浏览器中的兼容模式使页面在IE浏览器中以其最高可用版本的模式来渲染如果安装了Chrome Frame插件则优先使用该插件进行渲染以此增强页面在IE浏览器中的兼容性和显示效果 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- 设置页面的视口viewport属性width=device-width表示页面宽度跟随设备宽度自适应initial-scale=1设置初始缩放比例为1
maximum-scale=1限制最大缩放比例为1用于确保页面在移动设备等不同屏幕尺寸下能有合适的展示效果 -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Title</title>
<!-- 引入layui框架的CSS样式表路径通过EL表达式结合pageContext对象获取项目相对路径用于为页面应用layui框架提供的各种样式构建页面的外观布局 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/lib/layui/css/layui.css">
<!-- 引入layui框架中layer模块的默认CSS样式表用于为layer弹出层等相关组件设置特定的样式使其展示效果符合预期 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/lib/layui/css/modules/layer/default/layer.css">
<!-- 引入jQuery库其路径通过EL表达式结合pageContext获取项目相对路径jQuery是常用的JavaScript库方便在页面中操作DOM元素、处理页面事件、发起AJAX异步请求等操作 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
</head>
<body>
<!-- 创建一个fieldset字段集元素应用layui的相关样式类layui-elem-field和layui-field-title用于对页面中的相关内容进行分组和标题显示
设置了顶部外边距为30px使其在页面中有一定的间距看起来更美观 -->
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<!-- 在字段集中创建一个legend图例元素用于显示该组内容的标题这里显示的标题是“访客时间线” -->
<legend>访客时间线</legend>
</fieldset>
<!-- 创建一个无序列表ul元素应用layui的时间线样式类layui-timeline用于以时间线的形式展示访客相关的信息 -->
<ul class="layui-timeline">
<!-- 创建一个列表项li元素作为时间线中的一个节点应用layui的时间线项目样式类layui-timeline-item -->
<li class="layui-timeline-item">
<!-- 创建一个图标i元素应用layui的图标样式类layui-icon以及时间轴样式类layui-timeline-axis显示特定的图标这里图标对应的字符编码为“”具体图标样式由layui框架定义用于表示时间线的节点标记 -->
<i class="layui-icon layui-timeline-axis"></i>
<!-- 创建一个div元素用于包裹时间线节点的具体内容应用layui的文本样式类layui-text使内部文本能按照layui框架的默认文本样式显示 -->
<div class="layui-timeline-content layui-text">
<!-- 创建一个标题h3元素应用layui的时间线标题样式类layui-timeline-title并设置了id为“mytime”用于后续通过JavaScript操作来动态更新显示的时间内容 -->
<h3 class="layui-timeline-title" id="mytime"></h3>
<p>
<!-- 显示访客日志的统计信息先是显示“访客日志共计”字样然后通过EL表达式展示pageInfo对象中total属性的值通常表示总日志条数接着显示“条”以及其他相关的日志显示数量等信息
例如当前显示的条数通过pageInfo对象的size属性获取用于让用户对访客日志的整体情况和当前展示情况有清晰的了解 -->
访客日志共计:&nbsp;${pageInfo.total}&nbsp;条&emsp;当前显示:${pageInfo.size}&nbsp;条&emsp;&emsp;
<!-- 通过JSTL的if条件判断标签判断pageInfo对象中的pageNum属性通常表示当前页码是否大于1如果大于1则表示不是第一页执行标签内的代码显示“上一页”的链接 -->
<c:if test="${pageInfo.pageNum > 1}">
<!-- 创建一个超链接a元素href属性通过EL表达式拼接出具体的URL路径用于跳转到上一页当前页码减1每页显示10条数据size=10链接显示的文本为“上一页”方便用户进行翻页操作 -->
<a href="${pageContext.request.contextPath}/visitor/log?page=${pageInfo.pageNum - 1}&size=10">上一页</a>&emsp;&emsp;
</c:if>
<!-- 通过JSTL的if条件判断标签判断pageInfo对象中的pageNum属性是否小于总页数pageInfo.pages如果小于总页数则表示不是最后一页执行标签内的代码显示“下一页”的链接 -->
<c:if test="${pageInfo.pageNum < pageInfo.pages}">
<!-- 创建一个超链接a元素href属性通过EL表达式拼接出具体的URL路径用于跳转到下一页当前页码加1每页显示10条数据size=10链接显示的文本为“下一页”方便用户进行翻页操作 -->
<a href="${pageContext.request.contextPath}/visitor/log?page=${pageInfo.pageNum + 1}&size=10">下一页</a>
</c:if>
</p>
<ul>
<!-- 使用JSTL的forEach循环标签开始循环遍历pageInfo.list中的数据通常是分页后的访客日志列表集合每次循环将当前元素赋值给log变量方便在列表中展示各个访客日志的详细信息 -->
<c:forEach items="${pageInfo.list}" var="log">
<!-- 通过JSTL的if条件判断标签判断访客日志对象log中的end_date属性是否为空字符串如果为空字符串则表示访客尚未离开执行标签内的代码显示相应的访客日志信息 -->
<c:if test="${log.end_date == ''}">
<!-- 创建一个列表项li元素用于展示访客的具体日志信息按照指定格式显示访客姓名、访问时间、访问地点、访问事因以及尚未离开的提示信息 -->
<li>【${log.name}】于&nbsp;${log.begin_date}&nbsp;访问了${log.place},事因${log.visit_result},目前尚未离开</li>
</c:if>
<c:if test="${log.end_date != ''}">
<!-- 通过JSTL的if条件判断标签判断访客日志对象log中的end_date属性是否不为空字符串如果不为空字符串则表示访客已经离开执行标签内的代码显示相应的访客日志信息 -->
<c:if test="${log.end_date!= ''}">
<!-- 创建一个列表项li元素用于展示访客的具体日志信息按照指定格式显示访客姓名、访问时间、访问地点、访问事因以及离开时间等信息 -->
<li>【${log.name}】于&nbsp;${log.begin_date}&nbsp;访问了${log.place},事因${log.visit_result},并与${log.end_date}离开</li>
</c:if>
</c:forEach>
</ul>
</div>
</li>
<!-- 创建另一个列表项li元素作为时间线中的另一个节点同样应用layui的时间线项目样式类layui-timeline-item -->
<li class="layui-timeline-item">
<!-- 创建一个图标i元素应用layui的图标样式类layui-icon以及时间轴样式类layui-timeline-axis显示特定的图标这里图标对应的字符编码为“”具体图标样式由layui框架定义用于表示时间线的节点标记 -->
<i class="layui-icon layui-timeline-axis"></i>
<!-- 创建一个div元素用于包裹时间线节点的具体内容应用layui的文本样式类layui-text使内部文本能按照layui框架的默认文本样式显示 -->
<div class="layui-timeline-content layui-text">
<!-- 创建一个标题div元素应用layui的时间线标题样式类layui-timeline-title显示固定的文本“2020.02.21日志开启”,用于标记日志开始的时间点等相关信息 -->
<div class="layui-timeline-title">2020.02.21日志开启</div>
</div>
</li>
</ul>
<script>
function showTime(){
// 创建一个Date对象用于获取当前的日期和时间信息
var nowtime =new Date();
// 通过Date对象的getFullYear方法获取当前的年份信息
var year=nowtime.getFullYear();
// 通过Date对象的getMonth方法获取当前的月份信息注意返回值是0 - 11所以需要加1才是实际的月份
var month=nowtime.getMonth()+1;
// 通过Date对象的getDate方法获取当前的日期信息即一个月中的第几天
var date=nowtime.getDate();
document.getElementById("mytime").innerText=year+"年"+month+"月"+date+"日";
// 通过JavaScript的DOM操作获取id为“mytime”的元素对应页面中的h3标题元素并设置其内部文本内容为按照指定格式拼接的当前日期信息
// 用于在页面上动态显示当前的时间(年、月、日)
document.getElementById("mytime").innerText=year+"年"+month+"日"+date+"日";
}
// 使用JavaScript的setInterval函数每隔一段时间这里是1000 * 60毫秒即60秒执行一次传入的函数这里是showTime函数
// 实现每隔60秒更新一次页面上显示的时间通过调用showTime函数来更新id为“mytime”的元素显示的日期内容
setInterval("showTime()",1000*60);
</script>
</body>
</html>
</html>

@ -6,14 +6,36 @@
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!--
指令标签,用于设置页面的内容类型、字符编码和编程语言。
contentType: 设置响应的MIME类型为"text/html"表示这是一个HTML格式的页面内容同时设置字符编码为UTF-8确保页面中的中文等特殊字符能正确显示避免出现乱码情况。
language: 声明页面使用的编程语言是Java意味着在这个JSP页面中可以嵌入Java代码片段或者使用基于Java的各种标签库等功能来实现动态页面内容生成等操作。
-->
<html>
<head>
<!--
定义页面标题,当用户访问此页面时,浏览器标签页会显示“登记成功”,这个标题简洁明了地告知用户当前页面所对应的操作结果状态。
-->
<title>登记成功</title>
</head>
<body>
<!--
使用HTML的<h4>标签显示一条消息给用户,<h4>标签表示四级标题,在这里用于突出显示重要的提示信息,告知他们来访登记已经成功,
style="text-align: center;" 是内联样式属性设置,通过设置"text-align"为"center",使得该标题文本在水平方向上居中显示,提升页面的美观度和可读性。
-->
<h4 style="text-align: center;">恭喜您,来访登记成功!</h4>
<!--
HTML换行标签用于在“恭喜您来访登记成功”消息后添加一个空行它是一个单标签作用就是在页面布局中产生一个换行效果
以增加视觉上的间隔,使得页面内容看起来更加清晰、有条理,避免不同内容之间过于紧凑。
-->
<br>
<!--
创建一个超链接使用HTML的<a>标签来实现,允许用户点击以执行注销登记操作,
href属性指定了链接的目标URL通过EL表达式 "${pageContext.request.contextPath}/visitor/login_out?id=${id}" 动态生成链接地址,
其中 "${pageContext.request.contextPath}" 用于获取当前应用的上下文路径(通常是项目部署后的根路径部分),"/visitor/login_out" 是具体指向执行注销登记操作的后端接口路径,
"id=${id}" 表示将当前用户对应的ID作为参数传递给注销登记的接口这里的${id}应该是在页面渲染前通过相应的模型数据或者请求属性等方式设置好具体的值),
样式属性text-align: center; 同样是内联样式设置,使链接文本在水平方向上居中显示,保持页面整体的布局风格统一,方便用户查看和操作。
-->
<a href="${pageContext.request.contextPath}/visitor/login_out?id=${id}" style="text-align: center;">注销登记</a>
</body>
</html>
</html>

@ -4,36 +4,48 @@
Date: 2019/12/18
Time: 14:05
To change this template use File | Settings | File Templates.
这部分是HTML页面头部的注释说明了该文件创建时的相关信息如创建者、创建日期、时间以及提示如何修改模板等内容方便后续对代码来源及修改情况进行追溯。
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>欢迎页面</title>
<!-- 引入layui框架的CSS样式文件路径通过表达式语言获取当前页面上下文请求路径拼接而成layui是一个用于构建页面交互界面的前端框架这里引入的CSS文件用于设置页面基于layui框架的样式风格。 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/lib/layui/css/layui.css" />
<!-- 引入jQuery库的JavaScript文件这是一个常用的JavaScript库用于简化DOM操作、事件处理等功能方便后续编写页面的交互逻辑。 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script>
</head>
<body>
<!-- 创建一个字段集fieldset元素应用layui的相关样式类layui-elem-field和layui-field-title用于对页面中的相关内容进行分组展示设置顶部外边距为30px使其与上方元素有一定间隔内部包含一个用于显示标题的<legend>元素,这里标题为“系统时间”,用于提示该部分内容的主题。 -->
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<legend>系统时间</legend>
</fieldset>
<!-- 创建一个引用块blockquote元素应用layui的相关样式类layui-elem-quote并设置id为“mytime”这个元素用于后续通过JavaScript代码动态显示系统时间初始时为空等待脚本填充内容。 -->
<blockquote class="layui-elem-quote" id="mytime"></blockquote>
<!-- 再次创建一个字段集元素同样应用layui的样式类设置顶部外边距为20px用于对下一部分内容进行分组内部标题为“控制面板”提示接下来展示的内容与系统控制面板相关。 -->
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 20px;">
<legend>控制面板</legend>
</fieldset>
<!-- 创建一个具有内边距和背景颜色设置的<div>元素,用于作为控制面板相关内容的容器,营造出一个视觉上区分开的区域,背景颜色设置为#F2F2F2浅灰色使其更突出显示。 -->
<div style="padding: 20px; background-color: #F2F2F2;">
<!-- 创建一个layui的行元素并设置列间距为15px基于layui的网格布局系统用于在水平方向上合理排列内部的各个模块使其分布更规整。 -->
<div class="layui-row layui-col-space15">
<!-- 创建一个占6列宽度基于layui的网格系统中md尺寸中等屏幕尺寸下的布局规则的列元素用于放置一个卡片式的模块。 -->
<div class="layui-col-md6">
<div class="layui-card">
<!-- 创建卡片的头部区域应用layui的卡片头部样式类显示文本“CPU利用率”用于提示该卡片内展示的内容主题。 -->
<div class="layui-card-header">CPU利用率</div>
<div class="layui-card-body">
<!-- 在卡片的主体区域内简单显示文本“CPU利用率”这里可能后续需要进一步完善比如通过JavaScript等方式动态获取并展示实际的CPU利用率数据等内容。 -->
CPU<br/>利用率
</div>
</div>
</div>
<!-- 再次创建一个占6列宽度的列元素同样放置一个卡片式模块结构与上面类似用于展示“系统出入流量”相关信息不过目前主体区域也只是简单显示文本有待进一步完善功能来展示真实数据。 -->
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">系统出入流量</div>
@ -43,6 +55,7 @@
</div>
</div>
<!-- 又创建一个占6列宽度的列元素及对应的卡片模块用于展示某个“模块”相关信息目前显示“模块待更新”文本推测后续可能会根据业务需求完善此处比如显示模块的版本、更新提示等具体内容。 -->
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">模块</div>
@ -52,6 +65,7 @@
</div>
</div>
<!-- 最后再创建一个占6列宽度的列元素及卡片模块同样显示“模块待更新”文本结构和功能与上一个模块类似可能是多个需要展示和更新管理的模块在页面上的布局体现。 -->
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">模块</div>
@ -65,16 +79,25 @@
</div>
<script>
function showTime(){
var nowtime =new Date();
var year=nowtime.getFullYear();
var month=nowtime.getMonth()+1;
var date=nowtime.getDate();
// 创建一个Date对象用于获取当前的系统时间信息它会包含年、月、日、时、分、秒等详细时间数据。
var nowtime = new Date();
// 通过Date对象的getFullYear()方法获取当前的年份例如2024年等。
var year = nowtime.getFullYear();
// 通过Date对象的getMonth()方法获取当前的月份注意返回值是0 - 11所以需要加1才是我们日常使用的1 - 12月的表示方式。
var month = nowtime.getMonth() + 1;
// 通过Date对象的getDate()方法获取当前的日期即一个月中的第几天范围是1 - 31。
var date = nowtime.getDate();
// 通过Date对象的getHours()方法获取当前的小时数范围是0 - 23。
var h = nowtime.getHours();
// 通过Date对象的getMinutes()方法获取当前的分钟数范围是0 - 59。
var m = nowtime.getMinutes();
// 通过Date对象的getSeconds()方法获取当前的秒数范围是0 - 59。
var s = nowtime.getSeconds();
document.getElementById("mytime").innerText=year+"年"+month+"月"+date+"日"+" "+h+"时"+m+"分"+s+"秒";
// 将获取到的年、月、日、时、分、秒等时间信息组合成一个格式化后的字符串并通过DOM操作使用document.getElementById获取id为“mytime”的元素然后设置其innerText属性将这个时间字符串显示在页面上对应的引用块元素中实现动态显示系统当前时间的功能。
document.getElementById("mytime").innerText = year + "年" + month + "月" + date + "日" + " " + h + "时" + m + "分" + s + "秒";
}
setInterval("showTime()",1000);
// 使用JavaScript的setInterval函数每隔1000毫秒即1秒调用一次showTime函数从而实现每隔1秒更新一次页面上显示的系统时间达到实时显示当前时间的效果。
setInterval("showTime()", 1000);
</script>
</body>
</html>
</html>

File diff suppressed because it is too large Load Diff

@ -1,150 +1,193 @@
/* 定义一个名为 mobileSelect 的类,用于设置选择器的样式 */
.mobileSelect {
position: relative;
z-index: 0;
opacity: 0;
visibility: hidden;
-webkit-transition: opacity 0.4s, z-index 0.4s;
transition: opacity 0.4s, z-index 0.4s;
}
position: relative; /* 相对定位 */
z-index: 0; /* 层级为0 */
opacity: 0; /* 初始透明度为0即不可见 */
visibility: hidden; /* 初始状态为隐藏 */
-webkit-transition: opacity 0.4s, z-index 0.4s; /* 过渡效果透明度和层级变化持续0.4秒 */
transition: opacity 0.4s, z-index 0.4s; /* 标准过渡效果 */
}
/* 设置 mobileSelect 内所有元素的边距和填充为0并使用盒模型计算方式 */
.mobileSelect * {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
/* 定义 mobileSelect 内的 grayLayer 类的样式 */
.mobileSelect .grayLayer {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: #eee;
background: rgba(0, 0, 0, 0.7);
z-index: 888;
display: block;
}
position: fixed; /* 固定定位 */
top: 0; /* 距离顶部0 */
left: 0; /* 距离左侧0 */
bottom: 0; /* 距离底部0 */
right: 0; /* 距离右侧0 */
background: #eee; /* 背景色 */
background: rgba(0, 0, 0, 0.7); /* 半透明黑色背景 */
z-index: 888; /* 层级为888 */
display: block; /* 显示为块级元素 */
}
/* 定义 mobileSelect 内的 content 类的样式 */
.mobileSelect .content {
width: 100%;
display: block;
position: fixed;
z-index: 889;
color: black;
-webkit-transition: all 0.4s;
transition: all 0.4s;
bottom: -350px;
left: 0;
background: white;
}
width: 100%; /* 宽度100% */
display: block; /* 显示为块级元素 */
position: fixed; /* 固定定位 */
z-index: 889; /* 层级为889 */
color: black; /* 文字颜色为黑色 */
-webkit-transition: all 0.4s; /* 所有属性的过渡效果持续0.4秒 */
transition: all 0.4s; /* 标准过渡效果 */
bottom: -350px; /* 初始位置在视口下方350px处 */
left: 0; /* 距离左侧0 */
background: white; /* 背景色为白色 */
}
/* 定义 content 内的 fixWidth 类的样式 */
.mobileSelect .content .fixWidth {
width: 90%;
margin: 0 auto;
position: relative;
width: 90%; /* 宽度为90% */
margin: 0 auto; /* 上下边距为0左右自动调整 */
position: relative; /* 相对定位 */
}
/* 定义 fixWidth 内的伪元素样式,用于清除浮动 */
.mobileSelect .content .fixWidth:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
content: "."; /* 内容为点号 */
display: block; /* 显示为块级元素 */
height: 0; /* 高度为0 */
clear: both; /* 清除浮动 */
visibility: hidden; /* 隐藏 */
}
/* 定义 content 内的 btnBar 类的样式 */
.mobileSelect .content .btnBar {
border-bottom: 1px solid #DCDCDC;
font-size: 15px;
height: 45px;
position: relative;
text-align: center;
line-height: 45px;
}
border-bottom: 1px solid #DCDCDC; /* 底部边框 */
font-size: 15px; /* 字体大小 */
height: 45px; /* 高度 */
position: relative; /* 相对定位 */
text-align: center; /* 文本居中 */
line-height: 45px; /* 行高 */
}
/* 定义 btnBar 内的 cancel 和 ensure 按钮的样式 */
.mobileSelect .content .btnBar .cancel,
.mobileSelect .content .btnBar .ensure {
height: 45px;
width: 55px;
cursor: pointer;
position: absolute;
top: 0;
}
height: 45px; /* 高度 */
width: 55px; /* 宽度 */
cursor: pointer; /* 鼠标指针样式 */
position: absolute; /* 绝对定位 */
top: 0; /* 距离顶部0 */
}
/* cancel 按钮的样式 */
.mobileSelect .content .btnBar .cancel {
left: 0;
color: #666;
left: 0; /* 距离左侧0 */
color: #666; /* 文字颜色 */
}
/* ensure 按钮的样式 */
.mobileSelect .content .btnBar .ensure {
right: 0;
color: #1e83d3;
right: 0; /* 距离右侧0 */
color: #1e83d3; /* 文字颜色 */
}
/* title 的样式 */
.mobileSelect .content .btnBar .title {
font-size: 15px;
padding: 0 15%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
font-size: 15px; /* 字体大小 */
padding: 0 15%; /* 内边距 */
overflow: hidden; /* 溢出隐藏 */
white-space: nowrap; /* 不换行 */
text-overflow: ellipsis; /* 超出部分显示省略号 */
}
/* panel 内的伪元素样式,用于清除浮动 */
.mobileSelect .content .panel:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
content: "."; /* 内容为点号 */
display: block; /* 显示为块级元素 */
height: 0; /* 高度为0 */
clear: both; /* 清除浮动 */
visibility: hidden; /* 隐藏 */
}
/* wheels 的样式 */
.mobileSelect .content .panel .wheels {
width: 100%;
height: 200px;
overflow: hidden;
width: 100%; /* 宽度100% */
height: 200px; /* 高度200px */
overflow: hidden; /* 溢出隐藏 */
}
/* wheel 的样式 */
.mobileSelect .content .panel .wheel {
position: relative;
z-index: 0;
float: left;
width: 50%;
height: 200px;
overflow: hidden;
-webkit-transition: width 0.3s ease;
transition: width 0.3s ease;
}
position: relative; /* 相对定位 */
z-index: 0; /* 层级为0 */
float: left; /* 左浮动 */
width: 100%; /* 宽度100% */
height: 200px; /* 高度200% */
overflow: hidden; /* 溢出隐藏 */
-webkit-transition: width 0.3s ease; /* Webkit浏览器的过渡效果 */
transition: width 0.3s ease; /* 标准过渡效果 */
}
/* selectContainer 的样式 */
.mobileSelect .content .panel .wheel .selectContainer {
display: block;
text-align: center;
-webkit-transition: -webkit-transform 0.18s ease-out;
transition: -webkit-transform 0.18s ease-out;
transition: transform 0.18s ease-out;
transition: transform 0.18s ease-out, -webkit-transform 0.18s ease-out;
}
display: block; /* 显示为块级元素 */
text-align: center; /* 文本居中 */
-webkit-transition: -webkit-transform 0.18s ease-out; /* Webkit浏览器的过渡效果 */
transition: -webkit-transform 0.18s ease-out; /* Webkit浏览器的标准过渡效果 */
transition: transform 0.18s ease-out; /* 标准过渡效果 */
transition: transform 0.18s ease-out, -webkit-transform 0.18s ease-out; /* 同时应用两种过渡效果 */
}
/* selectContainer li元素的样式 */
.mobileSelect .content .panel .wheel .selectContainer li {
font-size: 15px;
display: block;
height: 40px;
line-height: 40px;
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
font-size: 15px; /* 字体大小 */
display: block; /* 显示为块级元素 */
height: 40px; /* 高度40px */
line-height: 40px; /* 行高40px */
color: #ffffff; /* 文字颜色为白色 */
cursor: pointer; /* 鼠标指针样式 */
white-space: nowrap; /* 不换行 */
text-overflow: ellipsis; /* 超出部分显示省略号 */
}
/* selectLine的样式 */
.mobileSelect .content .panel .selectLine {
height: 40px;
width: 100%;
position: absolute;
top: 80px;
pointer-events: none;
-webkit-box-sizing: border-box;
box-sizing: border-box;
border-top: 1px solid #DCDCDC;
border-bottom: 1px solid #DCDCDC;
}
height: 40px; /* 高度40px */
width: 100%; /* 宽度100% */
position: absolute; /* 绝对定位 */
top: 80px; /* 距离顶部80px */
pointer-events: none; /* 禁止鼠标事件 */
-webkit-box-sizing: border-box; /* Webkit浏览器的盒模型计算方式 */
box-sizing: border-box; /* 标准盒模型计算方式 */
border-top: 1px solid #DCDCDC; /* 上边框 */
border-bottom: 1px solid #DCDCDC; /* 下边框 */
}
/* shadowMask的样式 */
.mobileSelect .content .panel .shadowMask {
position: absolute;
top: 0;
width: 100%;
height: 200px;
background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), color-stop(rgba(255, 255, 255, 0)), to(#ffffff));
background: -webkit-linear-gradient(top, #ffffff, rgba(255, 255, 255, 0), #ffffff);
background: linear-gradient(to bottom, #ffffff, rgba(255, 255, 255, 0), #ffffff);
opacity: 0.9;
pointer-events: none;
}
position: absolute; /* 绝对定位 */
top: 0; /* 距离顶部0 */
width: 100%; /* 宽度100% */
height: 200px; /* 高度200px */
background: -webkit-linear-gradient(top, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变 */
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* 标准背景渐变 */
background: -webkit-linear-gradient(top, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
background: linear-gradient(to bottom, #ffffff, rgba(255,255,255,0), #ffffff); /* Webkit浏览器的背景渐变重复*/
}
/* mobileSelect-show类的样式用于显示时的状态 */
.mobileSelect-show {
opacity: 1;
z-index: 10000;
visibility: visible;
z-index: 10000; /* z轴层级提高至10000 */
}
/* mobileSelect-show类的content子元素的样式用于显示时的状态 */
.mobileSelect-show .content {
bottom: 0;
bottom: -350px; /* bottom属性设置为-350px使其完全显示在视窗内 */
}

@ -2,7 +2,9 @@
/* Functional styling;
* These styles are required for noUiSlider to function.
* You don't need to change these rules to apply your design.
*/
* nouiSlider */
/* 针对.noUi-target类以及其内部所有元素设置一些交互相关的属性禁止长按弹出菜单、去除点击高亮颜色、禁止用户选择文本等操作同时设置盒模型为border-box使得元素的尺寸计算包含边框和内边距 */
.noUi-target,
.noUi-target * {
-webkit-touch-callout: none;
@ -16,10 +18,14 @@
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* 设置.noUi-target类元素一般是滑块的外层容器为相对定位并且设置文本方向从左到右ltr这符合常规的页面布局习惯 */
.noUi-target {
position: relative;
direction: ltr;
}
/* 设置.noUi-base类元素一般是滑块的基础部分比如轨道等宽度和高度都占满父容器并且设置相对定位以及较高的z-index值使其在堆叠顺序中处于较上层方便后续元素基于它进行定位注释中的“Fix 401”可能是针对某个特定问题的修复说明具体需结合相关开发背景理解 */
.noUi-base {
width: 100%;
height: 100%;
@ -27,6 +33,8 @@
z-index: 1;
/* Fix 401 */
}
/* 设置.noUi-connect类元素一般是滑块轨道上表示已选择范围的连接部分为绝对定位使其占满整个.noUi-target元素即滑块外层容器的内部空间通过设置上下左右都为0来实现 */
.noUi-connect {
position: absolute;
right: 0;
@ -34,59 +42,82 @@
left: 0;
bottom: 0;
}
/* 设置.noUi-origin类元素可能与滑块的起始位置等相关概念对应为绝对定位并且初始高度和宽度都设置为0后续可能会通过JavaScript等动态改变其尺寸和位置来实现滑块的功能逻辑 */
.noUi-origin {
position: absolute;
height: 0;
width: 0;
}
/* 设置.noUi-handle类元素即滑块的手柄部分为相对定位并且设置较高的z-index值使其在堆叠顺序中处于较上层能显示在轨道等元素之上 */
.noUi-handle {
position: relative;
z-index: 1;
}
.noUi-state-tap .noUi-connect,
.noUi-state-tap .noUi-origin {
/* 当.noUi-target元素处于点击状态.noUi-state-tap类存在时对其内部的.noUi-connect和.noUi-origin元素设置过渡效果当它们的位置属性top、right、bottom、left改变时会有平滑的过渡动画过渡时间为0.3秒 */
.noUi-state-tap.noUi-connect,
.noUi-state-tap.noUi-origin {
-webkit-transition: top 0.3s, right 0.3s, bottom 0.3s, left 0.3s;
transition: top 0.3s, right 0.3s, bottom 0.3s, left 0.3s;
}
/* 当.noUi-target元素处于拖动状态.noUi-state-drag类存在时将其内部所有元素的鼠标指针样式强制设置为继承父元素的样式这样可以确保在拖动过程中鼠标指针样式符合预期不会出现异常 */
.noUi-state-drag * {
cursor: inherit !important;
cursor: inherit!important;
}
/* Painting and performance;
* Browsers can paint handles in their own layer.
*/
* 使3D */
.noUi-base,
.noUi-handle {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
/* Slider size and handle placement;
*/
* */
/* 当滑块为水平布局(.noUi-horizontal类存在时设置滑块的高度为18px */
.noUi-horizontal {
height: 18px;
}
.noUi-horizontal .noUi-handle {
/* 当滑块为水平布局时,对其内部的.noUi-handle类元素滑块手柄进行样式设置设置宽度、高度、水平和垂直方向的偏移量使其在滑块轨道上处于合适的位置 */
.noUi-horizontal.noUi-handle {
width: 34px;
height: 28px;
left: -17px;
top: -6px;
}
/* 当滑块为垂直布局(.noUi-vertical类存在时设置滑块的宽度为18px */
.noUi-vertical {
width: 18px;
}
.noUi-vertical .noUi-handle {
/* 当滑块为垂直布局时,对其内部的.noUi-handle类元素滑块手柄进行样式设置设置宽度、高度、水平和垂直方向的偏移量使其在滑块轨道上处于合适的位置 */
.noUi-vertical.noUi-handle {
width: 28px;
height: 34px;
left: -6px;
top: -17px;
}
/* Styling;
*/
* */
/* 设置.noUi-target类元素滑块外层容器的背景颜色、边框圆角、边框样式以及内部阴影效果使其呈现出一种特定的外观风格 */
.noUi-target {
background: #FAFAFA;
border-radius: 4px;
border: 1px solid #D3D3D3;
box-shadow: inset 0 1px 1px #F0F0F0, 0 3px 6px -5px #BBB;
}
/* 设置.noUi-connect类元素滑块轨道上表示已选择范围的连接部分的背景颜色、边框圆角以及内部阴影效果并且设置其背景颜色改变时有过渡动画过渡时间为450毫秒用于实现一些交互时的视觉效果 */
.noUi-connect {
background: #3FB8AF;
border-radius: 4px;
@ -94,14 +125,21 @@
-webkit-transition: background 450ms;
transition: background 450ms;
}
/* Handles and cursors;
*/
* */
/* 当滑块可拖动(.noUi-draggable类存在时一般是水平滑块的情况设置鼠标指针样式为左右拉伸的样式符合水平拖动操作的视觉提示 */
.noUi-draggable {
cursor: ew-resize;
}
.noUi-vertical .noUi-draggable {
/* 当滑块为垂直可拖动(.noUi-vertical类且.noUi-draggable类存在时即垂直滑块情况设置鼠标指针样式为上下拉伸的样式符合垂直拖动操作的视觉提示 */
.noUi-vertical.noUi-draggable {
cursor: ns-resize;
}
/* 设置.noUi-handle类元素滑块手柄的边框样式、边框圆角、背景颜色以及多种阴影效果使其呈现出立体、有质感的外观并且将默认鼠标指针样式设置为默认样式default */
.noUi-handle {
border: 1px solid #D9D9D9;
border-radius: 3px;
@ -109,11 +147,16 @@
cursor: default;
box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;
}
/* 当.noUi-handle类元素处于激活状态.noUi-active类存在时比如正在被点击或拖动时改变其阴影效果呈现出一种不同的视觉反馈用于提示用户当前正在操作滑块手柄 */
.noUi-active {
box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #DDD, 0 3px 6px -3px #BBB;
}
/* Handle stripes;
*/
* :before:after */
/* 在.noUi-handle类元素滑块手柄的:before伪元素上设置样式创建一个竖条样式用于模拟手柄上的条纹装饰效果设置其内容为空因为只是用于装饰、显示为块状元素、设置高度、宽度、背景颜色以及位置等属性 */
.noUi-handle:before,
.noUi-handle:after {
content: "";
@ -125,69 +168,98 @@
left: 14px;
top: 6px;
}
/* 同样在.noUi-handle类元素滑块手柄的:after伪元素上设置样式创建另一个竖条样式位置与:before略有不同共同构成手柄上的条纹装饰效果 */
.noUi-handle:after {
left: 17px;
}
.noUi-vertical .noUi-handle:before,
.noUi-vertical .noUi-handle:after {
/* 当滑块为垂直布局时,对.noUi-handle类元素滑块手柄的:before和:after伪元素重新设置样式将竖条变为横条通过改变宽度和高度属性以及位置来实现以适配垂直方向的手柄外观 */
.noUi-vertical.noUi-handle:before,
.noUi-vertical.noUi-handle:after {
width: 14px;
height: 1px;
left: 6px;
top: 14px;
}
.noUi-vertical .noUi-handle:after {
/* 针对垂直布局下的.noUi-handle类元素滑块手柄的:after伪元素进一步调整其位置使其与:before伪元素配合形成合适的横条装饰效果 */
.noUi-vertical.noUi-handle:after {
top: 17px;
}
/* Disabled state;
*/
[disabled] .noUi-connect {
* */
/* 当元素处于禁用状态([disabled]选择器匹配时),对.noUi-connect类元素滑块轨道上表示已选择范围的连接部分设置背景颜色使其呈现出一种表示不可用的视觉效果 */
[disabled].noUi-connect {
background: #B8B8B8;
}
/* 当元素处于禁用状态时,对.noUi-target、.noUi-handle以及.noUi-handle类元素分别对应滑块外层容器、滑块手柄等设置鼠标指针样式为不允许操作的样式not-allowed提示用户当前滑块不可用 */
[disabled].noUi-target,
[disabled].noUi-handle,
[disabled] .noUi-handle {
[disabled].noUi-handle {
cursor: not-allowed;
}
/* Base;
*
*/
* .noUi-pipsborder-box */
.noUi-pips,
.noUi-pips * {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* 设置.noUi-pips类元素一般是用于放置刻度标记、数值显示等内容的容器为绝对定位并且设置文字颜色 */
.noUi-pips {
position: absolute;
color: #999;
}
/* Values;
*
*/
* */
/* 设置.noUi-value类元素一般用于显示具体的数值为绝对定位并且设置文本不换行、文本水平居中对齐确保数值能正确显示在相应位置 */
.noUi-value {
position: absolute;
white-space: nowrap;
text-align: center;
}
/* 设置.noUi-value-sub类元素可能是用于显示数值的副标题、辅助信息等比如小数部分等的文字颜色和字体大小使其与主数值有一定的视觉区分 */
.noUi-value-sub {
color: #ccc;
font-size: 10px;
}
/* Markings;
*
*/
* 线 */
/* 设置.noUi-marker类元素一般是滑块上的刻度线等标记为绝对定位并且设置背景颜色用于呈现出刻度线的外观 */
.noUi-marker {
position: absolute;
background: #CCC;
}
/* 设置.noUi-marker-sub类元素可能是细分刻度线等更小的标记的背景颜色使其与普通刻度线有一定视觉区分 */
.noUi-marker-sub {
background: #AAA;
}
/* 设置.noUi-marker-large类元素可能是较大的重要刻度线等标记的背景颜色同样用于视觉区分突出显示重要刻度 */
.noUi-marker-large {
background: #AAA;
}
/* Horizontal layout;
*
*/
* */
/* 设置.noUi-pips-horizontal类元素水平布局下的刻度标记等容器的内边距、高度、垂直位置以及宽度使其在水平滑块下方合适的位置显示 */
.noUi-pips-horizontal {
padding: 10px 0;
height: 80px;
@ -195,66 +267,61 @@
left: 0;
width: 100%;
}
/* 当滑块为水平布局时,对.noUi-value类元素数值显示部分进行位置调整通过3D变换将其在水平和垂直方向上移动到合适位置使其能准确显示在对应的刻度位置上方 */
.noUi-value-horizontal {
-webkit-transform: translate3d(-50%, 50%, 0);
transform: translate3d(-50%, 50%, 0);
}
/* 当滑块为水平布局时,对.noUi-marker-horizontal类元素水平布局下的刻度线等标记进行样式设置设置其宽度、高度以及左右外边距等使其呈现出水平方向的刻度线外观 */
.noUi-marker-horizontal.noUi-marker {
margin-left: -1px;
width: 2px;
height: 5px;
}
/* 当滑块为水平布局时,对.noUi-marker-horizontal类元素水平布局下的细分刻度线等标记进行样式设置调整其高度使其与普通刻度线有一定视觉区分 */
.noUi-marker-horizontal.noUi-marker-sub {
height: 10px;
}
/* 当滑块为水平布局时,对.noUi-marker-horizontal类元素水平布局下的较大刻度线等标记进行样式设置调整其高度使其更加突出显示与其他刻度线区分开来 */
.noUi-marker-horizontal.noUi-marker-large {
height: 15px;
}
/* Vertical layout;
*
*/
* */
/* 设置.noUi-pips-vertical类元素垂直布局下的刻度标记等容器的内边距、高度、垂直和水平位置使其在垂直滑块右侧合适的位置显示 */
.noUi-pips-vertical {
padding: 0 10px;
height: 100%;
top: 0;
left: 100%;
}
/* 当滑块为垂直布局时,对.noUi-value类元素数值显示部分进行位置调整通过3D变换将其在水平和垂直方向上移动到合适位置使其能准确显示在对应的刻度位置右侧并且设置左边距使其与刻度线等有合适的间距 */
.noUi-value-vertical {
-webkit-transform: translate3d(0, 50%, 0);
transform: translate3d(0, 50%, 0);
padding-left: 25px;
}
/* 当滑块为垂直布局时,对.noUi-marker-vertical类元素垂直布局下的刻度线等标记进行样式设置设置其宽度、高度以及上下外边距等使其呈现出垂直方向的刻度线外观 */
.noUi-marker-vertical.noUi-marker {
width: 5px;
height: 2px;
margin-top: -1px;
}
/* 当滑块为垂直布局时,对.noUi-marker-vertical类元素垂直布局下的细分刻度线等标记进行样式设置调整其宽度使其与普通刻度线有一定视觉区分 */
.noUi-marker-vertical.noUi-marker-sub {
width: 10px;
}
/* 当滑块为垂直布局时,对.noUi-marker-vertical类元素垂直布局下的较大刻度线等标记进行样式设置调整其宽度使其更加突出显示与其他刻度线区分开来 */
.noUi-marker-vertical.noUi-marker-large {
width: 15px;
}
.noUi-tooltip {
display: block;
position: absolute;
border: 1px solid #D9D9D9;
border-radius: 3px;
background: #fff;
color: #000;
padding: 5px;
text-align: center;
white-space: nowrap;
}
.noUi-horizontal .noUi-tooltip {
-webkit-transform: translate(-50%, 0);
transform: translate(-50%, 0);
left: 50%;
bottom: 120%;
}
.noUi-vertical .noUi-tooltip {
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%);
top: 50%;
right: 120%;
}
width: 15px;}

@ -1,64 +1,75 @@
html,body{
width:100%;
height:100%;
/* 设置html和body元素的宽度和高度都占满整个视口确保页面能铺满浏览器窗口 */
html,body{
width:100%;
height:100%;
}
/* 设置canvas元素的显示方式为块级元素并且在垂直方向上与父元素底部对齐常用于图形绘制等相关场景比如一些基于canvas的动画、特效展示等 */
canvas{
display:block;
vertical-align:bottom;
display:block;
vertical-align:bottom;
}
/* 类名为.count-particles的元素样式用于统计粒子相关的显示设置 */
/* 设置背景颜色为深黑色绝对定位指定其在页面中的位置距离顶部48px左侧0px设置宽度为80px文字颜色为特定的亮色字体大小为相对父元素的0.8em,文本左对齐,设置首行缩进,行高,底部内边距等样式,并且指定字体族以及加粗字体样式 */
.count-particles{
background: #000022;
position: absolute;
top: 48px;
left: 0;
width: 80px;
color: #13E8E9;
font-size: .8em;
text-align: left;
text-indent: 4px;
line-height: 14px;
padding-bottom: 2px;
font-family: Helvetica, Arial, sans-serif;
font-weight: bold;
background: #000022;
position: absolute;
top: 48px;
left: 0;
width: 80px;
color: #13E8E9;
font-size:.8em;
text-align: left;
text-indent: 4px;
line-height: 14px;
padding-bottom: 2px;
font-family: Helvetica, Arial, sans-serif;
font-weight: bold;
}
/* 类名为.js-count-particles的元素样式可能用于通过JavaScript动态控制的粒子计数相关元素设置字体大小为相对父元素的1.1em,相对.count-particles类中的字体大小有所增大用于突出显示等目的 */
.js-count-particles{
font-size: 1.1em;
font-size: 1.1em;
}
/* 对id为stats以及类名为count-particles的元素设置样式禁止用户选择文本内容在一些交互场景下避免用户误操作选择文本并且设置顶部和左侧的外边距为5px使其在页面中有一定的间距 */
#stats,
.count-particles{
-webkit-user-select: none;
margin-top: 5px;
margin-left: 5px;
-webkit-user-select: none;
margin-top: 5px;
margin-left: 5px;
}
/* 对id为stats的元素设置样式设置其边框右上角和左上角的圆角半径为3px右下角和左下角的圆角半径为0并且设置超出部分隐藏常用于一些需要展示特定形状且不希望内容溢出的容器元素比如统计信息展示框等 */
#stats{
border-radius: 3px 3px 0 0;
overflow: hidden;
border-radius: 3px 3px 0 0;
overflow: hidden;
}
/* 对类名为count-particles的元素设置样式设置其边框右下角和左下角的圆角半径为3px右上角和左上角的圆角半径为0与#stats元素的边框圆角设置配合可能用于形成一个完整的、有特定外观的容器样式 */
.count-particles{
border-radius: 0 0 3px 3px;
border-radius: 0 0 3px 3px;
}
/* 对id为particles-js的元素设置样式通常用于承载粒子效果的容器 */
/* 设置宽度和高度都占满父容器一般就是整个页面可视区域相对定位设置背景图片指定其在水平和垂直方向上都居中显示设置背景图片铺满整个容器根据容器大小自动缩放并且不重复显示使其作为页面的背景铺满整个页面同时让其在水平方向上自动居中通过设置左右外边距为auto实现 */
#particles-js{
width: 100%;
height: 100%;
position: relative;
background-image: url(../images/bg.jpg);
background-position: 50% 50%;
background-size: cover;
background-repeat: no-repeat;
margin-left: auto;
margin-right: auto;
width: 100%;
height: 100%;
position: relative;
background-image: url(../images/bg.jpg);
background-position: 50% 50%;
background-size: cover;
background-repeat: no-repeat;
margin-left: auto;
margin-right: auto;
}
/* 类名为sk-rotating-plane的元素样式一般用于实现旋转动画效果的元素 */
/* 初始设置为不显示display: none指定宽度和高度设置自动水平居中通过设置左右外边距为auto实现背景颜色为白色定义动画名称、持续时间以及循环播放且缓动效果为ease-in-out设置较高的z-index值使其能显示在其他元素之上绝对定位并且通过设置top和left属性以及负外边距来使其在页面中垂直和水平方向上都居中显示 */
.sk-rotating-plane {
display: none;
display: none;
width: 80px;
height: 80px;
margin: auto;
@ -72,42 +83,182 @@ canvas{
margin-left: -40px;
margin-top: -80px;
}
/* 当类名为sk-rotating-plane的元素同时具有active类时将其显示出来display: block可能通过JavaScript动态添加active类来控制其显示隐藏实现特定的交互效果 */
.sk-rotating-plane.active{display: block;}
/* 定义名为sk-rotating-plane的关键帧动画 */
/* 在动画的不同阶段0%、50%、100%设置元素的3D旋转效果通过transform属性以及不同浏览器前缀来兼容各种浏览器实现一个围绕X轴和Y轴旋转的动画效果用于呈现旋转的视觉效果 */
@keyframes sk-rotating-plane{
0% {
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
}
50% {
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
}
100% {
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
0% {
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
}
50% {
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
}
100% {
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
}
/* 定义名为login-small的关键帧动画 */
/* 在动画的开始0%和结束100%阶段设置元素的缩放效果通过不同浏览器前缀的transform属性来兼容各种浏览器实现从原始大小缩放到较小尺寸的动画效果可能用于登录框等元素的隐藏或缩小展示等交互场景 */
@keyframes login-small{
0%{
transform: scale(1);-moz-transform: scale(1); /* Firefox 4 */-webkit-transform: scale(1); /* Safari 和 Chrome */-o-transform: scale(1); /* Opera */-ms-transform:scale(1); /* IE 9 */
}
100%{
transform: scale(0.2);-moz-transform: scale(0.1); /* Firefox 4 */-webkit-transform: scale(0.2); /* Safari 和 Chrome */-o-transform: scale(0.1); /* Opera */-ms-transform:scale(0.1); /* IE 9 */
}
}
.login{z-index: 2;position:absolute;width: 350px;border-radius: 5px;height: 500px;background: white;box-shadow: 0px 0px 5px #333333;top: 50%;left: 50%;margin-top: -250px;margin-left: -175px;transition: all 1s;-moz-transition: all 1s; /* Firefox 4 */-webkit-transition: all 1s; /* Safari 和 Chrome */-o-transition: all 1s; /* Opera */}
.login-top{font-size: 24px;margin-top: 100px;padding-left: 40px;box-sizing: border-box;color: #333333;margin-bottom: 50px;}
.login-center{width: 100%;box-sizing: border-box;padding: 0 40px;margin-bottom: 30px;}
.login-center-img{width: 20px;height: 20px;float: left;margin-top: 5px;}
.login-center-img>img{width: 100%;}
.login-center-input{float: left;width: 230px;margin-left: 15px;height: 30px;position: relative;}
.login-center-input input{z-index: 2;transition: all 0.5s;padding-left: 10px;color: #333333;width: 100%;height: 30px;border: 0;border-bottom: 1px solid #cccccc;border-top: 1px solid #ffffff;border-left: 1px solid #ffffff;border-right: 1px solid #ffffff;box-sizing: border-box;outline: none;position: relative;}
.login-center-input input:focus{border: 1px solid dodgerblue;}
.login-center-input-text{background: white;padding: 0 5px;position: absolute;z-index: 0;opacity: 0;height: 20px;top: 50%;margin-top: -10px;font-size: 14px;left: 5px;color: dodgerblue;line-height: 20px;transition: all 0.5s;-moz-transition: all 0.5s; /* Firefox 4 */-webkit-transition: all 0.5s; /* Safari 和 Chrome */-o-transition: all 0.5s; /* Opera */}
.login-center-input input:focus~.login-center-input-text{top: 0;z-index: 3;opacity: 1;margin-top: -15px;}
.login.active{-webkit-animation: login-small 0.8s ; animation: login-small 0.8s ;animation-fill-mode:forwards;-webkit-animation-fill-mode:forwards}
.login-button{cursor: pointer;width: 250px;text-align: center;height: 40px;line-height: 40px;background-color: dodgerblue;border-radius: 5px;margin: 0 auto;margin-top: 50px;color: white;}
0%{
transform: scale(1);
-moz-transform: scale(1); /* Firefox 4 */
-webkit-transform: scale(1); /* Safari 和 Chrome */
-o-transform: scale(1); /* Opera */
-ms-transform:scale(1); /* IE 9 */
}
100%{
transform: scale(0.2);
-moz-transform: scale(0.1); /* Firefox 4 */
-webkit-transform: scale(0.2); /* Safari 和 Chrome */
-o-transform: scale(0.1); /* Opera */
-ms-transform:scale(0.1); /* IE 9 */
}
}
/* 类名为login的元素样式一般用于登录框相关的整体布局和外观设置 */
/* 设置较高的z-index值使其能显示在其他元素之上绝对定位指定宽度、边框圆角、高度以及背景颜色为白色添加阴影效果使其有立体感通过设置top和left属性以及负外边距来使其在页面中垂直和水平方向上都居中显示并且设置所有属性改变时的过渡效果用于实现一些动画过渡效果比如显示隐藏、大小改变等操作时的平滑过渡 */
.login{
z-index: 2;
position:absolute;
width: 350px;
border-radius: 5px;
height: 500px;
background: white;
box-shadow: 0px 0px 5px #333333;
top: 50%;
left: 50%;
margin-top: -250px;
margin-left: -175px;
transition: all 1s;
-moz-transition: all 1s; /* Firefox 4 */
-webkit-transition: all 1s; /* Safari 和 Chrome */
-o-transition: all 1s; /* Opera */
}
/* 类名为login-top的元素样式一般是登录框顶部区域比如用于显示登录标题等内容 */
/* 设置字体大小、顶部外边距、文本左对齐时的左侧内边距,指定文字颜色以及底部外边距,用于调整其在登录框内的布局和外观显示 */
.login-top{
font-size: 24px;
margin-top: 100px;
padding-left: 40px;
box-sizing: border-box;
color: #333333;
margin-bottom: 50px;
}
/* 类名为login-center的元素样式一般是登录框中间部分用于放置输入框等登录相关的表单元素 */
/* 设置宽度占满父容器设置盒模型为border-box尺寸计算包含边框和内边距设置左右内边距并且设置底部外边距用于调整其内部元素的布局和整体在登录框中的位置 */
.login-center{
width: 100%;
box-sizing: border-box;
padding: 0 40px;
margin-bottom: 30px;
}
/* 类名为login-center-img的元素样式一般用于登录框中输入框左侧的图标等图片元素 */
/* 设置宽度、高度,使其向左浮动,并且设置顶部外边距,用于调整其在登录框中输入框左侧的位置和显示效果 */
.login-center-img{
width: 20px;
height: 20px;
float: left;
margin-top: 5px;
}
/* 类名为login-center-img内部的img元素样式设置图片宽度占满父元素即.login-center-img元素确保图片能正确显示 */
.login-center-img>img{
width: 100%;
}
/* 类名为login-center-input的元素样式一般是登录框中输入框相关的外层容器样式 */
/* 设置向左浮动,指定宽度、左侧外边距以及高度,并且设置相对定位,方便内部输入框等元素进行相对定位布局 */
.login-center-input{
float: left;
width: 230px;
margin-left: 15px;
height: 30px;
position: relative;
}
/* 类名为login-center-input内部的input元素样式一般就是实际的输入框样式 */
/* 设置较高的z-index值使其能显示在一些提示文字等元素之上设置所有属性改变时的过渡效果设置文本输入的内边距、文字颜色、宽度、高度以及边框样式只保留底部边框其他边框设置为透明去除默认的轮廓线outline: none并且设置相对定位方便与其他相关元素如提示文字进行交互布局 */
.login-center-input input{
z-index: 2;
transition: all 0.5s;
padding-left: 10px;
color: #333333;
width: 100%;
height: 30px;
border: 0;
border-bottom: 1px solid #cccccc;
border-top: 1px solid #ffffff;
border-left: 1px solid #ffffff;
border-right: 1px solid #ffffff;
box-sizing: border-box;
outline: none;
position: relative;
}
/* 当类名为login-center-input内部的input元素获取焦点时:focus伪类改变其边框样式为实线且颜色为特定的亮色dodgerblue用于提示用户当前输入框处于激活状态 */
.login-center-input input:focus{
border: 1px solid dodgerblue;
}
/* 类名为login-center-input-text的元素样式一般用于登录框中输入框的提示文字相关样式 */
/* 设置背景颜色为白色设置内边距绝对定位初始透明度为0隐藏状态设置高度、垂直方向上的位置通过top和margin-top属性使其垂直居中指定字体大小、文字颜色以及行高并且设置所有属性改变时的过渡效果用于实现提示文字在输入框获取焦点等情况下的显示隐藏动画效果 */
.login-center-input-text{
background: white;
padding: 0 5px;
position: absolute;
z-index: 0;
opacity: 0;
height: 20px;
top: 50%;
margin-top: -10px;
font-size: 14px;
left: 5px;
color: dodgerblue;
line-height: 20px;
transition: all 0.5s;
-moz-transition: all 0.5s; /* Firefox 4 */
-webkit-transition: all 0.5s; /* Safari 和 Chrome */
-o-transition: all 0.5s; /* Opera */
}
/* 当类名为login-center-input内部的input元素获取焦点时对其同级的.login-center-input-text元素进行样式改变使其向上移动到输入框顶部提高z-index值显示在输入框上方并且设置透明度为1完全显示通过调整外边距使其垂直位置更合适用于实现输入框获取焦点时提示文字上移显示的交互效果 */
.login-center-input input:focus~.login-center-input-text{
top: 0;
z-index: 3;
opacity: 1;
margin-top: -15px;
}
/* 当类名为login的元素具有active类时应用名为login-small的动画效果并且设置动画结束后保持最后一帧的状态animation-fill-mode:forwards以及-webkit-animation-fill-mode:forwards可能用于实现登录框缩小隐藏等特定交互效果 */
.login.active{
-webkit-animation: login-small 0.8s ;
animation: login-small 0.8s ;
animation-fill-mode:forwards;
-webkit-animation-fill-mode:forwards;
}
/* 类名为login-button的元素样式一般用于登录框中的登录按钮样式 */
/* 设置鼠标指针样式为指针形状cursor: pointer指定宽度、文本水平居中对齐、高度以及行高设置背景颜色为特定的亮色设置边框圆角并且设置自动水平居中通过设置左右外边距为auto实现指定文字颜色为白色用于呈现出一个美观的登录按钮外观 */
.login-button{
cursor: pointer;
width: 250px;
text-align: center;
height: 40px;
line-height: 40px;
background-color: dodgerblue;
border-radius: 5px;
margin: 0 auto;
margin-top: 50px;
color: white;
}

@ -1,433 +1,439 @@
@charset "utf-8";
@import url(../lib/layui/css/layui.css);
*{
/* 全局样式 */
* {
margin: 0px;
padding: 0px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
a{
text-decoration: none;
a {
text-decoration: none; /* 去掉链接下划线 */
}
html{
html {
width: 100%;
height: 100%;
overflow-x:hidden;
overflow-y:auto;
overflow-x: hidden; /* 隐藏水平滚动条 */
overflow-y: auto; /* 允许垂直滚动 */
}
body{
body {
width: 100%;
min-height: 100%;
min-height: 100%; /* 最小高度为视口高度 */
}
.x-body{
padding: 20px;
/* 页面主体内容样式 */
.x-body {
padding: 20px; /* 内边距 */
}
.x-nav{
padding: 0 20px;
position: relative;
z-index: 99;
border-bottom: 1px solid #e5e5e5;
line-height: 39px;
height: 39px;
overflow: hidden;
.x-nav {
padding: 0 20px; /* 左右内边距 */
position: relative; /* 相对定位 */
z-index: 99; /* 层级 */
border-bottom: 1px solid #e5e5e5; /* 底部边框 */
line-height: 39px; /* 行高 */
height: 39px; /* 固定高度 */
overflow: hidden; /* 隐藏溢出内容 */
}
xblock{
display: block;
margin-bottom: 10px;
padding: 5px;
line-height: 22px;
/* border-left: 5px solid #009688; */
border-radius: 0 2px 2px 0;
background-color: #f2f2f2;
xblock {
display: block; /* 块级元素 */
margin-bottom: 10px; /* 下边距 */
padding: 5px; /* 内边距 */
line-height: 22px; /* 行高 */
border-radius: 0 2px 2px 0; /* 圆角 */
background-color: #f2f2f2; /* 背景色 */
}
.x-right{
float: right;
.x-right {
float: right; /* 右浮动 */
}
.x-so{
/*text-align: center;*/
/*background: #f2f2f2 url() 0 0 no-repeat;*/
margin-bottom: 20px;
.x-so {
margin-bottom: 20px; /* 下边距 */
}
.x-so input.layui-input{
width: 150px;
padding-left: 25px;
.x-so input.layui-input {
width: 150px; /* 宽度 */
padding-left: 25px; /* 左内边距 */
}
.x-so .layui-form-label{
display: inline-block;
.x-so .layui-form-label {
display: inline-block; /* 行内块级元素 */
}
.x-so input.layui-input,.x-so input.layui-btn{
display: inline-block;
.x-so input.layui-input, .x-so input.layui-btn {
display: inline-block; /* 行内块级元素 */
}
.x-red{
color: red;
.x-red {
color: red; /* 红色字体 */
}
.x-a{
color: #1AA093;
.x-a {
color: #1AA093; /* 绿色字体 */
}
.x-a:hover{
color: #127F74;
.x-a:hover {
color: #127F74; /* 悬停时的颜色 */
}
.x-sort{
height: 30px;
.x-sort {
height: 30px; /* 高度 */
}
.x-show{
cursor: pointer;
.x-show {
cursor: pointer; /* 鼠标指针 */
}
.layui-form-switch{
margin-top: 0px;
.layui-form-switch {
margin-top: 0px; /* 上边距 */
}
.layui-input:focus, .layui-textarea:focus {
border-color: #189f92!important;
}
.page{
margin-top: 20px;
text-align: center;
border-color: #189f92!important; /* 焦点状态下的边框颜色 */
}
.page a{
display: inline-block;
background: #fff url(#) 0 0 no-repeat;
color: #888;
padding: 10px;
min-width: 15px;
border: 1px solid #E2E2E2;
/* 分页样式 */
.page {
margin-top: 20px; /* 上边距 */
text-align: center; /* 居中对齐 */
}
.page a {
display: inline-block; /* 行内块级元素 */
background: #fff url(#) 0 0 no-repeat; /* 背景图 */
color: #888; /* 灰色字体 */
padding: 10px; /* 内边距 */
min-width: 15px; /* 最小宽度 */
border: 1px solid #E2E2E2; /* 边框 */
}
.page span {
display: inline-block; /* 行内块级元素 */
padding: 10px; /* 内边距 */
min-width: 15px; /* 最小宽度 */
border: 1px solid #E2E2E2; /* 边框 */
}
.page span.current {
display: inline-block; /* 行内块级元素 */
background: #009688 url(#) 0 0 no-repeat; /* 背景图 */
color: #fff; /* 白色字体 */
padding: 10px; /* 内边距 */
min-width: 15px; /* 最小宽度 */
border: 1px solid #009688; /* 边框 */
}
.page .pagination li {
display: inline-block; /* 行内块级元素 */
margin-right: 5px; /* 右边距 */
text-align: center; /* 居中对齐 */
}
.page .pagination li.active span {
background: #009688 url(#) 0 0 no-repeat; /* 背景图 */
color: #fff; /* 白色字体 */
border: 1px solid #009688; /* 边框 */
}
.page span{
display: inline-block;
padding: 10px;
min-width: 15px;
border: 1px solid #E2E2E2;
}
.page span.current{
display: inline-block;
background: #009688 url(#) 0 0 no-repeat;
color: #fff;
padding: 10px;
min-width: 15px;
border: 1px solid #009688;
}
.page .pagination li{
display: inline-block;
margin-right: 5px;
text-align: center;
}
.page .pagination li.active span{
background: #009688 url(#) 0 0 no-repeat;
color: #fff;
border: 1px solid #009688;
}
/* 登录样式 */
/* 头部 */
.container {
width: 100%; /* 宽度 */
height: 45px; /* 高度 */
background-color: #222; /* 背景色 */
border-bottom: 1px solid rgba(255, 255, 255, 0.2); /* 底部边框 */
}
.container .logo a {
float: left; /* 左浮动 */
color: #fff; /* 白色字体 */
font-size: 18px; /* 字体大小 */
padding-left: 20px; /* 左内边距 */
line-height: 45px; /* 行高 */
width: 200px; /* 宽度 */
}
.container .right {
background-color: rgba(0,0,0,0); /* 透明背景 */
float: right; /* 右浮动 */
}
.container .left_open {
height: 45px; /* 高度 */
float: left; /* 左浮动 */
}
.container .left_open i {
display: block; /* 块级元素 */
background: rgba(255,255,255,0.1) url(#) 0 0 no-repeat; /* 背景图 */
color: #fff; /* 白色字体 */
width: 32px; /* 宽度 */
height: 32px; /* 高度 */
line-height: 32px; /* 行高 */
border-radius: 3px; /* 圆角 */
text-align: center; /* 居中对齐 */
margin-top: 7px; /* 上边距 */
cursor: pointer; /* 鼠标指针 */
}
.container .left_open i:hover {
background: rgba(255,255,255,0.3) url(#) 0 0 no-repeat; /* 悬停时的背景图 */
}
.container .left {
background-color: rgba(0,0,0,0); /* 透明背景 */
float: left; /* 左浮动 */
}
.container .layui-nav-item {
line-height: 45px; /* 行高 */
}
.container .layui-nav-more {
top: 20px; /* 上边距 */
}
.container .layui-nav-child {
top: 50px; /* 上边距 */
}
.container .layui-nav-child i {
margin-right: 10px; /* 右边距 */
}
.left-nav {
position: absolute; /* 绝对定位 */
top: 46px; /* 上边距 */
bottom: 42px; /* 下边距 */
left: 0; /* 左边距 */
z-index: 2; /* 层级 */
padding-top: 10px; /* 上内边距 */
width: 220px; /* 宽度 */
max-width: 220px; /* 最大宽度 */
background-color: #EEEEEE; /* 背景色 */
overflow: auto; /* 自动溢出处理 */
/*登录样式*/
/*头部*/
.container{
width: 100%;
height: 45px;
background-color: #222;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.container .logo a{
float: left;
color: #fff;
font-size: 18px;
padding-left: 20px;
line-height: 45px;
width: 200px;
}
.container .right{
background-color:rgba(0,0,0,0);
float: right;
}
.container .left_open{
height: 45px;
float: left;
}
.container .left_open i{
display: block;
background: rgba(255,255,255,0.1) url(#) 0 0 no-repeat;
color: #fff;
width: 32px;
height: 32px;
line-height: 32px;
border-radius: 3px;
text-align: center;
margin-top: 7px;
cursor: pointer;
}
.container .left_open i:hover{
background: rgba(255,255,255,0.3) url(#) 0 0 no-repeat;
}
.container .left{
background-color:rgba(0,0,0,0);
float: left;
}
.container .layui-nav-item{
line-height: 45px;
}
.container .layui-nav-more{
top: 20px;
}
.container .layui-nav-child{
top: 50px;
}
.container .layui-nav-child i{
margin-right: 10px;
}
.layui-nav .layui-nav-item a{
color: #fff;
cursor: pointer;
}
.layui-nav .layui-nav-child a{
color: #333;
cursor: pointer;
}
.left-nav{
position: absolute;
top: 46px;
bottom: 42px;
left: 0;
z-index: 2;
padding-top: 10px;
background-color: #EEEEEE;
width: 220px;
max-width: 220px;
overflow: auto;
overflow-x:hidden;
/* 设置溢出内容不显示 */
overflow-x: hidden;
border-right: 1px solid #e5e5e5;
/*width: 0px;*/
}
.left-nav #nav li{
border-bottom: 1px solid #e5e5e5;
}
.left-nav #nav li:hover > a{
/*color: blue;*/
}
.left-nav #nav .current{
background-color: rgba(0, 0, 0, 0.3);
}
.left-nav #nav li a{
font-size: 14px;
padding: 10px 15px 10px 20px;
display: block;
cursor: pointer;
}
.left-nav #nav li a cite{
font-size: 14px;
}
/* 左侧导航样式 */
.left-nav {
/* 宽度设置为0注释掉的代码可以设置具体宽度 */
/* width: 0px; */
}
.left-nav #nav li .sub-menu{
display: none;
}
.left-nav #nav li .opened{
display: block;
}
.left-nav #nav li .opened:hover{
/*background: #fff url() 0 0 no-repeat;*/
}
.left-nav #nav li .opened .current{
}
.left-nav #nav li .sub-menu li:hover{
/*color: blue;*/
/*background: #fff url() 0 0 no-repeat;*/
}
.left-nav #nav li .sub-menu li a{
padding: 12px 15px 12px 30px;
font-size: 14px;
cursor: pointer;
}
.left-nav #nav li .sub-menu li .sub-menu li a{
padding-left: 45px;
}
.left-nav #nav li .sub-menu li a:hover{
color: #148cf1;
}
.left-nav #nav li .sub-menu li a i{
font-size: 12px;
}
.left-nav #nav li a i{
padding-right: 10px;
line-height: 14px;
}
.left-nav #nav li .nav_right{
float: right;
font-size: 16px;
}
.x-slide_left {
width: 17px;
height: 61px;
background: url(#) 0 0 no-repeat;
position: absolute;
top: 200px;
left: 221px;
cursor: pointer;
z-index: 3;
}
.page-content{
position: absolute;
top: 46px;
right: 0;
bottom: 42px;
left: 221px;
overflow: hidden;
z-index: 1;
}
.page-content-bg{
position: absolute;
top: 46px;
right: 0;
bottom: 42px;
left: 221px;
background: rgba(0,0,0,0.5); url() 0 0 no-repeat;
overflow: hidden;
z-index: 100;
display: none;
}
/* 左侧导航列表项样式 */
.left-nav #nav li {
border-bottom: 1px solid #e5e5e5; /* 底部边框 */
}
.page-content .tab{
height: 100%;
width: 100%;
background: #EFEEF0 url(#) 0 0 no-repeat;
margin: 0px;
}
.page-content .layui-tab-title{
/*padding-top: 5px;*/
height: 35px;
background: #EFEEF0 url(#) 0 0 no-repeat;
position: relative;
z-index: 100;
}
.page-content .layui-tab-title li.home i{
padding-right: 5px;
}
.page-content .layui-tab-title li.home .layui-tab-close{
display: none;
}
.page-content .layui-tab-title li{
line-height: 35px;
}
.page-content .layui-tab-title .layui-this:after{
height: 36px;
}
.page-content .layui-tab-title li .layui-tab-close{
border-radius: 50%;
}
.page-content .layui-tab-title .layui-this{
background: #fff url(#) 0 0 no-repeat;
}
.page-content .layui-tab-bar{
height:34px;
line-height: 35px;
}
.page-content .layui-tab-content{
position: absolute;
top: 36px;
bottom: 0px;
width: 100%;
background: #fff url(#) 0 0 no-repeat;
padding: 0px;
overflow: hidden;
}
.page-content .layui-tab-content .layui-tab-item{
width: 100%;
height: 100%;
/* 左侧导航列表项鼠标悬停样式 */
.left-nav #nav li:hover > a {
/* color: blue; */ /* 注释掉的颜色设置 */
}
}
.page-content .layui-tab-content .layui-tab-item iframe{
width: 100%;
height: 100%;
/* 左侧导航列表项当前选中样式 */
.left-nav #nav li .current {
background-color: rgba(0, 0, 0, 0.3); /* 背景色 */
}
}
.x-admin-carousel,.layui-carousel,.x-admin-carousel>[carousel-item]>* {
background-color:#fff
}
/* 左侧导航子菜单默认隐藏 */
.left-nav #nav li .sub-menu {
display: none;
}
.x-admin-backlog .x-admin-backlog-body {
display:block;
padding:10px 15px;
background-color:#f8f8f8;
color:#999;
border-radius:2px;
transition:all .3s;
-webkit-transition:all .3s
}
.x-admin-backlog-body h3 {
padding-bottom:10px;
font-size:12px
}
.x-admin-backlog-body p cite {
font-style:normal;
font-size:30px;
font-weight:300;
color:#009688
}
.x-admin-backlog-body:hover {
background-color:#CFCFCF;
color:#888
}
/* 左侧导航子菜单打开状态 */
.left-nav #nav li .opened {
display: block;
}
.welcome-footer{padding: 30px 0; line-height: 30px; text-align: center; background-color: #eee; color: #666; font-weight: 300;}
body .layui-layout-admin .footer-demo{height: auto; padding: 15px 0; line-height: 26px;}
.welcome-footer a{padding: 0 5px;}
/* 左侧导航子菜单打开状态鼠标悬停样式 */
.left-nav #nav li .opened:hover {
/* background: #fff url() 0 0 no-repeat; */ /* 注释掉的背景图设置 */
}
table th, table td {
word-break: break-all;
}
/* 左侧导航子菜单当前选中样式 */
.left-nav #nav li .opened .current {
/* background: rgba(0, 0, 0, 0); */ /* 注释掉的背景色设置 */
}
.footer{
position: fixed;
bottom: 0px;
width: 100%;
background-color: #222;
border-top: 1px solid rgba(255, 255, 255, 0.2);
line-height: 41px;
color: #fff;
/*padding-left: 10px;*/
}
.footer .copyright{
margin-left: 10px;
}
/* 左侧导航子菜单列表项样式 */
.left-nav #nav li .sub-menu li a {
padding: 12px 15px 12px 30px; /* 内边距 */
font-size: 14px; /* 字体大小 */
cursor: pointer; /* 鼠标指针样式 */
}
/* 左侧导航子菜单列表项二级菜单样式 */
.left-nav #nav li .sub-menu li .sub-menu li a {
padding-left: 45px; /* 左内边距 */
}
@media screen and (max-width: 768px){
.fast-add{
display: none;
/* 左侧导航子菜单列表项鼠标悬停样式 */
.left-nav #nav li .sub-menu li:hover a {
color: #148cf1; /* 颜色 */
/* background: #fff url() 0 0 no-repeat; */ /* 注释掉的背景图设置 */
}
.layui-nav .to-index{
display: none;
/* 左侧导航子菜单列表项图标样式 */
.left-nav #nav li .sub-menu li a i {
font-size: 12px; /* 字体大小 */
}
.container .logo a{
width: 140px;
/* 左侧导航列表项右侧箭头样式 */
.left-nav #nav li a i {
float: right; /* 右浮动 */
font-size: 16px; /* 字体大小 */
line-height: 14px; /* 行高 */
padding-right: 10px; /* 右内边距 */
}
/* 页面内容样式 */
.page-content {
position: absolute; /* 绝对定位 */
top: 46px; /* 顶部位置 */
right: 0; /* 右边位置 */
bottom: 42px; /* 底部位置 */
left: 221px; /* 左边位置 */
overflow: hidden; /* 隐藏溢出内容 */
z-index: 1; /* z轴顺序 */
}
/* 页面内容背景样式 */
.page-content-bg {
position: absolute; /* 绝对定位 */
top: 46px; /* 顶部位置 */
right: 0; /* 右边位置 */
bottom: 42px; /* 底部位置 */
left: 221px; /* 左边位置 */
background: rgba(0, 0, 0, 0.5); /* 背景色 */
url(); /* 背景图 */
z-index: 100; /* z轴顺序 */
display: none; /* 默认隐藏 */
}
/* x轴滑动按钮样式 */
.x-slide_left {
width: 17px; /* 宽度 */
height: 61px; /* 高度 */
background: url(#) 0 0 no-repeat; /* 背景图 */
position: absolute; /* 绝对定位 */
top: 200px; /* 顶部位置 */
left: 221px; /* 左边位置 */
cursor: pointer; /* 鼠标指针样式 */
z-index: 3; /* z轴顺序 */
}
.container .left_open {
/*float: right;*/
/* 页面内容标签页样式 */
.page-content .tab {
height: 100%; /* 高度 */
margin: 0px; /* 外边距 */
background: #EFEEF0 url(#) 0 0 no-repeat; /* 背景图 */
}
.left-nav{
left: -221px;
/* 页面内容标签页标题样式 */
.page-content .layui-tab-title {
height: 35px; /* 高度 */
background: #EFEEF0 url(#) 0 0 no-repeat; /* 背景图 */
position: relative; /* 相对定位 */
z-index: 100; /* z轴顺序 */
}
.page-content{
left: 0px;
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-title li.home i {
padding-right: 5px; /* 右内边距 */
}
.page-content .layui-tab-content .layui-tab-item{
-webkit-overflow-scrolling: touch;
overflow-y: scroll;
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-title li.home .layui-tab-close {
display: none; /* 隐藏关闭按钮 */
}
.x-so input.layui-input{
width: 100%;
margin: 10px;
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-title li {
line-height: 35px; /* 行高 */
}
.layui-input{
margin-left: 20px;
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-title li.layui-this:after {
height: 63px; /* 高度 */
}
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-title li.layui-this {
background: #fff url(#) 0 0 no-repeat; /* 背景图 */
}
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-title li.layui-this .layui-tab-close {
border-radius: 50%; /* 圆角 */
}
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-title li {
border-radius: 50%; /* 圆角 */
}
/* 页面内容标签页标题当前选中样式 */
.page-content .layui-tab-bar {
height: 34px; /* 高度 */
line-height: 34px; /* 行高 */
}
/* 页面内容标签页内容样式 */
.page-content .layui-tab-content {
top: 36px; /* 顶部位置 */
bottom: 0px; /* 底部位置 */
width: 100%; /* 宽度 */
background: #fff url(#) 0 0 no-repeat; /* 背景图 */
padding: 0px; /* 内边距 */
overflow: hidden; /* 隐藏溢出内容 */
}
/* 页面内容标签页内容项样式 */
.page-content .layui-tab-content .layui-tab-item {
width: 100%; /* 宽度 */
height: 100%; /* 高度 */
}
/* 页面内容标签页内容项iframe样式 */
.page-content .layui-tab-content .layui-tab-item iframe {
width: 100%; /* 宽度 */
height: 100%; /* 高度 */
}
/* xadmin后台日志样式 */
.x-admin-backlog-body {
display: block; /* 显示块级元素 */
padding: 10px 15px; /* 内边距 */
background-color: #f8f8f8; /* 背景色 */
color: #999; /* 文字颜色 */
border-radius: 2px; /* 圆角 */
transition: all .3s ease; /* CSS3过渡效果 */
}
/* xadmin后台日志标题样式 */
.x-admin-backlog-body h3 {
padding-bottom: 10px; /* 底部内边距 */
font-size: 12px; /* 字体大小 */
}
/* xadmin后台日志内容样式 */
.x-admin-backlog-body p {
font-style: normal; /* 正常字体风格 */
font-size: 30px; /* 字体大小 */
font-weight: 300; /* 字体粗细 */
color: #009689; /* 文字颜色 */
}
/* xadmin后台日志内容鼠标悬停样式 */
.x-admin-backlog-body:hover {
background-color: #CFCFCF; /* 背景色 */
color: #888; /* 文字颜色 */
}
/* welcome页脚样式 */
.welcome-footer {
padding: 30px 0; /* 内边距 */
text-align: center; /* 文本居中对齐 */
line-height: 30px; /* 行高 */
color: #eee; /* 文字颜色 */
background-color: #222; /* 背景色 */
border-top: 1px solid rgba(255, 255, 255, 0.1); /* 边框样式 */
}
/* foot页脚样式 */
.footer {
position: fixed; /* 固定定位 */
bottom: 0px; /* 底部位置 */
width: 100%; /* 宽度 */
background-color: #222; /* 背景色 */
line-height: 41px; /* 行高 */
color: #fff; /* 文字颜色 */
}
/* foot页脚版权样式 */
.footer .copyright {
margin-left: 10px; /* 左内边距 */
}
/* table表格样式 */
table th, table td {
word-break: break-all; /* CSS属性允许在单词内换行 */
}
}

@ -1,53 +1,90 @@
function highlight(s,id) {
if(s.length == 0) {
function highlight(s, id) {
// 判断传入的字符串s的长度是否为0如果长度为0表示可能不需要进行高亮相关操作了执行以下代码块
if (s.length == 0) {
// 通过document.getElementById方法根据传入的id获取对应的DOM元素并将其赋值给变量obj后续会对这个元素的innerHTML内容进行处理
var obj = document.getElementById(id);
// 使用正则表达式替换obj元素innerHTML中的内容目的是去除已经存在的带有"highlight"类名的<span>标签,只保留其内部的文本内容,
// 正则表达式 /<span\s+class=.?highlight.?>([^<>]*)<\/span>/gi 用于匹配包含"highlight"类名的<span>标签及其内部的非尖括号内容(通过 ([^<>]*) 捕获),并将匹配到的内容替换为捕获的内部文本内容(通过 $1 引用捕获组)
var t = obj.innerHTML.replace(/<span\s+class=.?highlight.?>([^<>]*)<\/span>/gi, "$1");
// 将处理后的文本内容重新赋值给obj元素的innerHTML属性实现去除已有高亮标签的效果
obj.innerHTML = t;
// 返回false表示在这种字符串长度为0的情况下没有进行实际的搜索和高亮操作
return false;
}
// 调用内部定义的encode函数对传入的字符串s进行编码处理主要是对一些特殊字符进行转义等操作从函数内部实现可以看到具体转义的字符并将结果重新赋值给s
s = encode(s);
// 通过document.getElementById方法根据传入的id获取对应的DOM元素赋值给变量obj后续会基于这个元素来查找匹配的文本并进行高亮显示操作
var obj = document.getElementById(id);
// 同样使用正则表达式替换obj元素innerHTML中的内容去除已有的带有"highlight"类名的<span>标签只保留其内部文本内容与前面长度为0时的处理类似目的是先清理之前可能存在的高亮标记准备进行新的高亮操作
var t = obj.innerHTML.replace(/<span\s+class=.?highlight.?>([^<>]*)<\/span>/gi, "$1");
// 将清理后的文本内容重新赋值给obj元素的innerHTML属性
obj.innerHTML = t;
// 调用内部定义的loopSearch函数传入经过编码处理的字符串s和获取到的DOM元素obj这个函数会递归地在DOM元素及其子元素中查找匹配的文本内容并返回匹配到的次数将返回的结果赋值给变量cnt
var cnt = loopSearch(s, obj);
t = obj.innerHTML
// 获取obj元素当前的innerHTML内容并赋值给变量t后续会基于这个内容再次进行处理添加高亮显示的标签
var t = obj.innerHTML
// 定义一个正则表达式r用于匹配之前在文本中标记好的需要高亮显示的位置通过 {searchHL} 和 {/searchHL} 包裹的内容),以便后续将其替换为带有"highlight"类名的<span>标签来实现可视化的高亮效果
var r = /{searchHL}(({(?!\/searchHL})|[^{])*){\/searchHL}/g
// 使用正则表达式r对变量t即obj元素的innerHTML内容进行替换操作将匹配到的用 {searchHL} 和 {/searchHL} 包裹的内容替换为带有"highlight"类名的<span>标签包裹的内容实现文本的高亮显示效果然后将替换后的结果重新赋值给变量t
t = t.replace(r, "<span class='highlight'>$1</span>");
// 将添加了高亮显示标签后的文本内容重新赋值给obj元素的innerHTML属性使得页面上对应的DOM元素中的文本呈现出高亮显示的效果
obj.innerHTML = t;
// 定义一个名为encode的内部函数用于对传入的字符串进行编码处理主要是对一些在正则表达式中有特殊含义或者HTML中有特殊用途的字符进行转义防止出现意外的匹配或解析问题
function encode(s) {
// 使用字符串的replace方法通过正则表达式匹配并替换相应的特殊字符将 & 替换为 & HTML实体编码转义< 替换为 < 防止被解析为HTML标签开头> 替换为 > 同理防止被解析为HTML标签结尾
// 对于正则表达式中有特殊含义的字符(如 \、.、*、[、]、(、)、$、^ 等),在其前面添加 \ 进行转义,使其在后续作为正则表达式内容时能按字面意思进行匹配,最后将处理后的字符串返回
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/([\\\.\*\[\]\(\)\$\^])/g, "\\$1");
}
// 定义一个名为decode的内部函数与encode函数作用相反用于对经过编码的字符串进行解码还原操作将转义后的字符恢复为原来的字符形式
function decode(s) {
// 使用字符串的replace方法通过正则表达式匹配并替换相应的转义字符将前面添加了 \ 转义的字符(如 \[ 等)还原为原来的字符(去除前面的 \
// 然后将 > 替换为 > < 替换为 < & 替换为 & ,恢复字符串中这些特殊字符的原始形式,最后将处理后的字符串返回
return s.replace(/\\([\\\.\*\[\]\(\)\$\^])/g, "$1").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
}
// 定义一个名为loopSearch的内部函数它会递归地在给定的DOM元素及其子元素中查找与传入字符串s匹配的文本内容并统计匹配的次数返回统计的匹配次数
function loopSearch(s, obj) {
// 初始化一个变量cnt用于记录匹配到的次数初始值设为0
var cnt = 0;
if(obj.nodeType == 3) {
// 判断当前DOM元素obj的节点类型是否为3在DOM中节点类型3表示文本节点如果是文本节点则调用内部的replace函数在这个文本节点中查找并替换匹配的文本内容并将返回的匹配次数赋值给cnt然后直接返回cnt
if (obj.nodeType == 3) {
cnt = replace(s, obj);
return cnt;
}
for(var i = 0, c; c = obj.childNodes[i]; i++) {
if(!c.className || c.className != "highlight") {
// 如果当前DOM元素不是文本节点说明可能是包含子节点的元素节点如<div>等通过循环遍历它的子节点使用childNodes属性获取子节点列表
// 对于每个子节点c判断如果其不存在className属性或者className属性不等于"highlight"即不是已经处理过的高亮显示的节点则递归调用loopSearch函数在这个子节点中继续查找匹配内容并将返回的匹配次数累加到变量cnt中
for (var i = 0, c; c = obj.childNodes[i]; i++) {
if (!c.className || c.className!= "highlight") {
cnt += loopSearch(s, c);
}
}
// 循环结束后将统计好的匹配次数cnt返回这个cnt就是整个DOM元素及其所有子元素中匹配到传入字符串s的总次数
return cnt;
}
// 定义一个名为replace的内部函数它用于在给定的文本节点dest中查找与传入字符串s匹配的文本内容并进行替换操作将匹配的内容用特定标记包裹起来后续会进一步处理为高亮显示的标签同时返回匹配到的次数
function replace(s, dest) {
// 根据传入的字符串s创建一个正则表达式对象r设置全局匹配模式g标志用于在文本节点中查找所有匹配的内容
var r = new RegExp(s, "g");
// 初始化一个变量tm用于存储通过正则表达式匹配到的结果初始值设为null
var tm = null;
// 获取文本节点dest的nodeValue属性即文本节点中的文本内容赋值给变量t后续会基于这个文本内容进行查找和替换操作
var t = dest.nodeValue;
// 初始化一个变量cnt用于记录匹配到的次数初始值设为0
var cnt = 0;
if(tm = t.match(r)) {
// 使用match方法在文本t中查找所有与正则表达式r匹配的内容如果匹配到了即tm不为null则执行以下代码块
if (tm = t.match(r)) {
// 将匹配到的次数即tm数组的长度因为match方法返回的数组包含了所有匹配到的内容赋值给变量cnt记录匹配的次数
cnt = tm.length;
// 使用replace方法对文本t进行替换操作将匹配到的内容替换为用 {searchHL} 和 {/searchHL} 包裹起来并且内部通过decode函数对匹配的字符串s进行解码还原后的内容
// 这样就标记好了需要后续处理为高亮显示的文本位置然后将替换后的结果重新赋值给文本节点dest的nodeValue属性实现文本内容的初步替换标记
t = t.replace(r, "{searchHL}" + decode(s) + "{/searchHL}")
dest.nodeValue = t;
}
// 将记录的匹配次数cnt返回供外部调用的函数如loopSearch函数获取并进一步处理比如累加统计总的匹配次数等
return cnt;
}
}

@ -1,147 +1,242 @@
layui.define(['jquery', 'layer'], function (exports){
layui.define(['jquery', 'layer'], function (exports) {
// 获取layui框架中引入的jQuery模块并将其赋值给变量$方便后续使用jQuery的相关功能如DOM操作、AJAX请求等
var $ = layui.jquery;
// 创建一个空对象chekedArr用于存储一些被选中的数据相关信息从后续代码推测可能是记录过滤组件中被选中的选项等情况其结构和具体用途会在后续代码中逐渐清晰
var chekedArr = {};
// 创建一个名为layfilter的对象用于封装与查询过滤组件相关的一系列功能方法比如初始化组件、获取选中值、绑定事件等操作
var layfilter = {
render:function(options){
// 定义名为render的方法用于渲染查询过滤组件该方法接收一个名为options的参数参数中应该包含了组件渲染所需的各种配置信息如请求数据的URL、筛选条件等
render: function (options) {
// 从传入的options参数中获取名为url的属性值该值可能是用于获取过滤组件数据的接口地址后续根据这个地址来发起数据请求
var url = options.url;
// 定义一个布尔变量flag并初始化为true用于标记数据获取及组件渲染过程中的一些状态比如数据获取是否成功等情况后续会根据不同情况修改这个值来控制流程
var flag = true;
//传入了地址,则直接将此地址覆盖
if(url){
$.getJSON(url,options.where,function(res){
if(res.code == 0){
var data = res.data;
// 判断如果传入的url属性存在即有值则执行以下代码块意味着如果配置了数据请求地址就按照这个地址去获取数据来渲染组件
if (url) {
// 使用jQuery的$.getJSON方法发起一个GET类型的AJAX请求请求的URL就是前面获取到的url同时传入options.where作为请求参数可能是一些筛选条件等数据请求成功后的回调函数用于处理返回的数据
$.getJSON(url, options.where, function (res) {
// 判断返回数据中的code属性是否等于0如果等于0通常表示请求成功数据正常获取到了可以进行后续的组件渲染等操作
if (res.code == 0) {
// 从返回的数据中获取名为data的属性值这应该就是实际用于渲染组件的数据源例如包含了各种过滤选项的数据列表等内容
var data = res.data;
// 此处疑似拼写错误将flase应该是想写false赋值为true不过从逻辑上推测可能是想重置某个用于判断的标志位但这个变量名错误可能会导致意想不到的问题先按照正确的逻辑理解此处应该是设置一个表示数据获取成功等相关含义的标志为true
flase = true;
layfilter.init(options,data);
}else{
layer.msg(res.msg||'查询过滤组件数据异常',{icon:2});
// 调用layfilter对象自身的init方法传入options和获取到的data数据进行查询过滤组件的初始化操作将数据展示在页面上形成可交互的过滤组件
layfilter.init(options, data);
} else {
// 如果返回数据中的code属性不等于0表示请求出现异常比如服务器端返回错误等情况使用layer弹出提示框显示相应的错误信息优先显示res.msg中的内容如果res.msg不存在则显示默认的提示信息'查询过滤组件数据异常'同时设置提示框的图标为2通常表示错误图标
layer.msg(res.msg || '查询过滤组件数据异常', {icon: 2});
// 将flag标志位设置为false表示数据获取或处理出现问题后续可能根据这个标志来决定是否继续进行组件渲染等操作
flag = false
}
})
}
if(!flag){
// 判断如果flag为false即前面的数据获取或处理出现问题了则直接使用return语句结束当前函数的执行不再进行后续可能的组件渲染等操作
if (!flag) {
return;
}
},
init:function(options,dataSource){
// 定义名为init的方法用于初始化查询过滤组件接收两个参数options包含了组件的各种配置信息dataSource则是具体要展示在组件中的数据列表等数据源信息
init: function (options, dataSource) {
// 从options参数中获取名为elem的属性值该值可能是一个DOM元素的选择器或者DOM元素本身用于指定查询过滤组件在页面中要挂载的位置后续会将生成的组件内容添加到这个元素内
var elem = options.elem;
// 使用jQuery根据elem选择器或者传入的就是DOM元素本身获取对应的DOM元素并赋值给变量$dom方便后续对这个挂载元素进行操作比如添加子元素等
var $dom = $(elem);
// 从options参数中获取名为itemWidth的属性值从变量名推测可能是用于设置组件中每个选项元素的宽度相关信息后续会根据这个值来进行宽度的具体设置
var itemWidth = options.itemWidth
// 创建一个空对象arr同样从后续代码推测可能是用于临时存储一些与组件选项相关的数据结构具体用途会随着代码执行逐渐清晰
var arr = {};
// 使用jQuery创建一个<table>元素,并添加类名"filterTable",这个表格元素将用于构建查询过滤组件的可视化布局,后续会往里面添加行、列以及具体的选项内容
var $table = $('<table class="filterTable"></table>');
for(var i=0;i<dataSource.length;i++){
var $tr =$('<tr></tr>');
var $td1 = $('<td class="item-title">'+dataSource[i].title+':</td>');
// 开始循环遍历数据源dataSourcedataSource应该是一个数组里面每个元素代表一组过滤选项数据等相关内容循环是为了逐个处理并展示这些数据到组件中
for (var i = 0; i < dataSource.length; i++) {
// 使用jQuery创建一个<tr>元素,代表表格中的一行,用于放置一组过滤选项的相关标题和具体选项内容,后续会将这行添加到前面创建的表格$table中
var $tr = $('<tr></tr>');
// 使用jQuery创建一个<td>元素,作为表格的单元格,添加类名"item-title"并将当前数据源中对应元素的title属性值应该是这组过滤选项的标题名称添加到单元格内作为文本内容用于展示这组选项的标题
var $td1 = $('<td class="item-title">' + dataSource[i].title + ':</td>');
// 使用jQuery创建另一个<td>元素,添加类名"items",这个单元格将用于放置具体的过滤选项内容(如单选框、复选框等选项列表),后续会将构建好的选项列表添加到这个单元格内
var $td2 = $('<td class="items"></td>');
// 从当前数据源中对应元素获取名为type的属性值该值可能用于指定这组过滤选项的类型比如是单选、复选等类型后续会根据这个类型来构建不同样式和交互逻辑的选项元素
var type = dataSource[i].type;
if(!type){
console.warn('第'+(i+1)+'个元素的类型[type]为空设为默认值[radio]');
// 判断如果type属性不存在即为空则在控制台输出警告信息提示第几个元素的类型[type]为空,并将其默认设置为'radio'(单选类型),以保证组件能正常构建,避免因类型未定义出现错误
if (!type) {
console.warn('第' + (i + 1) + '个元素的类型[type]为空设为默认值[radio]');
type = 'radio';
}
var $ul = $('<ul class="layfilter-ul" type="'+type+'" name="'+dataSource[i].name+'"></ul>');
var width = itemWidth && itemWidth.length>0 ? (itemWidth.length>i ? itemWidth[i]:itemWidth[itemWidth.length-1]):80;
arr[dataSource[i].name]=[];
for(var j=0;j<dataSource[i].data.length;j++){
var item = dataSource[i].data;
// 使用jQuery创建一个<ul>元素,添加类名"layfilter-ul"并设置type和name属性type属性使用前面获取到的或者默认设置的选项类型值name属性则使用当前数据源中对应元素的name属性值可能用于唯一标识这组选项等用途这个<ul>元素将作为具体选项的容器,后续会往里面添加一个个具体的选项<li>元素
var $ul = $('<ul class="layfilter-ul" type="' + type + '" name="' + dataSource[i].name + '"></ul>');
// 根据前面获取到的itemWidth属性值来计算每个选项的宽度逻辑是如果itemWidth存在且长度大于0再判断其长度是否大于当前循环的索引i如果大于则使用itemWidth中对应索引位置的值作为宽度否则使用最后一个值作为宽度如果itemWidth不符合条件不存在或者长度为0则默认宽度设置为80像素这样可以灵活地配置每个选项的宽度
var width = itemWidth && itemWidth.length > 0? (itemWidth.length > i? itemWidth[i] : itemWidth[itemWidth.length - 1]) : 80;
// 在arr对象中以当前数据源中对应元素的name属性值为键创建一个空数组作为值从后续代码推测可能是用于存储这组选项中被选中的具体数据等情况方便后续获取和操作选中的数据
arr[dataSource[i].name] = [];
// 开始内层循环遍历当前数据源中对应元素的data属性应该是包含了这组选项的具体每个选项的数据列表用于逐个构建并添加具体的选项元素到前面创建的<ul>容器中
for (var j = 0; j < dataSource[i].data.length; j++) {
// 获取当前数据源中对应元素的data属性也就是这组选项的具体每个选项的数据列表不过此处变量名使用item可能不太准确容易和外层循环的含义混淆从逻辑上理解这里应该是获取具体的一个选项数据对象
var item = dataSource[i].data;
// 创建一个类名变量className并初始化为'layfilter-item',这个类名可能用于设置选项元素的基本样式等,后续会根据选项是否被选中等情况来动态修改这个类名,添加额外的样式类
var className = 'layfilter-item';
if(item[j].checked && item[j].checked=='true'){
// 判断当前选项数据对象中的checked属性是否存在且值为'true'如果满足这个条件表示这个选项是初始被选中的状态那么就修改className类名添加额外的'layfilter-item-checked'类名用于应用选中状态的样式比如改变背景色等样式效果同时将这个选项的相关数据name和value属性值添加到前面创建的arr对象中对应name的数组里用于记录被选中的选项信息
if (item[j].checked && item[j].checked == 'true') {
className = "layfilter-item layfilter-item-checked";
arr[dataSource[i].name].push({name:item[j].name,value:item[j].value});
arr[dataSource[i].name].push({name: item[j].name, value: item[j].value});
}
//判断是否禁用
if(item[j].disabled && item[j].disabled=='true'){
$ul.append('<li value="'+item[j].value+'" style="width:'+width+'px;height: 28px;line-height: 28px;" class="'+className+'"><a disabled="disabled" class="layui-disabled">'+item[j].name+'</a></li>');
}else{
$ul.append('<li value="'+item[j].value+'" style="width:'+width+'px;height: 28px;line-height: 28px;" class="'+className+'"><a>'+item[j].name+'</a></li>');
// 判断当前选项数据对象中的disabled属性是否存在且值为'true',如果满足这个条件,表示这个选项是被禁用的状态,那么在构建选项元素时,添加'disabled'属性,并应用'layui-disabled'类名可能是layui框架中用于表示禁用样式的类使得这个选项呈现出被禁用的视觉效果如灰色显示、不可点击等并添加到<ul>容器中
if (item[j].disabled && item[j].disabled == 'true') {
$ul.append('<li value="' + item[j].value + '" style="width:' + width + 'px;height: 28px;line-height: 28px;" class="' + className + '"><a disabled="disabled" class="layui-disabled">' + item[j].name + '</a></li>');
} else {
// 如果选项不是被禁用状态,则正常构建选项元素,添加到<ul>容器中设置相应的value属性、宽度、高度、行高等样式属性并应用前面定义的className类名选项内容显示为其name属性值即用户看到的选项文本
$ul.append('<li value="' + item[j].value + '" style="width:' + width + 'px;height: 28px;line-height: 28px;" class="' + className + '"><a>' + item[j].name + '</a></li>');
}
}
// 将构建好的包含具体选项的<ul>元素添加到前面创建的用于放置选项的<td>单元格($td2
$td2.append($ul);
// 将包含标题的<td>单元格($td1和包含选项的<td>单元格($td2添加到代表一行的<tr>元素($tr
$tr.append($td1).append($td2);
// 将构建好的这一行($tr添加到前面创建的表格元素$table这样逐行添加最终形成完整的查询过滤组件的可视化表格布局
$table.append($tr);
}
// 将构建好的包含所有过滤选项内容的表格元素($table添加到前面获取到的用于挂载组件的DOM元素$dom使得组件在页面上显示出来
$dom.append($table);
chekedArr=arr;
//注册点击事件
$('.filterTable tr td li a').bind('click',function(){
if($(this).attr('disabled')){
// 将记录选中选项信息的arr对象赋值给全局的chekedArr对象这样在其他方法中如获取选中值、处理点击事件等操作时可以访问和操作这些选中的数据信息
chekedArr = arr;
// 使用jQuery的bind方法为'.filterTable tr td li a'(也就是查询过滤组件中每个选项内的<a>链接元素,通常用于触发选项的选择操作等交互)绑定点击事件处理函数,当用户点击这些元素时,会执行以下的函数逻辑来处理选项的选中、取消选中等操作以及更新相关数据状态
$('.filterTable tr td li a').bind('click', function () {
// 判断当前点击的<a>元素是否有'disabled'属性即是否是被禁用的选项如果有则直接使用return语句结束当前函数执行不做后续的选中相关操作因为被禁用的选项不应该响应点击选择操作
if ($(this).attr('disabled')) {
return;
}
// 获取当前点击的<a>元素的父元素(<li>元素)的父元素(<ul>元素的type属性值也就是获取这个选项所属的那组选项的类型如单选、复选等类型用于后续根据不同类型来处理选项的选中逻辑
var itemType = $(this).parent().parent().attr('type');
var name = $(this).parent().parent().attr('name');
//取消选择
if($(this).parent().hasClass('layfilter-item-checked')){
// 获取当前点击的<a>元素的父元素(<li>元素)的父元素(<ul>元素的name属性值也就是获取这个选项所属的那组选项的唯一标识名称用于后续在记录选中数据的对象中查找和更新对应的数据
var name = $(this).parent().parent().attr('name');
// 判断当前点击的<a>元素的父元素(<li>元素)是否有'layfilter-item-checked'类名,即判断这个选项当前是否是被选中状态,如果是,则执行以下取消选中的相关操作逻辑
if ($(this).parent().hasClass('layfilter-item-checked')) {
// 如果选项当前是被选中状态使用removeClass方法移除'layfilter-item-checked'类名,使其视觉上呈现未选中的样式效果(比如取消背景色等选中样式)
$(this).parent().removeClass('layfilter-item-checked');
var obj = chekedArr[name]||[];
for(var i=0;i<obj.length;i++){
if(obj[i].value==$(this).parent().attr('value')){
// 获取chekedArr对象中以当前选项所属的name为键对应的数组可能包含了这组选项中已被选中的其他选项数据等情况如果不存在则创建一个空数组用于后续操作
var obj = chekedArr[name] || [];
// 循环遍历这个数组查找与当前点击的选项的value属性值相等的元素即找到当前要取消选中的那个选项在已记录选中数据中的位置找到后使用splice方法从数组中删除这个元素实现取消选中的操作并更新记录选中数据的对象
for (var i = 0; i < obj.length; i++) {
if (obj[i].value == $(this).parent().attr('value')) {
obj.splice(i, 1);
break;
}
}
// 将更新后的数组重新赋值给chekedArr对象中对应的name键完成取消选中操作后的数据更新
chekedArr[name] = obj;
}else{
if(itemType && ('checbox' == itemType || 'radio' == itemType)){
//判断类型
if('radio' == itemType){
} else {
// 如果当前点击的选项不是被选中状态,则执行以下选中相关的操作逻辑,首先判断选项所属的类型是否存在并且是'checbox'(应该是拼写错误,正确的是'checkbox',复选框类型)或者'radio'(单选框类型),如果满足这个条件,则根据不同类型来进行相应的选中操作处理
if (itemType && ('checbox' == itemType || 'radio' == itemType)) {
// 判断如果是单选类型('radio' == itemType则获取当前点击的<a>元素的父元素(<li>元素的所有兄弟元素也就是这组单选选项中的其他选项元素然后循环遍历这些兄弟元素使用removeClass方法移除它们的'layfilter-item-checked'类名,确保在单选模式下,只有当前点击的选项被选中,其他选项都变为未选中状态,实现单选的互斥效果
if ('radio' == itemType) {
var objs = $(this).parent().siblings();
chekedArr[name]=[];
for(var i=0;i<objs.length;i++){
chekedArr[name] = [];
for (var i = 0; i < objs.length; i++) {
objs.eq(i).removeClass('layfilter-item-checked');
}
}
var obj = chekedArr[name]||[];
obj.push({name:$(this).text(),value:$(this).parent().attr('value')});
chekedArr[name]=obj;
// 获取chekedArr对象中以当前选项所属的name为键对应的数组可能为空数组如果之前没有选中的选项用于后续操作
var obj = chekedArr[name] || [];
// 将当前点击的选项的相关数据name和value属性对应的文本和值通过$(this).text()和$(this).parent().attr('value')获取)封装成一个对象,添加到这个数组中,表示将这个选项标记为选中状态,并更新记录选中数据的对象
obj.push({name: $(this).text(), value: $(this).parent().attr('value')});
chekedArr[name] = obj;
// 为当前点击的选项的父元素(<li>元素)添加'layfilter-item-checked'类名,使其视觉上呈现选中的样式效果(比如添加背景色等选中样式)
$(this).parent().addClass('layfilter-item-checked');
}else{
} else {
// 如果选项所属的类型不是预期的复选或单选类型
console.error('复选或单选类型为空?');
}
}
});
},
// 定义名为getValue的方法它是layfilter对象的一个方法该方法接收一个名为callback的参数
// 其作用应该是用于获取过滤组件中当前被选中项的数据并通过传入的回调函数callback将数据传递出去
getValue:function(callback){
// 调用内部定义的getCheckData函数该函数的作用从名字推测是获取经过整理后的已选中数据
// 并将返回的结果赋值给变量obj这个obj应该是包含了符合特定格式的已选中数据信息的对象
var obj = getCheckData();
// 通过call方法调用传入的回调函数callback并将当前的this上下文以及获取到的已选中数据对象obj作为参数传递进去
// 这样在外部调用getValue方法并传入相应回调函数时外部就能在回调函数中拿到并处理这些选中数据了
callback.call(this,obj);
},
// 定义名为on的方法它也是layfilter对象的一个方法用于给特定的元素绑定指定的事件以及对应的回调函数
// 接收两个参数filter参数可能是一个包含事件和选择器等信息的字符串callback则是对应的事件触发时要执行的回调函数
on:function(filter,callback){
// 通过substring方法截取filter字符串中从开头到第一个'('字符之前的内容赋值给变量f
// 推测这里是获取事件名称部分,例如可能是'click'等事件类型
var f = filter.substring(0,filter.indexOf('('));
// 通过substring方法截取filter字符串中从第一个'('字符之后到倒数第二个字符(去掉最后的')'字符的内容赋值给变量e
// 推测这里是获取选择器相关的部分用于在后续代码中找到要绑定事件的具体DOM元素
var e = filter.substring(filter.indexOf('(')+1,filter.length-1);
// 使用typeof操作符判断传入的callback参数是否是一个函数类型
// 如果是函数类型,表示传入的回调函数是合法有效的,就执行后续的绑定事件逻辑,否则执行下面的错误提示逻辑
if(typeof callback === "function"){
// 使用jQuery的on方法给满足选择器条件通过$("[lay-filter='"+e+"']"构造选择器其中e就是前面截取出来的选择器相关部分的DOM元素绑定指定的事件f就是前面截取出来的事件名称部分
// 当绑定的事件触发时会执行传入的回调函数在回调函数内部先调用getCheckData函数获取已选中数据然后再通过call方法将当前上下文以及已选中数据传递给外部传入的callback函数进行相应处理
$("[lay-filter='"+e+"']").on(f,function(){
var obj = getCheckData();
callback.call(this,obj);
});
}else{
// 如果传入的callback参数不是一个函数类型就在控制台输出错误信息提示'传入的参数不是一个函数',方便开发调试时发现参数使用错误的问题
console.error('传入的参数不是一个函数');
}
}
}
// 使用layui框架提供的link方法加载名为'layfilter/layfilter.css'的CSS样式文件
// 从路径推测这个CSS文件应该是用于设置查询过滤组件的样式使得组件在页面上呈现出预期的外观效果
// 这里的layui.cache.base可能是layui框架中用于获取基础路径的一种方式拼接上后面的相对路径就能准确找到对应的CSS文件了
layui.link(layui.cache.base + 'layfilter/layfilter.css');
layui.link(layui.cache.base + 'layfilter/layfilter.css');
function getCheckData(){
// 定义一个名为getCheckData的函数从名字可以看出它主要用于获取并整理查询过滤组件中已选中项的数据
// 最终将这些数据整理成特定的格式并返回供其他方法如getValue、on方法等使用
function getCheckData(){
// 创建一个空对象valueJson从后续代码来看它用于存储已选中项的value值可能是选项对应的实际值等信息
// 以选项对应的名称比如选项所属的分组名称等作为键来存储对应的value值字符串多个值会用逗号拼接等方式整理
var valueJson = {};
// 创建一个空对象nameJson与valueJson类似不过它主要用于存储已选中项的name值可能是选项显示的文本名称等信息
// 同样以选项对应的名称作为键存储对应的name值字符串多个值用逗号拼接等方式整理
var nameJson = {};
// 使用for...in循环遍历chekedArr对象chekedArr前面在代码中应该是用于记录各个选项组中已选中项相关信息的对象
// 循环遍历它的目的是提取出每个选项组中已选中项的name和value值并整理到valueJson和nameJson对象中
for(var name in chekedArr){
// 获取chekedArr对象中以当前循环的name为键对应的数组前面代码中应该是将每个选项组的已选中项数据存为数组形式赋值给变量json
// 这个数组中的每个元素应该是包含了name和value等属性的对象代表了一个已选中的选项信息
var json = chekedArr[name];
// 创建一个空字符串values用于拼接当前选项组中已选中项的value值后续会通过循环遍历json数组将每个选中项的value值添加到这个字符串中
var values = '';
// 创建一个空字符串names用于拼接当前选项组中已选中项的name值同样会通过循环遍历json数组把每个选中项的name值添加进来
var names = '';
// 开始循环遍历当前选项组对应的已选中项数组json目的是逐个提取并拼接已选中项的name和value值到对应的字符串中
for(var i=0;i<json.length;i++){
// 判断如果当前索引i不是数组的最后一个元素即不是最后一个选中项则执行以下代码块
// 将当前选中项的value值添加到values字符串后面并添加一个逗号作为分隔符方便后续解析等操作name值同理添加到names字符串后面并添加逗号分隔
if(i!=json.length-1){
values+=json[i].value+",";
names +=json[i].name+",";
}else{
// 如果当前索引i是数组的最后一个元素即最后一个选中项则直接将当前选中项的value值添加到values字符串后面
// 不需要添加逗号分隔了name值也同样直接添加到names字符串后面完成整个选项组的已选中项name和value值的拼接
values+=json[i].value;
names +=json[i].name;
}
}
// 将拼接好的当前选项组的已选中项value值字符串以当前选项组的名称name作为键存储到valueJson对象中
// 这样valueJson对象就记录了各个选项组的已选中项的value值信息了
valueJson[name]=values;
// 将拼接好的当前选项组的已选中项name值字符串同样以当前选项组的名称name作为键存储到nameJson对象中
// 使得nameJson对象记录了各个选项组的已选中项的name值信息
nameJson[name]=names;
}
// 将整理好的包含已选中项的value值和name值信息的两个对象valueJson和nameJson封装成一个新的对象并返回
// 返回的对象结构方便外部方法根据需要获取和使用这些已选中的数据信息,例如可以方便地获取某个选项组的已选中项的名称和对应的值等内容
return {values:valueJson,names:nameJson};
}
// 使用layui框架提供的exports方法将名为layfilter的对象包含了前面定义的一系列查询过滤组件相关的方法和属性等内容导出
// 这样在其他使用layui框架的模块中就可以通过引入这个模块来使用layfilter对象提供的功能了
exports('layfilter', layfilter);
})

@ -1,63 +1,97 @@
/*
* minimobile.js v0.0.1 by chenyaowen
* 在保留作者签名的情况下允许使用与商业用途
* 该文件是一个用于移动端页面布局相关功能的JavaScript代码库包含了一些处理页面缩放适配以及常见UI组件功能的代码例如处理viewport设置侧栏显示隐藏返回顶部功能进度条展示等
*/
if(!window.Zepto && !window.jQuery){
// 检查页面是否引入了Zepto.js或者jQuery.js如果都没引入则在控制台输出提示信息因为后续代码依赖这两个库之一。
if (!window.Zepto &&!window.jQuery) {
console.log("minimobile 是基于Zepto.js 或者 jQuery.js 的请检查页面是否已在miniMobile之前引入")
}
;(function(win, lib) {
//摘自淘宝移动端
}
// 立即执行函数用于创建一个局部作用域避免全局变量污染同时接收window对象和一个名为lib的对象如果不存在则创建一个空对象作为参数在函数内部进行相关页面适配等功能的实现。
;(function (win, lib) {
// 获取当前页面的document对象后续会用于操作页面元素、获取页面相关属性等操作。
var doc = win.document;
// 获取页面根元素(<html>元素),很多页面样式和布局相关的设置会基于这个元素来操作,例如设置页面字体大小等属性。
var docEl = doc.documentElement;
// 通过选择器查找页面中name属性为"viewport"的meta标签viewport元标签常用于控制页面在移动端的缩放、布局等显示相关设置。
var metaEl = doc.querySelector('meta[name="viewport"]');
// 通过选择器查找页面中name属性为"flexible"的meta标签从代码逻辑看用于获取一些和页面缩放比例相关的自定义配置信息。
var flexibleEl = doc.querySelector('meta[name="flexible"]');
// 用于存储设备像素比devicePixelRatio相关的缩放因子初始化为0后续会根据不同情况计算并赋值。
var dpr = 0;
// 用于存储页面的缩放比例初始化为0会根据meta标签内容或者设备类型等情况来确定具体值。
var scale = 0;
// 用于存储定时器的标识在处理页面resize和pageshow等事件时通过定时器来延迟执行一些操作避免频繁触发导致性能问题初始化为null或未定义取决于JavaScript环境
var tid;
// 创建一个名为flexible的对象用于存储页面适配相关的一些属性和方法如果外部传入的lib对象中已经存在flexible属性则使用传入的否则创建一个新的空对象赋值给lib.flexible。
var flexible = lib.flexible || (lib.flexible = {});
var designPixel = 750;//设计稿件尺寸
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
// 定义设计稿件的尺寸单位可能是像素这里设定为750用于后续根据页面实际宽度计算缩放比例等相关操作使页面在不同设备上能按比例适配显示。
var designPixel = 750;
// 如果页面中存在name为"viewport"的meta标签则根据其content属性内容来获取初始缩放比例并计算出对应的设备像素比dpr
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
// 通过正则表达式匹配获取content属性中initial-scale的值该值表示页面初始缩放比例。
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
// 将匹配到的初始缩放比例字符串转换为浮点数赋值给scale变量。
scale = parseFloat(match[1]);
// 根据缩放比例计算设备像素比设备像素比是物理像素与逻辑像素的比例关系例如scale为0.5则dpr为2表示物理像素是逻辑像素的2倍。
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
// 获取name为"flexible"的meta标签的content属性内容用于进一步解析获取相关缩放比例配置信息。
var content = flexibleEl.getAttribute('content');
if (content) {
// 通过正则表达式匹配尝试获取content属性中initial-dpr的值用于设置设备像素比dpr
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
// 通过正则表达式匹配尝试获取content属性中maximum-dpr的值同样用于设置设备像素比dpr可能会覆盖前面initialDpr的设置取决于具体匹配情况。
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
// 将匹配到的initial-dpr的值转换为浮点数赋值给dpr变量用于设置设备像素比。
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
// 根据设备像素比计算缩放比例并保留两位小数赋值给scale变量。
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
// 同理如果匹配到了maximum-dpr的值更新设备像素比dpr和缩放比例scale
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
// 如果经过前面的步骤都没有确定dpr和scale的值即都为0则根据设备类型是iPhone还是其他安卓设备等来设置默认的设备像素比dpr和缩放比例scale
if (!dpr &&!scale) {
// 通过正则表达式判断当前设备是否为安卓系统。
var isAndroid = win.navigator.appVersion.match(/android/gi);
// 通过正则表达式判断当前设备是否为iPhone。
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
// 获取当前设备的设备像素比,即物理像素与逻辑像素的实际比例关系。
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
if (isIPhone) {
// 如果是iPhone设备根据设备像素比来设置合适的设备像素比dpr例如设备像素比大于等于3且之前未设置或设置的dpr大于等于3则设置dpr为3以此类推。
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
dpr = 2;
} else {
dpr = 1;
}
} else {
} else {
// 如果不是iPhone设备一般为安卓等其他设备默认设置设备像素比dpr为1。
dpr = 1;
}
// 根据设备像素比dpr计算缩放比例scale两者互为倒数关系。
scale = 1 / dpr;
}
// 将计算得到的设备像素比dpr设置为页面根元素<html>元素的data-dpr属性值方便在CSS等地方通过属性选择器等方式根据不同的设备像素比来应用不同的样式规则。
docEl.setAttribute('data-dpr', dpr);
// 如果页面中不存在name为"viewport"的meta标签则动态创建一个这样的meta标签并设置其content属性用于控制页面的缩放、用户缩放是否可用等显示相关设置然后将其添加到页面中合适的位置一般是<head>标签内)。
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
@ -71,46 +105,65 @@
}
}
function refreshRem(){
// 定义一个用于刷新页面根元素字体大小rem单位的函数根据页面宽度、设计稿件尺寸以及设备像素比等信息来动态计算并设置根元素的字体大小实现页面的自适应布局效果。
function refreshRem() {
// 获取页面根元素(<html>元素的可视宽度不包含滚动条等占据的宽度单位为像素后续会基于这个宽度来计算rem值。
var width = docEl.getBoundingClientRect().width;
if (width / dpr > designPixel) { //如果分辨率不是1那么获取的物理宽度应该乘以分辨率才是最终可用的width
// 如果设备像素比dpr不为1说明物理像素和逻辑像素不一致那么需要将获取到的物理宽度乘以设备像素比得到真正用于计算rem的可用宽度这样能保证在不同分辨率设备上布局的准确性。
if (width / dpr > designPixel) {
width = width * dpr;
}
var rem = width / (designPixel/100); //计算最终还原到设计图上的比例,从而设置到文档上
// 根据设计稿件尺寸designPixel和当前页面可用宽度width计算rem值这里是将页面宽度按照设计稿件尺寸等比例缩放例如设计稿件宽度是750px页面当前宽度是375px则rem值会相应变小实现页面元素按比例缩放显示。
var rem = width / (designPixel / 100);
// 将计算得到的rem值设置为页面根元素<html>元素的字体大小单位为px通过设置根元素字体大小为rem单位页面中使用rem单位的元素尺寸等会根据根元素字体大小动态变化从而实现自适应布局。
docEl.style.fontSize = rem + 'px';
// 将计算得到的rem值存储到flexible对象和全局的win对象即window对象方便其他地方可以访问和使用这个rem值例如用于将px单位转换为rem单位等操作。
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
// 监听页面的resize事件当页面大小发生改变时触发当触发该事件时先清除之前可能存在的定时器避免重复执行或频繁执行刷新rem的操作然后设置一个新的定时器延迟300毫秒后调用refreshRem函数来重新计算并更新页面根元素的字体大小实现页面在大小改变后的自适应布局调整。
win.addEventListener('resize', function () {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
// 监听页面的pageshow事件当页面显示时触发比如浏览器前进、后退等操作导致页面重新显示时如果页面是从缓存中加载显示通过e.persisted判断同样先清除之前的定时器再设置新定时器延迟300毫秒调用refreshRem函数来更新页面布局确保页面在各种显示场景下都能正确自适应。
win.addEventListener('pageshow', function (e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
// 如果页面已经加载完成document.readyState为'complete'则直接设置页面body元素的字体大小为16乘以设备像素比dpr的像素值这是一种基础的字体大小设置通常配合rem单位的自适应布局使用确保文字显示大小合适。
if (doc.readyState === 'complete') {
doc.body.style.fontSize = 16 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
// 如果页面还未加载完成则监听DOMContentLoaded事件当页面DOM结构加载完成但可能资源如图片等还未完全加载时触发在该事件触发时设置页面body元素的字体大小同样为16乘以设备像素比dpr的像素值。
doc.addEventListener('DOMContentLoaded', function (e) {
doc.body.style.fontSize = 16 * dpr + 'px';
}, false);
}
// 首次加载页面时调用refreshRem函数初始化页面根元素的字体大小确保页面一开始就能以正确的自适应布局显示。
refreshRem();
// 将计算得到的设备像素比dpr存储到flexible对象和全局的win对象即window对象方便其他地方获取和使用设备像素比信息例如在处理高清图片显示等场景下可能会用到。
flexible.dpr = win.dpr = dpr;
// 将refreshRem函数存储到flexible对象上方便外部可以手动调用该函数来刷新页面的rem值实现手动触发页面自适应布局调整例如在某些动态改变页面布局结构的情况下可以使用。
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
// 定义一个方法用于将rem单位的数值转换为px单位的数值接收一个参数d可以是数字或者以rem结尾的字符串先将其转换为浮点数然后乘以当前的rem值通过this.rem获取this指向flexible对象如果传入的参数是字符串且以rem结尾则在返回结果后面加上'px'单位,方便在样式设置等场景下直接使用。
flexible.rem2px = function (d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
// 定义一个方法用于将px单位的数值转换为rem单位的数值接收一个参数d可以是数字或者以px结尾的字符串先将其转换为浮点数然后除以当前的rem值通过this.rem获取this指向flexible对象如果传入的参数是字符串且以px结尾则在返回结果后面加上'rem'单位方便在样式设置等场景下直接使用例如在根据设计稿尺寸计算元素的rem单位尺寸时会用到。
flexible.px2rem = function (d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
@ -119,114 +172,40 @@
}
})(window, window['lib'] || (window['lib'] = {}));
/*
* asideUi 侧栏
* 以下代码定义了一个名为asideUi的jQuery或Zepto插件取决于页面引入的是哪个库用于创建一个具有特定交互效果的侧边栏组件例如可以通过点击切换侧边栏的显示隐藏状态并且可以配置一些属性如大小是否显示遮罩位置以及动画过渡时间等
*/
;
(function($) {
$.fn.asideUi = function(options) {
var defaults = {
size: '100%',
hasmask: true,
position: 'left',
sidertime: 300
};
var val = $.extend(defaults, options);
var obj = function() {},
_self = this,
thisMask = $("<div class='ui-aside-mask'></div>"),
thisCss = {},
thisCss2 = {};
thisCss[val.position] = '-' + val.size;
this.css({
'top': (val.position == "bottom") ? "auto" : 0,
'bottom': 0
});
thisCss2[val.position] = 0;
_self.css(thisCss);
obj.toggle = function() {
if(_self.hasClass('ui-aside-open')) {
_self.removeClass('ui-aside-open');
_self.animate(thisCss, val.sidertime);
$('.ui-aside-mask').animate({
'opacity': 0
}, 100, function() {
$(this).remove();
});
} else {
_self.addClass('ui-aside-open');
_self.animate(thisCss2, val.sidertime);
if(val.hasmask) {
$('body').append(thisMask);
$(".ui-aside-mask").animate({
'opacity': 1
}, 100);
}
}
}
thisMask.tap(function() {
obj.toggle();
})
return obj;
};
})(window.Zepto || window.jQuery)
/*
* 返回顶部
*/
function goTop(acceleration, time) {
acceleration = acceleration || 0.1;
time = time || 16;
var x1 = 0;
var y1 = 0;
var x2 = 0;
var y2 = 0;
var x3 = 0;
var y3 = 0;
if(document.documentElement) {
x1 = document.documentElement.scrollLeft || 0;
y1 = document.documentElement.scrollTop || 0;
}
if(document.body) {
x2 = document.body.scrollLeft || 0;
y2 = document.body.scrollTop || 0;
}
var x3 = window.scrollX || 0;
var y3 = window.scrollY || 0;
// 滚动条到页面顶部的水平距离
var x = Math.max(x1, Math.max(x2, x3));
// 滚动条到页面顶部的垂直距离
var y = Math.max(y1, Math.max(y2, y3));
// 滚动距离 = 目前距离 / 速度, 因为距离原来越小, 速度是大于 1 的数, 所以滚动距离会越来越小
var speed = 1 + acceleration;
window.scrollTo(Math.floor(x / speed), Math.floor(y / speed));
// 如果距离不为零, 继续调用迭代本函数
if(x > 0 || y > 0) {
var invokeFunction = "goTop(" + acceleration + ", " + time + ")";
window.setTimeout(invokeFunction, time);
}
}
(function ($) {
// 通过$.fn向jQuery或Zepto的原型对象上添加一个名为asideUi的方法这样就可以在选择器选中的元素上调用该方法来创建侧边栏组件实例接收一个options参数用于传入配置选项。
$.fn.asideUi = function (options) {
// 定义默认的配置选项对象,包含侧边栏的大小(默认为'100%'可以是具体的宽度值或者百分比等、是否显示遮罩默认为true、显示位置默认为'left',还可以是'right'、'bottom'等以及侧边栏展开收起的动画过渡时间默认为300毫秒
var defaults = {
size: '100%',
hasmask: true,
position: 'left',
sidertime: 300
};
// 使用$.extend方法将传入的options参数与默认的配置选项defaults进行合并返回合并后的配置对象这样既可以使用默认配置又可以通过传入的参数覆盖部分默认配置。
var val = $.extend(defaults, options);
// 创建一个空的函数对象,后续会在这个对象上添加一些方法用于操作侧边栏的显示隐藏等功能,目前只是一个占位,方便代码组织和扩展。
var obj = function () { };
// 将当前调用asideUi方法的jQuery或Zepto对象即选中的元素集合赋值给_self变量方便在后续代码中引用例如设置选中元素的样式、添加移除类名等操作。
var _self = this;
// 创建一个用于作为侧边栏遮罩层的<div>元素,添加一个名为'ui-aside-mask'的类名后续可以通过CSS样式来设置其外观如透明度、背景色等以及交互效果如点击隐藏侧边栏等
var thisMask = $("<div class='ui-aside-mask'></div>");
// 创建一个空对象thisCss用于存储侧边栏的初始样式设置主要是控制侧边栏的显示位置和隐藏状态相关样式后续会根据配置的侧边栏位置等信息来设置具体的样式属性。
var thisCss = {};
// 创建另一个空对象thisCss2用于存储侧边栏展开后的样式设置同样是控制侧边栏的位置相关样式与thisCss相对应用于在侧边栏切换显示隐藏时应用不同的样式实现动画过渡效果。
var thisCss2 = {};
/*
* ui-progress进度条
*/
;
(function($) {
$.fn.progressUi = function(options) {
var defaults = {
skin: ''
};
var val = $.extend(defaults, options);
var attrs = {
max: this.attr('max') || 0,
value: this.attr("value") || 0
},
doms = $('<div class="ui-progressBox"></div>');
domsContent = $('<div class="progress-content ' + val.skin + '"></div>');
this.wrap(doms);
domsContent.animate({
'width': attrs.value / attrs.max * 100 + '%',
});
doms.prepend(domsContent);
};
})(window.Zepto || window.jQuery)
// 根据配置的侧边栏位置val.position设置侧边栏的初始位置样式例如如果位置是'left'则将其left属性设置为负的侧边栏大小val.size实现将侧边栏隐藏在屏幕左侧的效果通过CSS的left属性负值来隐藏元素其他位置同理。
thisCss[val.position] = '-' + val.size;
// 设置侧边栏的top和bottom属性根据侧边栏的显示位置val.position来决定top属性是否自动如果是'bottom'位置则top为'auto'其他位置top为0同时设置bottom属性为0用于控制侧边栏在垂直方向上的定位。
this.css({
'top': (val.position == "bottom")? "auto" : 0,
'bottom': 0
});}})
// 根据

File diff suppressed because it is too large Load Diff

@ -1,19 +1,33 @@
(function() {
// 立即执行函数,用于创建一个局部作用域,避免全局变量污染,在这个函数内部定义了一个基础的类继承机制以及一些与表单验证相关的功能代码。
(function () {
/**
* 所有类的基类提供继承机制
* 这里通过一些巧妙的代码逻辑实现了一个简单的类继承模式允许创建类并能方便地继承其他类的属性和方法同时处理了在子类中调用父类同名方法的情况通过 _super 机制
*/
var initializing = false, fnTest = /xyz/.test(function() {xyz;}) ? /\b_super\b/ : /.*/;
this.Class = function() {};
Class.extend = function(prop) {
// 用于检测当前JavaScript环境是否支持在函数内部通过名字访问函数自身的代码用于判断是否是严格模式等情况根据检测结果确定后续用于检测函数中是否包含 _super 关键字的正则表达式。
var initializing = false, fnTest = /xyz/.test(function () { xyz; })? /\b_super\b/ : /.*/;
// 创建一个名为 Class 的全局函数在严格模式下这里的this指向全局对象非严格模式下指向调用者的上下文对象一般在浏览器环境下是 window 对象),这个函数后续作为创建类的构造函数,初始时它只是一个空函数,后续会通过扩展功能来完善类的创建逻辑。
this.Class = function () { };
// 为 Class 函数添加一个 extend 方法用于实现类的继承功能通过传入一个包含属性和方法的对象prop来定义子类要扩展或重写的内容。
Class.extend = function (prop) {
// 获取当前类(调用 extend 方法的类)的原型对象,也就是父类的原型,后续用于在子类中访问父类的方法等操作,实现继承关系中的方法复用和重写逻辑。
var _super = this.prototype;
// 设置 initializing 为 true表示正在初始化一个新的类在继承过程中创建子类的原型对象阶段用于后续在构造函数中判断是否是初始化阶段避免一些不必要的操作比如重复调用初始化方法等
initializing = true;
// 通过使用 new 操作符调用当前类this 指向调用 extend 的类,也就是父类)的构造函数来创建一个新的对象,这个对象将作为子类的原型对象,它会继承父类原型上的属性和方法。
var prototype = new this();
// 完成子类原型对象的创建后,将 initializing 重新设置为 false表示初始化阶段结束。
initializing = false;
for ( var name in prop) {
prototype[name] = typeof prop[name] == "function"
&& typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn) {
return function() {
// 遍历传入的属性对象prop中的每个属性一般是方法或新定义的属性进行相应的处理判断是普通属性赋值还是函数属性的特殊处理涉及到父类同名函数的调用情况
for (var name in prop) {
// 判断当前属性prop[name]是否是函数类型并且父类原型上是否存在同名的函数属性_super[name]),同时还要检测该函数的代码中是否包含 _super 关键字(通过 fnTest 正则表达式判断),如果满足这些条件,则进行特殊的函数包装处理,用于实现子类中调用父类同名函数的功能。
prototype[name] = typeof prop[name] == "function"
&& typeof _super[name] == "function" && fnTest.test(prop[name])?
// 如果满足上述条件,返回一个新的函数,这个函数内部实现了先临时保存当前对象的 _super 属性(可能是之前保存的父类同名函数引用),然后将 _super 属性指向父类的同名函数,接着调用传入的函数(也就是子类重写的函数),在调用完成后恢复 _super 属性的原始值,最后返回函数执行的结果,这样就巧妙地实现了在子类函数中通过 this._super 调用父类同名函数的功能。
(function (name, fn) {
return function () {
var tmp = this._super;
this._super = _super[name];
@ -25,155 +39,177 @@
};
})(name, prop[name]) : prop[name];
}
// 创建一个新的函数(作为子类的构造函数),在这个构造函数中,如果当前不是处于初始化阶段(即不是在创建子类原型对象过程中),并且子类定义了 init 方法(一般用于初始化操作),则调用子类的 init 方法,并传入相应的参数,实现子类实例化时的初始化逻辑。
function Class() {
if (!initializing && this.init)
this.init.apply(this, arguments);
}
// 将前面创建并处理好的原型对象prototype赋值给新创建的子类构造函数Class的原型属性这样通过这个构造函数创建的实例就能继承原型对象上的属性和方法了。
Class.prototype = prototype;
// 修复子类构造函数的 constructor 属性,将其指向正确的子类构造函数本身,确保在使用 instanceof 等操作时能正确识别对象的构造函数类型。
Class.prototype.constructor = Class;
// 将 extend 方法也添加到子类的构造函数上,使得子类也能继续通过调用 extend 方法来实现进一步的继承,形成继承链,这里通过 arguments.callee 引用当前的 extend 函数本身来实现这个功能不过在严格模式下arguments.callee 是不允许使用的,代码可能需要调整)。
Class.extend = arguments.callee;
// 返回创建好的子类构造函数,外部可以通过调用这个构造函数来创建子类的实例对象,完成类的继承和实例化操作。
return Class;
};
})();
// 使用前面定义的 Class 类及继承机制创建一个名为 validate 的类,它继承自 Class主要用于实现表单验证相关的功能比如验证表单字段是否符合特定的规则、显示错误提示等。
var validate = Class
.extend({
defaultCfg:{
rules:{},
submitFun:function(){},
errorLabel:'<label style="color:red"></label>',
errorFun:function(){}
},
init:function(cfg){
this.cfg = $.extend({},this.defaultCfg,cfg);
this.flag=0;
this.toAction(this);
if(this.flag==0){
for(var i in this.cfg.rules){
$("#"+i).unbind("keyup");
}
this.cfg.submitFun();
.extend({
// 默认配置对象包含了验证相关的各种默认设置如验证规则rules、提交表单时执行的函数submitFun、用于显示错误信息的HTML标签模板errorLabel以及出现错误时执行的函数errorFun等属性。
defaultCfg: {
rules: {},
submitFun: function () { },
errorLabel: '<label style="color:red"></label>',
errorFun: function () { }
},
// 初始化方法,在创建 validate 类的实例时会被调用(如果不是处于类继承的初始化阶段,也就是 new 操作实例化时会执行),用于初始化验证相关的配置信息以及绑定一些事件处理等操作。
init: function (cfg) {
// 使用 jQuery 的 extend 方法将传入的配置对象cfg与默认配置对象defaultCfg进行合并得到最终的配置对象并赋值给 this.cfg这样既可以使用默认配置又能通过传入的参数覆盖部分默认配置。
this.cfg = $.extend({}, this.defaultCfg, cfg);
// 初始化一个标志变量flag为0用于记录表单验证过程中是否出现错误等情况后续根据这个标志来决定是否执行提交表单等操作。
this.flag = 0;
// 调用 toAction 方法并传入当前实例对象this开始进行表单验证相关的操作比如遍历验证规则并对相应的表单字段进行验证。
this.toAction(this);
// 如果验证过程中没有出现错误flag 仍然为0则解除表单字段的 keyup 事件绑定可能是之前绑定的用于实时验证的事件这里在全部验证通过后解除避免重复验证等不必要的操作然后执行提交表单的函数submitFun提交表单数据等操作具体由这个函数的实现决定
if (this.flag == 0) {
for (var i in this.cfg.rules) {
$("#" + i).unbind("keyup");
}
},
toAction:function(that){
for(var i in that.cfg.rules){
this.toVal("#"+i,that.cfg.rules[i]);
}
},
toVal:function(ele,constant){
validateConstant[constant].test($(ele).val())?
this.toRemoveError(ele):this.toShowError(ele,errorMsg[constant]);
this.cfg.submitFun();
}
},
// 用于执行表单验证的主要方法接收一个表示当前验证实例的对象that在这个方法内部会遍历配置的验证规则并针对每个规则调用 toVal 方法对相应的表单字段进行验证操作。
toAction: function (that) {
for (var i in that.cfg.rules) {
this.toVal("#" + i, that.cfg.rules[i]);
}
},
// 具体验证单个表单字段的方法接收一个表单字段的选择器ele一般是类似 "#inputId" 的形式表示通过ID选择元素以及对应的验证规则常量constant用于确定使用哪种验证规则来验证该字段根据验证结果调用相应的方法来显示或移除错误提示信息。
toVal: function (ele, constant) {
// 调用 validateConstant 对象中对应的验证规则函数(通过 constant 作为键来查找),传入表单字段的值(通过 jQuery 获取元素的值)进行验证,如果验证通过(返回 true则调用 toRemoveError 方法移除该字段的错误提示信息,否则调用 toShowError 方法显示相应的错误提示信息(传入错误提示消息,通过 errorMsg 对象根据验证规则常量获取)。
validateConstant[constant].test($(ele).val())?
this.toRemoveError(ele) : this.toShowError(ele, errorMsg[constant]);
},
toRemoveError:function(ele){
var that = this;
if($(ele).closest(".form-group").attr("not-allow")){
$(ele).removeAttr("style").closest(".form-group").removeAttr("style")
.removeAttr("not-allow");
$(ele).next().remove();
$(ele).keyup(function(){
ele = ele.replace("#","");
that.toVal("#"+ele,that.cfg.rules[ele]);
});
}
},
toShowError:function(ele,message){
var error = $(this.cfg.errorLabel).text(message);
if(!$(ele).closest(".form-group").attr("not-allow")){
$(ele).after(error);
$(ele).css("border","1px solid red").closest(".form-group")
.css("color","red").attr("not-allow","true");
$(ele).keyup(function(){
ele = ele.replace("#","");
that.toVal("#"+ele,that.cfg.rules[ele]);
});
}
this.flag++;
var that = this;
},
// 用于移除表单字段错误提示信息的方法接收一个表单字段的选择器ele首先获取当前验证实例对象通过 this 赋值给 that 变量),然后判断该字段所在的表单组元素(通过 closest 方法查找父级的.form-group 元素)是否有 "not-allow" 属性,如果有则表示之前添加过错误提示等限制属性,现在需要移除这些属性,恢复表单字段和表单组的原始样式(通过 removeAttr 方法移除相关样式属性),同时移除该字段后面的错误提示标签(通过 next 方法找到并 remove 方法移除),最后重新绑定 keyup 事件,当用户再次输入内容时重新进行验证(调用 toVal 方法)。
toRemoveError: function (ele) {
var that = this;
if ($(ele).closest(".form-group").attr("not-allow")) {
$(ele).removeAttr("style").closest(".form-group").removeAttr("style")
.removeAttr("not-allow");
$(ele).next().remove();
$(ele).keyup(function () {
ele = ele.replace("#", "");
that.toVal("#" + ele, that.cfg.rules[ele]);
});
}
})
},
// 用于显示表单字段错误提示信息的方法接收一个表单字段的选择器ele以及对应的错误提示消息message首先根据配置的错误标签模板cfg.errorLabel创建一个包含错误消息的 <label> 标签元素(通过 jQuery 的 text 方法设置文本内容),然后判断该字段所在的表单组元素是否已经有 "not-allow" 属性(如果没有则表示之前没有添加过错误提示,需要添加),如果没有则将错误提示标签添加到表单字段后面(通过 after 方法),同时设置表单字段和表单组的样式为红色边框、红色文字等错误提示样式(通过 css 方法设置样式属性,并通过 attr 方法添加 "not-allow" 属性表示已经添加了错误提示),最后重新绑定 keyup 事件当用户再次输入内容时重新进行验证并且每次显示错误提示时会将标志变量flag加1表示出现了错误情况后续可以根据这个标志来判断是否能提交表单等操作。
toShowError: function (ele, message) {
var error = $(this.cfg.errorLabel).text(message);
if (!$(ele).closest(".form-group").attr("not-allow")) {
$(ele).after(error);
$(ele).css("border", "1px solid red").closest(".form-group")
.css("color", "red").attr("not-allow", "true");
$(ele).keyup(function () {
ele = ele.replace("#", "");
that.toVal("#" + ele, that.cfg.rules[ele]);
});
}
this.flag++;
var that = this;
}
})
// 定义一个名为 validateConstant 的对象,用于存储各种表单字段验证的正则表达式或验证函数,通过不同的键(验证规则常量,如 "notEmpty"、"password" 等)来对应不同的验证逻辑,用于验证表单输入是否符合相应的格式要求。
var validateConstant = {
"notEmpty" : /^.+$/,// 合法字符
"password" : /^[0-9A-Za-z]{1,18}$/,// 密码
"rightfulString" : /^[A-Za-z0-9_-]+$/,// 合法字符
"number" : /^\d+$/,// 数字
"endlish" : /^[A-Za-z]+$/,// 纯英文
"numberEnglish" : /^[A-Za-z0-9]+$/,// 英文和数字
"float" : /^[+]?\d+(\.\d+)?$/,// 浮点型
"money" : /(^[1-9]\d{0,9}(\.\d{1,2})?$)/,
"chinese" : "/^[\u4e00-\u9fa5]+$/",// 纯中文
"mobile" : /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1})|(14[0-9]{1}))+\d{8})$/,// 手机号
"tel" : /^(\d{3,4}-?)?\d{7,9}$/g,// 电话
"qq" : /^[1-9]\d{4,12}$/,// qq
"zipCode" : /^[0-9]{6}$/,// 邮政编码
"email" : /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,// 邮箱
"positive":/^[1-9][0-9]+$/,//大于0的数字
"checkIdCard" : function(idcard) {// 校验身份证
var area={11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江",31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",
37:"山东",41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",61:"陕西",62:"甘肃",
63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"}
var idcard,Y,JYM;
var S,M;
var idcard_array = new Array();
idcard_array = idcard.split("");
//地区检验
if(area[parseInt(idcard.substr(0,2))]==null){
return false;
"notEmpty": /^.+$/,// 合法字符,该正则表达式表示只要输入有内容(至少包含一个字符)就算符合要求,用于验证字段不能为空。
"password": /^[0-9A-Za-z]{1,18}$/,// 密码验证密码格式要求由数字、大小写字母组成长度在1到18位之间。
"rightfulString": /^[A-Za-z0-9_-]+$/,// 合法字符,验证输入是否是由大小写字母、数字、下划线和短横线组成的合法字符串。
"number": /^\d+$/,// 数字,验证输入是否只包含数字。
"endlish": /^[A-Za-z]+$/,// 纯英文,验证输入是否只包含英文字母。
"numberEnglish": /^[A-Za-z0-9]+$/,// 英文和数字,验证输入是否只包含英文字母和数字。
"float": /^[+]?\d+(\.\d+)?$/,// 浮点型,验证输入是否是合法的浮点数格式,可以包含正负号、整数部分和可选的小数部分。
"money": /(^[1-9]\d{0,9}(\.\d{1,2})?$)/,
"chinese": "/^[\u4e00-\u9fa5]+$/",// 纯中文验证输入是否只包含中文字符通过Unicode编码范围来判断不过这里的正则表达式写法有点问题外面的双引号应该去掉正确的是 /^[\u4e00-\u9fa5]+$/.
"mobile": /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1})|(14[0-9]{1}))+\d{8})$/,// 手机号,验证输入是否是符合常见手机号码格式的字符串。
"tel": /^(\d{3,4}-?)?\d{7,9}$/g,// 电话,验证输入是否是符合常见电话号码格式(可以包含区号,用 - 连接,也可以没有区号)的字符串,注意这里的 /g 表示全局匹配标志,在验证时会匹配所有符合的内容(不过在这个场景下一般只验证一个电话号码,是否需要全局匹配可根据实际情况调整)。
"qq": /^[1-9]\d{4,12}$/,// qq验证输入是否是符合QQ号码格式数字开头长度在5到13位之间的数字字符串。
"zipCode": /^[0-9]{6}$/,// 邮政编码验证输入是否是6位数字的邮政编码格式。
"email": /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,// 邮箱,验证输入是否是符合常见邮箱格式(包含用户名、@符号、域名等部分,这里只是简单的格式验证,不是非常严格)的字符串。
"positive": /^[1-9][0-9]+$/,//大于0的数字验证输入是否是大于0的整数数字开头且不是0后面可以跟其他数字
"checkIdCard": function (idcard) {// 校验身份证定义一个函数用于验证身份证号码的合法性根据身份证号码的位数15位或18位以及对应的出生日期、地区编码、校验位等规则来进行详细的验证返回 true 表示验证通过false 表示验证不通过。
var area = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西",
37: "山东", 41: "河南", 42: "湖北", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏", 61: "陕西", 62: "甘肃",
63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外" }
var idcard, Y, JYM;
var S, M;
var idcard_array = new Array();
idcard_array = idcard.split("");
//地区检验,通过截取身份证号码的前两位,在 area 对象中查找对应的地区名称,如果查找不到则表示地区编码不合法,返回 false。
if (area[parseInt(idcard.substr(0, 2))] == null) {
return false;
}
//身份号码位数及格式检验
switch(idcard.length){
case 15:
if ( (parseInt(idcard.substr(6,2))+1900) % 4 == 0 || ((parseInt(idcard.substr(6,2))+1900) % 100 == 0 && (parseInt(idcard.substr(6,2))+1900) % 4 == 0 )){
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$/;
//测试出生日期的合法性
} else {
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$/;
//测试出生日期的合法性
}
if(ereg.test(idcard)){
return true;
}else{
return false;
}
break;
case 18:
//18位身份号码检测
//出生日期的合法性检查
//闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
//平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
if ( parseInt(idcard.substr(6,4)) % 4 == 0 || (parseInt(idcard.substr(6,4)) % 100 == 0 && parseInt(idcard.substr(6,4))%4 == 0 )){
//身份号码位数及格式检验根据身份证号码的长度15位或18位分别进行不同的格式和合法性验证主要涉及出生日期的合法性检查以及18位身份证的校验位计算等操作。
switch (idcard.length) {case 15:
if ( (parseInt(idcard.substr(6,2))+1900) % 4 == 0 || ((parseInt(idcard.substr(6,2))+1900) % 100 == 0 && (parseInt(idcard.substr(6,2))+1900) % 4 == 0 )){
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$/;
//测试出生日期的合法性
} else {
ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$/;
//测试出生日期的合法性
}
if(ereg.test(idcard)){
return true;
}else{
return false;
}
break;
case 18:
//18位身份号码检测
//出生日期的合法性检查
//闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
//平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
if ( parseInt(idcard.substr(6,4)) % 4 == 0 || (parseInt(idcard.substr(6,4)) % 100 == 0 && parseInt(idcard.substr(6,4))%4 == 0 )){
ereg=/^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$/;
//闰年出生日期的合法性正则表达式
} else {
//闰年出生日期的合法性正则表达式
} else {
ereg=/^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$/;
//平年出生日期的合法性正则表达式
}
if(ereg.test(idcard)){//测试出生日期的合法性
//计算校验位
S = (parseInt(idcard_array[0]) + parseInt(idcard_array[10])) * 7 + (parseInt(idcard_array[1]) + parseInt(idcard_array[11])) * 9
+ (parseInt(idcard_array[2]) + parseInt(idcard_array[12])) * 10 + (parseInt(idcard_array[3]) + parseInt(idcard_array[13])) * 5
+ (parseInt(idcard_array[4]) + parseInt(idcard_array[14])) * 8 + (parseInt(idcard_array[5]) + parseInt(idcard_array[15])) * 4
+ (parseInt(idcard_array[6]) + parseInt(idcard_array[16])) * 2 + parseInt(idcard_array[7]) * 1 + parseInt(idcard_array[8]) * 6
+ parseInt(idcard_array[9]) * 3 ;
Y = S % 11;
M = "F";
JYM = "10X98765432";
M = JYM.substr(Y,1);//判断校验位
//平年出生日期的合法性正则表达式
}
if(ereg.test(idcard)){//测试出生日期的合法性
//计算校验位
S = (parseInt(idcard_array[0]) + parseInt(idcard_array[10])) * 7 + (parseInt(idcard_array[1]) + parseInt(idcard_array[11])) * 9
+ (parseInt(idcard_array[2]) + parseInt(idcard_array[12])) * 10 + (parseInt(idcard_array[3]) + parseInt(idcard_array[13])) * 5
+ (parseInt(idcard_array[4]) + parseInt(idcard_array[14])) * 8 + (parseInt(idcard_array[5]) + parseInt(idcard_array[15])) * 4
+ (parseInt(idcard_array[6]) + parseInt(idcard_array[16])) * 2 + parseInt(idcard_array[7]) * 1 + parseInt(idcard_array[8]) * 6
+ parseInt(idcard_array[9]) * 3 ;
Y = S % 11;
M = "F";
JYM = "10X98765432";
M = JYM.substr(Y,1);//判断校验位
if(M == idcard_array[17].toUpperCase()) {
return true; //检测ID的校验位
return true; //检测ID的校验位
}else{
return false;
}
}else{
return false;
}
break;
default:
return false;
break;
}
break;
default:
return false;
break;
}
}
}
var errorMsg = {

@ -1,289 +1,274 @@
;!function (win) {
"use strict";
var doc = document
,Xadmin = function(){
this.v = '2.2'; //版本号
}
Xadmin.prototype.init = function() {
var tab_list = this.get_data();
for(var i in tab_list){
this.add_lay_tab(tab_list[i].title,tab_list[i].url,i);
}
element.tabChange('xbs_tab', i);
};
/**
* [end 执行结束要做的]
* @return {[type]} [description]
*/
Xadmin.prototype.end = function() {
var cate_list = this.get_cate_data();
for(var i in cate_list){
if(cate_list[i]!=null){
$('.left-nav #nav li').eq(cate_list[i]).click();
}
// 定义一个立即执行的函数表达式 (IIFE),传入全局对象 window
!function(win) {
"use strict"; // 使用严格模式
var doc = document; // 获取文档对象
// 定义 Xadmin 构造函数
var Xadmin = function() {
this.v = '2.2'; // 版本号
}
};
Xadmin.prototype.add_tab = function (title,url,is_refresh) {
var id = md5(url);//md5每个url
//重复点击
for (var i = 0; i <$('.x-iframe').length; i++) {
if($('.x-iframe').eq(i).attr('tab-id')==id){
element.tabChange('xbs_tab', id);
if(is_refresh)
$('.x-iframe').eq(i).attr("src",$('.x-iframe').eq(i).attr('src'));
// 初始化方法
Xadmin.prototype.init = function() {
var tab_list = this.get_data(); // 获取所有标签页数据
for (var i in tab_list) {
this.add_lay_tab(tab_list[i].title, tab_list[i].url, i); // 添加标签页
}
element.tabChange('xbs_tab', i); // 切换到最后一个标签页
};
// 结束方法,用于执行一些收尾工作
Xadmin.prototype.end = function() {
var cate_list = this.get_cate_data(); // 获取分类数据
for (var i in cate_list) {
if (cate_list[i] != null) {
$('.left-nav #nav li').eq(cate_list[i]).click(); // 点击左侧导航栏的对应项
}
}
};
// 添加标签页方法
Xadmin.prototype.add_tab = function(title, url, is_refresh) {
var id = md5(url); // 对 URL 进行 MD5 加密生成唯一 ID
// 检查是否已经存在相同的标签页
for (var i = 0; i < $('.x-iframe').length; i++) {
if ($('.x-iframe').eq(i).attr('tab-id') == id) {
element.tabChange('xbs_tab', id); // 切换到已存在的标签页
if (is_refresh)
$('.x-iframe').eq(i).attr("src", $('.x-iframe').eq(i).attr('src')); // 刷新页面
return;
}
};
}
this.add_lay_tab(title,url,id);
this.set_data(title,url,id);
element.tabChange('xbs_tab', id);
this.add_lay_tab(title, url, id); // 添加新的标签页
this.set_data(title, url, id); // 保存标签页数据
element.tabChange('xbs_tab', id); // 切换到新添加的标签页
}
}
// 删除标签页方法
Xadmin.prototype.del_tab = function(id) {
if (id) {
console.log(88); // 打印日志(调试用)
} else {
var id = $(window.frameElement).attr('tab-id'); // 获取当前窗口的 tab-id
parent.element.tabDelete('xbs_tab', id); // 删除父窗口中的标签页
}
}
Xadmin.prototype.del_tab = function (id) {
// 添加 Layui 标签页方法
Xadmin.prototype.add_lay_tab = function(title, url, id) {
element.tabAdd('xbs_tab', {
title: title, // 标签标题
content: '<iframe tab-id="' + id + '" frameborder="0" scrolling="yes" class="x-iframe"></iframe>', // 标签内容为 iframe
id: id // 标签 ID
})
}
if(id){
console.log(88);
}else{
var id = $(window.frameElement).attr('tab-id');
parent.element.tabDelete('xbs_tab', id);
// 打开弹出层方法
Xadmin.prototype.open = function(title, url) {
if (title == null || title == '') {
var title = false; // 如果标题为空,则不显示标题
};
if (url == null || url == '') {
var url = "404.html"; // 如果 URL 为空,则默认指向 404 页面
};
if (w == null || w == '') {
var w = ($(window).width() * 0.9); // 设置宽度为窗口宽度的 90%
};
if (h == null || h == '') {
var h = ($(window).height() - 50); // 设置高度为窗口高度减去 50px
};
var index = layer.open({
type: 2, // 类型为 iframe
area: [w + 'px', h + 'px'], // 设置弹出层大小
fix: false, // 不固定位置
maxmin: true, // 允许最大化和最小化
shadeClose: true, // 点击遮罩关闭弹出层
shade: 0.4, // 设置遮罩透明度
title: title, // 弹出层标题
content: url // 弹出层内容 URL
});
if (full) {
layer.full(index); // 如果 full 为真,则全屏显示弹出层
}
}
// 关闭弹出层方法
Xadmin.prototype.close = function() {
var index = parent.layer.getFrameIndex(window.name); // 获取当前窗口索引
parent.layer.close(index); // 关闭弹出层
};
// 关闭弹出层并刷新父窗口方法
Xadmin.prototype.father_reload = function() {
parent.location.reload(); // 刷新父窗口
};
// 获取所有标签页数据方法
Xadmin.prototype.get_data = function() {
if (typeof is_remember != "undefined")
return false; // 如果 is_remember 被定义,则返回 false
return layui.data('tab_list') // 从本地存储中获取标签页数据
}
// 增加标签页数据方法
Xadmin.prototype.set_data = function(title, url, id) {
if (typeof is_remember != "undefined")
return false; // 如果 is_remember 被定义,则不执行任何操作
layui.data('tab_list', {
key: id, // 数据的键为标签页 ID
value: { title: title, url: url } // 数据的值为包含标题和 URL 的对象
});
};
// 获取分类数据方法
Xadmin.prototype.get_cate_data = function() {
if (typeof is_remember != "undefined")
return false; // 如果 is_remember 被定义,则返回 false
return layui.data('cate') // 从本地存储中获取分类数据
}
/**
* 设置分类数据
* @param {Object} data - 要存储的数据对象
*/
Xadmin.prototype.set_cate_data = function(data) {
if (typeof is_remember !== "undefined")
return false;
Xadmin.prototype.add_lay_tab = function(title,url,id) {
element.tabAdd('xbs_tab', {
title: title
,content: '<iframe tab-id="'+id+'" frameborder="0" src="'+url+'" scrolling="yes" class="x-iframe"></iframe>'
,id: id
})
}
/**
* [open 打开弹出层]
* @param {[type]} title [弹出层标题]
* @param {[type]} url [弹出层地址]
* @return {[type]} [description]
layui.data('cate', data);
};
/**
* 删除指定ID的数据
* @param {String} id - 要删除的数据的键值
*/
Xadmin.prototype.open = function (title, url) {
if (title == null || title == '') {
var title=false;
};
if (url == null || url == '') {
var url="404.html";
};
if (w == null || w == '') {
var w=($(window).width()*0.9);
};
if (h == null || h == '') {
var h=($(window).height() - 50);
};
var index = layer.open({
type: 2,
area: [w+'px', h +'px'],
fix: false, //不固定
maxmin: true,
shadeClose: true,
shade:0.4,
title: title,
content: url
});
if(full){
layer.full(index);
}
}
/**
* [close 关闭弹出层]
* @return {[type]} [description]
*/
Xadmin.prototype.close = function() {
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
};
/**
* [close 关闭弹出层父窗口关闭]
* @return {[type]} [description]
*/
Xadmin.prototype.father_reload = function() {
parent.location.reload();
};
/**
* [get_data 获取所有项]
* @return {[type]} [description]
*/
Xadmin.prototype.get_data = function () {
if(typeof is_remember!="undefined")
return false;
return layui.data('tab_list')
}
/**
* [set_data 增加某一项]
* @param {[type]} id [description]
*/
Xadmin.prototype.set_data = function(title,url,id) {
if(typeof is_remember!="undefined")
return false;
layui.data('tab_list', {
key: id
,value: {title:title,url:url}
});
};
/**
* [get_data 获取所有项]
* @return {[type]} [description]
*/
Xadmin.prototype.get_cate_data = function () {
if(typeof is_remember!="undefined")
return false;
return layui.data('cate')
}
/**
* [set_data 增加某一项]
* @param {[type]} id [description]
*/
Xadmin.prototype.set_cate_data = function(data) {
if(typeof is_remember!="undefined")
return false;
layui.data('cate', data);
};
/**
* [del_data 删除某一项]
* @param {[type]} id [description]
* @return {[type]} [description]
*/
Xadmin.prototype.del_data = function(id) {
if(typeof is_remember!="undefined")
return false;
if(typeof id!="undefined"){
layui.data('tab_list', {
key: id
,remove: true
});
}else{
layui.data('tab_list',null);
}
};
/**
* [del_other_data 删除其它]
* @param {[type]} id [description]
* @return {[type]} [description]
*/
Xadmin.prototype.del_other_data = function(id) {
if(typeof is_remember!="undefined")
return false;
var tab_list = this.get_data();
layui.data('tab_list',null);
layui.data('tab_list', {
key: id
,value: tab_list[id]
});
};
win.xadmin = new Xadmin();
Xadmin.prototype.del_data = function(id) {
if (typeof is_remember !== "undefined")
return false;
if (typeof id !== "undefined") {
layui.data('tab_list', {
key: id,
remove: true
});
} else {
layui.data('tab_list', null);
}
};
/**
* 删除其他数据只保留指定ID的数据
* @param {String} id - 要保留的数据的键值
*/
Xadmin.prototype.del_other_data = function(id) {
if (typeof is_remember !== "undefined")
return false;
var tab_list = this.get_data();
layui.data('tab_list', null);
layui.data('tab_list', {
key: id,
value: tab_list[id]
});
};
// 初始化xadmin实例
win.xadmin = new Xadmin();
}(window);
layui.use(['layer','element','jquery'],function() {
layui.use(['layer', 'element', 'jquery'], function() {
layer = layui.layer;
element = layui.element;
$ = layui.jquery;
// 打开页面初始
xadmin.init();
//关闭tab清除记忆
element.on('tabDelete(xbs_tab)', function(data){
var id = $(this).parent().attr('lay-id');
// 关闭tab清除记忆
element.on('tabDelete(xbs_tab)', function(data) {
var id = $(this).parent().attr('lay-id');
xadmin.del_data(id);
});
//左侧菜单
$('.left-nav #nav').on('click', 'li', function(event) {
if($(this).parent().attr('id')=='nav'){
xadmin.set_cate_data({key:'f1',value:$('.left-nav #nav li').index($(this))})
xadmin.set_cate_data({key:'f2',value:null})
xadmin.set_cate_data({key:'f3',value:null})
// 左侧菜单点击事件处理
$('.left-nav #nav').on('click', 'li', function(event) {
if ($(this).parent().attr('id') == 'nav') {
xadmin.set_cate_data({ key: 'f1', value: $('.left-nav #nav li').index($(this)) });
xadmin.set_cate_data({ key: 'f2', value: null });
xadmin.set_cate_data({ key: 'f3', value: null });
}
if($(this).parent().parent().parent().attr('id')=='nav'){
xadmin.set_cate_data({key:'f2',value:$('.left-nav #nav li').index($(this))})
xadmin.set_cate_data({key:'f3',value:null})
if ($(this).parent().parent().parent().attr('id') == 'nav') {
xadmin.set_cate_data({ key: 'f2', value: $('.left-nav #nav li').index($(this)) });
xadmin.set_cate_data({ key: 'f3', value: null });
}
if($(this).parent().parent().parent().parent().parent().attr('id')=='nav'){
xadmin.set_cate_data({key:'f3',value:$('.left-nav #nav li').index($(this))})
if ($(this).parent().parent().parent().parent().parent().attr('id') == 'nav') {
xadmin.set_cate_data({ key: 'f3', value: $('.left-nav #nav li').index($(this)) });
}
if($('.left-nav').css('width')=='60px'){
$('.left-nav').animate({width: '220px'}, 100);
$('.page-content').animate({left: '220px'}, 100);
$('.left-nav i').css('font-size','14px');
$('.left-nav cite,.left-nav .nav_right').show();
if ($('.left-nav').css('width') == '60px') {
$('.left-nav').animate({ width: '220px' }, 100);
$('.page-content').animate({ left: '220px' }, 100);
$('.left-nav i').css('font-size', '14px');
$('.left-nav cite,.left-nav .nav_right').show();
}
if($(window).width()<768){
if ($(window).width() < 768) {
$('.page-content-bg').show();
}
$('.left-nav').find('a').removeClass('active');
$(this).children('a').addClass('active');
if($(this).children('.sub-menu').length){
if($(this).hasClass('open')){
if ($(this).children('.sub-menu').length) {
if ($(this).hasClass('open')) {
$(this).removeClass('open');
$(this).find('.nav_right').html('&#xe697;');
$(this).children('.sub-menu').stop(true,true).slideUp();
$(this).children('.sub-menu').stop(true, true).slideUp();
$(this).siblings().children('.sub-menu').slideUp();
}else{
} else {
$(this).addClass('open');
$(this).children('a').find('.nav_right').html('&#xe6a6;');
$(this).children('.sub-menu').stop(true,true).slideDown();
$(this).siblings().children('.sub-menu').stop(true,true).slideUp();
$(this).children('.sub-menu').stop(true, true).slideDown();
$(this).siblings().children('.sub-menu').stop(true, true).slideUp();
$(this).siblings().find('.nav_right').html('&#xe697;');
$(this).siblings().removeClass('open');
}
}
event.stopPropagation();
})
event.stopPropagation();
});
var left_tips_index = null;
$('.left-nav #nav').on('mouseenter', '.left-nav-li', function(event) {
if($('.left-nav').css('width')!='220px'){
var tips = $(this).attr('lay-tips');
left_tips_index = layer.tips(tips, $(this));
}
})
if ($('.left-nav').css('width') != '220px') {
var tips = $(this).attr('lay-tips');
left_tips_index = layer.tips(tips, $(this));
}
});
$('.left-nav #nav').on('mouseout', '.left-nav-li', function(event) {
layer.close(left_tips_index);
})
// 隐藏左侧
layer.close(left_tips_index);
});
// 隐藏左侧导航栏
$('.container .left_open i').click(function(event) {
if($('.left-nav').css('width')=='220px'){
if ($('.left-nav').css('width') == '220px') {
$('.left-nav .open').click();
$('.left-nav i').css('font-size','18px');
$('.left-nav').animate({width: '60px'}, 100);
$('.left-nav i').css('font-size', '18px');
$('.left-nav').animate({ width: '60px' }, 100);
$('.left-nav cite,.left-nav .nav_right').hide();
$('.page-content').animate({left: '60px'}, 100);
$('.page-content').animate({ left: '60px' }, 100);
$('.page-content-bg').hide();
}else{
$('.left-nav').animate({width: '220px'}, 100);
$('.page-content').animate({left: '220px'}, 100);
$('.left-nav i').css('font-size','14px');
} else {
$('.left-nav').animate({ width: '220px' }, 100);
$('.page-content').animate({ left: '220px' }, 100);
$('.left-nav i').css('font-size', '14px');
$('.left-nav cite,.left-nav .nav_right').show();
if($(window).width()<768){
if ($(window).width() < 768) {
$('.page-content-bg').show();
}
}
@ -339,243 +324,265 @@ layui.use(['layer','element','jquery'],function() {
* to work around bugs in some JS interpreters.
*/
function safeAdd (x, y) {
var lsw = (x & 0xffff) + (y & 0xffff)
var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
return (msw << 16) | (lsw & 0xffff)
// 将 x 和 y 分别限制在 16 位,然后相加
var lsw = (x & 0xffff) + (y & 0xffff)
// 计算高位部分的和,并考虑低位部分可能产生的进位
var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
// 返回合并后的 32 位结果
return (msw << 16) | (lsw & 0xffff)
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
* Bitwise rotate a 32-bit number to the left.
*/
function bitRotateLeft (num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
// 使用位移操作实现循环左移
return (num << cnt) | (num >>> (32 - cnt))
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
* These functions implement the four basic operations the algorithm uses.
*/
function md5cmn (q, a, b, x, s, t) {
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b)
// 执行 MD5 算法中的一个基本操作
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b)
}
function md5ff (a, b, c, d, x, s, t) {
return md5cmn((b & c) | (~b & d), a, b, x, s, t)
// 执行 MD5 算法中的 F 函数操作
return md5cmn((b & c) | (~b & d), a, b, x, s, t)
}
function md5gg (a, b, c, d, x, s, t) {
return md5cmn((b & d) | (c & ~d), a, b, x, s, t)
// 执行 MD5 算法中的 G 函数操作
return md5cmn((b & d) | (c & ~d), a, b, x, s, t)
}
function md5hh (a, b, c, d, x, s, t) {
return md5cmn(b ^ c ^ d, a, b, x, s, t)
// 执行 MD5 算法中的 H 函数操作
return md5cmn(b ^ c ^ d, a, b, x, s, t)
}
function md5ii (a, b, c, d, x, s, t) {
return md5cmn(c ^ (b | ~d), a, b, x, s, t)
// 执行 MD5 算法中的 I 函数操作
return md5cmn(c ^ (b | ~d), a, b, x, s, t)
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
function binlMD5 (x, len) {
/* append padding */
x[len >> 5] |= 0x80 << (len % 32)
x[((len + 64) >>> 9 << 4) + 14] = len
var i
var olda
var oldb
var oldc
var oldd
var a = 1732584193
var b = -271733879
var c = -1732584194
var d = 271733878
for (i = 0; i < x.length; i += 16) {
olda = a
oldb = b
oldc = c
oldd = d
a = md5ff(a, b, c, d, x[i], 7, -680876936)
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586)
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819)
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330)
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897)
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426)
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341)
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983)
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416)
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417)
c = md5ff(c, d, a, b, x[i + 10], 17, -42063)
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162)
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682)
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101)
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290)
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329)
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510)
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632)
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713)
b = md5gg(b, c, d, a, x[i], 20, -373897302)
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691)
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083)
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335)
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848)
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438)
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690)
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961)
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501)
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467)
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784)
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473)
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734)
a = md5hh(a, b, c, d, x[i + 5], 4, -378558)
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463)
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562)
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556)
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060)
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353)
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632)
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640)
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174)
d = md5hh(d, a, b, c, x[i], 11, -358537222)
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979)
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189)
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487)
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835)
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520)
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651)
a = md5ii(a, b, c, d, x[i], 6, -198630844)
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415)
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905)
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055)
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571)
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606)
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523)
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799)
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359)
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744)
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380)
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649)
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070)
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379)
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259)
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551)
a = safeAdd(a, olda)
b = safeAdd(b, oldb)
c = safeAdd(c, oldc)
d = safeAdd(d, oldd)
}
return [a, b, c, d]
/* append padding */
// 添加填充数据,使数据长度满足要求
x[len >> 5] |= 0x80 << (len % 32)
// 添加原始数据长度信息(以位为单位)
x[(((len + 64) >>> 9) << 4) + 14] = len
var i
var olda
var oldb
var oldc
var oldd
var a = 1732584193
var b = -271733879
var c = -1732584194
var d = 271733878
for (i = 0; i < x.length; i += 16) {
// 保存当前状态
olda = a
oldb = b
oldc = c
oldd = d
// 执行 MD5 算法的主循环,处理每个块的数据
a = md5ff(a, b, c, d, x[i], 7, -680876936)
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586)
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819)
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330)
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897)
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426)
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341)
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983)
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416)
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417)
c = md5ff(c, d, a, b, x[i + 10], 17, -42063)
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162)
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682)
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101)
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290)
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329)
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510)
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632)
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713)
b = md5gg(b, c, d, a, x[i], 20, -373897302)
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691)
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083)
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335)
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848)
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438)
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690)
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961)
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501)
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467)
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784)
c = md5gg(c, d, a, b, x[i + 7], 14, 173537119)
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734)
a = md5hh(a, b, c, d, x[i + 5], 4, -378558)
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463)
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562)
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556)
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060)
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353)
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632)
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640)
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174)
d = md5hh(d, a, b, c, x[i + 0], 11, -358537222)
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979)
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189)
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487)
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835)
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520)
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651)
a = md5ii(a, b, c, d, x[i], 6, -198630844)
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415)
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905)
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055)
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571)
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606)
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523)
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799)
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359)
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744)
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380)
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649)
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070)
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379)
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259)
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551)
a = safeAdd(a, olda)
b = safeAdd(b, oldb)
c = safeAdd(c, oldc)
d = safeAdd(d, oldd)
}
return [a, b, c, d]
}
/*
* Convert an array of little-endian words to a string
*/
/*
* 将小端序的字数组转换为字符串
*/
function binl2rstr (input) {
var i
var output = ''
var length32 = input.length * 32
for (i = 0; i < length32; i += 8) {
output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff)
}
return output
var i;
var output = '';
var length32 = input.length * 32; // 计算输入数组的总位数
for (i = 0; i < length32; i += 8) {
// 从输入数组中提取每个字节并转换为字符
output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff);
}
return output;
}
/*
* Convert a raw string to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
* 将原始字符串转换为小端序的字数组
* 字符值大于255的高字节将被忽略
*/
function rstr2binl (input) {
var i
var output = []
output[(input.length >> 2) - 1] = undefined
for (i = 0; i < output.length; i += 1) {
output[i] = 0
}
var length8 = input.length * 8
for (i = 0; i < length8; i += 8) {
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32)
}
return output
var i;
var output = [];
output[(input.length >> 2) - 1] = undefined; // 确保输出数组有足够的空间
for (i = 0; i < output.length; i += 1) {
output[i] = 0; // 用零初始化输出数组
}
var length8 = input.length * 8; // 计算输入字符串的总位数
for (i = 0; i < length8; i += 8) {
// 将每个字符打包到输出数组中作为小端序字
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32);
}
return output;
}
/*
* Calculate the MD5 of a raw string
*/
* 计算原始字符串的MD5哈希值
*/
function rstrMD5 (s) {
return binl2rstr(binlMD5(rstr2binl(s), s.length * 8))
return binl2rstr(binlMD5(rstr2binl(s), s.length * 8)); // 将原始字符串转换为二进制,进行哈希运算,然后转换回原始字符串
}
/*
* Calculate the HMAC-MD5, of a key and some data (raw strings)
*/
* 计算HMAC-MD5密钥和数据
*/
function rstrHMACMD5 (key, data) {
var i
var bkey = rstr2binl(key)
var ipad = []
var opad = []
var hash
ipad[15] = opad[15] = undefined
if (bkey.length > 16) {
bkey = binlMD5(bkey, key.length * 8)
}
for (i = 0; i < 16; i += 1) {
ipad[i] = bkey[i] ^ 0x36363636
opad[i] = bkey[i] ^ 0x5c5c5c5c
}
hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8)
return binl2rstr(binlMD5(opad.concat(hash), 512 + 128))
var i;
var bkey = rstr2binl(key); // 将密钥转换为二进制数组
var ipad = [];
var opad = [];
var hash;
ipad[15] = opad[15] = undefined; // 确保ipad和opad数组有足够的空间
if (bkey.length > 16) {
bkey = binlMD5(bkey, key.length * 8); // 如果密钥长度超过16个字先对其进行哈希运算
}
for (i = 0; i < 16; i += 1) {
ipad[i] = bkey[i] ^ 0x36363636; // 使用ipad常量对密钥进行异或操作
opad[i] = bkey[i] ^ 0x5c5c5c5c; // 使用opad常量对密钥进行异或操作
}
hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); // 对内填充的密钥和数据进行哈希运算
return binl2rstr(binlMD5(opad.concat(hash), 512 + 128)); // 对外填充的密钥和之前的哈希结果进行哈希运算,然后转换为原始字符串
}
/*
* Convert a raw string to a hex string
*/
* 将原始字符串转换为十六进制字符串
*/
function rstr2hex (input) {
var hexTab = '0123456789abcdef'
var output = ''
var x
var i
for (i = 0; i < input.length; i += 1) {
x = input.charCodeAt(i)
output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f)
}
return output
var hexTab = '0123456789abcdef'; // 十六进制字符表
var output = '';
var x;
var i;
for (i = 0; i < input.length; i += 1) {
x = input.charCodeAt(i); // 获取每个字符的ASCII码
output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f); // 将每个字符转换为其十六进制表示
}
return output;
}
/*
* Encode a string as utf-8
*/
* 将字符串编码为UTF-8格式
*/
function str2rstrUTF8 (input) {
return unescape(encodeURIComponent(input))
return unescape(encodeURIComponent(input)); // 将输入字符串编码为UTF-8格式
}
/*
* Take string arguments and return either raw or hex encoded strings
*/
* 接受字符串参数并返回原始或十六进制编码的字符串
*/
function rawMD5 (s) {
return rstrMD5(str2rstrUTF8(s))
return rstrMD5(str2rstrUTF8(s)); // 将输入字符串转换为原始格式并计算其MD5哈希值
}
function hexMD5 (s) {
return rstr2hex(rawMD5(s))
return rstr2hex(rawMD5(s)); // 将输入字符串转换为原始格式计算其MD5哈希值然后转换为十六进制格式
}
function rawHMACMD5 (k, d) {
return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d))
return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d)); // 将密钥和数据转换为原始格式计算它们的HMAC-MD5哈希值并返回原始结果
}
function hexHMACMD5 (k, d) {
return rstr2hex(rawHMACMD5(k, d))
return rstr2hex(rawHMACMD5(k, d)); // 将密钥和数据转换为原始格式计算它们的HMAC-MD5哈希值转换为十六进制格式并返回十六进制结果
}
/*
* 根据提供的参数计算MD5或HMAC-MD5的主函数
*/
function md5 (string, key, raw) {
if (!key) {
if (!raw) {
return hexMD5(string)
}
return rawMD5(string)
}
if (!raw) {
return hexHMACMD5(key, string)
}
return rawHMACMD5(key, string)
if (!key) { // 如果没有提供密钥计算输入字符串的MD5哈希值
if (!raw) {
return hexMD5(string); // 返回十六进制编码的MD5哈希值
}
return rawMD5(string); // 返回原始MD5哈希值
}
if (!raw) { // 如果提供了密钥使用密钥计算输入字符串的HMAC-MD5哈希值
return hexHMACMD5(key, string); // 返回十六进制编码的HMAC-MD5哈希值
}
return rawHMACMD5(key, string);
}

@ -15,9 +15,9 @@
this.p.html('');
is_pName = false;
for (var i in provinceList) {
if(pName==provinceList[i].name){
is_pName = true;
this.cityList = provinceList[i].cityList;
@ -29,7 +29,7 @@
if(!is_pName){
this.cityList = provinceList[0].cityList;
}
}
this.showC = function (cityList) {
@ -57,7 +57,7 @@
this.a.html('');
for (var i in areaList) {
if(aName==areaList[i]){
this.a.append("<option selected value='"+areaList[i]+"'>"+areaList[i]+"</option>")
}else{
@ -87,420 +87,420 @@
return this;
}
var provinceList = [
{name:'北京', cityList:[
{name:'市辖区', areaList:['东城区','西城区','崇文区','宣武区','朝阳区','丰台区','石景山区','海淀区','门头沟区','房山区','通州区','顺义区','昌平区','大兴区','怀柔区','平谷区']},
{name:'县', areaList:['密云县','延庆县']}
]},
{name:'上海', cityList:[
{name:'市辖区', areaList:['黄浦区','卢湾区','徐汇区','长宁区','静安区','普陀区','闸北区','虹口区','杨浦区','闵行区','宝山区','嘉定区','浦东新区','金山区','松江区','青浦区','南汇区','奉贤区']},
{name:'县', areaList:['崇明县']}
]},
{name:'天津', cityList:[
{name:'市辖区', areaList:['和平区','河东区','河西区','南开区','河北区','红桥区','塘沽区','汉沽区','大港区','东丽区','西青区','津南区','北辰区','武清区','宝坻区']},
{name:'县', areaList:['宁河县','静海县','蓟 县']}
]},
{name:'重庆', cityList:[
{name:'市辖区', areaList:['万州区','涪陵区','渝中区','大渡口区','江北区','沙坪坝区','九龙坡区','南岸区','北碚区','万盛区','双桥区','渝北区','巴南区','黔江区','长寿区']},
{name:'县', areaList:['綦江县','潼南县','铜梁县','大足县','荣昌县','璧山县','梁平县','城口县','丰都县','垫江县','武隆县','忠 县','开 县','云阳县','奉节县','巫山县','巫溪县','石柱土家族自治县','秀山土家族苗族自治县','酉阳土家族苗族自治县','彭水苗族土家族自治县']},
{name:'市', areaList:['江津市','合川市','永川市','南川市']}
]},
{name:'四川', cityList:[
{name:'成都市', areaList:['市辖区','锦江区','青羊区','金牛区','武侯区','成华区','龙泉驿区','青白江区','新都区','温江县','金堂县','双流县','郫 县','大邑县','蒲江县','新津县','都江堰市','彭州市','邛崃市','崇州市']},
{name:'自贡市', areaList:['市辖区','自流井区','贡井区','大安区','沿滩区','荣 县','富顺县']},
{name:'攀枝花市', areaList:['市辖区','东 区','西 区','仁和区','米易县','盐边县']},
{name:'泸州市', areaList:['市辖区','江阳区','纳溪区','龙马潭区','泸 县','合江县','叙永县','古蔺县']},
{name:'德阳市', areaList:['市辖区','旌阳区','中江县','罗江县','广汉市','什邡市','绵竹市']},
{name:'绵阳市', areaList:['市辖区','涪城区','游仙区','三台县','盐亭县','安 县','梓潼县','北川羌族自治县','平武县','江油市']},
{name:'广元市', areaList:['市辖区','市中区','元坝区','朝天区','旺苍县','青川县','剑阁县','苍溪县']},
{name:'遂宁市', areaList:['市辖区','船山区','安居区','蓬溪县','射洪县','大英县']},
{name:'内江市', areaList:['市辖区','市中区','东兴区','威远县','资中县','隆昌县']},
{name:'乐山市', areaList:['市辖区','市中区','沙湾区','五通桥区','金口河区','犍为县','井研县','夹江县','沐川县','峨边彝族自治县','马边彝族自治县','峨眉山市']},
{name:'南充市', areaList:['市辖区','顺庆区','高坪区','嘉陵区','南部县','营山县','蓬安县','仪陇县','西充县','阆中市']},
{name:'眉山市', areaList:['市辖区','东坡区','仁寿县','彭山县','洪雅县','丹棱县','青神县']},
{name:'宜宾市', areaList:['市辖区','翠屏区','宜宾县','南溪县','江安县','长宁县','高 县','珙 县','筠连县','兴文县','屏山县']},
{name:'广安市', areaList:['市辖区','广安区','岳池县','武胜县','邻水县','华莹市']},
{name:'达州市', areaList:['市辖区','通川区','达 县','宣汉县','开江县','大竹县','渠 县','万源市']},
{name:'雅安市', areaList:['市辖区','雨城区','名山县','荥经县','汉源县','石棉县','天全县','芦山县','宝兴县']},
{name:'巴中市', areaList:['市辖区','巴州区','通江县','南江县','平昌县']},
{name:'资阳市', areaList:['市辖区','雁江区','安岳县','乐至县','简阳市']},
{name:'阿坝藏族羌族自治州', areaList:['汶川县','理 县','茂 县','松潘县','九寨沟县','金川县','小金县','黑水县','马尔康县','壤塘县','阿坝县','若尔盖县','红原县']},
{name:'甘孜藏族自治州', areaList:['康定县','泸定县','丹巴县','九龙县','雅江县','道孚县','炉霍县','甘孜县','新龙县','德格县','白玉县','石渠县','色达县','理塘县','巴塘县','乡城县','稻城县','得荣县']},
{name:'凉山彝族自治州', areaList:['西昌市','木里藏族自治县','盐源县','德昌县','会理县','会东县','宁南县','普格县','布拖县','金阳县','昭觉县','喜德县','冕宁县','越西县','甘洛县','美姑县','雷波县']}
]},
{name:'贵州', cityList:[
{name:'贵阳市', areaList:['市辖区','南明区','云岩区','花溪区','乌当区','白云区','小河区','开阳县','息烽县','修文县','清镇市']},
{name:'六盘水市', areaList:['钟山区','六枝特区','水城县','盘 县']},
{name:'遵义市', areaList:['市辖区','红花岗区','汇川区','遵义县','桐梓县','绥阳县','正安县','道真仡佬族苗族自治县','务川仡佬族苗族自治县','凤冈县','湄潭县','余庆县','习水县','赤水市','仁怀市']},
{name:'安顺市', areaList:['市辖区','西秀区','平坝县','普定县','镇宁布依族苗族自治县','关岭布依族苗族自治县','紫云苗族布依族自治县']},
{name:'铜仁地区', areaList:['铜仁市','江口县','玉屏侗族自治县','石阡县','思南县','印江土家族苗族自治县','德江县','沿河土家族自治县','松桃苗族自治县','万山特区']},
{name:'黔西南布依族苗族自治州', areaList:['兴义市','兴仁县','普安县','晴隆县','贞丰县','望谟县','册亨县','安龙县']},
{name:'毕节地区', areaList:['毕节市','大方县','黔西县','金沙县','织金县','纳雍县','威宁彝族回族苗族自治县','赫章县']},
{name:'黔东南苗族侗族自治州', areaList:['凯里市','黄平县','施秉县','三穗县','镇远县','岑巩县','天柱县','锦屏县','剑河县','台江县','黎平县','榕江县','从江县','雷山县','麻江县','丹寨县']},
{name:'黔南布依族苗族自治州', areaList:['都匀市','福泉市','荔波县','贵定县','瓮安县','独山县','平塘县','罗甸县','长顺县','龙里县','惠水县','三都水族自治县']}
]},
{name:'云南', cityList:[
{name:'昆明市', areaList:['市辖区','五华区','盘龙区','官渡区','西山区','东川区','呈贡县','晋宁县','富民县','宜良县','石林彝族自治县','嵩明县','禄劝彝族苗族自治县','寻甸回族彝族自治县','安宁市']},
{name:'曲靖市', areaList:['市辖区','麒麟区','马龙县','陆良县','师宗县','罗平县','富源县','会泽县','沾益县','宣威市']},
{name:'玉溪市', areaList:['市辖区','红塔区','江川县','澄江县','通海县','华宁县','易门县','峨山彝族自治县','新平彝族傣族自治县','元江哈尼族彝族傣族自治县']},
{name:'保山市', areaList:['市辖区','隆阳区','施甸县','腾冲县','龙陵县','昌宁县']},
{name:'昭通市', areaList:['市辖区','昭阳区','鲁甸县','巧家县','盐津县','大关县','永善县','绥江县','镇雄县','彝良县','威信县','水富县']},
{name:'丽江市', areaList:['市辖区','古城区','玉龙纳西族自治县','永胜县','华坪县','宁蒗彝族自治县']},
{name:'思茅市', areaList:['市辖区','翠云区','普洱哈尼族彝族自治县','墨江哈尼族自治县','景东彝族自治县','景谷傣族彝族自治县','镇沅彝族哈尼族拉祜族自治县','江城哈尼族彝族自治县','孟连傣族拉祜族佤族自治县','澜沧拉祜族自治县','西盟佤族自治县']},
{name:'临沧市', areaList:['市辖区','临翔区','凤庆县','云 县','永德县','镇康县','双江拉祜族佤族布朗族傣族自治县','耿马傣族佤族自治县','沧源佤族自治县']},
{name:'楚雄彝族自治州', areaList:['楚雄市','双柏县','牟定县','南华县','姚安县','大姚县','永仁县','元谋县','武定县','禄丰县']},
{name:'红河哈尼族彝族自治州', areaList:['个旧市','开远市','蒙自县','屏边苗族自治县','建水县','石屏县','弥勒县','泸西县','元阳县','红河县','金平苗族瑶族傣族自治县','绿春县','河口瑶族自治县']},
{name:'文山壮族苗族自治州', areaList:['文山县','砚山县','西畴县','麻栗坡县','马关县','丘北县','广南县','富宁县']},
{name:'西双版纳傣族自治州', areaList:['景洪市','勐海县','勐腊县']},
{name:'大理白族自治州', areaList:['大理市','漾濞彝族自治县','祥云县','宾川县','弥渡县','南涧彝族自治县','巍山彝族回族自治县','永平县','云龙县','洱源县','剑川县','鹤庆县']},
{name:'德宏傣族景颇族自治州', areaList:['瑞丽市','潞西市','梁河县','盈江县','陇川县']},
{name:'怒江傈僳族自治州', areaList:['泸水县','福贡县','贡山独龙族怒族自治县','兰坪白族普米族自治县']},
{name:'迪庆藏族自治州', areaList:['香格里拉县','德钦县','维西傈僳族自治县']}
]},
{name:'西藏', cityList:[
{name:'拉萨市', areaList:['市辖区','城关区','林周县','当雄县','尼木县','曲水县','堆龙德庆县','达孜县','墨竹工卡县']},
{name:'昌都地区', areaList:['昌都县','江达县','贡觉县','类乌齐县','丁青县','察雅县','八宿县','左贡县','芒康县','洛隆县','边坝县']},
{name:'山南地区', areaList:['乃东县','扎囊县','贡嘎县','桑日县','琼结县','曲松县','措美县','洛扎县','加查县','隆子县','错那县','浪卡子县']},
{name:'日喀则地区', areaList:['日喀则市','南木林县','江孜县','定日县','萨迦县','拉孜县','昂仁县','谢通门县','白朗县','仁布县','康马县','定结县','仲巴县','亚东县','吉隆县','聂拉木县','萨嘎县','岗巴县']},
{name:'那曲地区', areaList:['那曲县','嘉黎县','比如县','聂荣县','安多县','申扎县','索 县','班戈县','巴青县','尼玛县']},
{name:'阿里地区', areaList:['普兰县','札达县','噶尔县','日土县','革吉县','改则县','措勤县']},
{name:'林芝地区', areaList:['林芝县','工布江达县','米林县','墨脱县','波密县','察隅县','朗 县']}
]},
{name:'河南', cityList:[
{name:'郑州市', areaList:['市辖区','中原区','二七区','管城回族区','金水区','上街区','邙山区','中牟县','巩义市','荥阳市','新密市','新郑市','登封市']},
{name:'开封市', areaList:['市辖区','龙亭区','顺河回族区','鼓楼区','南关区','郊 区','杞 县','通许县','尉氏县','开封县','兰考县']},
{name:'洛阳市', areaList:['市辖区','老城区','西工区','廛河回族区','涧西区','吉利区','洛龙区','孟津县','新安县','栾川县','嵩 县','汝阳县','宜阳县','洛宁县','伊川县','偃师市']},
{name:'平顶山市', areaList:['市辖区','新华区','卫东区','石龙区','湛河区','宝丰县','叶 县','鲁山县','郏 县','舞钢市','汝州市']},
{name:'安阳市', areaList:['市辖区','文峰区','北关区','殷都区','龙安区','安阳县','汤阴县','滑 县','内黄县','林州市']},
{name:'鹤壁市', areaList:['市辖区','鹤山区','山城区','淇滨区','浚 县','淇 县']},
{name:'新乡市', areaList:['市辖区','红旗区','卫滨区','凤泉区','牧野区','新乡县','获嘉县','原阳县','延津县','封丘县','长垣县','卫辉市','辉县市']},
{name:'焦作市', areaList:['市辖区','解放区','中站区','马村区','山阳区','修武县','博爱县','武陟县','温 县','济源市','沁阳市','孟州市']},
{name:'濮阳市', areaList:['市辖区','华龙区','清丰县','南乐县','范 县','台前县','濮阳县']},
{name:'许昌市', areaList:['市辖区','魏都区','许昌县','鄢陵县','襄城县','禹州市','长葛市']},
{name:'漯河市', areaList:['市辖区','源汇区','郾城区','召陵区','舞阳县','临颍县']},
{name:'三门峡市', areaList:['市辖区','湖滨区','渑池县','陕 县','卢氏县','义马市','灵宝市']},
{name:'南阳市', areaList:['市辖区','宛城区','卧龙区','南召县','方城县','西峡县','镇平县','内乡县','淅川县','社旗县','唐河县','新野县','桐柏县','邓州市']},
{name:'商丘市', areaList:['市辖区','梁园区','睢阳区','民权县','睢 县','宁陵县','柘城县','虞城县','夏邑县','永城市']},
{name:'信阳市', areaList:['市辖区','师河区','平桥区','罗山县','光山县','新 县','商城县','固始县','潢川县','淮滨县','息 县']},
{name:'周口市', areaList:['市辖区','川汇区','扶沟县','西华县','商水县','沈丘县','郸城县','淮阳县','太康县','鹿邑县','项城市']},
{name:'驻马店市', areaList:['市辖区','驿城区','西平县','上蔡县','平舆县','正阳县','确山县','泌阳县','汝南县','遂平县','新蔡县']}
]},
{name:'湖北', cityList:[
{name:'武汉市', areaList:['市辖区','江岸区','江汉区','乔口区','汉阳区','武昌区','青山区','洪山区','东西湖区','汉南区','蔡甸区','江夏区','黄陂区','新洲区']},
{name:'黄石市', areaList:['市辖区','黄石港区','西塞山区','下陆区','铁山区','阳新县','大冶市']},
{name:'十堰市', areaList:['市辖区','茅箭区','张湾区','郧 县','郧西县','竹山县','竹溪县','房 县','丹江口市']},
{name:'宜昌市', areaList:['市辖区','西陵区','伍家岗区','点军区','猇亭区','夷陵区','远安县','兴山县','秭归县','长阳土家族自治县','五峰土家族自治县','宜都市','当阳市','枝江市']},
{name:'襄樊市', areaList:['市辖区','襄城区','樊城区','襄阳区','南漳县','谷城县','保康县','老河口市','枣阳市','宜城市']},
{name:'鄂州市', areaList:['市辖区','梁子湖区','华容区','鄂城区']},
{name:'荆门市', areaList:['市辖区','东宝区','掇刀区','京山县','沙洋县','钟祥市']},
{name:'孝感市', areaList:['市辖区','孝南区','孝昌县','大悟县','云梦县','应城市','安陆市','汉川市']},
{name:'荆州市', areaList:['市辖区','沙市区','荆州区','公安县','监利县','江陵县','石首市','洪湖市','松滋市']},
{name:'黄冈市', areaList:['市辖区','黄州区','团风县','红安县','罗田县','英山县','浠水县','蕲春县','黄梅县','麻城市','武穴市']},
{name:'咸宁市', areaList:['市辖区','咸安区','嘉鱼县','通城县','崇阳县','通山县','赤壁市']},
{name:'随州市', areaList:['市辖区','曾都区','广水市']},
{name:'恩施土家族苗族自治州', areaList:['恩施市','利川市','建始县','巴东县','宣恩县','咸丰县','来凤县','鹤峰县']},
{name:'省直辖行政单位', areaList:['仙桃市','潜江市','天门市','神农架林区']}
]},
{name:'湖南', cityList:[
{name:'长沙市', areaList:['市辖区','芙蓉区','天心区','岳麓区','开福区','雨花区','长沙县','望城县','宁乡县','浏阳市']},
{name:'株洲市', areaList:['市辖区','荷塘区','芦淞区','石峰区','天元区','株洲县','攸 县','茶陵县','炎陵县','醴陵市']},
{name:'湘潭市', areaList:['市辖区','雨湖区','岳塘区','湘潭县','湘乡市','韶山市']},
{name:'衡阳市', areaList:['市辖区','珠晖区','雁峰区','石鼓区','蒸湘区','南岳区','衡阳县','衡南县','衡山县','衡东县','祁东县','耒阳市','常宁市']},
{name:'邵阳市', areaList:['市辖区','双清区','大祥区','北塔区','邵东县','新邵县','邵阳县','隆回县','洞口县','绥宁县','新宁县','城步苗族自治县','武冈市']},
{name:'岳阳市', areaList:['市辖区','岳阳楼区','云溪区','君山区','岳阳县','华容县','湘阴县','平江县','汨罗市','临湘市']},
{name:'常德市', areaList:['市辖区','武陵区','鼎城区','安乡县','汉寿县','澧 县','临澧县','桃源县','石门县','津市市']},
{name:'张家界市', areaList:['市辖区','永定区','武陵源区','慈利县','桑植县']},
{name:'益阳市', areaList:['市辖区','资阳区','赫山区','南 县','桃江县','安化县','沅江市']},
{name:'郴州市', areaList:['市辖区','北湖区','苏仙区','桂阳县','宜章县','永兴县','嘉禾县','临武县','汝城县','桂东县','安仁县','资兴市']},
{name:'永州市', areaList:['市辖区','芝山区','冷水滩区','祁阳县','东安县','双牌县','道 县','江永县','宁远县','蓝山县','新田县','江华瑶族自治县']},
{name:'怀化市', areaList:['市辖区','鹤城区','中方县','沅陵县','辰溪县','溆浦县','会同县','麻阳苗族自治县','新晃侗族自治县','芷江侗族自治县','靖州苗族侗族自治县','通道侗族自治县','洪江市']},
{name:'娄底市', areaList:['市辖区','娄星区','双峰县','新化县','冷水江市','涟源市']},
{name:'湘西土家族苗族自治州', areaList:['吉首市','泸溪县','凤凰县','花垣县','保靖县','古丈县','永顺县','龙山县']}
]},
{name:'广东', cityList:[
{name:'广州市', areaList:['市辖区','东山区','荔湾区','越秀区','海珠区','天河区','芳村区','白云区','黄埔区','番禺区','花都区','增城市','从化市']},
{name:'韶关市', areaList:['市辖区','武江区','浈江区','曲江区','始兴县','仁化县','翁源县','乳源瑶族自治县','新丰县','乐昌市','南雄市']},
{name:'深圳市', areaList:['市辖区','罗湖区','福田区','南山区','宝安区','龙岗区','盐田区']},
{name:'珠海市', areaList:['市辖区','香洲区','斗门区','金湾区']},
{name:'汕头市', areaList:['市辖区','龙湖区','金平区','濠江区','潮阳区','潮南区','澄海区','南澳县']},
{name:'佛山市', areaList:['市辖区','禅城区','南海区','顺德区','三水区','高明区']},
{name:'江门市', areaList:['市辖区','蓬江区','江海区','新会区','台山市','开平市','鹤山市','恩平市']},
{name:'湛江市', areaList:['市辖区','赤坎区','霞山区','坡头区','麻章区','遂溪县','徐闻县','廉江市','雷州市','吴川市']},
{name:'茂名市', areaList:['市辖区','茂南区','茂港区','电白县','高州市','化州市','信宜市']},
{name:'肇庆市', areaList:['市辖区','端州区','鼎湖区','广宁县','怀集县','封开县','德庆县','高要市','四会市']},
{name:'惠州市', areaList:['市辖区','惠城区','惠阳区','博罗县','惠东县','龙门县']},
{name:'梅州市', areaList:['市辖区','梅江区','梅 县','大埔县','丰顺县','五华县','平远县','蕉岭县','兴宁市']},
{name:'汕尾市', areaList:['市辖区','城 区','海丰县','陆河县','陆丰市']},
{name:'河源市', areaList:['市辖区','源城区','紫金县','龙川县','连平县','和平县','东源县']},
{name:'阳江市', areaList:['市辖区','江城区','阳西县','阳东县','阳春市']},
{name:'清远市', areaList:['市辖区','清城区','佛冈县','阳山县','连山壮族瑶族自治县','连南瑶族自治县','清新县','英德市','连州市']},
{name:'东莞市', areaList:['东莞市']},
{name:'中山市', areaList:['中山市']},
{name:'潮州市', areaList:['市辖区','湘桥区','潮安县','饶平县']},
{name:'揭阳市', areaList:['市辖区','榕城区','揭东县','揭西县','惠来县','普宁市']},
{name:'云浮市', areaList:['市辖区','云城区','新兴县','郁南县','云安县','罗定市']}
]},
{name:'广西', cityList:[
{name:'南宁市', areaList:['市辖区','兴宁区','青秀区','江南区','西乡塘区','良庆区','邕宁区','武鸣县','隆安县','马山县','上林县','宾阳县','横 县']},
{name:'柳州市', areaList:['市辖区','城中区','鱼峰区','柳南区','柳北区','柳江县','柳城县','鹿寨县','融安县','融水苗族自治县','三江侗族自治县']},
{name:'桂林市', areaList:['市辖区','秀峰区','叠彩区','象山区','七星区','雁山区','阳朔县','临桂县','灵川县','全州县','兴安县','永福县','灌阳县','龙胜各族自治县','资源县','平乐县','荔蒲县','恭城瑶族自治县']},
{name:'梧州市', areaList:['市辖区','万秀区','蝶山区','长洲区','苍梧县','藤 县','蒙山县','岑溪市']},
{name:'北海市', areaList:['市辖区','海城区','银海区','铁山港区','合浦县']},
{name:'防城港市', areaList:['市辖区','港口区','防城区','上思县','东兴市']},
{name:'钦州市', areaList:['市辖区','钦南区','钦北区','灵山县','浦北县']},
{name:'贵港市', areaList:['市辖区','港北区','港南区','覃塘区','平南县','桂平市']},
{name:'玉林市', areaList:['市辖区','玉州区','容 县','陆川县','博白县','兴业县','北流市']},
{name:'百色市', areaList:['市辖区','右江区','田阳县','田东县','平果县','德保县','靖西县','那坡县','凌云县','乐业县','田林县','西林县','隆林各族自治县']},
{name:'贺州市', areaList:['市辖区','八步区','昭平县','钟山县','富川瑶族自治县']},
{name:'河池市', areaList:['市辖区','金城江区','南丹县','天峨县','凤山县','东兰县','罗城仫佬族自治县','环江毛南族自治县','巴马瑶族自治县','都安瑶族自治县','大化瑶族自治县','宜州市']},
{name:'来宾市', areaList:['市辖区','兴宾区','忻城县','象州县','武宣县','金秀瑶族自治县','合山市']},
{name:'崇左市', areaList:['市辖区','江洲区','扶绥县','宁明县','龙州县','大新县','天等县','凭祥市']}
]},
{name:'陕西', cityList:[
{name:'西安市', areaList:['市辖区','新城区','碑林区','莲湖区','灞桥区','未央区','雁塔区','阎良区','临潼区','长安区','蓝田县','周至县','户 县','高陵县']},
{name:'铜川市', areaList:['市辖区','王益区','印台区','耀州区','宜君县']},
{name:'宝鸡市', areaList:['市辖区','渭滨区','金台区','陈仓区','凤翔县','岐山县','扶风县','眉 县','陇 县','千阳县','麟游县','凤 县','太白县']},
{name:'咸阳市', areaList:['市辖区','秦都区','杨凌区','渭城区','三原县','泾阳县','乾 县','礼泉县','永寿县','彬 县','长武县','旬邑县','淳化县','武功县','兴平市']},
{name:'渭南市', areaList:['市辖区','临渭区','华 县','潼关县','大荔县','合阳县','澄城县','蒲城县','白水县','富平县','韩城市','华阴市']},
{name:'延安市', areaList:['市辖区','宝塔区','延长县','延川县','子长县','安塞县','志丹县','吴旗县','甘泉县','富 县','洛川县','宜川县','黄龙县','黄陵县']},
{name:'汉中市', areaList:['市辖区','汉台区','南郑县','城固县','洋 县','西乡县','勉 县','宁强县','略阳县','镇巴县','留坝县','佛坪县']},
{name:'榆林市', areaList:['市辖区','榆阳区','神木县','府谷县','横山县','靖边县','定边县','绥德县','米脂县','佳 县','吴堡县','清涧县','子洲县']},
{name:'安康市', areaList:['市辖区','汉滨区','汉阴县','石泉县','宁陕县','紫阳县','岚皋县','平利县','镇坪县','旬阳县','白河县']},
{name:'商洛市', areaList:['市辖区','商州区','洛南县','丹凤县','商南县','山阳县','镇安县','柞水县']}
]},
{name:'甘肃', cityList:[
{name:'兰州市', areaList:['市辖区','城关区','七里河区','西固区','安宁区','红古区','永登县','皋兰县','榆中县']},
{name:'嘉峪关市', areaList:['市辖区']},
{name:'金昌市', areaList:['市辖区','金川区','永昌县']},
{name:'白银市', areaList:['市辖区','白银区','平川区','靖远县','会宁县','景泰县']},
{name:'天水市', areaList:['市辖区','秦城区','北道区','清水县','秦安县','甘谷县','武山县','张家川回族自治县']},
{name:'武威市', areaList:['市辖区','凉州区','民勤县','古浪县','天祝藏族自治县']},
{name:'张掖市', areaList:['市辖区','甘州区','肃南裕固族自治县','民乐县','临泽县','高台县','山丹县']},
{name:'平凉市', areaList:['市辖区','崆峒区','泾川县','灵台县','崇信县','华亭县','庄浪县','静宁县']},
{name:'酒泉市', areaList:['市辖区','肃州区','金塔县','安西县','肃北蒙古族自治县','阿克塞哈萨克族自治县','玉门市','敦煌市']},
{name:'庆阳市', areaList:['市辖区','西峰区','庆城县','环 县','华池县','合水县','正宁县','宁 县','镇原县']},
{name:'定西市', areaList:['市辖区','安定区','通渭县','陇西县','渭源县','临洮县','漳 县','岷 县']},
{name:'陇南市', areaList:['市辖区','武都区','成 县','文 县','宕昌县','康 县','西和县','礼 县','徽 县','两当县']},
{name:'临夏回族自治州', areaList:['临夏市','临夏县','康乐县','永靖县','广河县','和政县','东乡族自治县','积石山保安族东乡族撒拉族自治县']},
{name:'甘南藏族自治州', areaList:['合作市','临潭县','卓尼县','舟曲县','迭部县','玛曲县','碌曲县','夏河县']}
]},
{name:'青海', cityList:[
{name:'西宁市', areaList:['市辖区','城东区','城中区','城西区','城北区','大通回族土族自治县','湟中县','湟源县']},
{name:'海东地区', areaList:['平安县','民和回族土族自治县','乐都县','互助土族自治县','化隆回族自治县','循化撒拉族自治县']},
{name:'海北藏族自治州', areaList:['门源回族自治县','祁连县','海晏县','刚察县']},
{name:'黄南藏族自治州', areaList:['同仁县','尖扎县','泽库县','河南蒙古族自治县']},
{name:'海南藏族自治州', areaList:['共和县','同德县','贵德县','兴海县','贵南县']},
{name:'果洛藏族自治州', areaList:['玛沁县','班玛县','甘德县','达日县','久治县','玛多县']},
{name:'玉树藏族自治州', areaList:['玉树县','杂多县','称多县','治多县','囊谦县','曲麻莱县']},
{name:'海西蒙古族藏族自治州', areaList:['格尔木市','德令哈市','乌兰县','都兰县','天峻县']}
]},
{name:'宁夏', cityList:[
{name:'银川市', areaList:['市辖区','兴庆区','西夏区','金凤区','永宁县','贺兰县','灵武市']},
{name:'石嘴山市', areaList:['市辖区','大武口区','惠农区','平罗县']},
{name:'吴忠市', areaList:['市辖区','利通区','盐池县','同心县','青铜峡市']},
{name:'固原市', areaList:['市辖区','原州区','西吉县','隆德县','泾源县','彭阳县','海原县']},
{name:'中卫市', areaList:['市辖区','沙坡头区','中宁县']}
]},
{name:'新疆', cityList:[
{name:'乌鲁木齐市', areaList:['市辖区','天山区','沙依巴克区','新市区','水磨沟区','头屯河区','达坂城区','东山区','乌鲁木齐县']},
{name:'克拉玛依市', areaList:['市辖区','独山子区','克拉玛依区','白碱滩区','乌尔禾区']},
{name:'吐鲁番地区', areaList:['吐鲁番市','鄯善县','托克逊县']},
{name:'哈密地区', areaList:['哈密市','巴里坤哈萨克自治县','伊吾县']},
{name:'昌吉回族自治州', areaList:['昌吉市','阜康市','米泉市','呼图壁县','玛纳斯县','奇台县','吉木萨尔县','木垒哈萨克自治县']},
{name:'博尔塔拉蒙古自治州', areaList:['博乐市','精河县','温泉县']},
{name:'巴音郭楞蒙古自治州', areaList:['库尔勒市','轮台县','尉犁县','若羌县','且末县','焉耆回族自治县','和静县','和硕县','博湖县']},
{name:'阿克苏地区', areaList:['阿克苏市','温宿县','库车县','沙雅县','新和县','拜城县','乌什县','阿瓦提县','柯坪县']},
{name:'克孜勒苏柯尔克孜自治州', areaList:['阿图什市','阿克陶县','阿合奇县','乌恰县']},
{name:'喀什地区', areaList:['喀什市','疏附县','疏勒县','英吉沙县','泽普县','莎车县','叶城县','麦盖提县','岳普湖县','伽师县','巴楚县','塔什库尔干塔吉克自治县']},
{name:'和田地区', areaList:['和田市','和田县','墨玉县','皮山县','洛浦县','策勒县','于田县','民丰县']},
{name:'伊犁哈萨克自治州', areaList:['伊宁市','奎屯市','伊宁县','察布查尔锡伯自治县','霍城县','巩留县','新源县','昭苏县','特克斯县','尼勒克县']},
{name:'塔城地区', areaList:['塔城市','乌苏市','额敏县','沙湾县','托里县','裕民县','和布克赛尔蒙古自治县']},
{name:'阿勒泰地区', areaList:['阿勒泰市','布尔津县','富蕴县','福海县','哈巴河县','青河县','吉木乃县']},
{name:'省直辖行政单位', areaList:['石河子市','阿拉尔市','图木舒克市','五家渠市']}
]},
{name:'河北', cityList:[
{name:'石家庄市', areaList:['市辖区','长安区','桥东区','桥西区','新华区','井陉矿区','裕华区','井陉县','正定县','栾城县','行唐县','灵寿县','高邑县','深泽县','赞皇县','无极县','平山县','元氏县','赵 县','辛集市','藁城市','晋州市','新乐市','鹿泉市']},
{name:'唐山市', areaList:['市辖区','路南区','路北区','古冶区','开平区','丰南区','丰润区','滦 县','滦南县','乐亭县','迁西县','玉田县','唐海县','遵化市','迁安市']},
{name:'秦皇岛市', areaList:['市辖区','海港区','山海关区','北戴河区','青龙满族自治县','昌黎县','抚宁县','卢龙县']},
{name:'邯郸市', areaList:['市辖区','邯山区','丛台区','复兴区','峰峰矿区','邯郸县','临漳县','成安县','大名县','涉 县','磁 县','肥乡县','永年县','邱 县','鸡泽县','广平县','馆陶县','魏 县','曲周县','武安市']},
{name:'邢台市', areaList:['市辖区','桥东区','桥西区','邢台县','临城县','内丘县','柏乡县','隆尧县','任 县','南和县','宁晋县','巨鹿县','新河县','广宗县','平乡县','威 县','清河县','临西县','南宫市','沙河市']},
{name:'保定市', areaList:['市辖区','新市区','北市区','南市区','满城县','清苑县','涞水县','阜平县','徐水县','定兴县','唐 县','高阳县','容城县','涞源县','望都县','安新县','易 县','曲阳县','蠡 县','顺平县','博野县','雄 县','涿州市','定州市','安国市','高碑店市']},
{name:'张家口市', areaList:['市辖区','桥东区','桥西区','宣化区','下花园区','宣化县','张北县','康保县','沽源县','尚义县','蔚 县','阳原县','怀安县','万全县','怀来县','涿鹿县','赤城县','崇礼县']},
{name:'承德市', areaList:['市辖区','双桥区','双滦区','鹰手营子矿区','承德县','兴隆县','平泉县','滦平县','隆化县','丰宁满族自治县','宽城满族自治县','围场满族蒙古族自治县']},
{name:'沧州市', areaList:['市辖区','新华区','运河区','沧 县','青 县','东光县','海兴县','盐山县','肃宁县','南皮县','吴桥县','献 县','孟村回族自治县','泊头市','任丘市','黄骅市','河间市']},
{name:'廊坊市', areaList:['市辖区','安次区','广阳区','固安县','永清县','香河县','大城县','文安县','大厂回族自治县','霸州市','三河市']},
{name:'衡水市', areaList:['市辖区','桃城区','枣强县','武邑县','武强县','饶阳县','安平县','故城县','景 县','阜城县','冀州市','深州市']}
]},
{name:'山西', cityList:[
{name:'太原市', areaList:['市辖区','小店区','迎泽区','杏花岭区','尖草坪区','万柏林区','晋源区','清徐县','阳曲县','娄烦县','古交市']},
{name:'大同市', areaList:['市辖区','城 区','矿 区','南郊区','新荣区','阳高县','天镇县','广灵县','灵丘县','浑源县','左云县','大同县']},
{name:'阳泉市', areaList:['市辖区','城 区','矿 区','郊 区','平定县','盂 县']},
{name:'长治市', areaList:['市辖区','城 区','郊 区','长治县','襄垣县','屯留县','平顺县','黎城县','壶关县','长子县','武乡县','沁 县','沁源县','潞城市']},
{name:'晋城市', areaList:['市辖区','城 区','沁水县','阳城县','陵川县','泽州县','高平市']},
{name:'朔州市', areaList:['市辖区','朔城区','平鲁区','山阴县','应 县','右玉县','怀仁县']},
{name:'晋中市', areaList:['市辖区','榆次区','榆社县','左权县','和顺县','昔阳县','寿阳县','太谷县','祁 县','平遥县','灵石县','介休市']},
{name:'运城市', areaList:['市辖区','盐湖区','临猗县','万荣县','闻喜县','稷山县','新绛县','绛 县','垣曲县','夏 县','平陆县','芮城县','永济市','河津市']},
{name:'忻州市', areaList:['市辖区','忻府区','定襄县','五台县','代 县','繁峙县','宁武县','静乐县','神池县','五寨县','岢岚县','河曲县','保德县','偏关县','原平市']},
{name:'临汾市', areaList:['市辖区','尧都区','曲沃县','翼城县','襄汾县','洪洞县','古 县','安泽县','浮山县','吉 县','乡宁县','大宁县','隰 县','永和县','蒲 县','汾西县','侯马市','霍州市']},
{name:'吕梁市', areaList:['市辖区','离石区','文水县','交城县','兴 县','临 县','柳林县','石楼县','岚 县','方山县','中阳县','交口县','孝义市','汾阳市']}
]},
{name:'内蒙古', cityList:[
{name:'呼和浩特市', areaList:['市辖区','新城区','回民区','玉泉区','赛罕区','土默特左旗','托克托县','和林格尔县','清水河县','武川县']},
{name:'包头市', areaList:['市辖区','东河区','昆都仑区','青山区','石拐区','白云矿区','九原区','土默特右旗','固阳县','达尔罕茂明安联合旗']},
{name:'乌海市', areaList:['市辖区','海勃湾区','海南区','乌达区']},
{name:'赤峰市', areaList:['市辖区','红山区','元宝山区','松山区','阿鲁科尔沁旗','巴林左旗','巴林右旗','林西县','克什克腾旗','翁牛特旗','喀喇沁旗','宁城县','敖汉旗']},
{name:'通辽市', areaList:['市辖区','科尔沁区','科尔沁左翼中旗','科尔沁左翼后旗','开鲁县','库伦旗','奈曼旗','扎鲁特旗','霍林郭勒市']},
{name:'鄂尔多斯市', areaList:['东胜区','达拉特旗','准格尔旗','鄂托克前旗','鄂托克旗','杭锦旗','乌审旗','伊金霍洛旗']},
{name:'呼伦贝尔市', areaList:['市辖区','海拉尔区','阿荣旗','莫力达瓦达斡尔族自治旗','鄂伦春自治旗','鄂温克族自治旗','陈巴尔虎旗','新巴尔虎左旗','新巴尔虎右旗','满洲里市','牙克石市','扎兰屯市','额尔古纳市','根河市']},
{name:'巴彦淖尔市', areaList:['市辖区','临河区','五原县','磴口县','乌拉特前旗','乌拉特中旗','乌拉特后旗','杭锦后旗']},
{name:'乌兰察布市', areaList:['市辖区','集宁区','卓资县','化德县','商都县','兴和县','凉城县','察哈尔右翼前旗','察哈尔右翼中旗','察哈尔右翼后旗','四子王旗','丰镇市']},
{name:'兴安盟', areaList:['乌兰浩特市','阿尔山市','科尔沁右翼前旗','科尔沁右翼中旗','扎赉特旗','突泉县']},
{name:'锡林郭勒盟', areaList:['二连浩特市','锡林浩特市','阿巴嘎旗','苏尼特左旗','苏尼特右旗','东乌珠穆沁旗','西乌珠穆沁旗','太仆寺旗','镶黄旗','正镶白旗','正蓝旗','多伦县']},
{name:'阿拉善盟', areaList:['阿拉善左旗','阿拉善右旗','额济纳旗']}
]},
{name:'江苏', cityList:[
{name:'南京市', areaList:['市辖区','玄武区','白下区','秦淮区','建邺区','鼓楼区','下关区','浦口区','栖霞区','雨花台区','江宁区','六合区','溧水县','高淳县']},
{name:'无锡市', areaList:['市辖区','崇安区','南长区','北塘区','锡山区','惠山区','滨湖区','江阴市','宜兴市']},
{name:'徐州市', areaList:['市辖区','鼓楼区','云龙区','九里区','贾汪区','泉山区','丰 县','沛 县','铜山县','睢宁县','新沂市','邳州市']},
{name:'常州市', areaList:['市辖区','天宁区','钟楼区','戚墅堰区','新北区','武进区','溧阳市','金坛市']},
{name:'苏州市', areaList:['市辖区','沧浪区','平江区','金阊区','虎丘区','吴中区','相城区','常熟市','张家港市','昆山市','吴江市','太仓市']},
{name:'南通市', areaList:['市辖区','崇川区','港闸区','海安县','如东县','启东市','如皋市','通州市','海门市']},
{name:'连云港市', areaList:['市辖区','连云区','新浦区','海州区','赣榆县','东海县','灌云县','灌南县']},
{name:'淮安市', areaList:['市辖区','清河区','楚州区','淮阴区','清浦区','涟水县','洪泽县','盱眙县','金湖县']},
{name:'盐城市', areaList:['市辖区','亭湖区','盐都区','响水县','滨海县','阜宁县','射阳县','建湖县','东台市','大丰市']},
{name:'扬州市', areaList:['市辖区','广陵区','邗江区','郊 区','宝应县','仪征市','高邮市','江都市']},
{name:'镇江市', areaList:['市辖区','京口区','润州区','丹徒区','丹阳市','扬中市','句容市']},
{name:'泰州市', areaList:['市辖区','海陵区','高港区','兴化市','靖江市','泰兴市','姜堰市']},
{name:'宿迁市', areaList:['市辖区','宿城区','宿豫区','沭阳县','泗阳县','泗洪县']}
]},
{name:'浙江', cityList:[
{name:'杭州市', areaList:['市辖区','上城区','下城区','江干区','拱墅区','西湖区','滨江区','萧山区','余杭区','桐庐县','淳安县','建德市','富阳市','临安市']},
{name:'宁波市', areaList:['市辖区','海曙区','江东区','江北区','北仑区','镇海区','鄞州区','象山县','宁海县','余姚市','慈溪市','奉化市']},
{name:'温州市', areaList:['市辖区','鹿城区','龙湾区','瓯海区','洞头县','永嘉县','平阳县','苍南县','文成县','泰顺县','瑞安市','乐清市']},
{name:'嘉兴市', areaList:['市辖区','秀城区','秀洲区','嘉善县','海盐县','海宁市','平湖市','桐乡市']},
{name:'湖州市', areaList:['市辖区','吴兴区','南浔区','德清县','长兴县','安吉县']},
{name:'绍兴市', areaList:['市辖区','越城区','绍兴县','新昌县','诸暨市','上虞市','嵊州市']},
{name:'金华市', areaList:['市辖区','婺城区','金东区','武义县','浦江县','磐安县','兰溪市','义乌市','东阳市','永康市']},
{name:'衢州市', areaList:['市辖区','柯城区','衢江区','常山县','开化县','龙游县','江山市']},
{name:'舟山市', areaList:['市辖区','定海区','普陀区','岱山县','嵊泗县']},
{name:'台州市', areaList:['市辖区','椒江区','黄岩区','路桥区','玉环县','三门县','天台县','仙居县','温岭市','临海市']},
{name:'丽水市', areaList:['市辖区','莲都区','青田县','缙云县','遂昌县','松阳县','云和县','庆元县','景宁畲族自治县','龙泉市']}
]},
{name:'安徽', cityList:[
{name:'合肥市', areaList:['市辖区','瑶海区','庐阳区','蜀山区','包河区','长丰县','肥东县','肥西县']},
{name:'芜湖市', areaList:['市辖区','镜湖区','马塘区','新芜区','鸠江区','芜湖县','繁昌县','南陵县']},
{name:'蚌埠市', areaList:['市辖区','龙子湖区','蚌山区','禹会区','淮上区','怀远县','五河县','固镇县']},
{name:'淮南市', areaList:['市辖区','大通区','田家庵区','谢家集区','八公山区','潘集区','凤台县']},
{name:'马鞍山市', areaList:['市辖区','金家庄区','花山区','雨山区','当涂县']},
{name:'淮北市', areaList:['市辖区','杜集区','相山区','烈山区','濉溪县']},
{name:'铜陵市', areaList:['市辖区','铜官山区','狮子山区','郊 区','铜陵县']},
{name:'安庆市', areaList:['市辖区','迎江区','大观区','郊 区','怀宁县','枞阳县','潜山县','太湖县','宿松县','望江县','岳西县','桐城市']},
{name:'黄山市', areaList:['市辖区','屯溪区','黄山区','徽州区','歙 县','休宁县','黟 县','祁门县']},
{name:'滁州市', areaList:['市辖区','琅琊区','南谯区','来安县','全椒县','定远县','凤阳县','天长市','明光市']},
{name:'阜阳市', areaList:['市辖区','颍州区','颍东区','颍泉区','临泉县','太和县','阜南县','颍上县','界首市']},
{name:'宿州市', areaList:['市辖区','墉桥区','砀山县','萧 县','灵璧县','泗 县']},
{name:'巢湖市', areaList:['市辖区','居巢区','庐江县','无为县','含山县','和 县']},
{name:'六安市', areaList:['市辖区','金安区','裕安区','寿 县','霍邱县','舒城县','金寨县','霍山县']},
{name:'亳州市', areaList:['市辖区','谯城区','涡阳县','蒙城县','利辛县']},
{name:'池州市', areaList:['市辖区','贵池区','东至县','石台县','青阳县']},
{name:'宣城市', areaList:['市辖区','宣州区','郎溪县','广德县','泾 县','绩溪县','旌德县','宁国市']}
]},
{name:'福建', cityList:[
{name:'福州市', areaList:['市辖区','鼓楼区','台江区','仓山区','马尾区','晋安区','闽侯县','连江县','罗源县','闽清县','永泰县','平潭县','福清市','长乐市']},
{name:'厦门市', areaList:['市辖区','思明区','海沧区','湖里区','集美区','同安区','翔安区']},
{name:'莆田市', areaList:['市辖区','城厢区','涵江区','荔城区','秀屿区','仙游县']},
{name:'三明市', areaList:['市辖区','梅列区','三元区','明溪县','清流县','宁化县','大田县','尤溪县','沙 县','将乐县','泰宁县','建宁县','永安市']},
{name:'泉州市', areaList:['市辖区','鲤城区','丰泽区','洛江区','泉港区','惠安县','安溪县','永春县','德化县','金门县','石狮市','晋江市','南安市']},
{name:'漳州市', areaList:['市辖区','芗城区','龙文区','云霄县','漳浦县','诏安县','长泰县','东山县','南靖县','平和县','华安县','龙海市']},
{name:'南平市', areaList:['市辖区','延平区','顺昌县','浦城县','光泽县','松溪县','政和县','邵武市','武夷山市','建瓯市','建阳市']},
{name:'龙岩市', areaList:['市辖区','新罗区','长汀县','永定县','上杭县','武平县','连城县','漳平市']},
{name:'宁德市', areaList:['市辖区','蕉城区','霞浦县','古田县','屏南县','寿宁县','周宁县','柘荣县','福安市','福鼎市']}
]},
{name:'江西', cityList:[
{name:'南昌市', areaList:['市辖区','东湖区','西湖区','青云谱区','湾里区','青山湖区','南昌县','新建县','安义县','进贤县']},
{name:'景德镇市', areaList:['市辖区','昌江区','珠山区','浮梁县','乐平市']},
{name:'萍乡市', areaList:['市辖区','安源区','湘东区','莲花县','上栗县','芦溪县']},
{name:'九江市', areaList:['市辖区','庐山区','浔阳区','九江县','武宁县','修水县','永修县','德安县','星子县','都昌县','湖口县','彭泽县','瑞昌市']},
{name:'新余市', areaList:['市辖区','渝水区','分宜县']},
{name:'鹰潭市', areaList:['市辖区','月湖区','余江县','贵溪市']},
{name:'赣州市', areaList:['市辖区','章贡区','赣 县','信丰县','大余县','上犹县','崇义县','安远县','龙南县','定南县','全南县','宁都县','于都县','兴国县','会昌县','寻乌县','石城县','瑞金市','南康市']},
{name:'吉安市', areaList:['市辖区','吉州区','青原区','吉安县','吉水县','峡江县','新干县','永丰县','泰和县','遂川县','万安县','安福县','永新县','井冈山市']},
{name:'宜春市', areaList:['市辖区','袁州区','奉新县','万载县','上高县','宜丰县','靖安县','铜鼓县','丰城市','樟树市','高安市']},
{name:'抚州市', areaList:['市辖区','临川区','南城县','黎川县','南丰县','崇仁县','乐安县','宜黄县','金溪县','资溪县','东乡县','广昌县']},
{name:'上饶市', areaList:['市辖区','信州区','上饶县','广丰县','玉山县','铅山县','横峰县','弋阳县','余干县','鄱阳县','万年县','婺源县','德兴市']}
]},
{name:'山东', cityList:[
{name:'济南市', areaList:['市辖区','历下区','市中区','槐荫区','天桥区','历城区','长清区','平阴县','济阳县','商河县','章丘市']},
{name:'青岛市', areaList:['市辖区','市南区','市北区','四方区','黄岛区','崂山区','李沧区','城阳区','胶州市','即墨市','平度市','胶南市','莱西市']},
{name:'淄博市', areaList:['市辖区','淄川区','张店区','博山区','临淄区','周村区','桓台县','高青县','沂源县']},
{name:'枣庄市', areaList:['市辖区','市中区','薛城区','峄城区','台儿庄区','山亭区','滕州市']},
{name:'东营市', areaList:['市辖区','东营区','河口区','垦利县','利津县','广饶县']},
{name:'烟台市', areaList:['市辖区','芝罘区','福山区','牟平区','莱山区','长岛县','龙口市','莱阳市','莱州市','蓬莱市','招远市','栖霞市','海阳市']},
{name:'潍坊市', areaList:['市辖区','潍城区','寒亭区','坊子区','奎文区','临朐县','昌乐县','青州市','诸城市','寿光市','安丘市','高密市','昌邑市']},
{name:'济宁市', areaList:['市辖区','市中区','任城区','微山县','鱼台县','金乡县','嘉祥县','汶上县','泗水县','梁山县','曲阜市','兖州市','邹城市']},
{name:'泰安市', areaList:['市辖区','泰山区','岱岳区','宁阳县','东平县','新泰市','肥城市']},
{name:'威海市', areaList:['市辖区','环翠区','文登市','荣成市','乳山市']},
{name:'日照市', areaList:['市辖区','东港区','岚山区','五莲县','莒 县']},
{name:'莱芜市', areaList:['市辖区','莱城区','钢城区']},
{name:'临沂市', areaList:['市辖区','兰山区','罗庄区','河东区','沂南县','郯城县','沂水县','苍山县','费 县','平邑县','莒南县','蒙阴县','临沭县']},
{name:'德州市', areaList:['市辖区','德城区','陵 县','宁津县','庆云县','临邑县','齐河县','平原县','夏津县','武城县','乐陵市','禹城市']},
{name:'聊城市', areaList:['市辖区','东昌府区','阳谷县','莘 县','茌平县','东阿县','冠 县','高唐县','临清市']},
{name:'滨州市', areaList:['市辖区','滨城区','惠民县','阳信县','无棣县','沾化县','博兴县','邹平县']},
{name:'荷泽市', areaList:['市辖区','牡丹区','曹 县','单 县','成武县','巨野县','郓城县','鄄城县','定陶县','东明县']}
]},
{name:'辽宁', cityList:[
{name:'沈阳市', areaList:['市辖区','和平区','沈河区','大东区','皇姑区','铁西区','苏家屯区','东陵区','新城子区','于洪区','辽中县','康平县','法库县','新民市']},
{name:'大连市', areaList:['市辖区','中山区','西岗区','沙河口区','甘井子区','旅顺口区','金州区','长海县','瓦房店市','普兰店市','庄河市']},
{name:'鞍山市', areaList:['市辖区','铁东区','铁西区','立山区','千山区','台安县','岫岩满族自治县','海城市']},
{name:'抚顺市', areaList:['市辖区','新抚区','东洲区','望花区','顺城区','抚顺县','新宾满族自治县','清原满族自治县']},
{name:'本溪市', areaList:['市辖区','平山区','溪湖区','明山区','南芬区','本溪满族自治县','桓仁满族自治县']},
{name:'丹东市', areaList:['市辖区','元宝区','振兴区','振安区','宽甸满族自治县','东港市','凤城市']},
{name:'锦州市', areaList:['市辖区','古塔区','凌河区','太和区','黑山县','义 县','凌海市','北宁市']},
{name:'营口市', areaList:['市辖区','站前区','西市区','鲅鱼圈区','老边区','盖州市','大石桥市']},
{name:'阜新市', areaList:['市辖区','海州区','新邱区','太平区','清河门区','细河区','阜新蒙古族自治县','彰武县']},
{name:'辽阳市', areaList:['市辖区','白塔区','文圣区','宏伟区','弓长岭区','太子河区','辽阳县','灯塔市']},
{name:'盘锦市', areaList:['市辖区','双台子区','兴隆台区','大洼县','盘山县']},
{name:'铁岭市', areaList:['市辖区','银州区','清河区','铁岭县','西丰县','昌图县','调兵山市','开原市']},
{name:'朝阳市', areaList:['市辖区','双塔区','龙城区','朝阳县','建平县','喀喇沁左翼蒙古族自治县','北票市','凌源市']},
{name:'葫芦岛市', areaList:['市辖区','连山区','龙港区','南票区','绥中县','建昌县','兴城市']}
]},
{name:'吉林', cityList:[
{name:'长春市', areaList:['市辖区','南关区','宽城区','朝阳区','二道区','绿园区','双阳区','农安县','九台市','榆树市','德惠市']},
{name:'吉林市', areaList:['市辖区','昌邑区','龙潭区','船营区','丰满区','永吉县','蛟河市','桦甸市','舒兰市','磐石市']},
{name:'四平市', areaList:['市辖区','铁西区','铁东区','梨树县','伊通满族自治县','公主岭市','双辽市']},
{name:'辽源市', areaList:['市辖区','龙山区','西安区','东丰县','东辽县']},
{name:'通化市', areaList:['市辖区','东昌区','二道江区','通化县','辉南县','柳河县','梅河口市','集安市']},
{name:'白山市', areaList:['市辖区','八道江区','抚松县','靖宇县','长白朝鲜族自治县','江源县','临江市']},
{name:'松原市', areaList:['市辖区','宁江区','前郭尔罗斯蒙古族自治县','长岭县','乾安县','扶余县']},
{name:'白城市', areaList:['市辖区','洮北区','镇赉县','通榆县','洮南市','大安市']},
{name:'延边朝鲜族自治州', areaList:['延吉市','图们市','敦化市','珲春市','龙井市','和龙市','汪清县','安图县']}
]},
{name:'黑龙江', cityList:[
{name:'哈尔滨市', areaList:['市辖区','道里区','南岗区','道外区','香坊区','动力区','平房区','松北区','呼兰区','依兰县','方正县','宾 县','巴彦县','木兰县','通河县','延寿县','阿城市','双城市','尚志市','五常市']},
{name:'齐齐哈尔市', areaList:['市辖区','龙沙区','建华区','铁锋区','昂昂溪区','富拉尔基区','碾子山区','梅里斯达斡尔族区','龙江县','依安县','泰来县','甘南县','富裕县','克山县','克东县','拜泉县','讷河市']},
{name:'鸡西市', areaList:['市辖区','鸡冠区','恒山区','滴道区','梨树区','城子河区','麻山区','鸡东县','虎林市','密山市']},
{name:'鹤岗市', areaList:['市辖区','向阳区','工农区','南山区','兴安区','东山区','兴山区','萝北县','绥滨县']},
{name:'双鸭山市', areaList:['市辖区','尖山区','岭东区','四方台区','宝山区','集贤县','友谊县','宝清县','饶河县']},
{name:'大庆市', areaList:['市辖区','萨尔图区','龙凤区','让胡路区','红岗区','大同区','肇州县','肇源县','林甸县','杜尔伯特蒙古族自治县']},
{name:'伊春市', areaList:['市辖区','伊春区','南岔区','友好区','西林区','翠峦区','新青区','美溪区','金山屯区','五营区','乌马河区','汤旺河区','带岭区','乌伊岭区','红星区','上甘岭区','嘉荫县','铁力市']},
{name:'佳木斯市', areaList:['市辖区','永红区','向阳区','前进区','东风区','郊 区','桦南县','桦川县','汤原县','抚远县','同江市','富锦市']},
{name:'七台河市', areaList:['市辖区','新兴区','桃山区','茄子河区','勃利县']},
{name:'牡丹江市', areaList:['市辖区','东安区','阳明区','爱民区','西安区','东宁县','林口县','绥芬河市','海林市','宁安市','穆棱市']},
{name:'黑河市', areaList:['市辖区','爱辉区','嫩江县','逊克县','孙吴县','北安市','五大连池市']},
{name:'绥化市', areaList:['市辖区','北林区','望奎县','兰西县','青冈县','庆安县','明水县','绥棱县','安达市','肇东市','海伦市']},
{name:'大兴安岭地区', areaList:['呼玛县','塔河县','漠河县']}
]},
{name:'海南', cityList:[
{name:'海口市', areaList:['市辖区','秀英区','龙华区','琼山区','美兰区']},
{name:'三亚市', areaList:['市辖区']},
{name:'省直辖县级行政单位', areaList:['五指山市','琼海市','儋州市','文昌市','万宁市','东方市','定安县','屯昌县','澄迈县','临高县','白沙黎族自治县','昌江黎族自治县','乐东黎族自治县','陵水黎族自治县','保亭黎族苗族自治县','琼中黎族苗族自治县','西沙群岛','南沙群岛','中沙群岛的岛礁及其海域']}
]},
{name:'台湾', cityList:[
{name:'台湾', areaList:['台湾']}
]},
{name:'香港', cityList:[
{name:'香港', areaList:['香港']}
]},
{name:'澳门', cityList:[
{name:'澳门', areaList:['澳门']}
]}
{name:'北京', cityList:[
{name:'市辖区', areaList:['东城区','西城区','崇文区','宣武区','朝阳区','丰台区','石景山区','海淀区','门头沟区','房山区','通州区','顺义区','昌平区','大兴区','怀柔区','平谷区']},
{name:'县', areaList:['密云县','延庆县']}
]},
{name:'上海', cityList:[
{name:'市辖区', areaList:['黄浦区','卢湾区','徐汇区','长宁区','静安区','普陀区','闸北区','虹口区','杨浦区','闵行区','宝山区','嘉定区','浦东新区','金山区','松江区','青浦区','南汇区','奉贤区']},
{name:'县', areaList:['崇明县']}
]},
{name:'天津', cityList:[
{name:'市辖区', areaList:['和平区','河东区','河西区','南开区','河北区','红桥区','塘沽区','汉沽区','大港区','东丽区','西青区','津南区','北辰区','武清区','宝坻区']},
{name:'县', areaList:['宁河县','静海县','蓟 县']}
]},
{name:'重庆', cityList:[
{name:'市辖区', areaList:['万州区','涪陵区','渝中区','大渡口区','江北区','沙坪坝区','九龙坡区','南岸区','北碚区','万盛区','双桥区','渝北区','巴南区','黔江区','长寿区']},
{name:'县', areaList:['綦江县','潼南县','铜梁县','大足县','荣昌县','璧山县','梁平县','城口县','丰都县','垫江县','武隆县','忠 县','开 县','云阳县','奉节县','巫山县','巫溪县','石柱土家族自治县','秀山土家族苗族自治县','酉阳土家族苗族自治县','彭水苗族土家族自治县']},
{name:'市', areaList:['江津市','合川市','永川市','南川市']}
]},
{name:'四川', cityList:[
{name:'成都市', areaList:['市辖区','锦江区','青羊区','金牛区','武侯区','成华区','龙泉驿区','青白江区','新都区','温江县','金堂县','双流县','郫 县','大邑县','蒲江县','新津县','都江堰市','彭州市','邛崃市','崇州市']},
{name:'自贡市', areaList:['市辖区','自流井区','贡井区','大安区','沿滩区','荣 县','富顺县']},
{name:'攀枝花市', areaList:['市辖区','东 区','西 区','仁和区','米易县','盐边县']},
{name:'泸州市', areaList:['市辖区','江阳区','纳溪区','龙马潭区','泸 县','合江县','叙永县','古蔺县']},
{name:'德阳市', areaList:['市辖区','旌阳区','中江县','罗江县','广汉市','什邡市','绵竹市']},
{name:'绵阳市', areaList:['市辖区','涪城区','游仙区','三台县','盐亭县','安 县','梓潼县','北川羌族自治县','平武县','江油市']},
{name:'广元市', areaList:['市辖区','市中区','元坝区','朝天区','旺苍县','青川县','剑阁县','苍溪县']},
{name:'遂宁市', areaList:['市辖区','船山区','安居区','蓬溪县','射洪县','大英县']},
{name:'内江市', areaList:['市辖区','市中区','东兴区','威远县','资中县','隆昌县']},
{name:'乐山市', areaList:['市辖区','市中区','沙湾区','五通桥区','金口河区','犍为县','井研县','夹江县','沐川县','峨边彝族自治县','马边彝族自治县','峨眉山市']},
{name:'南充市', areaList:['市辖区','顺庆区','高坪区','嘉陵区','南部县','营山县','蓬安县','仪陇县','西充县','阆中市']},
{name:'眉山市', areaList:['市辖区','东坡区','仁寿县','彭山县','洪雅县','丹棱县','青神县']},
{name:'宜宾市', areaList:['市辖区','翠屏区','宜宾县','南溪县','江安县','长宁县','高 县','珙 县','筠连县','兴文县','屏山县']},
{name:'广安市', areaList:['市辖区','广安区','岳池县','武胜县','邻水县','华莹市']},
{name:'达州市', areaList:['市辖区','通川区','达 县','宣汉县','开江县','大竹县','渠 县','万源市']},
{name:'雅安市', areaList:['市辖区','雨城区','名山县','荥经县','汉源县','石棉县','天全县','芦山县','宝兴县']},
{name:'巴中市', areaList:['市辖区','巴州区','通江县','南江县','平昌县']},
{name:'资阳市', areaList:['市辖区','雁江区','安岳县','乐至县','简阳市']},
{name:'阿坝藏族羌族自治州', areaList:['汶川县','理 县','茂 县','松潘县','九寨沟县','金川县','小金县','黑水县','马尔康县','壤塘县','阿坝县','若尔盖县','红原县']},
{name:'甘孜藏族自治州', areaList:['康定县','泸定县','丹巴县','九龙县','雅江县','道孚县','炉霍县','甘孜县','新龙县','德格县','白玉县','石渠县','色达县','理塘县','巴塘县','乡城县','稻城县','得荣县']},
{name:'凉山彝族自治州', areaList:['西昌市','木里藏族自治县','盐源县','德昌县','会理县','会东县','宁南县','普格县','布拖县','金阳县','昭觉县','喜德县','冕宁县','越西县','甘洛县','美姑县','雷波县']}
]},
{name:'贵州', cityList:[
{name:'贵阳市', areaList:['市辖区','南明区','云岩区','花溪区','乌当区','白云区','小河区','开阳县','息烽县','修文县','清镇市']},
{name:'六盘水市', areaList:['钟山区','六枝特区','水城县','盘 县']},
{name:'遵义市', areaList:['市辖区','红花岗区','汇川区','遵义县','桐梓县','绥阳县','正安县','道真仡佬族苗族自治县','务川仡佬族苗族自治县','凤冈县','湄潭县','余庆县','习水县','赤水市','仁怀市']},
{name:'安顺市', areaList:['市辖区','西秀区','平坝县','普定县','镇宁布依族苗族自治县','关岭布依族苗族自治县','紫云苗族布依族自治县']},
{name:'铜仁地区', areaList:['铜仁市','江口县','玉屏侗族自治县','石阡县','思南县','印江土家族苗族自治县','德江县','沿河土家族自治县','松桃苗族自治县','万山特区']},
{name:'黔西南布依族苗族自治州', areaList:['兴义市','兴仁县','普安县','晴隆县','贞丰县','望谟县','册亨县','安龙县']},
{name:'毕节地区', areaList:['毕节市','大方县','黔西县','金沙县','织金县','纳雍县','威宁彝族回族苗族自治县','赫章县']},
{name:'黔东南苗族侗族自治州', areaList:['凯里市','黄平县','施秉县','三穗县','镇远县','岑巩县','天柱县','锦屏县','剑河县','台江县','黎平县','榕江县','从江县','雷山县','麻江县','丹寨县']},
{name:'黔南布依族苗族自治州', areaList:['都匀市','福泉市','荔波县','贵定县','瓮安县','独山县','平塘县','罗甸县','长顺县','龙里县','惠水县','三都水族自治县']}
]},
{name:'云南', cityList:[
{name:'昆明市', areaList:['市辖区','五华区','盘龙区','官渡区','西山区','东川区','呈贡县','晋宁县','富民县','宜良县','石林彝族自治县','嵩明县','禄劝彝族苗族自治县','寻甸回族彝族自治县','安宁市']},
{name:'曲靖市', areaList:['市辖区','麒麟区','马龙县','陆良县','师宗县','罗平县','富源县','会泽县','沾益县','宣威市']},
{name:'玉溪市', areaList:['市辖区','红塔区','江川县','澄江县','通海县','华宁县','易门县','峨山彝族自治县','新平彝族傣族自治县','元江哈尼族彝族傣族自治县']},
{name:'保山市', areaList:['市辖区','隆阳区','施甸县','腾冲县','龙陵县','昌宁县']},
{name:'昭通市', areaList:['市辖区','昭阳区','鲁甸县','巧家县','盐津县','大关县','永善县','绥江县','镇雄县','彝良县','威信县','水富县']},
{name:'丽江市', areaList:['市辖区','古城区','玉龙纳西族自治县','永胜县','华坪县','宁蒗彝族自治县']},
{name:'思茅市', areaList:['市辖区','翠云区','普洱哈尼族彝族自治县','墨江哈尼族自治县','景东彝族自治县','景谷傣族彝族自治县','镇沅彝族哈尼族拉祜族自治县','江城哈尼族彝族自治县','孟连傣族拉祜族佤族自治县','澜沧拉祜族自治县','西盟佤族自治县']},
{name:'临沧市', areaList:['市辖区','临翔区','凤庆县','云 县','永德县','镇康县','双江拉祜族佤族布朗族傣族自治县','耿马傣族佤族自治县','沧源佤族自治县']},
{name:'楚雄彝族自治州', areaList:['楚雄市','双柏县','牟定县','南华县','姚安县','大姚县','永仁县','元谋县','武定县','禄丰县']},
{name:'红河哈尼族彝族自治州', areaList:['个旧市','开远市','蒙自县','屏边苗族自治县','建水县','石屏县','弥勒县','泸西县','元阳县','红河县','金平苗族瑶族傣族自治县','绿春县','河口瑶族自治县']},
{name:'文山壮族苗族自治州', areaList:['文山县','砚山县','西畴县','麻栗坡县','马关县','丘北县','广南县','富宁县']},
{name:'西双版纳傣族自治州', areaList:['景洪市','勐海县','勐腊县']},
{name:'大理白族自治州', areaList:['大理市','漾濞彝族自治县','祥云县','宾川县','弥渡县','南涧彝族自治县','巍山彝族回族自治县','永平县','云龙县','洱源县','剑川县','鹤庆县']},
{name:'德宏傣族景颇族自治州', areaList:['瑞丽市','潞西市','梁河县','盈江县','陇川县']},
{name:'怒江傈僳族自治州', areaList:['泸水县','福贡县','贡山独龙族怒族自治县','兰坪白族普米族自治县']},
{name:'迪庆藏族自治州', areaList:['香格里拉县','德钦县','维西傈僳族自治县']}
]},
{name:'西藏', cityList:[
{name:'拉萨市', areaList:['市辖区','城关区','林周县','当雄县','尼木县','曲水县','堆龙德庆县','达孜县','墨竹工卡县']},
{name:'昌都地区', areaList:['昌都县','江达县','贡觉县','类乌齐县','丁青县','察雅县','八宿县','左贡县','芒康县','洛隆县','边坝县']},
{name:'山南地区', areaList:['乃东县','扎囊县','贡嘎县','桑日县','琼结县','曲松县','措美县','洛扎县','加查县','隆子县','错那县','浪卡子县']},
{name:'日喀则地区', areaList:['日喀则市','南木林县','江孜县','定日县','萨迦县','拉孜县','昂仁县','谢通门县','白朗县','仁布县','康马县','定结县','仲巴县','亚东县','吉隆县','聂拉木县','萨嘎县','岗巴县']},
{name:'那曲地区', areaList:['那曲县','嘉黎县','比如县','聂荣县','安多县','申扎县','索 县','班戈县','巴青县','尼玛县']},
{name:'阿里地区', areaList:['普兰县','札达县','噶尔县','日土县','革吉县','改则县','措勤县']},
{name:'林芝地区', areaList:['林芝县','工布江达县','米林县','墨脱县','波密县','察隅县','朗 县']}
]},
{name:'河南', cityList:[
{name:'郑州市', areaList:['市辖区','中原区','二七区','管城回族区','金水区','上街区','邙山区','中牟县','巩义市','荥阳市','新密市','新郑市','登封市']},
{name:'开封市', areaList:['市辖区','龙亭区','顺河回族区','鼓楼区','南关区','郊 区','杞 县','通许县','尉氏县','开封县','兰考县']},
{name:'洛阳市', areaList:['市辖区','老城区','西工区','廛河回族区','涧西区','吉利区','洛龙区','孟津县','新安县','栾川县','嵩 县','汝阳县','宜阳县','洛宁县','伊川县','偃师市']},
{name:'平顶山市', areaList:['市辖区','新华区','卫东区','石龙区','湛河区','宝丰县','叶 县','鲁山县','郏 县','舞钢市','汝州市']},
{name:'安阳市', areaList:['市辖区','文峰区','北关区','殷都区','龙安区','安阳县','汤阴县','滑 县','内黄县','林州市']},
{name:'鹤壁市', areaList:['市辖区','鹤山区','山城区','淇滨区','浚 县','淇 县']},
{name:'新乡市', areaList:['市辖区','红旗区','卫滨区','凤泉区','牧野区','新乡县','获嘉县','原阳县','延津县','封丘县','长垣县','卫辉市','辉县市']},
{name:'焦作市', areaList:['市辖区','解放区','中站区','马村区','山阳区','修武县','博爱县','武陟县','温 县','济源市','沁阳市','孟州市']},
{name:'濮阳市', areaList:['市辖区','华龙区','清丰县','南乐县','范 县','台前县','濮阳县']},
{name:'许昌市', areaList:['市辖区','魏都区','许昌县','鄢陵县','襄城县','禹州市','长葛市']},
{name:'漯河市', areaList:['市辖区','源汇区','郾城区','召陵区','舞阳县','临颍县']},
{name:'三门峡市', areaList:['市辖区','湖滨区','渑池县','陕 县','卢氏县','义马市','灵宝市']},
{name:'南阳市', areaList:['市辖区','宛城区','卧龙区','南召县','方城县','西峡县','镇平县','内乡县','淅川县','社旗县','唐河县','新野县','桐柏县','邓州市']},
{name:'商丘市', areaList:['市辖区','梁园区','睢阳区','民权县','睢 县','宁陵县','柘城县','虞城县','夏邑县','永城市']},
{name:'信阳市', areaList:['市辖区','师河区','平桥区','罗山县','光山县','新 县','商城县','固始县','潢川县','淮滨县','息 县']},
{name:'周口市', areaList:['市辖区','川汇区','扶沟县','西华县','商水县','沈丘县','郸城县','淮阳县','太康县','鹿邑县','项城市']},
{name:'驻马店市', areaList:['市辖区','驿城区','西平县','上蔡县','平舆县','正阳县','确山县','泌阳县','汝南县','遂平县','新蔡县']}
]},
{name:'湖北', cityList:[
{name:'武汉市', areaList:['市辖区','江岸区','江汉区','乔口区','汉阳区','武昌区','青山区','洪山区','东西湖区','汉南区','蔡甸区','江夏区','黄陂区','新洲区']},
{name:'黄石市', areaList:['市辖区','黄石港区','西塞山区','下陆区','铁山区','阳新县','大冶市']},
{name:'十堰市', areaList:['市辖区','茅箭区','张湾区','郧 县','郧西县','竹山县','竹溪县','房 县','丹江口市']},
{name:'宜昌市', areaList:['市辖区','西陵区','伍家岗区','点军区','猇亭区','夷陵区','远安县','兴山县','秭归县','长阳土家族自治县','五峰土家族自治县','宜都市','当阳市','枝江市']},
{name:'襄樊市', areaList:['市辖区','襄城区','樊城区','襄阳区','南漳县','谷城县','保康县','老河口市','枣阳市','宜城市']},
{name:'鄂州市', areaList:['市辖区','梁子湖区','华容区','鄂城区']},
{name:'荆门市', areaList:['市辖区','东宝区','掇刀区','京山县','沙洋县','钟祥市']},
{name:'孝感市', areaList:['市辖区','孝南区','孝昌县','大悟县','云梦县','应城市','安陆市','汉川市']},
{name:'荆州市', areaList:['市辖区','沙市区','荆州区','公安县','监利县','江陵县','石首市','洪湖市','松滋市']},
{name:'黄冈市', areaList:['市辖区','黄州区','团风县','红安县','罗田县','英山县','浠水县','蕲春县','黄梅县','麻城市','武穴市']},
{name:'咸宁市', areaList:['市辖区','咸安区','嘉鱼县','通城县','崇阳县','通山县','赤壁市']},
{name:'随州市', areaList:['市辖区','曾都区','广水市']},
{name:'恩施土家族苗族自治州', areaList:['恩施市','利川市','建始县','巴东县','宣恩县','咸丰县','来凤县','鹤峰县']},
{name:'省直辖行政单位', areaList:['仙桃市','潜江市','天门市','神农架林区']}
]},
{name:'湖南', cityList:[
{name:'长沙市', areaList:['市辖区','芙蓉区','天心区','岳麓区','开福区','雨花区','长沙县','望城县','宁乡县','浏阳市']},
{name:'株洲市', areaList:['市辖区','荷塘区','芦淞区','石峰区','天元区','株洲县','攸 县','茶陵县','炎陵县','醴陵市']},
{name:'湘潭市', areaList:['市辖区','雨湖区','岳塘区','湘潭县','湘乡市','韶山市']},
{name:'衡阳市', areaList:['市辖区','珠晖区','雁峰区','石鼓区','蒸湘区','南岳区','衡阳县','衡南县','衡山县','衡东县','祁东县','耒阳市','常宁市']},
{name:'邵阳市', areaList:['市辖区','双清区','大祥区','北塔区','邵东县','新邵县','邵阳县','隆回县','洞口县','绥宁县','新宁县','城步苗族自治县','武冈市']},
{name:'岳阳市', areaList:['市辖区','岳阳楼区','云溪区','君山区','岳阳县','华容县','湘阴县','平江县','汨罗市','临湘市']},
{name:'常德市', areaList:['市辖区','武陵区','鼎城区','安乡县','汉寿县','澧 县','临澧县','桃源县','石门县','津市市']},
{name:'张家界市', areaList:['市辖区','永定区','武陵源区','慈利县','桑植县']},
{name:'益阳市', areaList:['市辖区','资阳区','赫山区','南 县','桃江县','安化县','沅江市']},
{name:'郴州市', areaList:['市辖区','北湖区','苏仙区','桂阳县','宜章县','永兴县','嘉禾县','临武县','汝城县','桂东县','安仁县','资兴市']},
{name:'永州市', areaList:['市辖区','芝山区','冷水滩区','祁阳县','东安县','双牌县','道 县','江永县','宁远县','蓝山县','新田县','江华瑶族自治县']},
{name:'怀化市', areaList:['市辖区','鹤城区','中方县','沅陵县','辰溪县','溆浦县','会同县','麻阳苗族自治县','新晃侗族自治县','芷江侗族自治县','靖州苗族侗族自治县','通道侗族自治县','洪江市']},
{name:'娄底市', areaList:['市辖区','娄星区','双峰县','新化县','冷水江市','涟源市']},
{name:'湘西土家族苗族自治州', areaList:['吉首市','泸溪县','凤凰县','花垣县','保靖县','古丈县','永顺县','龙山县']}
]},
{name:'广东', cityList:[
{name:'广州市', areaList:['市辖区','东山区','荔湾区','越秀区','海珠区','天河区','芳村区','白云区','黄埔区','番禺区','花都区','增城市','从化市']},
{name:'韶关市', areaList:['市辖区','武江区','浈江区','曲江区','始兴县','仁化县','翁源县','乳源瑶族自治县','新丰县','乐昌市','南雄市']},
{name:'深圳市', areaList:['市辖区','罗湖区','福田区','南山区','宝安区','龙岗区','盐田区']},
{name:'珠海市', areaList:['市辖区','香洲区','斗门区','金湾区']},
{name:'汕头市', areaList:['市辖区','龙湖区','金平区','濠江区','潮阳区','潮南区','澄海区','南澳县']},
{name:'佛山市', areaList:['市辖区','禅城区','南海区','顺德区','三水区','高明区']},
{name:'江门市', areaList:['市辖区','蓬江区','江海区','新会区','台山市','开平市','鹤山市','恩平市']},
{name:'湛江市', areaList:['市辖区','赤坎区','霞山区','坡头区','麻章区','遂溪县','徐闻县','廉江市','雷州市','吴川市']},
{name:'茂名市', areaList:['市辖区','茂南区','茂港区','电白县','高州市','化州市','信宜市']},
{name:'肇庆市', areaList:['市辖区','端州区','鼎湖区','广宁县','怀集县','封开县','德庆县','高要市','四会市']},
{name:'惠州市', areaList:['市辖区','惠城区','惠阳区','博罗县','惠东县','龙门县']},
{name:'梅州市', areaList:['市辖区','梅江区','梅 县','大埔县','丰顺县','五华县','平远县','蕉岭县','兴宁市']},
{name:'汕尾市', areaList:['市辖区','城 区','海丰县','陆河县','陆丰市']},
{name:'河源市', areaList:['市辖区','源城区','紫金县','龙川县','连平县','和平县','东源县']},
{name:'阳江市', areaList:['市辖区','江城区','阳西县','阳东县','阳春市']},
{name:'清远市', areaList:['市辖区','清城区','佛冈县','阳山县','连山壮族瑶族自治县','连南瑶族自治县','清新县','英德市','连州市']},
{name:'东莞市', areaList:['东莞市']},
{name:'中山市', areaList:['中山市']},
{name:'潮州市', areaList:['市辖区','湘桥区','潮安县','饶平县']},
{name:'揭阳市', areaList:['市辖区','榕城区','揭东县','揭西县','惠来县','普宁市']},
{name:'云浮市', areaList:['市辖区','云城区','新兴县','郁南县','云安县','罗定市']}
]},
{name:'广西', cityList:[
{name:'南宁市', areaList:['市辖区','兴宁区','青秀区','江南区','西乡塘区','良庆区','邕宁区','武鸣县','隆安县','马山县','上林县','宾阳县','横 县']},
{name:'柳州市', areaList:['市辖区','城中区','鱼峰区','柳南区','柳北区','柳江县','柳城县','鹿寨县','融安县','融水苗族自治县','三江侗族自治县']},
{name:'桂林市', areaList:['市辖区','秀峰区','叠彩区','象山区','七星区','雁山区','阳朔县','临桂县','灵川县','全州县','兴安县','永福县','灌阳县','龙胜各族自治县','资源县','平乐县','荔蒲县','恭城瑶族自治县']},
{name:'梧州市', areaList:['市辖区','万秀区','蝶山区','长洲区','苍梧县','藤 县','蒙山县','岑溪市']},
{name:'北海市', areaList:['市辖区','海城区','银海区','铁山港区','合浦县']},
{name:'防城港市', areaList:['市辖区','港口区','防城区','上思县','东兴市']},
{name:'钦州市', areaList:['市辖区','钦南区','钦北区','灵山县','浦北县']},
{name:'贵港市', areaList:['市辖区','港北区','港南区','覃塘区','平南县','桂平市']},
{name:'玉林市', areaList:['市辖区','玉州区','容 县','陆川县','博白县','兴业县','北流市']},
{name:'百色市', areaList:['市辖区','右江区','田阳县','田东县','平果县','德保县','靖西县','那坡县','凌云县','乐业县','田林县','西林县','隆林各族自治县']},
{name:'贺州市', areaList:['市辖区','八步区','昭平县','钟山县','富川瑶族自治县']},
{name:'河池市', areaList:['市辖区','金城江区','南丹县','天峨县','凤山县','东兰县','罗城仫佬族自治县','环江毛南族自治县','巴马瑶族自治县','都安瑶族自治县','大化瑶族自治县','宜州市']},
{name:'来宾市', areaList:['市辖区','兴宾区','忻城县','象州县','武宣县','金秀瑶族自治县','合山市']},
{name:'崇左市', areaList:['市辖区','江洲区','扶绥县','宁明县','龙州县','大新县','天等县','凭祥市']}
]},
{name:'陕西', cityList:[
{name:'西安市', areaList:['市辖区','新城区','碑林区','莲湖区','灞桥区','未央区','雁塔区','阎良区','临潼区','长安区','蓝田县','周至县','户 县','高陵县']},
{name:'铜川市', areaList:['市辖区','王益区','印台区','耀州区','宜君县']},
{name:'宝鸡市', areaList:['市辖区','渭滨区','金台区','陈仓区','凤翔县','岐山县','扶风县','眉 县','陇 县','千阳县','麟游县','凤 县','太白县']},
{name:'咸阳市', areaList:['市辖区','秦都区','杨凌区','渭城区','三原县','泾阳县','乾 县','礼泉县','永寿县','彬 县','长武县','旬邑县','淳化县','武功县','兴平市']},
{name:'渭南市', areaList:['市辖区','临渭区','华 县','潼关县','大荔县','合阳县','澄城县','蒲城县','白水县','富平县','韩城市','华阴市']},
{name:'延安市', areaList:['市辖区','宝塔区','延长县','延川县','子长县','安塞县','志丹县','吴旗县','甘泉县','富 县','洛川县','宜川县','黄龙县','黄陵县']},
{name:'汉中市', areaList:['市辖区','汉台区','南郑县','城固县','洋 县','西乡县','勉 县','宁强县','略阳县','镇巴县','留坝县','佛坪县']},
{name:'榆林市', areaList:['市辖区','榆阳区','神木县','府谷县','横山县','靖边县','定边县','绥德县','米脂县','佳 县','吴堡县','清涧县','子洲县']},
{name:'安康市', areaList:['市辖区','汉滨区','汉阴县','石泉县','宁陕县','紫阳县','岚皋县','平利县','镇坪县','旬阳县','白河县']},
{name:'商洛市', areaList:['市辖区','商州区','洛南县','丹凤县','商南县','山阳县','镇安县','柞水县']}
]},
{name:'甘肃', cityList:[
{name:'兰州市', areaList:['市辖区','城关区','七里河区','西固区','安宁区','红古区','永登县','皋兰县','榆中县']},
{name:'嘉峪关市', areaList:['市辖区']},
{name:'金昌市', areaList:['市辖区','金川区','永昌县']},
{name:'白银市', areaList:['市辖区','白银区','平川区','靖远县','会宁县','景泰县']},
{name:'天水市', areaList:['市辖区','秦城区','北道区','清水县','秦安县','甘谷县','武山县','张家川回族自治县']},
{name:'武威市', areaList:['市辖区','凉州区','民勤县','古浪县','天祝藏族自治县']},
{name:'张掖市', areaList:['市辖区','甘州区','肃南裕固族自治县','民乐县','临泽县','高台县','山丹县']},
{name:'平凉市', areaList:['市辖区','崆峒区','泾川县','灵台县','崇信县','华亭县','庄浪县','静宁县']},
{name:'酒泉市', areaList:['市辖区','肃州区','金塔县','安西县','肃北蒙古族自治县','阿克塞哈萨克族自治县','玉门市','敦煌市']},
{name:'庆阳市', areaList:['市辖区','西峰区','庆城县','环 县','华池县','合水县','正宁县','宁 县','镇原县']},
{name:'定西市', areaList:['市辖区','安定区','通渭县','陇西县','渭源县','临洮县','漳 县','岷 县']},
{name:'陇南市', areaList:['市辖区','武都区','成 县','文 县','宕昌县','康 县','西和县','礼 县','徽 县','两当县']},
{name:'临夏回族自治州', areaList:['临夏市','临夏县','康乐县','永靖县','广河县','和政县','东乡族自治县','积石山保安族东乡族撒拉族自治县']},
{name:'甘南藏族自治州', areaList:['合作市','临潭县','卓尼县','舟曲县','迭部县','玛曲县','碌曲县','夏河县']}
]},
{name:'青海', cityList:[
{name:'西宁市', areaList:['市辖区','城东区','城中区','城西区','城北区','大通回族土族自治县','湟中县','湟源县']},
{name:'海东地区', areaList:['平安县','民和回族土族自治县','乐都县','互助土族自治县','化隆回族自治县','循化撒拉族自治县']},
{name:'海北藏族自治州', areaList:['门源回族自治县','祁连县','海晏县','刚察县']},
{name:'黄南藏族自治州', areaList:['同仁县','尖扎县','泽库县','河南蒙古族自治县']},
{name:'海南藏族自治州', areaList:['共和县','同德县','贵德县','兴海县','贵南县']},
{name:'果洛藏族自治州', areaList:['玛沁县','班玛县','甘德县','达日县','久治县','玛多县']},
{name:'玉树藏族自治州', areaList:['玉树县','杂多县','称多县','治多县','囊谦县','曲麻莱县']},
{name:'海西蒙古族藏族自治州', areaList:['格尔木市','德令哈市','乌兰县','都兰县','天峻县']}
]},
{name:'宁夏', cityList:[
{name:'银川市', areaList:['市辖区','兴庆区','西夏区','金凤区','永宁县','贺兰县','灵武市']},
{name:'石嘴山市', areaList:['市辖区','大武口区','惠农区','平罗县']},
{name:'吴忠市', areaList:['市辖区','利通区','盐池县','同心县','青铜峡市']},
{name:'固原市', areaList:['市辖区','原州区','西吉县','隆德县','泾源县','彭阳县','海原县']},
{name:'中卫市', areaList:['市辖区','沙坡头区','中宁县']}
]},
{name:'新疆', cityList:[
{name:'乌鲁木齐市', areaList:['市辖区','天山区','沙依巴克区','新市区','水磨沟区','头屯河区','达坂城区','东山区','乌鲁木齐县']},
{name:'克拉玛依市', areaList:['市辖区','独山子区','克拉玛依区','白碱滩区','乌尔禾区']},
{name:'吐鲁番地区', areaList:['吐鲁番市','鄯善县','托克逊县']},
{name:'哈密地区', areaList:['哈密市','巴里坤哈萨克自治县','伊吾县']},
{name:'昌吉回族自治州', areaList:['昌吉市','阜康市','米泉市','呼图壁县','玛纳斯县','奇台县','吉木萨尔县','木垒哈萨克自治县']},
{name:'博尔塔拉蒙古自治州', areaList:['博乐市','精河县','温泉县']},
{name:'巴音郭楞蒙古自治州', areaList:['库尔勒市','轮台县','尉犁县','若羌县','且末县','焉耆回族自治县','和静县','和硕县','博湖县']},
{name:'阿克苏地区', areaList:['阿克苏市','温宿县','库车县','沙雅县','新和县','拜城县','乌什县','阿瓦提县','柯坪县']},
{name:'克孜勒苏柯尔克孜自治州', areaList:['阿图什市','阿克陶县','阿合奇县','乌恰县']},
{name:'喀什地区', areaList:['喀什市','疏附县','疏勒县','英吉沙县','泽普县','莎车县','叶城县','麦盖提县','岳普湖县','伽师县','巴楚县','塔什库尔干塔吉克自治县']},
{name:'和田地区', areaList:['和田市','和田县','墨玉县','皮山县','洛浦县','策勒县','于田县','民丰县']},
{name:'伊犁哈萨克自治州', areaList:['伊宁市','奎屯市','伊宁县','察布查尔锡伯自治县','霍城县','巩留县','新源县','昭苏县','特克斯县','尼勒克县']},
{name:'塔城地区', areaList:['塔城市','乌苏市','额敏县','沙湾县','托里县','裕民县','和布克赛尔蒙古自治县']},
{name:'阿勒泰地区', areaList:['阿勒泰市','布尔津县','富蕴县','福海县','哈巴河县','青河县','吉木乃县']},
{name:'省直辖行政单位', areaList:['石河子市','阿拉尔市','图木舒克市','五家渠市']}
]},
{name:'河北', cityList:[
{name:'石家庄市', areaList:['市辖区','长安区','桥东区','桥西区','新华区','井陉矿区','裕华区','井陉县','正定县','栾城县','行唐县','灵寿县','高邑县','深泽县','赞皇县','无极县','平山县','元氏县','赵 县','辛集市','藁城市','晋州市','新乐市','鹿泉市']},
{name:'唐山市', areaList:['市辖区','路南区','路北区','古冶区','开平区','丰南区','丰润区','滦 县','滦南县','乐亭县','迁西县','玉田县','唐海县','遵化市','迁安市']},
{name:'秦皇岛市', areaList:['市辖区','海港区','山海关区','北戴河区','青龙满族自治县','昌黎县','抚宁县','卢龙县']},
{name:'邯郸市', areaList:['市辖区','邯山区','丛台区','复兴区','峰峰矿区','邯郸县','临漳县','成安县','大名县','涉 县','磁 县','肥乡县','永年县','邱 县','鸡泽县','广平县','馆陶县','魏 县','曲周县','武安市']},
{name:'邢台市', areaList:['市辖区','桥东区','桥西区','邢台县','临城县','内丘县','柏乡县','隆尧县','任 县','南和县','宁晋县','巨鹿县','新河县','广宗县','平乡县','威 县','清河县','临西县','南宫市','沙河市']},
{name:'保定市', areaList:['市辖区','新市区','北市区','南市区','满城县','清苑县','涞水县','阜平县','徐水县','定兴县','唐 县','高阳县','容城县','涞源县','望都县','安新县','易 县','曲阳县','蠡 县','顺平县','博野县','雄 县','涿州市','定州市','安国市','高碑店市']},
{name:'张家口市', areaList:['市辖区','桥东区','桥西区','宣化区','下花园区','宣化县','张北县','康保县','沽源县','尚义县','蔚 县','阳原县','怀安县','万全县','怀来县','涿鹿县','赤城县','崇礼县']},
{name:'承德市', areaList:['市辖区','双桥区','双滦区','鹰手营子矿区','承德县','兴隆县','平泉县','滦平县','隆化县','丰宁满族自治县','宽城满族自治县','围场满族蒙古族自治县']},
{name:'沧州市', areaList:['市辖区','新华区','运河区','沧 县','青 县','东光县','海兴县','盐山县','肃宁县','南皮县','吴桥县','献 县','孟村回族自治县','泊头市','任丘市','黄骅市','河间市']},
{name:'廊坊市', areaList:['市辖区','安次区','广阳区','固安县','永清县','香河县','大城县','文安县','大厂回族自治县','霸州市','三河市']},
{name:'衡水市', areaList:['市辖区','桃城区','枣强县','武邑县','武强县','饶阳县','安平县','故城县','景 县','阜城县','冀州市','深州市']}
]},
{name:'山西', cityList:[
{name:'太原市', areaList:['市辖区','小店区','迎泽区','杏花岭区','尖草坪区','万柏林区','晋源区','清徐县','阳曲县','娄烦县','古交市']},
{name:'大同市', areaList:['市辖区','城 区','矿 区','南郊区','新荣区','阳高县','天镇县','广灵县','灵丘县','浑源县','左云县','大同县']},
{name:'阳泉市', areaList:['市辖区','城 区','矿 区','郊 区','平定县','盂 县']},
{name:'长治市', areaList:['市辖区','城 区','郊 区','长治县','襄垣县','屯留县','平顺县','黎城县','壶关县','长子县','武乡县','沁 县','沁源县','潞城市']},
{name:'晋城市', areaList:['市辖区','城 区','沁水县','阳城县','陵川县','泽州县','高平市']},
{name:'朔州市', areaList:['市辖区','朔城区','平鲁区','山阴县','应 县','右玉县','怀仁县']},
{name:'晋中市', areaList:['市辖区','榆次区','榆社县','左权县','和顺县','昔阳县','寿阳县','太谷县','祁 县','平遥县','灵石县','介休市']},
{name:'运城市', areaList:['市辖区','盐湖区','临猗县','万荣县','闻喜县','稷山县','新绛县','绛 县','垣曲县','夏 县','平陆县','芮城县','永济市','河津市']},
{name:'忻州市', areaList:['市辖区','忻府区','定襄县','五台县','代 县','繁峙县','宁武县','静乐县','神池县','五寨县','岢岚县','河曲县','保德县','偏关县','原平市']},
{name:'临汾市', areaList:['市辖区','尧都区','曲沃县','翼城县','襄汾县','洪洞县','古 县','安泽县','浮山县','吉 县','乡宁县','大宁县','隰 县','永和县','蒲 县','汾西县','侯马市','霍州市']},
{name:'吕梁市', areaList:['市辖区','离石区','文水县','交城县','兴 县','临 县','柳林县','石楼县','岚 县','方山县','中阳县','交口县','孝义市','汾阳市']}
]},
{name:'内蒙古', cityList:[
{name:'呼和浩特市', areaList:['市辖区','新城区','回民区','玉泉区','赛罕区','土默特左旗','托克托县','和林格尔县','清水河县','武川县']},
{name:'包头市', areaList:['市辖区','东河区','昆都仑区','青山区','石拐区','白云矿区','九原区','土默特右旗','固阳县','达尔罕茂明安联合旗']},
{name:'乌海市', areaList:['市辖区','海勃湾区','海南区','乌达区']},
{name:'赤峰市', areaList:['市辖区','红山区','元宝山区','松山区','阿鲁科尔沁旗','巴林左旗','巴林右旗','林西县','克什克腾旗','翁牛特旗','喀喇沁旗','宁城县','敖汉旗']},
{name:'通辽市', areaList:['市辖区','科尔沁区','科尔沁左翼中旗','科尔沁左翼后旗','开鲁县','库伦旗','奈曼旗','扎鲁特旗','霍林郭勒市']},
{name:'鄂尔多斯市', areaList:['东胜区','达拉特旗','准格尔旗','鄂托克前旗','鄂托克旗','杭锦旗','乌审旗','伊金霍洛旗']},
{name:'呼伦贝尔市', areaList:['市辖区','海拉尔区','阿荣旗','莫力达瓦达斡尔族自治旗','鄂伦春自治旗','鄂温克族自治旗','陈巴尔虎旗','新巴尔虎左旗','新巴尔虎右旗','满洲里市','牙克石市','扎兰屯市','额尔古纳市','根河市']},
{name:'巴彦淖尔市', areaList:['市辖区','临河区','五原县','磴口县','乌拉特前旗','乌拉特中旗','乌拉特后旗','杭锦后旗']},
{name:'乌兰察布市', areaList:['市辖区','集宁区','卓资县','化德县','商都县','兴和县','凉城县','察哈尔右翼前旗','察哈尔右翼中旗','察哈尔右翼后旗','四子王旗','丰镇市']},
{name:'兴安盟', areaList:['乌兰浩特市','阿尔山市','科尔沁右翼前旗','科尔沁右翼中旗','扎赉特旗','突泉县']},
{name:'锡林郭勒盟', areaList:['二连浩特市','锡林浩特市','阿巴嘎旗','苏尼特左旗','苏尼特右旗','东乌珠穆沁旗','西乌珠穆沁旗','太仆寺旗','镶黄旗','正镶白旗','正蓝旗','多伦县']},
{name:'阿拉善盟', areaList:['阿拉善左旗','阿拉善右旗','额济纳旗']}
]},
{name:'江苏', cityList:[
{name:'南京市', areaList:['市辖区','玄武区','白下区','秦淮区','建邺区','鼓楼区','下关区','浦口区','栖霞区','雨花台区','江宁区','六合区','溧水县','高淳县']},
{name:'无锡市', areaList:['市辖区','崇安区','南长区','北塘区','锡山区','惠山区','滨湖区','江阴市','宜兴市']},
{name:'徐州市', areaList:['市辖区','鼓楼区','云龙区','九里区','贾汪区','泉山区','丰 县','沛 县','铜山县','睢宁县','新沂市','邳州市']},
{name:'常州市', areaList:['市辖区','天宁区','钟楼区','戚墅堰区','新北区','武进区','溧阳市','金坛市']},
{name:'苏州市', areaList:['市辖区','沧浪区','平江区','金阊区','虎丘区','吴中区','相城区','常熟市','张家港市','昆山市','吴江市','太仓市']},
{name:'南通市', areaList:['市辖区','崇川区','港闸区','海安县','如东县','启东市','如皋市','通州市','海门市']},
{name:'连云港市', areaList:['市辖区','连云区','新浦区','海州区','赣榆县','东海县','灌云县','灌南县']},
{name:'淮安市', areaList:['市辖区','清河区','楚州区','淮阴区','清浦区','涟水县','洪泽县','盱眙县','金湖县']},
{name:'盐城市', areaList:['市辖区','亭湖区','盐都区','响水县','滨海县','阜宁县','射阳县','建湖县','东台市','大丰市']},
{name:'扬州市', areaList:['市辖区','广陵区','邗江区','郊 区','宝应县','仪征市','高邮市','江都市']},
{name:'镇江市', areaList:['市辖区','京口区','润州区','丹徒区','丹阳市','扬中市','句容市']},
{name:'泰州市', areaList:['市辖区','海陵区','高港区','兴化市','靖江市','泰兴市','姜堰市']},
{name:'宿迁市', areaList:['市辖区','宿城区','宿豫区','沭阳县','泗阳县','泗洪县']}
]},
{name:'浙江', cityList:[
{name:'杭州市', areaList:['市辖区','上城区','下城区','江干区','拱墅区','西湖区','滨江区','萧山区','余杭区','桐庐县','淳安县','建德市','富阳市','临安市']},
{name:'宁波市', areaList:['市辖区','海曙区','江东区','江北区','北仑区','镇海区','鄞州区','象山县','宁海县','余姚市','慈溪市','奉化市']},
{name:'温州市', areaList:['市辖区','鹿城区','龙湾区','瓯海区','洞头县','永嘉县','平阳县','苍南县','文成县','泰顺县','瑞安市','乐清市']},
{name:'嘉兴市', areaList:['市辖区','秀城区','秀洲区','嘉善县','海盐县','海宁市','平湖市','桐乡市']},
{name:'湖州市', areaList:['市辖区','吴兴区','南浔区','德清县','长兴县','安吉县']},
{name:'绍兴市', areaList:['市辖区','越城区','绍兴县','新昌县','诸暨市','上虞市','嵊州市']},
{name:'金华市', areaList:['市辖区','婺城区','金东区','武义县','浦江县','磐安县','兰溪市','义乌市','东阳市','永康市']},
{name:'衢州市', areaList:['市辖区','柯城区','衢江区','常山县','开化县','龙游县','江山市']},
{name:'舟山市', areaList:['市辖区','定海区','普陀区','岱山县','嵊泗县']},
{name:'台州市', areaList:['市辖区','椒江区','黄岩区','路桥区','玉环县','三门县','天台县','仙居县','温岭市','临海市']},
{name:'丽水市', areaList:['市辖区','莲都区','青田县','缙云县','遂昌县','松阳县','云和县','庆元县','景宁畲族自治县','龙泉市']}
]},
{name:'安徽', cityList:[
{name:'合肥市', areaList:['市辖区','瑶海区','庐阳区','蜀山区','包河区','长丰县','肥东县','肥西县']},
{name:'芜湖市', areaList:['市辖区','镜湖区','马塘区','新芜区','鸠江区','芜湖县','繁昌县','南陵县']},
{name:'蚌埠市', areaList:['市辖区','龙子湖区','蚌山区','禹会区','淮上区','怀远县','五河县','固镇县']},
{name:'淮南市', areaList:['市辖区','大通区','田家庵区','谢家集区','八公山区','潘集区','凤台县']},
{name:'马鞍山市', areaList:['市辖区','金家庄区','花山区','雨山区','当涂县']},
{name:'淮北市', areaList:['市辖区','杜集区','相山区','烈山区','濉溪县']},
{name:'铜陵市', areaList:['市辖区','铜官山区','狮子山区','郊 区','铜陵县']},
{name:'安庆市', areaList:['市辖区','迎江区','大观区','郊 区','怀宁县','枞阳县','潜山县','太湖县','宿松县','望江县','岳西县','桐城市']},
{name:'黄山市', areaList:['市辖区','屯溪区','黄山区','徽州区','歙 县','休宁县','黟 县','祁门县']},
{name:'滁州市', areaList:['市辖区','琅琊区','南谯区','来安县','全椒县','定远县','凤阳县','天长市','明光市']},
{name:'阜阳市', areaList:['市辖区','颍州区','颍东区','颍泉区','临泉县','太和县','阜南县','颍上县','界首市']},
{name:'宿州市', areaList:['市辖区','墉桥区','砀山县','萧 县','灵璧县','泗 县']},
{name:'巢湖市', areaList:['市辖区','居巢区','庐江县','无为县','含山县','和 县']},
{name:'六安市', areaList:['市辖区','金安区','裕安区','寿 县','霍邱县','舒城县','金寨县','霍山县']},
{name:'亳州市', areaList:['市辖区','谯城区','涡阳县','蒙城县','利辛县']},
{name:'池州市', areaList:['市辖区','贵池区','东至县','石台县','青阳县']},
{name:'宣城市', areaList:['市辖区','宣州区','郎溪县','广德县','泾 县','绩溪县','旌德县','宁国市']}
]},
{name:'福建', cityList:[
{name:'福州市', areaList:['市辖区','鼓楼区','台江区','仓山区','马尾区','晋安区','闽侯县','连江县','罗源县','闽清县','永泰县','平潭县','福清市','长乐市']},
{name:'厦门市', areaList:['市辖区','思明区','海沧区','湖里区','集美区','同安区','翔安区']},
{name:'莆田市', areaList:['市辖区','城厢区','涵江区','荔城区','秀屿区','仙游县']},
{name:'三明市', areaList:['市辖区','梅列区','三元区','明溪县','清流县','宁化县','大田县','尤溪县','沙 县','将乐县','泰宁县','建宁县','永安市']},
{name:'泉州市', areaList:['市辖区','鲤城区','丰泽区','洛江区','泉港区','惠安县','安溪县','永春县','德化县','金门县','石狮市','晋江市','南安市']},
{name:'漳州市', areaList:['市辖区','芗城区','龙文区','云霄县','漳浦县','诏安县','长泰县','东山县','南靖县','平和县','华安县','龙海市']},
{name:'南平市', areaList:['市辖区','延平区','顺昌县','浦城县','光泽县','松溪县','政和县','邵武市','武夷山市','建瓯市','建阳市']},
{name:'龙岩市', areaList:['市辖区','新罗区','长汀县','永定县','上杭县','武平县','连城县','漳平市']},
{name:'宁德市', areaList:['市辖区','蕉城区','霞浦县','古田县','屏南县','寿宁县','周宁县','柘荣县','福安市','福鼎市']}
]},
{name:'江西', cityList:[
{name:'南昌市', areaList:['市辖区','东湖区','西湖区','青云谱区','湾里区','青山湖区','南昌县','新建县','安义县','进贤县']},
{name:'景德镇市', areaList:['市辖区','昌江区','珠山区','浮梁县','乐平市']},
{name:'萍乡市', areaList:['市辖区','安源区','湘东区','莲花县','上栗县','芦溪县']},
{name:'九江市', areaList:['市辖区','庐山区','浔阳区','九江县','武宁县','修水县','永修县','德安县','星子县','都昌县','湖口县','彭泽县','瑞昌市']},
{name:'新余市', areaList:['市辖区','渝水区','分宜县']},
{name:'鹰潭市', areaList:['市辖区','月湖区','余江县','贵溪市']},
{name:'赣州市', areaList:['市辖区','章贡区','赣 县','信丰县','大余县','上犹县','崇义县','安远县','龙南县','定南县','全南县','宁都县','于都县','兴国县','会昌县','寻乌县','石城县','瑞金市','南康市']},
{name:'吉安市', areaList:['市辖区','吉州区','青原区','吉安县','吉水县','峡江县','新干县','永丰县','泰和县','遂川县','万安县','安福县','永新县','井冈山市']},
{name:'宜春市', areaList:['市辖区','袁州区','奉新县','万载县','上高县','宜丰县','靖安县','铜鼓县','丰城市','樟树市','高安市']},
{name:'抚州市', areaList:['市辖区','临川区','南城县','黎川县','南丰县','崇仁县','乐安县','宜黄县','金溪县','资溪县','东乡县','广昌县']},
{name:'上饶市', areaList:['市辖区','信州区','上饶县','广丰县','玉山县','铅山县','横峰县','弋阳县','余干县','鄱阳县','万年县','婺源县','德兴市']}
]},
{name:'山东', cityList:[
{name:'济南市', areaList:['市辖区','历下区','市中区','槐荫区','天桥区','历城区','长清区','平阴县','济阳县','商河县','章丘市']},
{name:'青岛市', areaList:['市辖区','市南区','市北区','四方区','黄岛区','崂山区','李沧区','城阳区','胶州市','即墨市','平度市','胶南市','莱西市']},
{name:'淄博市', areaList:['市辖区','淄川区','张店区','博山区','临淄区','周村区','桓台县','高青县','沂源县']},
{name:'枣庄市', areaList:['市辖区','市中区','薛城区','峄城区','台儿庄区','山亭区','滕州市']},
{name:'东营市', areaList:['市辖区','东营区','河口区','垦利县','利津县','广饶县']},
{name:'烟台市', areaList:['市辖区','芝罘区','福山区','牟平区','莱山区','长岛县','龙口市','莱阳市','莱州市','蓬莱市','招远市','栖霞市','海阳市']},
{name:'潍坊市', areaList:['市辖区','潍城区','寒亭区','坊子区','奎文区','临朐县','昌乐县','青州市','诸城市','寿光市','安丘市','高密市','昌邑市']},
{name:'济宁市', areaList:['市辖区','市中区','任城区','微山县','鱼台县','金乡县','嘉祥县','汶上县','泗水县','梁山县','曲阜市','兖州市','邹城市']},
{name:'泰安市', areaList:['市辖区','泰山区','岱岳区','宁阳县','东平县','新泰市','肥城市']},
{name:'威海市', areaList:['市辖区','环翠区','文登市','荣成市','乳山市']},
{name:'日照市', areaList:['市辖区','东港区','岚山区','五莲县','莒 县']},
{name:'莱芜市', areaList:['市辖区','莱城区','钢城区']},
{name:'临沂市', areaList:['市辖区','兰山区','罗庄区','河东区','沂南县','郯城县','沂水县','苍山县','费 县','平邑县','莒南县','蒙阴县','临沭县']},
{name:'德州市', areaList:['市辖区','德城区','陵 县','宁津县','庆云县','临邑县','齐河县','平原县','夏津县','武城县','乐陵市','禹城市']},
{name:'聊城市', areaList:['市辖区','东昌府区','阳谷县','莘 县','茌平县','东阿县','冠 县','高唐县','临清市']},
{name:'滨州市', areaList:['市辖区','滨城区','惠民县','阳信县','无棣县','沾化县','博兴县','邹平县']},
{name:'荷泽市', areaList:['市辖区','牡丹区','曹 县','单 县','成武县','巨野县','郓城县','鄄城县','定陶县','东明县']}
]},
{name:'辽宁', cityList:[
{name:'沈阳市', areaList:['市辖区','和平区','沈河区','大东区','皇姑区','铁西区','苏家屯区','东陵区','新城子区','于洪区','辽中县','康平县','法库县','新民市']},
{name:'大连市', areaList:['市辖区','中山区','西岗区','沙河口区','甘井子区','旅顺口区','金州区','长海县','瓦房店市','普兰店市','庄河市']},
{name:'鞍山市', areaList:['市辖区','铁东区','铁西区','立山区','千山区','台安县','岫岩满族自治县','海城市']},
{name:'抚顺市', areaList:['市辖区','新抚区','东洲区','望花区','顺城区','抚顺县','新宾满族自治县','清原满族自治县']},
{name:'本溪市', areaList:['市辖区','平山区','溪湖区','明山区','南芬区','本溪满族自治县','桓仁满族自治县']},
{name:'丹东市', areaList:['市辖区','元宝区','振兴区','振安区','宽甸满族自治县','东港市','凤城市']},
{name:'锦州市', areaList:['市辖区','古塔区','凌河区','太和区','黑山县','义 县','凌海市','北宁市']},
{name:'营口市', areaList:['市辖区','站前区','西市区','鲅鱼圈区','老边区','盖州市','大石桥市']},
{name:'阜新市', areaList:['市辖区','海州区','新邱区','太平区','清河门区','细河区','阜新蒙古族自治县','彰武县']},
{name:'辽阳市', areaList:['市辖区','白塔区','文圣区','宏伟区','弓长岭区','太子河区','辽阳县','灯塔市']},
{name:'盘锦市', areaList:['市辖区','双台子区','兴隆台区','大洼县','盘山县']},
{name:'铁岭市', areaList:['市辖区','银州区','清河区','铁岭县','西丰县','昌图县','调兵山市','开原市']},
{name:'朝阳市', areaList:['市辖区','双塔区','龙城区','朝阳县','建平县','喀喇沁左翼蒙古族自治县','北票市','凌源市']},
{name:'葫芦岛市', areaList:['市辖区','连山区','龙港区','南票区','绥中县','建昌县','兴城市']}
]},
{name:'吉林', cityList:[
{name:'长春市', areaList:['市辖区','南关区','宽城区','朝阳区','二道区','绿园区','双阳区','农安县','九台市','榆树市','德惠市']},
{name:'吉林市', areaList:['市辖区','昌邑区','龙潭区','船营区','丰满区','永吉县','蛟河市','桦甸市','舒兰市','磐石市']},
{name:'四平市', areaList:['市辖区','铁西区','铁东区','梨树县','伊通满族自治县','公主岭市','双辽市']},
{name:'辽源市', areaList:['市辖区','龙山区','西安区','东丰县','东辽县']},
{name:'通化市', areaList:['市辖区','东昌区','二道江区','通化县','辉南县','柳河县','梅河口市','集安市']},
{name:'白山市', areaList:['市辖区','八道江区','抚松县','靖宇县','长白朝鲜族自治县','江源县','临江市']},
{name:'松原市', areaList:['市辖区','宁江区','前郭尔罗斯蒙古族自治县','长岭县','乾安县','扶余县']},
{name:'白城市', areaList:['市辖区','洮北区','镇赉县','通榆县','洮南市','大安市']},
{name:'延边朝鲜族自治州', areaList:['延吉市','图们市','敦化市','珲春市','龙井市','和龙市','汪清县','安图县']}
]},
{name:'黑龙江', cityList:[
{name:'哈尔滨市', areaList:['市辖区','道里区','南岗区','道外区','香坊区','动力区','平房区','松北区','呼兰区','依兰县','方正县','宾 县','巴彦县','木兰县','通河县','延寿县','阿城市','双城市','尚志市','五常市']},
{name:'齐齐哈尔市', areaList:['市辖区','龙沙区','建华区','铁锋区','昂昂溪区','富拉尔基区','碾子山区','梅里斯达斡尔族区','龙江县','依安县','泰来县','甘南县','富裕县','克山县','克东县','拜泉县','讷河市']},
{name:'鸡西市', areaList:['市辖区','鸡冠区','恒山区','滴道区','梨树区','城子河区','麻山区','鸡东县','虎林市','密山市']},
{name:'鹤岗市', areaList:['市辖区','向阳区','工农区','南山区','兴安区','东山区','兴山区','萝北县','绥滨县']},
{name:'双鸭山市', areaList:['市辖区','尖山区','岭东区','四方台区','宝山区','集贤县','友谊县','宝清县','饶河县']},
{name:'大庆市', areaList:['市辖区','萨尔图区','龙凤区','让胡路区','红岗区','大同区','肇州县','肇源县','林甸县','杜尔伯特蒙古族自治县']},
{name:'伊春市', areaList:['市辖区','伊春区','南岔区','友好区','西林区','翠峦区','新青区','美溪区','金山屯区','五营区','乌马河区','汤旺河区','带岭区','乌伊岭区','红星区','上甘岭区','嘉荫县','铁力市']},
{name:'佳木斯市', areaList:['市辖区','永红区','向阳区','前进区','东风区','郊 区','桦南县','桦川县','汤原县','抚远县','同江市','富锦市']},
{name:'七台河市', areaList:['市辖区','新兴区','桃山区','茄子河区','勃利县']},
{name:'牡丹江市', areaList:['市辖区','东安区','阳明区','爱民区','西安区','东宁县','林口县','绥芬河市','海林市','宁安市','穆棱市']},
{name:'黑河市', areaList:['市辖区','爱辉区','嫩江县','逊克县','孙吴县','北安市','五大连池市']},
{name:'绥化市', areaList:['市辖区','北林区','望奎县','兰西县','青冈县','庆安县','明水县','绥棱县','安达市','肇东市','海伦市']},
{name:'大兴安岭地区', areaList:['呼玛县','塔河县','漠河县']}
]},
{name:'海南', cityList:[
{name:'海口市', areaList:['市辖区','秀英区','龙华区','琼山区','美兰区']},
{name:'三亚市', areaList:['市辖区']},
{name:'省直辖县级行政单位', areaList:['五指山市','琼海市','儋州市','文昌市','万宁市','东方市','定安县','屯昌县','澄迈县','临高县','白沙黎族自治县','昌江黎族自治县','乐东黎族自治县','陵水黎族自治县','保亭黎族苗族自治县','琼中黎族苗族自治县','西沙群岛','南沙群岛','中沙群岛的岛礁及其海域']}
]},
{name:'台湾', cityList:[
{name:'台湾', areaList:['台湾']}
]},
{name:'香港', cityList:[
{name:'香港', areaList:['香港']}
]},
{name:'澳门', cityList:[
{name:'澳门', areaList:['澳门']}
]}
];

@ -1,30 +1,64 @@
/** layui-v2.4.5 MIT License By https://www.layui.com */
;layui.define(["laytpl", "laypage", "layer", "form", "util"], function (e) {
// 使用严格模式,有助于发现代码中潜在的错误,避免一些在非严格模式下可能出现的不规范或容易出错的用法
"use strict";
var t = layui.$, i = layui.laytpl, a = layui.laypage, l = layui.layer, n = layui.form,
o = (layui.util, layui.hint()), r = layui.device(), d = {
// 通过 `layui.$` 获取 jQuery 对象(在 layui 框架中如果集成了 jQuery 或者对其进行了类似的封装,则可以这样获取),并赋值给变量 `t`,方便后续使用 jQuery 的相关方法进行 DOM 操作、元素查找等功能
var t = layui.$,
// 从 `layui` 框架中获取 `laytpl` 模块(可能是用于模板渲染相关功能的模块),并赋值给变量 `i`,后续可以调用这个模块提供的方法来处理模板相关的业务逻辑
i = layui.laytpl,
// 从 `layui` 框架中获取 `laypage` 模块(可能是用于分页功能相关的模块),并赋值给变量 `a`,方便后续进行分页相关的操作,比如生成分页组件、处理分页数据等
a = layui.laypage,
// 从 `layui` 框架中获取 `layer` 模块(可能是用于弹出层、提示框等交互组件相关功能的模块),并赋值给变量 `l`,用于后续展示各种提示信息或者弹出层等交互操作
l = layui.layer,
// 从 `layui` 框架中获取 `form` 模块(可能是用于表单相关功能的模块,比如表单验证、表单元素操作等),并赋值给变量 `n`,便于后续处理表单相关的业务逻辑
n = layui.form,
// 先执行 `layui.util`(可能是调用 `layui` 框架中的工具类相关功能,不过这里代码只是执行了一下,具体作用要结合 `layui.util` 内部实现来看),然后获取 `layui.hint` 函数(从前面代码推测可能是用于输出提示信息等功能的函数)的执行结果,并赋值给变量 `o`,方便后续进行错误提示等操作
o = (layui.util, layui.hint()),
// 调用 `layui.device` 函数(从前面代码推测可能是用于获取设备相关信息的函数,比如判断当前是在移动端还是桌面端等设备情况),获取设备信息并赋值给变量 `r`,后续可以根据设备信息来进行一些页面适配或者功能调整等操作
r = layui.device(),
// 创建一个对象 `d`,用于存储表格相关的配置信息、缓存数据、索引值以及一些操作表格的方法等,以下是对象 `d` 的各个属性和方法的详细介绍:
d = {
// `config` 属性,用于存储表格的一些默认配置选项,比如用于标识选中状态的属性名、索引属性名等,初始设置了 `checkName` 和 `indexName` 的默认值
config: {checkName: "LAY_CHECKED", indexName: "LAY_TABLE_INDEX"},
// `cache` 属性,用于存储表格相关的缓存数据,初始值为空对象,后续可以根据需要在这里存储比如已加载的数据、临时状态数据等信息
cache: {},
index: layui.table ? layui.table.index + 1e4 : 0,
// `index` 属性,用于记录表格的索引值,如果 `layui.table` 存在(从代码逻辑推测可能是判断 `layui` 框架中表格模块是否已经初始化或者可用),则基于 `layui.table.index` 的值加上 `1e4` 作为当前表格的索引,否则初始化为 `0`,这个索引值可能用于区分不同的表格实例等用途
index: layui.table? layui.table.index + 1e4 : 0,
// `set` 方法,用于更新表格的配置信息,它接收一个参数 `e`(应该是一个包含新配置选项的对象),在方法内部先将当前实例对象(通过 `this` 指代)保存到变量 `i` 中,然后使用 `t.extend` 方法(可能是基于 jQuery 或者 layui 自定义的扩展对象属性的方法,将两个对象的属性合并到一起)将原有的配置对象(`i.config`)、一个空对象(`{}`,用于确保不会受到原对象引用的影响)以及传入的新配置对象 `e` 进行合并,最后返回当前实例对象 `i`,实现配置信息的更新并支持链式调用(方便后续继续调用实例对象的其他方法等)
set: function (e) {
var i = this;
return i.config = t.extend({}, i.config, e), i
},
// `on` 方法,用于绑定表格相关的事件,它接收两个参数 `e`(事件名称相关的字符串)和 `t`(事件处理函数等相关信息),在方法内部通过调用 `layui.onevent.call` 方法(从前面代码推测 `layui.onevent` 应该是用于处理事件绑定的一个通用函数,这里使用 `call` 方法改变函数内部的 `this` 指向为当前实例对象 `this`),传入特定的事件名称相关参数(这里使用变量 `u`,从后续代码看应该是固定为 `"table"`,表示表格相关的事件)、实际的事件名称 `e` 和事件处理函数 `t`,来实现表格事件的绑定操作,最后返回相应的结果(具体返回值要结合 `layui.onevent` 函数的实现来看)
on: function (e, t) {
return layui.onevent.call(this, u, e, t)
}
}, c = function () {
},
// 定义一个函数 `c`,这个函数可能用于获取或操作表格实例相关的一些配置和方法等信息,以下是函数内部的详细逻辑代码:
c = function () {
// 将当前调用此函数的对象(通过 `this` 指代)保存到变量 `e` 中,方便后续引用当前对象的属性和方法等,然后获取当前对象的 `config` 属性(也就是表格的配置信息对象),并赋值给变量 `t`,再获取配置对象中的 `id` 属性值,如果 `id` 属性不存在则获取 `index` 属性值(这两个属性都可能用于标识当前表格实例),将获取到的值赋值给变量 `i`
var e = this, t = e.config, i = t.id || t.index;
// 判断如果 `i` 有值(也就是有有效的表格实例标识),则将当前表格实例对象 `e` 存储到 `c.that` 对象中(以 `i` 为键,方便后续通过标识查找对应的表格实例对象),同时将表格的配置信息 `t` 存储到 `c.config` 对象中(同样以 `i` 为键,方便后续通过标识查找对应的配置信息),最后返回一个包含多个方法的对象,这些方法用于对表格进行不同的操作,比如重新加载数据(`reload` 方法)、设置列宽(`setColsWidth` 方法)、调整表格大小(`resize` 方法)以及获取表格配置信息(`config` 方法)等,以下是返回对象中各个方法的详细介绍:
return i && (c.that[i] = e, c.config[i] = t), {
// `reload` 方法,当外部调用这个方法时(传入相应的参数 `t`,参数的具体含义要结合 `e.reload` 方法的实现来看),会执行 `e.reload.call(e, t)`,也就是调用当前表格实例对象 `e` 的 `reload` 方法(从代码逻辑推测 `e.reload` 方法应该是用于重新加载表格数据的具体业务逻辑所在,这里通过 `call` 方法确保 `reload` 方法内部的 `this` 指向正确的表格实例对象),实现重新加载表格数据的功能
reload: function (t) {
e.reload.call(e, t)
}, setColsWidth: function () {
},
// `setColsWidth` 方法,当外部调用这个方法时,会执行 `e.setColsWidth.call(e)`,也就是调用当前表格实例对象 `e` 的 `setColsWidth` 方法(从代码逻辑推测 `e.setColsWidth` 方法应该是用于设置表格列宽的具体业务逻辑所在,这里同样通过 `call` 方法确保 `this` 指向正确的表格实例对象),实现设置表格列宽的功能
setColsWidth: function () {
e.setColsWidth.call(e)
}, resize: function () {
},
// `resize` 方法,当外部调用这个方法时,会执行 `e.resize.call(e)`,也就是调用当前表格实例对象 `e` 的 `resize` 方法(从代码逻辑推测 `e.resize` 方法应该是用于调整表格大小的具体业务逻辑所在,同样通过 `call` 方法确保 `this` 指向正确的表格实例对象),实现调整表格大小的功能
resize: function () {
e.resize.call(e)
}, config: t
},
// `config` 方法,直接返回当前表格实例对象的配置信息对象 `t`,方便外部获取表格的当前配置情况
config: t
}
}, s = function (e) {
},
// 定义一个函数 `s`,这个函数接收一个参数 `e`(可能是表格实例的标识等相关信息),用于查找并返回对应的表格配置信息,以下是函数内部的详细逻辑代码:
s = function (e) {
// 通过 `c.config` 对象(前面定义的用于存储表格配置信息的对象,以表格实例标识为键来存储对应的配置信息)查找并获取以 `e` 为键的配置信息对象,如果找到了就返回这个配置信息对象,如果没找到,则调用 `o.error` 函数(前面获取的用于输出错误提示信息的函数),输出提示信息表示在表格实例中没有找到 `ID` 选项(从错误提示内容推测这里 `e` 可能是作为表格的 `ID` 标识来查找配置信息的),最后无论是否找到配置信息,都返回查找的结果(找到则返回配置信息对象,没找到则返回 `null`
var t = c.config[e];
return t || o.error("The ID option was not found in the table instance"), t || null
}, u = "table", h = ".layui-table", y = "layui-hide", f = "layui-none", p = "layui-table-view",
@ -164,137 +198,479 @@
t.style.width = parseFloat(i) + d + "px", e.layMain.height() - e.layMain.prop("clientHeight") > 0 && (t.style.width = parseFloat(t.style.width) - 1 + "px")
})
}
// 调用 `e` 函数(从前面代码上下文推测,`e` 应该是在 `layui.define` 回调函数中传入的一个用于向外暴露功能或者执行相关操作的函数,不过具体功能要结合 `layui` 框架整体设计来看),并传入参数 `!0`(可能用于开启某种加载相关的功能或者状态,具体要根据 `e` 函数内部实现以及 `loading` 操作在 `layui` 框架中的含义来确定)
e.loading(!0)
}, F.prototype.resize = function () {
var e = this;
e.fullSize(), e.setColsWidth(), e.scrollPatch()
}, F.prototype.reload = function (e) {
},
// 在 `F` 构造函数的原型上定义一个名为 `resize` 的方法,这个方法用于调整表格相关的一些尺寸、宽度等属性,以下是方法内部的详细逻辑代码
F.prototype.resize = function () {
// 将当前调用此方法的 `F` 构造函数实例对象自身保存到变量 `e` 中,方便后续在方法内部引用实例对象的属性和方法等
var e = this;
// 调用实例对象 `e` 的 `fullSize` 方法(从方法名推测可能是用于设置表格为全尺寸显示或者根据页面大小自适应尺寸等相关功能,不过具体功能要结合其内部实现来看)
e.fullSize();
// 调用实例对象 `e` 的 `setColsWidth` 方法(从方法名推测是用于设置表格列的宽度相关功能,比如根据内容自适应宽度、按照配置设置固定宽度等操作,具体要结合其内部实现来看)
e.setColsWidth();
// 调用实例对象 `e` 的 `scrollPatch` 方法(从方法名推测可能是用于处理表格滚动相关的一些问题或者设置滚动相关的属性等功能,不过具体功能要结合其内部实现来看)
e.scrollPatch()
},
// 在 `F` 构造函数的原型上定义一个名为 `reload` 的方法,这个方法接收一个参数 `e`,用于重新加载表格的数据以及更新相关配置信息,以下是方法内部的详细逻辑代码
F.prototype.reload = function (e) {
// 将当前调用此方法的 `F` 构造函数实例对象自身保存到变量 `i` 中,方便后续在方法内部引用实例对象的属性和方法等
var i = this;
// 判断如果实例对象 `i` 的 `config` 对象中存在 `data` 属性,并且 `data` 属性的值的构造函数是 `Array`(也就是 `data` 是数组类型,表示当前表格有已有的数据),则删除 `i.config.data`(可能是为了重新加载新数据做准备,先清空原有的数据)
i.config.data && i.config.data.constructor === Array && delete i.config.data;
// 使用 `t.extend` 方法(可能是基于 jQuery 或者 layui 自定义的扩展对象属性的方法,将两个对象的属性合并到一起)将实例对象 `i` 的 `config` 对象与传入的参数 `e` 所代表的对象进行合并,实现用新的配置信息更新原有的配置信息,然后调用实例对象 `i` 的 `render` 方法(从前面代码可知 `render` 方法可能是用于重新渲染表格的功能,基于更新后的配置信息重新绘制表格等操作)
i.config = t.extend({}, i.config, e);
i.render()
},
// 在 `F` 构造函数的原型上定义一个属性 `page`,并赋值为 `1`,从代码逻辑推测这个属性可能用于记录表格当前的页码信息,初始化为第一页,方便后续在分页相关操作或者数据加载等操作中使用这个页码值进行计算、判断等功能
F.prototype.page = 1;
// 在 `F` 构造函数的原型上定义一个名为 `pullData` 的方法,这个方法接收一个参数 `e`(可能是页码等相关信息,用于根据页码拉取对应的数据),用于从服务器或者已有数据中获取表格需要展示的数据,并进行相应的处理、渲染等操作,以下是方法内部的详细逻辑代码
F.prototype.pullData = function (e) {
// 将当前调用此方法的 `F` 构造函数实例对象自身保存到变量 `i` 中,方便后续在方法内部引用实例对象的属性和方法等
var i = this;
i.config.data && i.config.data.constructor === Array && delete i.config.data, i.config = t.extend({}, i.config, e), i.render()
}, F.prototype.page = 1, F.prototype.pullData = function (e) {
var i = this, a = i.config, l = a.request, n = a.response, o = function () {
// 获取实例对象 `i` 的 `config` 对象(包含表格的各种配置信息),并分别赋值给变量 `a`,方便后续直接通过 `a` 来访问配置信息中的各个属性
var a = i.config;
// 获取 `a`(配置对象)中的 `request` 属性(从名称推测是用于配置数据请求相关的参数,比如请求的页码参数名、每页数量参数名等信息),并赋值给变量 `l`,方便后续构建请求数据时使用这些参数名
var l = a.request;
// 获取 `a`(配置对象)中的 `response` 属性(从名称推测是用于配置服务器响应数据相关的处理参数,比如响应中状态码字段名、数据字段名等信息),并赋值给变量 `n`,方便后续根据这些参数名来解析响应数据
var n = a.response;
// 创建一个匿名函数,并赋值给变量 `o`,这个函数内部的逻辑是判断如果 `a`(配置对象)中的 `initSort` 属性是对象类型(从代码逻辑推测可能是用于配置表格初始排序相关信息的对象,比如排序的字段、排序类型等),则调用实例对象 `i` 的 `sort` 方法(从前面代码推测应该是用于对表格数据进行排序的方法,不过具体功能要结合其内部实现来看),传入 `a.initSort.field`(初始排序的字段)和 `a.initSort.type`(初始排序的类型)作为参数,进行初始排序相关的操作,这里先定义好这个函数,后续会在合适的地方调用它来执行排序逻辑
var o = function () {
"object" == typeof a.initSort && i.sort(a.initSort.field, a.initSort.type)
};
// 判断如果实例对象 `i` 的 `config` 对象中的 `url` 属性存在(也就是配置了数据请求的地址,意味着要从服务器端获取数据),则执行以下代码块进行服务器端数据请求及处理操作:
if (i.startTime = (new Date).getTime(), a.url) {
// 创建一个空对象 `r`,用于存储即将要发送的请求数据,后续会根据配置信息将页码、每页数量等参数添加到这个对象中
var r = {};
r[l.pageName] = e, r[l.limitName] = a.limit;
// 将当前页码 `e` 作为值,以 `l.pageName`(前面获取的请求参数中页码参数名)为键,添加到 `r` 对象中,表示请求的页码信息;将 `a.limit`(从配置对象中获取的每页显示数据的数量限制)作为值,以 `l.limitName`(前面获取的请求参数中每页数量参数名)为键,添加到 `r` 对象中,表示请求每页的数据数量信息,这样就构建好了基本的分页请求数据
r[l.pageName] = e;
r[l.limitName] = a.limit;
// 使用 `t.extend` 方法将 `r` 对象与 `a.where`(从配置对象中获取的可能是其他请求相关的额外参数,比如查询条件等信息)进行合并,将合并后的结果重新赋值给 `r` 对象,这样 `r` 对象就包含了完整的请求数据信息
var d = t.extend(r, a.where);
a.contentType && 0 == a.contentType.indexOf("application/json") && (d = JSON.stringify(d)), t.ajax({
// 判断如果 `a`(配置对象)中的 `contentType` 属性存在,并且其值以 `"application/json"` 开头(也就是表示请求的数据格式是 JSON 格式),则将 `r` 对象通过 `JSON.stringify` 方法转换为 JSON 字符串格式,因为如果是 JSON 格式请求,需要将请求数据转换为字符串形式发送给服务器端,将转换后的结果重新赋值给 `d`(也就是请求数据对象)
a.contentType && 0 == a.contentType.indexOf("application/json") && (d = JSON.stringify(d));
// 使用 `t.ajax` 方法(从代码逻辑推测是基于 jQuery 或者 layui 自定义的用于发送 AJAX 请求的方法,功能类似原生的 `XMLHttpRequest` 或者 `fetch` 等发送网络请求的方式)发送请求,传入一系列配置参数来指定请求的详细信息,以下是各个参数的详细介绍:
t.ajax({
// 设置请求的类型(`type`),如果 `a`(配置对象)中配置了 `method` 属性(表示请求方法,比如 `get`、`post` 等),则使用配置的方法,否则默认使用 `"get"` 方法发送请求
type: a.method || "get",
// 设置请求的 URL 地址,从 `a.url`(配置对象中的数据请求地址属性)获取
url: a.url,
// 设置请求的数据格式类型(`contentType`),从 `a.contentType`(配置对象中的对应属性)获取,如果没有配置则使用默认值(不过默认值在这里没有明确体现,要结合 `t.ajax` 方法的内部实现来看)
contentType: a.contentType,
// 设置请求发送的数据内容,这里使用前面构建好的 `d` 对象(包含了分页信息、其他请求参数等完整的请求数据内容)
data: d,
// 设置期望服务器返回的数据格式类型为 JSON 格式(`dataType`),这样 `t.ajax` 方法会自动将服务器返回的 JSON 字符串解析为 JavaScript 对象供后续使用
dataType: "json",
// 设置请求的头部信息(`headers`),如果 `a`(配置对象)中配置了 `headers` 属性(可能包含如认证信息、自定义的请求头字段等内容),则使用配置的内容,否则使用一个空对象表示没有额外的头部信息
headers: a.headers || {},
// 定义请求成功后的回调函数(`success`当服务器成功返回数据并且按照期望的数据格式JSON 格式)解析成功后,会执行这个回调函数,回调函数接收一个参数 `t`,代表服务器返回的解析后的响应数据对象,以下是回调函数内部的详细逻辑代码:
success: function (t) {
"function" == typeof a.parseData && (t = a.parseData(t) || t), t[n.statusName] != n.statusCode ? (i.renderForm(), i.layMain.html('<div class="' + f + '">' + (t[n.msgName] || "返回的数据不符合规范,正确的成功状态码 (" + n.statusName + ") 应为:" + n.statusCode) + "</div>")) : (i.renderData(t, e, t[n.countName]), o(), a.time = (new Date).getTime() - i.startTime + " ms"), i.setColsWidth(), "function" == typeof a.done && a.done(t, e, t[n.countName])
// 判断如果 `a`(配置对象)中配置了 `parseData` 方法(从名称推测是用于进一步解析服务器返回数据的自定义方法,比如对数据进行格式转换、提取特定字段等操作),并且这个方法是函数类型,则调用 `a.parseData` 方法,传入服务器返回的响应数据 `t` 作为参数,将方法返回的结果(如果有)重新赋值给 `t`,也就是使用自定义解析后的结果作为最终的响应数据;如果没有配置 `parseData` 方法或者不是函数类型,则直接使用服务器返回的原始数据 `t`,这样就完成了对响应数据的可能的进一步解析处理
"function" == typeof a.parseData && (t = a.parseData(t) || t);
// 判断如果服务器返回的响应数据 `t` 中,以 `n.statusName`(前面获取的响应数据中状态码字段名)为键的值不等于 `n.statusCode`(前面获取的表示正确状态码的配置值),则表示服务器返回的数据不符合规范,执行以下代码块进行错误处理操作:
t[n.statusName]!= n.statusCode? (
// 调用实例对象 `i` 的 `renderForm` 方法(从代码逻辑推测可能是用于重新渲染表格的表单部分或者处理表单相关的显示逻辑等功能,不过具体功能要结合其内部实现来看)
i.renderForm(),
// 使用 `i.layMain`(从前面代码推测应该是指向表格主体内容所在的 DOM 元素或者 jQuery 对象,用于操作表格主体区域的显示内容),调用 `html` 方法(可能是 jQuery 的 `html` 方法,用于设置元素的内部 HTML 内容),设置其内容为一段包含错误提示信息的 HTML 字符串,提示信息表示返回的数据不符合规范,并展示正确的状态码应该是多少(通过拼接 `n.msgName`、`n.statusName` 和 `n.statusCode` 等配置信息构建完整的提示内容),同时添加一个特定的 CSS 类名 `f`(从前面代码可知这个类名可能用于标识某种特定的样式状态,比如元素不可见或者错误提示样式等相关的样式语义),这样就在表格主体区域显示了相应的错误提示信息
i.layMain.html('<div class="' + f + '">' + (t[n.msgName] || "返回的数据不符合规范,正确的成功状态码 (" + n.statusName + ") 应为:" + n.statusCode) + "</div>")) : (
// 如果服务器返回的数据符合规范(状态码正确),则执行以下代码块进行正常的数据处理和渲染操作:
// 调用实例对象 `i` 的 `renderData` 方法(从代码逻辑推测是用于将获取到的数据渲染到表格中展示的功能,不过具体功能要结合其内部实现来看),传入服务器返回的响应数据 `t`、当前页码 `e` 和响应数据中以 `n.countName`(前面获取的响应数据中数据总数字段名)为键的值(也就是数据的总数量)作为参数,将数据渲染到表格中进行展示
i.renderData(t, e, t[n.countName]),
// 调用前面定义的匿名函数 `o`(用于执行初始排序相关操作的函数),执行可能的初始排序逻辑,确保表格数据按照配置的初始排序规则进行展示
o(),
// 计算从发送请求到接收到响应数据所花费的时间,通过获取当前时间(`(new Date).getTime()`)减去发送请求时记录的开始时间 `i.startTime`,并将结果转换为字符串格式(加上 `" ms"` 表示毫秒单位),将计算得到的时间赋值给 `a.time`(配置对象中的时间属性,用于记录这次数据请求的耗时情况,方便后续查看性能或者进行相关统计等操作)
a.time = (new Date).getTime() - i.startTime + " ms"),
// 调用实例对象 `i` 的 `setColsWidth` 方法(前面提到用于设置表格列宽的功能,确保表格列宽根据数据情况或者配置进行合适的调整)
i.setColsWidth(),
// 判断如果 `a`(配置对象)中配置了 `done` 方法(从名称推测是用于在数据加载完成后执行的一些自定义操作,比如进行额外的数据处理、触发其他相关的业务逻辑等功能),并且这个方法是函数类型,则调用 `a.done` 方法,传入服务器返回的响应数据 `t`、当前页码 `e` 和响应数据中数据总数量(`t[n.countName]`)作为参数,执行相应的自定义操作
"function" == typeof a.done && a.done(t, e, t[n.countName])
},
// 定义请求失败后的回调函数(`error`),当请求过程中出现错误(比如网络问题、服务器返回错误状态码等情况)时,会执行这个回调函数,回调函数接收两个参数 `e`(错误对象,包含了错误相关的详细信息,不过具体内容要结合 `t.ajax` 方法以及底层的网络请求机制来看)和 `t`(可能是服务器返回的错误相关信息,同样具体内容要结合实际情况确定),以下是回调函数内部的详细逻辑代码:
error: function (e, t) {
i.layMain.html('<div class="' + f + '">数据接口请求异常:' + t + "</div>"), i.renderForm(), i.setColsWidth()
// 使用 `i.layMain`(表格主体内容的 DOM 元素或 jQuery 对象),调用 `html` 方法设置其内部 HTML 内容为一段包含错误提示信息的 HTML 字符串,提示信息表示数据接口请求出现异常,并展示具体的异常信息 `t`,同时添加 `f` CSS 类名用于显示相应的错误提示样式,在表格主体区域显示请求异常的提示信息
i.layMain.html('<div class="' + f + '">数据接口请求异常:' + t + "</div>");
// 调用实例对象 `i` 的 `renderForm` 方法(可能用于处理表格表单部分相关的显示逻辑等功能)
i.renderForm();
// 调用实例对象 `i` 的 `setColsWidth` 方法(用于设置表格列宽,确保在请求失败的情况下表格列宽也能保持合适的状态或者进行相应的调整)
i.setColsWidth()
}
})
} else if (a.data && a.data.constructor === Array) {
var c = {}, s = e * a.limit - a.limit;
c[n.dataName] = a.data.concat().splice(s, a.limit), c[n.countName] = a.data.length, i.renderData(c, e, a.data.length), o(), i.setColsWidth(), "function" == typeof a.done && a.done(c, e, c[n.countName])
// 如果实例对象 `i` 的 `config` 对象中的 `url` 属性不存在(也就是没有配置服务器端数据请求地址,意味着要使用已有的本地数据进行展示),并且 `a.data` 属性存在且是数组类型(表示有本地的表格数据可用),则执行以下代码块进行本地数据的处理和渲染操作:
// 创建一个空对象 `c`,用于存储处理后的要渲染到表格的数据信息,后续会根据分页等情况对本地数据进行提取、整理后放入这个对象中
var c = {};
// 计算当前页码对应的起始数据索引,通过当前页码 `e` 乘以每页数据数量 `a.limit` 再减去 `a.limit`(也就是 `(e - 1) * a.limit` 的计算逻辑,得到当前页数据在整个数据数组中的起始位置索引),将计算结果赋值给变量 `s`
var s = e * a.limit - a.limit;
// 从 `a.data`(本地数据数组)中提取当前页需要展示的数据,通过 `concat` 方法创建一个副本(避免直接修改原数据数组),然后使用 `splice` 方法截取从索引 `s` 开始,长度为 `a.limit` 的数据片段,将截取的数据作为值,以 `n.dataName`(前面获取的响应数据中数据字段名,这里用于规范本地数据结构,保持和服务器返回数据结构的一致性)为键,添加到 `c` 对象中,表示当前页要展示的数据内容;同时将 `a.data` 数组的长度(也就是本地数据的总数量)作为值,以 `n.count
c[n.dataName] = a.data.concat().splice(s, a.limit),
// 将本地数据 `a.data` 先通过 `concat` 方法创建一个副本(避免直接修改原数组),再使用 `splice` 方法截取从索引 `s` 开始,长度为 `a.limit` 的数据片段,
// 把截取出来的数据作为值,以 `n.dataName`(从配置中获取的表示数据字段名的属性)为键,赋值给 `c` 对象,这样 `c` 对象就存储了当前页要展示的数据内容
c[n.countName] = a.data.length,
// 将本地数据 `a.data` 的长度(也就是总的数据数量)作为值,以 `n.countName`(从配置中获取的表示数据总数字段名的属性)为键,赋值给 `c` 对象,用于记录数据总数信息,方便后续操作(比如分页等情况判断数据是否全部展示完等)
i.renderData(c, e, a.data.length),
// 调用当前实例对象 `i`(也就是 `F` 构造函数的实例,代表表格相关操作对象)的 `renderData` 方法,传入处理好的当前页数据 `c`、当前页码 `e` 以及本地数据的总长度 `a.data.length` 作为参数,
// 目的是将提取出来的当前页数据渲染到表格中进行展示,具体的渲染逻辑在 `renderData` 方法内部实现
o(),
// 调用前面定义的匿名函数 `o`(其内部逻辑是判断如果配置中有初始排序相关信息,则执行相应的排序操作,用于保证表格数据按照初始设定进行排序展示),执行可能的初始排序逻辑,确保表格数据的顺序符合要求
i.setColsWidth(),
// 调用当前实例对象 `i` 的 `setColsWidth` 方法,用于设置表格各列的宽度,可能会根据数据内容、配置信息等来动态调整列宽,保证表格显示效果良好
"function" == typeof a.done && a.done(c, e, c[n.countName])
// 判断 `a`(配置对象)中 `done` 方法是否是函数类型,如果是,则调用 `a.done` 方法,传入当前页处理好的数据 `c`、当前页码 `e` 以及当前页数据的总数(`c[n.countName]`)作为参数,
// 这个 `done` 方法通常用于在数据加载及渲染完成后执行一些自定义的额外操作,比如进行其他数据关联处理、触发相关业务逻辑等
}
}, F.prototype.eachCols = function (e) {
var t = this;
return d.eachCols(null, e, t.config.cols), t
}, F.prototype.renderData = function (e, n, o, r) {
var c = this, s = c.config, u = e[s.response.dataName] || [], h = [], p = [], v = [], m = function () {
var e;
return !r && c.sortKey ? c.sort(c.sortKey.field, c.sortKey.sort, !0) : (layui.each(u, function (a, l) {
var o = [], u = [], f = [], m = a + s.limit * (n - 1) + 1;
0 !== l.length && (r || (l[d.config.indexName] = a), c.eachCols(function (n, r) {
var c = r.field || n, h = s.index + "-" + r.key, p = l[c];
if (void 0 !== p && null !== p || (p = ""), !r.colGroup) {
var v = ['<td data-field="' + c + '" data-key="' + h + '" ' + function () {
var e = [];
return r.edit && e.push('data-edit="' + r.edit + '"'), r.align && e.push('align="' + r.align + '"'), r.templet && e.push('data-content="' + p + '"'), r.toolbar && e.push('data-off="true"'), r.event && e.push('lay-event="' + r.event + '"'), r.style && e.push('style="' + r.style + '"'), r.minWidth && e.push('data-minwidth="' + r.minWidth + '"'), e.join(" ")
}() + ' class="' + function () {
var e = [];
return r.hide && e.push(y), r.field || e.push("layui-table-col-special"), e.join(" ")
}() + '">', '<div class="layui-table-cell laytable-cell-' + function () {
return "normal" === r.type ? h : h + " laytable-cell-" + r.type
}() + '">' + function () {
var n = t.extend(!0, {LAY_INDEX: m}, l), o = d.config.checkName;
switch (r.type) {
case"checkbox":
return '<input type="checkbox" name="layTableCheckbox" lay-skin="primary" ' + function () {
return r[o] ? (l[o] = r[o], r[o] ? "checked" : "") : n[o] ? "checked" : ""
}() + ">";
case"radio":
return n[o] && (e = a), '<input type="radio" name="layTableRadio_' + s.index + '" ' + (n[o] ? "checked" : "") + ' lay-type="layTableRadio">';
case"numbers":
return m
}
return r.toolbar ? i(t(r.toolbar).html() || "").render(n) : r.templet ? function () {
return "function" == typeof r.templet ? r.templet(n) : i(t(r.templet).html() || String(p)).render(n)
}() : p
}(), "</div></td>"].join("");
o.push(v), r.fixed && "right" !== r.fixed && u.push(v), "right" === r.fixed && f.push(v)
}
}), h.push('<tr data-index="' + a + '">' + o.join("") + "</tr>"), p.push('<tr data-index="' + a + '">' + u.join("") + "</tr>"), v.push('<tr data-index="' + a + '">' + f.join("") + "</tr>"))
}), c.layBody.scrollTop(0), c.layMain.find("." + f).remove(), c.layMain.find("tbody").html(h.join("")), c.layFixLeft.find("tbody").html(p.join("")), c.layFixRight.find("tbody").html(v.join("")), c.renderForm(), "number" == typeof e && c.setThisRowChecked(e), c.syncCheckAll(), c.haveInit ? c.scrollPatch() : setTimeout(function () {
c.scrollPatch()
}, 50), c.haveInit = !0, l.close(c.tipsIndex), s.HAS_SET_COLS_PATCH || c.setColsPatch(), void (s.HAS_SET_COLS_PATCH = !0))
},
// 在 `F` 构造函数的原型上定义一个名为 `eachCols` 的方法,这个方法接收一个参数 `e`,从方法名和代码逻辑推测可能是用于遍历表格的列信息并执行相应操作的功能,以下是方法内部的详细逻辑代码
F.prototype.eachCols = function (e) {
// 将当前调用此方法的 `F` 构造函数实例对象自身保存到变量 `t` 中,方便后续在方法内部引用实例对象的属性和方法等
var t = this;
// 调用 `d.eachCols` 函数(从前面代码推测 `d` 是一个包含了很多表格相关操作和属性的对象,`d.eachCols` 函数应该是用于执行通用的表格列遍历操作的函数,不过具体功能要结合其内部实现来看),传入 `null`(第一个参数的具体含义要结合 `d.eachCols` 函数的定义确定,这里传入 `null` 可能是一种默认情况或者占位的用法)、参数 `e`(要遍历的列相关信息,具体格式要结合调用处传入的内容确定)以及 `t.config.cols`(当前实例对象 `t` 的配置信息中的列信息,是一个数组或者对象结构,存储了表格各列的配置详情)作为参数,进行表格列的遍历操作,然后返回当前实例对象 `t`,这样可以支持链式调用(方便后续继续调用实例对象的其他方法等)
return d.eachCols(null, e, t.config.cols), t
},
// 在 `F` 构造函数的原型上定义一个名为 `renderData` 的方法,这个方法接收四个参数 `e`(要渲染的数据信息,可能是从服务器获取或者本地提取的表格数据)、`n`(可能是当前页码等相关信息)、`o`(从参数位置和代码逻辑推测可能是数据总数相关信息,不过具体含义要结合整体逻辑确定)、`r`(从代码逻辑推测可能是用于控制是否排序等相关操作的一个标识或者参数,不过具体含义要结合整体逻辑确定),用于将数据渲染到表格中进行展示,以下是方法内部的详细逻辑代码
F.prototype.renderData = function (e, n, o, r) {
// 将当前调用此方法的 `F` 构造函数实例对象自身保存到变量 `c` 中,方便后续在方法内部引用实例对象的属性和方法等
var c = this;
// 获取当前实例对象 `c` 的 `config` 对象(包含了表格的各种配置信息),并赋值给变量 `s`,方便后续通过 `s` 来访问配置信息中的各个属性
var s = c.config;
// 从 `e`(传入的要渲染的数据信息对象)中获取以 `s.response.dataName`(从配置对象中获取的表示数据字段名的属性)为键的值,如果不存在则使用空数组 `[]` 作为默认值,将获取到的数据数组赋值给变量 `u`,后续会基于这个数据数组来遍历并渲染到表格的每一行中
var u = e[s.response.dataName] || [];
// 创建一个空数组 `h`,从后续代码看这个数组可能用于存储一些临时的表格行相关的数据或者信息,不过具体用途要结合后续逻辑确定
var h = [];
// 创建一个空数组 `p`,同样从后续代码看这个数组可能用于存储一些临时的表格相关的数据或者信息,具体用途要结合后续逻辑确定
var p = [];
// 创建一个空数组 `v`,也是可能用于存储临时的表格相关的数据或者信息,具体作用要结合后续代码逻辑来看
var v = [];
// 创建一个匿名函数,并赋值给变量 `m`,这个函数内部包含了复杂的逻辑用于根据不同列类型、数据情况等来构建表格每一行每一列的 HTML 结构以及相关属性设置等操作,以下是函数内部的详细逻辑代码:
var m = function () {
var e;
// 判断如果参数 `r` 为假值(也就是可能表示不需要根据特定排序条件进行排序等情况)并且当前实例对象 `c` 的 `sortKey` 属性存在(从代码逻辑推测 `sortKey` 应该是用于记录排序相关的字段、排序方式等信息的属性,不过具体要结合前面代码对它的设置情况确定),则调用当前实例对象 `c` 的 `sort` 方法(从前面代码可知应该是用于对表格数据进行排序的方法,不过具体功能要结合其内部实现来看),传入 `c.sortKey.field`(排序的字段)、`c.sortKey.sort`(排序的类型,比如升序、降序等)以及 `!0`(表示可能是某种强制排序或者特定排序规则的标识,具体含义要结合 `sort` 方法的定义确定)作为参数,对数据进行排序操作;
// 如果不满足前面的条件(也就是不需要排序或者没有排序相关信息等情况),则执行以下代码块进行遍历数据并构建表格行、列 HTML 结构等操作:
return!r && c.sortKey? c.sort(c.sortKey.field, c.sortKey.sort,!0) : (
// 使用 `layui.each` 方法layui 框架自定义的用于循环遍历数组或者对象属性的方法,类似原生的 `forEach` 功能)遍历 `u` 数组(前面获取的要渲染的数据数组),在每次遍历中,参数 `a` 表示当前遍历的索引,`l` 表示当前遍历到的元素(也就是每一条数据记录,通常是一个对象结构,包含了各列对应的数据值等信息),以下是遍历过程中的详细逻辑代码:
layui.each(u, function (a, l) {
// 创建四个空数组 `o`、`u`、`f`、`m`,从后续代码看这些数组分别用于存储当前表格行中各列相关的一些临时信息,比如 HTML 结构片段、数据值、样式类名等情况,不过具体用途要结合后续逻辑确定
var o = [], u = [], f = [], m = a + s.limit * (n - 1) + 1;
// 判断如果当前遍历到的数据 `l` 的长度不为 `0`(也就是数据记录不为空,表示有实际的数据内容需要渲染),则执行以下代码块进行构建表格行、列 HTML 结构等操作:
0!== l.length && (
// 判断如果参数 `r` 为假值(也就是可能不需要进行某些特殊的索引设置等情况),则将当前数据记录 `l` 的 `d.config.indexName`(从配置对象中获取的用于标识数据索引的属性名)属性值设置为当前遍历的索引 `a`,用于记录这条数据在整个数据集中的索引位置,方便后续操作(比如排序、筛选等操作中通过索引来定位数据等情况);
r || (l[d.config.indexName] = a),
// 调用当前实例对象 `c` 的 `eachCols` 方法(前面定义的用于遍历表格列信息的方法),传入当前遍历的索引 `n`(这里传入的参数作用要结合 `eachCols` 方法内部实现确定,从前面代码看可能是用于在遍历列过程中传递当前数据记录的相关索引信息等情况)和当前遍历到的列相关配置信息 `r`(从代码逻辑推测 `r` 应该是包含了当前列的各种配置详情,比如列类型、是否隐藏、字段名等信息的对象,不过具体要结合前面代码对它的获取和设置情况确定)作为参数,进行表格列的遍历操作,在遍历列的过程中会根据列的配置信息等来构建每一列对应的 HTML 结构等内容,以下是 `eachCols` 方法内部以及后续构建列 HTML 结构等操作的详细逻辑代码:
c.eachCols(function (n, r) {
// 获取当前列的字段名,如果 `r`(当前列的配置对象)中存在 `field` 属性(也就是明确配置了对应的数据字段名),则使用 `r.field` 作为字段名,否则使用当前遍历的索引 `n` 作为字段名(可能是一种默认情况,比如对于没有明确配置字段名的特殊列等情况),将获取到的字段名赋值给变量 `c`,方便后续通过字段名来获取当前列对应的数据值等操作;
var c = r.field || n,
// 构建一个用于标识当前列的唯一字符串,格式为 `s.index`(当前实例对象 `c` 的配置信息中的索引值,用于区分不同的表格实例等情况)加上 `-` 再加上 `r.key`(从代码逻辑推测 `r.key` 可能是当前列的一个唯一标识或者是基于前面构建的列相关的索引等信息组成的字符串,不过具体要结合前面代码对它的获取和设置情况确定),将构建好的字符串赋值给变量 `h`,后续会在构建列的 HTML 结构中使用这个标识字符串来区分不同的列等情况;
h = s.index + "-" + r.key,
// 通过当前数据记录 `l` 中以 `c`(前面获取的当前列的字段名)为键的值来获取当前列对应的数据值,如果不存在则使用空字符串 `""` 作为默认值(通过 `void 0!== p && null!== p || (p = "")` 这个逻辑判断来确保数据值的有效性,避免出现 `undefined` 或者 `null` 等情况影响后续 HTML 结构构建等操作),将获取到的数据值赋值给变量 `p`,方便后续将数据值渲染到对应的列中显示;
p = l[c];
// 判断如果当前列的 `colGroup` 属性为假值(也就是当前列不属于列组等特殊情况,从代码逻辑推测 `colGroup` 用于标识列是否是一组相关列的一部分等情况,不过具体要结合前面代码对它的定义确定),则执行以下代码块进行构建当前列的 HTML 结构以及设置相关属性等操作:
if (void 0!== p && null!== p || (p = ""),!r.colGroup) {
// 创建一个包含表格单元格(`<td>` 元素HTML 结构片段的数组 `v`,并通过一系列模板语法(从代码中的 `{{#if...}}` 等格式推测是 layui 自定义的模板语法,类似 Handlebars 等模板引擎的语法风格,不过具体功能要结合 layui 框架对这些语法的定义确定)和 JavaScript 代码混合的方式来构建 `<td>` 元素的各种属性和内容,以下是构建 `<td>` 元素的详细逻辑代码:
var v = ['<td data-field="' + c + '" data-key="' + h + '" ' + function () {
var e = [];
// 判断如果当前列的 `edit` 属性存在(从代码逻辑推测 `edit` 可能是用于标识当前列是否可编辑等情况,不过具体要结合前面代码对它的定义确定),则将 `data-edit` 属性添加到 `<td>` 元素中,属性值为 `r.edit`(当前列的编辑相关配置信息),用于后续在表格编辑相关操作中识别可编辑列等情况;
return r.edit && e.push('data-edit="' + r.edit + '"'),
// 判断如果当前列的 `align` 属性存在(从代码逻辑推测 `align` 可能是用于标识当前列内容的对齐方式等情况,不过具体要结合前面代码对它的定义确定),则将 `align` 属性添加到 `<td>` 元素中,属性值为 `r.align`(当前列的对齐方式配置信息),用于设置列内容的对齐样式;
r.align && e.push('align="' + r.align + '"'),
// 判断如果当前列的 `templet` 属性存在(从代码逻辑推测 `templet` 可能是用于定义当前列内容的模板等情况,不过具体要结合前面代码对它的定义确定),则将 `data-content` 属性添加到 `<td>` 元素中,属性值为当前列对应的数据值 `p`(前面获取的),用于根据模板来渲染列内容等操作;
r.templet && e.push('data-content="' + p + '"'),
// 判断如果当前列的 `toolbar` 属性存在(从代码逻辑推测 `toolbar` 可能是用于标识当前列是否有工具栏等相关操作元素等情况,不过具体要结合前面代码对它的定义确定),则将 `data-off` 属性添加到 `<td>` 元素中,属性值为 `true`,用于控制工具栏等相关元素的显示隐藏等操作;
r.toolbar && e.push('data-off="true"'),
// 判断如果当前列的 `event` 属性存在(从代码逻辑推测 `event` 可能是用于定义当前列相关的事件等情况,不过具体要结合前面代码对它的定义确定),则将 `lay-event` 属性添加到 `<td>` 元素中,属性值为 `r.event`(当前列的事件相关配置信息),用于后续绑定列相关的事件操作;
r.event && e.push('lay-event="' + r.event + '"'),
// 判断如果当前列的 `style` 属性存在(从代码逻辑推测 `style` 可能是用于定义当前列的自定义样式等情况,不过具体要结合前面代码对它的定义确定),则将 `style` 属性添加到 `<td>` 元素中,属性值为 `r.style`(当前列的样式配置信息),用于设置列的额外样式;
r.style && e.push('style="' + r.style + '"'),
// 判断如果当前列的 `minWidth` 属性存在(从代码逻辑推测 `minWidth` 可能是用于定义当前列的最小宽度等情况,不过具体要结合前面代码对它的定义确定),则将 `data-minwidth` 属性添加到 `<td>` 元素中,属性值为 `r.minWidth`(当前列的最小宽度配置信息),用于限制列宽度不会过小等操作,最后将构建好的属性字符串数组通过 `join` 方法连接成一个完整的属性字符串,并返回这个属性字符串,用于添加到 `<td>` 元素的 HTML 结构中;
r.minWidth && e.push('data-minwidth="' + r.minWidth + '"'),
e.join(" ")
}() + ' class="' + function () {
var e = [];
// 判断如果当前列的 `hide` 属性存在且值为真(从代码逻辑推测 `hide` 可能是用于标识当前列是否隐藏等情况,不过具体要结合前面代码对它的定义确定),则将 `layui-hide` CSS 类名(从前面代码可知这个类名用于隐藏元素的样式类)添加到 `<td>` 元素的 `class` 属性中,用于隐藏当前列;
return r.hide && e.push(y),
// 判断如果当前列的 `field` 属性不存在(也就是前面没有明确配置字段名的特殊列等情况),则将 `layui-table-col-special` CSS 类名(从代码逻辑推测这个类名可能用于标识特殊类型的列等情况,不过具体要结合前面代码对它的定义确定)添加到 `<td>` 元素的 `class` 属性中,用于给这类特殊列添加特定的样式或者进行相关操作区分,最后将构建好的 CSS 类名数组通过 `join` 方法连接成一个完整的类名字符串,并返回这个类名字符串,用于添加到 `<td>` 元素的 `class` 属性中;
r.field || e.push("layui-table-col-special"),
// 判断当前列的 `field` 属性是否不存在(也就是该列在配置中没有明确指定对应的字段名),如果不存在,
// 则将 `"layui-table-col-special"` 这个 CSS 类名添加到数组 `e` 中,从代码上下文推测这个类名可能用于标识特殊类型的列,方便后续通过样式等方式对这类特殊列进行区分处理
e.join(" ");
// 将数组 `e` 中的元素使用空格连接成一个字符串,这个字符串将作为 `<td>` 元素 `class` 属性的一部分,用于设置单元格的样式类名,以体现该列的特殊属性或样式需求
}() + '">',
// 闭合前面构建的 `<td>` 元素的开始标签,至此完成了 `<td>` 元素属性部分的构建,接下来要在这个 `<td>` 元素内部构建具体的展示内容相关的 HTML 结构
'<div class="layui-table-cell laytable-cell-' + function () {
return "normal" === r.type? h : h + " laytable-cell-" + r.type
}() + '">',
// 根据当前列的类型(`r.type`)来构建表格单元格内部 `<div>` 元素的类名。如果列类型是 `"normal"`(普通类型),则类名设置为前面构建的 `h`(从代码逻辑看 `h` 应该是用于唯一标识该列的字符串),
// 如果不是普通类型,则类名设置为 `h` 加上 `"laytable-cell-"` 再加上具体的列类型,这样通过不同的类名可以方便后续针对不同类型列的单元格内容进行样式设置以及操作上的区分等,然后创建 `<div>` 元素的开始标签并添加相应的类名属性,用于包裹单元格内具体要展示的内容(如文本、输入框等元素)
function () {
var n = t.extend(!0, {LAY_INDEX: m}, l), o = d.config.checkName;
switch (r.type) {
case"checkbox":
return '<input type="checkbox" name="layTableCheckbox" lay-skin="primary" ' + function () {
return r[o]? (l[o] = r[o], r[o]? "checked" : "") : n[o]? "checked" : ""
}() + ">";
// 如果当前列类型是 `"checkbox"`(复选框类型),则构建一个 `<input>` 类型为 `checkbox`(复选框)的 HTML 元素,设置其 `name` 属性为 `"layTableCheckbox"``lay-skin` 属性为 `"primary"`(从代码逻辑推测这可能是用于设置复选框的外观样式,是 layui 框架自定义的一种样式设置方式),
// 然后通过判断条件来设置该复选框是否为选中状态。如果当前列配置对象 `r` 中存在以 `d.config.checkName`(从前面代码可知这是用于标识选中状态相关的属性名,比如可能是 `"LAY_CHECKED"` 之类的,具体值在 `d` 对象的配置中定义)为名称的属性,并且其值为真(也就是配置了该复选框默认选中),则将当前数据记录 `l` 中对应的选中状态属性(`l[o]`)设置为 `r[o]` 的值,并且根据 `r[o]` 的值来确定是否添加 `checked` 属性(如果 `r[o]` 为真则添加 `checked`,表示选中);
// 如果 `r` 中不存在该选中属性,则判断 `n``n` 是通过扩展当前数据记录 `l` 并添加 `LAY_INDEX` 属性后得到的对象,`LAY_INDEX` 属性值为前面计算的 `m`,用于标识该行数据的索引等相关信息)中是否存在以 `o`(也就是 `d.config.checkName`)为名称的属性且其值为真,如果是则添加 `checked` 属性,表示选中,最后返回构建好的 `<input>` 元素的 HTML 字符串
case"radio":
return n[o] && (e = a), '<input type="radio" name="layTableRadio_' + s.index + '" ' + (n[o]? "checked" : "") + ' lay-type="layTableRadio">';
// 如果当前列类型是 `"radio"`(单选框类型),首先判断 `n`(前面提到的扩展后的对象)中是否存在以 `o``d.config.checkName`)为名称的属性且其值为真(也就是是否有对应的选中状态配置),如果存在,则将变量 `e` 的值设置为当前行的索引 `a`(这里 `e` 的具体用途可能要结合后续代码来看,不过从当前逻辑推测可能是用于记录选中的单选框所在行等相关信息),
// 然后构建一个 `<input>` 类型为 `radio`(单选框)的 HTML 元素,设置其 `name` 属性为 `"layTableRadio_"` 加上当前表格实例的索引 `s.index`(用于区分不同表格实例中的单选框,确保同一表格内的单选框按组进行选择控制),根据 `n[o]` 的值来确定是否添加 `checked` 属性(如果 `n[o]` 为真则添加 `checked`,表示选中),并设置 `lay-type` 属性为 `"layTableRadio"`(同样从代码逻辑推测这可能是 layui 框架用于标识单选框的一种自定义属性,方便后续进行相关操作),最后返回构建好的 `<input>` 元素的 HTML 字符串
case"numbers":
return m;
// 如果当前列类型是 `"numbers"`(从代码逻辑推测可能是用于展示序号之类的数字列类型),则直接返回变量 `m` 的值,从前面代码可知 `m` 是根据当前行索引等信息计算出来的一个值,可能用于作为序号显示在该列单元格中
default:
return r.toolbar? i(t(r.toolbar).html() || "").render(n) : r.templet? function () {
return "function" == typeof r.templet? r.templet(n) : i(t(r.templet).html() || String(p)).render(n)
}() : p;
// 如果当前列类型不是上述几种特定类型,则进行以下逻辑判断:
// 如果当前列配置了 `toolbar`(从代码逻辑推测可能是表示该列有相关的工具栏等操作元素),则首先获取 `r.toolbar`(可能是包含工具栏 HTML 结构或者相关配置信息的内容,不过具体要结合其定义来看),通过 `t`(从前面代码推测可能是基于 jQuery 或者 layui 自定义的操作 DOM 元素等功能的函数或对象,类似 jQuery 的 `$` 函数)将其转换为 jQuery 对象(如果存在内容的话,否则使用空字符串 `""`),然后调用 `i`(从前面代码可知是 `laytpl` 模块相关的用于模板渲染的函数,可能是用于将特定模板内容渲染成实际的 HTML 结构)的 `render` 方法,传入 `n`(前面提到的扩展后的包含行索引等信息的对象)作为参数,将渲染后的结果作为该单元格的内容返回;
// 如果当前列配置了 `templet`(从代码逻辑推测可能是用于定义该列内容的模板信息,比如可以自定义如何展示数据等情况),则进行以下判断:如果 `r.templet` 是函数类型,则直接调用 `r.templet` 函数,传入 `n` 作为参数,将函数返回的结果作为单元格内容返回;如果 `r.templet` 不是函数类型,则先获取 `r.templet`(同样可能是包含模板 HTML 结构或者相关配置信息的内容,通过 `t` 转换为 jQuery 对象,如果存在内容则获取其 `html` 内容,否则使用数据值 `p` 转换为字符串形式),然后调用 `i` 的 `render` 方法,传入 `n` 作为参数,将渲染后的结果作为单元格内容返回;
// 如果当前列既没有配置 `toolbar` 也没有配置 `templet`,则直接返回数据值 `p`(前面从当前数据记录中根据列字段名获取到的对应列的数据值)作为单元格内容
}
}(), "</div></td>"].join("");
// 将前面构建的包含单元格内部内容的函数执行结果(也就是最终的单元格内部 `<div>` 元素及其内容等完整的 HTML 字符串)、闭合 `<div>` 元素的 `</div>` 标签以及闭合 `<td>` 元素的 `</td>` 标签通过 `join` 方法连接成一个完整的字符串,形成一个完整的表格单元格(`<td>` 元素)的 HTML 结构字符串,用于后续添加到表格行中展示
o.push(v),
// 将构建好的当前列的 `<td>` 元素 HTML 结构字符串所在的数组 `v`(从前面代码可知是用于存储当前行各列相关的临时 HTML 结构等信息的数组之一)添加到数组 `o` 中,从代码逻辑推测 `o` 可能是用于存储当前行非固定列的 `<td>` 元素 HTML 结构字符串的数组,方便后续将这些非固定列的单元格组合成完整的表格行
r.fixed && "right"!== r.fixed && u.push(v),
// 判断如果当前列配置了 `fixed` 属性(表示该列是固定列,比如固定在左侧或者右侧不随表格滚动而滚动的列),并且 `fixed` 属性的值不是 `"right"`(也就是固定在左侧的列),则将构建好的当前列的 `<td>` 元素 HTML 结构字符串所在的数组 `v` 添加到数组 `u` 中,从代码逻辑推测 `u` 可能是用于存储当前行固定在左侧的列的 `<td>` 元素 HTML 结构字符串的数组,用于后续构建固定在左侧的列所在的表格行
"right" === r.fixed && f.push(v);
// 判断如果当前列的 `fixed` 属性值是 `"right"`(也就是固定在右侧的列),则将构建好的当前列的 `<td>` 元素 HTML 结构字符串所在的数组 `v` 添加到数组 `f` 中,从代码逻辑推测 `f` 可能是用于存储当前行固定在右侧的列的 `<td>` 元素 HTML 结构字符串的数组,用于后续构建固定在右侧的列所在的表格行
}
// 结束当前 `eachCols` 方法内部的遍历列的逻辑代码块(这个 `eachCols` 方法是在 `renderData` 方法内部调用,用于遍历每一行数据中的每一列来构建相应的 HTML 结构)
h.push('<tr data-index="' + a + '">' + o.join("") + "</tr>"),
// 将一个包含 `<tr>` (表格行)元素开始标签、设置 `data-index` 属性为当前行的索引 `a`(用于标识该行数据的索引,方便后续操作,比如定位行、处理行相关事件等)、通过 `o.join("")` 将前面存储的当前行非固定列的 `<td>` 元素 HTML 结构字符串连接成一个完整的字符串作为表格行的内容、以及 `<tr>` 元素的闭合标签 `</tr>` 的完整字符串添加到数组 `h` 中,从代码逻辑推测 `h` 是用于存储包含非固定列的表格行 HTML 结构字符串的数组,方便后续将这些行添加到表格主体区域进行展示
p.push('<tr data-index="' + a + '">' + u.join("") + "</tr>"),
// 类似上面的操作,将一个包含 `<tr>` 元素开始标签、设置 `data-index` 属性为当前行的索引 `a`、通过 `u.join("")` 将前面存储的当前行固定在左侧的列的 `<td>` 元素 HTML 结构字符串连接成一个完整的字符串作为表格行的内容、以及 `<tr>` 元素的闭合标签 `</tr>` 的完整字符串添加到数组 `p` 中,从代码逻辑推测 `p` 是用于存储包含固定在左侧的列的表格行 HTML 结构字符串的数组,用于后续添加到表格左侧固定列区域进行展示
v.push('<tr data-index="' + a + '">' + f.join("") + "</tr>");}
// 同样的操作,将一个包含 `<tr>` 元素开始标签、设置 `data-index` 属性为当前行的索引 `a`、通过 `f.join("")` 将前面存储的当前行固定在右侧的列的 `<td>` 元素 HTML 结构字符串连接成一个完整的字符串作为表格行的内容、以及 `<tr>` 元素的闭合标签 `</tr>` 的完整字符串添加到数组 `v` 中,从代码逻辑推测 `v` 是用于存储包含固定在右侧的列的表格行 HTML 结构字符串的数组,用于后续添加到表格右侧固定列区域进行展示
)), c.layBody.scrollTop(0),
// 调用当前表格实例对象 `c` 的 `layBody`(从前面代码推测应该是指向表格主体内容所在的 DOM 元素或者 jQuery 对象,用于操作表格主体区域相关内容)的 `scrollTop` 方法,将其滚动条位置设置为 `0`,也就是将表格主体内容区域的滚动条滚动到顶部位置,可能是为了在重新渲染数据后确保展示效果的一致性,让用户看到最新的数据从顶部开始展示
c.layMain.find("." + f).remove(),
// 通过 `c.layMain`(同样指向表格主体内容所在区域的元素)调用 `find` 方法,查找所有包含 `f` CSS 类名(从前面代码可知 `f` 是一个用于标识某种特定样式状态的类名,比如元素不可见或者错误提示样式等相关的样式语义)的元素,并调用 `remove` 方法将这些元素从 DOM 中移除,可能是在重新渲染数据前先清理掉之前残留的一些不需要的元素(比如之前显示错误提示等相关元素)
c.layMain.find("tbody").html(h.join("")),
// 通过 `c.layMain` 找到其内部的 `<tbody>` 元素(表格主体内容通常放在 `<tbody>` 元素内),然后调用 `html` 方法(可能是 jQuery 的 `html` 方法,用于设置元素的内部 HTML 内容),将前面构建好的包含非固定列的表格行 HTML 结构字符串数组 `h` 通过 `join` 方法连接成一个完整的字符串后设置为 `<tbody>` 元素的内部 HTML 内容,这样就将非固定列的数据行渲染到了表格主体区域进行展示
c.layFixLeft.find("tbody").html(p.join("")),
// 通过 `c.layFixLeft`(从前面代码推测是指向表格左侧固定列所在区域的元素)找到其内部的 `<tbody>` 元素,调用 `html` 方法将包含固定在左侧的列的表格行 HTML 结构字符串数组 `p` 通过 `join` 方法连接成一个完整的字符串后设置为 `<tbody>` 元素的内部 HTML 内容,实现将左侧固定列的数据行渲染到相应区域进行展示
c.layFixRight.find("tbody").html(v.join("")),
// 通过 `c.layFixRight`(指向表格右侧固定列所在区域的元素)找到其内部的 `<tbody>` 元素,调用 `html` 方法将包含固定在右侧的列的表格行 HTML 结构字符串数组 `v` 通过 `join` 方法连接成一个完整的字符串后设置为 `<tbody>` 元素的内部 HTML 内容,将右侧固定列的数据行渲染到相应区域进行展示
c.renderForm(),
// 调用当前表格实例对象 `c` 的 `renderForm` 方法(从代码逻辑推测可能是用于重新渲染表格的表单部分或者处理表单相关的显示逻辑等功能,不过具体功能要结合其内部实现来看),进行表单相关的渲染操作(如果表格中有表单元素的话)
"number" == typeof e && c.setThisRowChecked(e),
// 判断传入的参数 `e` 是否是数字类型,如果是数字类型,则调用当前表格实例对象 `c` 的 `setThisRowChecked` 方法(从方法名推测可能是用于设置指定行(根据传入的数字索引)为选中状态等相关操作的功能,不过具体功能要结合其内部实现来看),传入 `e` 作为参数,执行相应的设置行选中状态的操作
c.syncCheckAll(),
// 调用当前表格实例对象 `c` 的 `syncCheckAll` 方法(从方法名推测可能是用于同步所有选中状态相关操作的功能,比如确保复选框、单选框等选中状态在整个表格中的一致性等情况,不过具体功能要结合其内部实现来看),进行选中状态的同步操作
c.haveInit? c.scrollPatch() : setTimeout(function () {
c.scrollPatch();
}, 50),
// 判断当前表格实例对象 `c` 的 `haveInit` 属性(从代码逻辑推测可能是用于标识表格是否已经初始化完成的属性)是否为真,如果为真,则直接调用 `c` 的 `scrollPatch` 方法(从方法名推测可能是用于处理表格滚动相关的一些问题或者设置滚动相关的属性等功能,不过具体功能要结合其内部实现来看),进行滚动相关的处理操作;
// 如果 `haveInit` 为假(也就是表格还未初始化完成),则使用 `setTimeout` 函数设置一个延迟为 `50` 毫秒的定时器,在定时器回调函数中调用 `c.scrollPatch` 方法,也就是等一小段时间后再进行滚动相关的处理操作,这样做可能是为了确保在表格相关元素都准备好之后再进行滚动相关操作,避免出现问题
c.haveInit =!0,
// 将当前表格实例对象 `c` 的 `haveInit` 属性设置为 `true`,表示表格已经完成初始化操作,后续再进入这个逻辑判断时就可以直接执行 `scrollPatch` 方法等相关操作了
l.close(c.tipsIndex);
// 通过 `l`(从前面代码可知是 `layer` 模块相关的用于弹出 s.HAS_SET_COLS_PATCH || c.setColsPatch(), void (s.HAS_SET_COLS_PATCH = !0))
};
return c.key = s.id || s.index, d.cache[c.key] = u, c.layPage[0 == o || 0 === u.length && 1 == n ? "addClass" : "removeClass"](y), r ? m() : 0 === u.length ? (c.renderForm(), c.layFixed.remove(), c.layMain.find("tbody").html(""), c.layMain.find("." + f).remove(), c.layMain.append('<div class="' + f + '">' + s.text.none + "</div>")) : (m(), c.renderTotal(u), void (s.page && (s.page = t.extend({
elem: "layui-table-page" + s.index,
count: o,
limit: s.limit,
limits: s.limits || [10, 20, 30, 40, 50, 60, 70, 80, 90],
groups: 3,
layout: ["prev", "page", "next", "skip", "count", "limit"],
prev: '<i class="layui-icon">&#xe603;</i>',
next: '<i class="layui-icon">&#xe602;</i>',
jump: function (e, t) {
t || (c.page = e.curr, s.limit = e.limit, c.loading(), c.pullData(e.curr))
}
}, s.page), s.page.count = o, a.render(s.page))))
}, F.prototype.renderTotal = function (e) {
var t = this, i = t.config, a = {};
if (i.totalRow) {
layui.each(e, function (e, i) {
0 !== i.length && t.eachCols(function (e, t) {
var l = t.field || e, n = i[l];
t.totalRow && (a[l] = (a[l] || 0) + (parseFloat(n) || 0))
})
});
// 这一行代码执行了多个操作并返回最后一个操作的结果在JavaScript中逗号表达式会依次执行各个表达式最后返回最后一个表达式的值
return c.key = s.id || s.index,
// 将 `s.id` 或者 `s.index` 的值赋给 `c.key`(从代码上下文推测,`c` 是当前表格实例相关的对象,`s` 是表格的配置对象,这里是为 `c.key` 设置一个唯一标识,可能基于配置中的 `id` 属性,如果不存在则使用 `index` 属性值),同时这个赋值表达式的值(也就是赋给 `c.key` 的值)会作为逗号表达式的一部分继续参与后续运算
d.cache[c.key] = u,
// 以 `c.key`(前面刚设置好的唯一标识)作为键,将 `u`(从前面代码推测应该是要渲染的表格数据数组或者经过处理后的相关数据内容)存储到 `d.cache` 对象中(从代码逻辑看 `d.cache` 是用于缓存表格相关数据的对象,方便后续在其他地方根据这个唯一标识来获取对应的数据),这个赋值表达式同样作为逗号表达式的一部分继续参与后续运算
c.layPage[0 == o || 0 === u.length && 1 == n? "addClass" : "removeClass"](y),
// 根据条件判断来为 `c.layPage`(从代码逻辑推测 `c.layPage` 可能是指向表格分页相关的 DOM 元素或者 jQuery 对象,用于操作分页部分的样式等情况)添加或移除 `y` CSS 类名(从前面代码可知 `y` 应该是一个特定的 CSS 类名,用于控制元素的显示隐藏等样式相关情况)。判断条件为:如果 `o` 的值等于 `0``o` 的具体含义从前面代码推测可能是数据总数相关信息,等于 `0` 表示没有数据),或者 `u.length`(也就是要渲染的数据数组长度)等于 `0` 并且 `n` 的值等于 `1``n` 的具体含义结合前面代码推测可能是当前页码等相关信息),则调用 `addClass` 方法添加 `y` 类名;否则调用 `removeClass` 方法移除 `y` 类名,这个方法调用表达式同样作为逗号表达式的一部分继续参与后续运算
r? m() : 0 === u.length? (
// 判断变量 `r` 的值,如果 `r` 为真(具体 `r` 的含义要结合前面代码逻辑确定,可能是用于控制某种渲染逻辑的标识等情况),则调用函数 `m`(从前面代码可知 `m` 函数内部包含了构建表格行、列 HTML 结构以及相关数据渲染等复杂逻辑);如果 `r` 为假,再判断 `u.length`(要渲染的数据数组长度)是否等于 `0`(也就是是否没有数据可渲染),如果等于 `0`,则执行以下代码块进行无数据时的相关操作处理:
c.renderForm(),
// 调用当前表格实例对象 `c` 的 `renderForm` 方法(从代码逻辑推测可能是用于重新渲染表格的表单部分或者处理表单相关的显示逻辑等功能,不过具体功能要结合其内部实现来看),进行表单相关的处理(比如在没有数据时隐藏表单或者显示特定提示等情况)
c.layFixed.remove(),
// 调用 `c.layFixed`(从代码逻辑推测可能是指向表格中固定列相关的 DOM 元素或者 jQuery 对象,用于操作固定列部分的显示等情况)的 `remove` 方法,将固定列相关的元素从 DOM 中移除,可能在没有数据时不需要显示固定列部分
c.layMain.find("tbody").html(""),
// 通过 `c.layMain`(从代码逻辑推测是指向表格主体内容所在的 DOM 元素或者 jQuery 对象,用于操作表格主体区域的显示内容)找到其内部的 `<tbody>` 元素(表格主体内容通常放在 `<tbody>` 元素内),然后调用 `html` 方法(可能是 jQuery 的 `html` 方法,用于设置元素的内部 HTML 内容)将其内容设置为空字符串,也就是清空表格主体区域原本的内容,因为没有数据需要展示了
c.layMain.find("." + f).remove(),
// 通过 `c.layMain` 调用 `find` 方法查找所有包含 `f` CSS 类名(从前面代码可知 `f` 是一个用于标识某种特定样式状态的类名,比如元素不可见或者错误提示样式等相关的样式语义)的元素,并调用 `remove` 方法将这些元素从 DOM 中移除,可能是清理之前显示的一些提示信息等相关元素
c.layMain.append('<div class="' + f + '">' + s.text.none + "</div>")
// 通过 `c.layMain` 调用 `append` 方法,向表格主体区域添加一个包含特定 CSS 类名 `f` 和 `s.text.none`(从代码逻辑推测 `s.text.none` 应该是在配置中定义的用于显示无数据时的提示文本内容)的 `<div>` 元素,用于在表格没有数据时显示相应的无数据提示信息
) : (
// 如果前面判断 `u.length` 不等于 `0`(也就是有数据可渲染),则执行以下代码块进行正常的数据渲染及相关操作:
m(),
// 调用函数 `m`(前面提到的用于构建表格行、列 HTML 结构以及相关数据渲染等复杂逻辑的函数),进行数据渲染操作,构建表格的行、列结构并将数据展示到表格中
c.renderTotal(u),
// 调用当前表格实例对象 `c` 的 `renderTotal` 方法(下面就是这个方法的具体定义,从方法名推测是用于渲染表格数据的总计相关信息,比如统计各列数据的总和等情况),传入 `u`(要渲染的数据数组)作为参数,进行总计相关信息的渲染操作
void (s.page && (s.page = t.extend({
// 判断 `s.page`(从代码逻辑推测 `s` 是表格配置对象,`s.page` 应该是与分页相关的配置信息部分)是否存在(也就是是否配置了分页相关信息),如果存在,则使用 `t.extend` 方法(可能是基于 jQuery 或者 layui 自定义的扩展对象属性的方法,将两个对象的属性合并到一起)将一个包含分页相关默认配置信息的对象与 `s.page`(原有的分页配置信息)进行合并,以下是各个分页配置属性的详细介绍:
elem: "layui-table-page" + s.index,
// 设置分页元素的选择器标识,格式为 `"layui-table-page"` 加上当前表格实例的索引 `s.index`,用于在页面中定位到对应的分页 DOM 元素,方便后续操作(比如绑定事件、更新样式等情况)
count: o,
// 设置数据的总数量,从变量 `o` 获取(前面代码可知 `o` 与数据总数相关信息),用于分页组件知道总共有多少条数据来进行分页计算等操作
limit: s.limit,
// 设置每页显示的数据数量限制,从 `s.limit`(表格配置中的对应属性)获取,用于确定每页展示多少条数据
limits: s.limits || [10, 20, 30, 40, 50, 60, 70, 80, 90],
// 设置每页数据数量的可选限制值数组,如果 `s.limits`(表格配置中的对应属性)存在,则使用其值作为可选限制值,否则使用默认的数组 `[10, 20, 30, 40, 50, 60, 70, 80, 90]`,用于在分页组件中提供给用户选择每页显示多少条数据的下拉选项等情况
groups: 3,
// 设置分页页码分组数量,这里设置为 `3`,从代码逻辑推测可能是用于控制分页页码显示的分组情况,比如显示当前页前后各几页的页码等相关的分组展示逻辑,不过具体功能要结合分页组件的实现来看
layout: ["prev", "page", "next", "skip", "count", "limit"],
// 设置分页组件的布局结构,是一个包含字符串元素的数组,每个字符串代表分页组件中要显示的一个功能模块,比如 `"prev"` 表示上一页按钮,`"page"` 表示页码显示区域,`"next"` 表示下一页按钮,`"skip"` 表示跳转到指定页输入框,`"count"` 表示数据总数显示区域,`"limit"` 表示每页数据数量选择下拉框等,通过这个数组来定义分页组件的整体布局样式
prev: '<i class="layui-icon">&#xe603;</i>',
// 设置上一页按钮的 HTML 图标内容,这里使用了 layui 框架自定义的图标字体类名 `<i class="layui-icon">&#xe603;</i>`,用于显示一个向左的箭头图标作为上一页按钮的样式
next: '<i class="layui-icon">&#xe602;</i>',
// 设置下一页按钮的 HTML 图标内容,使用 `<i class="layui-icon">&#xe602;</i>`(向右的箭头图标)作为下一页按钮的样式
jump: function (e, t) {
t || (c.page = e.curr, s.limit = e.limit, c.loading(), c.pullData(e.curr))
}
// 设置分页组件中页码跳转相关的回调函数,当用户点击页码或者使用跳转到指定页输入框等操作进行页码跳转时,会触发这个回调函数。函数接收两个参数 `e`(包含了当前页码等相关信息的对象,比如 `e.curr` 表示当前跳转后的页码)和 `t`(从代码逻辑推测可能是用于判断是否是用户主动点击等情况的标识参数,不过具体含义要结合分页组件的实现来看),在回调函数内部,如果 `t` 为假(也就是用户主动进行了页码跳转操作等情况),则将当前表格实例对象 `c` 的 `page` 属性(用于记录当前页码)设置为 `e.curr`(跳转后的页码),将 `s.limit`(每页数据数量限制属性)设置为 `e.limit`(可能是用户选择了新的每页数据数量等情况),然后调用 `c.loading` 方法(从代码逻辑推测可能是用于显示加载提示等相关操作的方法,比如在切换页码加载新数据时显示加载中提示),再调用 `c.pullData` 方法(前面代码可知这个方法用于根据页码等信息拉取对应的数据),传入 `e.curr`(当前跳转后的页码)作为参数,进行数据的重新拉取和渲染操作
}, s.page), s.page.count = o, a.render(s.page))))
);
// 结束当前 `renderData` 方法的定义,返回相应的结果(根据前面代码逻辑,也就是执行完上述一系列操作后的最终状态,比如表格渲染完成、分页配置更新等情况)
// 在 `F` 构造函数的原型上定义一个名为 `renderTotal` 的方法,这个方法接收一个参数 `e`(从前面代码推测 `e` 应该是要渲染的表格数据数组,用于统计各列数据的总计等相关信息),用于渲染表格数据的总计相关信息,以下是方法内部的详细逻辑代码
F.prototype.renderTotal = function (e) {
var t = this,
// 将当前调用此方法的 `F` 构造函数实例对象自身保存到变量 `t` 中,方便后续在方法内部引用实例对象的属性和方法等
i = t.config,
// 获取当前实例对象 `t` 的 `config` 对象(包含了表格的各种配置信息),并赋值给变量 `i`,方便后续通过 `i` 来访问配置信息中的各个属性
a = {};
// 创建一个空对象 `a`,从后续代码看这个对象用于存储各列数据总计的结果,以列字段名作为键,总计值作为值,方便后续将总计信息渲染到表格中相应位置展示
if (i.totalRow) {
// 判断当前实例对象 `t` 的 `config` 对象中的 `totalRow` 属性是否存在且值为真(从代码逻辑推测 `totalRow` 应该是用于标识是否需要渲染数据总计信息的一个配置开关属性,值为真表示需要进行总计信息的渲染操作),如果是,则执行以下代码块进行数据总计的计算和相关处理操作:
layui.each(e, function (e, i) {
// 使用 `layui.each` 方法layui 框架自定义的用于循环遍历数组或者对象属性的方法,类似原生的 `forEach` 功能)遍历参数 `e`(要渲染的表格数据数组),在每次遍历中,参数 `e` 表示当前遍历的索引,`i` 表示当前遍历到的元素(也就是每一条数据记录,通常是一个对象结构,包含了各列对应的数据值等信息),以下是遍历过程中的详细逻辑代码:
0!== i.length && t.eachCols(function (e, t) {
// 判断当前遍历到的数据记录 `i` 的长度是否不为 `0`(也就是数据记录不为空,表示有实际的数据内容需要进行总计计算等操作),如果不为 `0`,则调用当前实例对象 `t` 的 `eachCols` 方法(从前面代码可知这个方法用于遍历表格的列信息并执行相应操作的功能),传入当前遍历的索引 `e`(这里传入的参数作用要结合 `eachCols` 方法内部实现确定,从前面代码看可能是用于在遍历列过程中传递当前数据记录的相关索引信息等情况)和当前遍历到的列相关配置信息 `t`(从代码逻辑推测 `t` 应该是包含了当前列的各种配置详情,比如列类型、是否隐藏、字段名等信息的对象,不过具体要结合前面代码对它的获取和设置情况确定)作为参数,进行表格列的遍历操作,在遍历列的过程中会根据列的配置信息等来计算每列数据的总计值等操作,以下是 `eachCols` 方法内部以及后续计算列总计值等操作的详细逻辑代码:
var l = t.field || e,
// 获取当前列的字段名,如果 `t`(当前列的配置对象)中存在 `field` 属性(也就是明确配置了对应的数据字段名),则使用 `t.field` 作为字段名,否则使用当前遍历的索引 `e` 作为字段名(可能是一种默认情况,比如对于没有明确配置字段名的特殊列等情况),将获取到的字段名赋值给变量 `l`,方便后续通过字段名来获取当前列对应的数据值等操作
n = i[l];
// 通过当前数据记录 `i` 中以 `l`(前面获取的当前列的字段名)为键的值来获取当前列对应的数据值,将获取到的数据值赋值给变量 `n`,方便后续进行数据值的计算(比如求和等操作)
t.totalRow && (a[l] = (a[l] || 0) + (parseFloat(n) || 0))
// 判断当前列的 `totalRow` 属性是否存在且值为真(从代码逻辑推测当前列的 `totalRow` 属性用于标识是否需要对该列数据进行总计计算,值为真表示需要计算),如果是,则进行以下总计值的计算操作:
// 将对象 `a`(用于存储各列数据总计结果的对象)中以 `l`(当前列的字段名)为键的值进行更新,更新的逻辑是先获取原来的值(如果不存在则默认为 `0`,通过 `a[l] || 0` 实现),然后加上将当前列对应的数据值 `n` 转换为浮点数(通过 `parseFloat` 方法转换,如果 `n` 本身就是数字字符串等可转换类型则转换为数字,否则转换为 `0`,通过 `(parseFloat(n) || 0)` 实现)后的结果,这样就实现了对每列数据的累加求和操作,将每列数据的总计值存储在对象 `a` 中,方便后续渲染到表格相应位置展示
})
});
}
};
// 初始化一个空数组用于存储单元格HTML
var l = [];
// 遍历表格的列配置
t.eachCols(function (e, t) {
// 获取列的字段名,如果没有则使用索引
var n = t.field || e,
// 构建单元格的HTML字符串
o = ['<td data-field="' + n + '" data-key="' + i.index + "-" + t.key + '" ' + function () {
// 构建单元格的属性字符串
var e = [];
return t.align && e.push('align="' + t.align + '"'), t.style && e.push('style="' + t.style + '"'), t.minWidth && e.push('data-minwidth="' + t.minWidth + '"'), e.join(" ")
// 如果设置了对齐方式,则添加对齐属性
t.align && e.push('align="' + t.align + '"'),
// 如果设置了样式,则添加样式属性
t.style && e.push('style="' + t.style + '"'),
// 如果设置了最小宽度,则添加最小宽度属性
t.minWidth && e.push('data-minwidth="' + t.minWidth + '"'),
// 返回属性字符串
e.join(" ")
}() + ' class="' + function () {
// 构建单元格的类名字符串
var e = [];
return t.hide && e.push(y), t.field || e.push("layui-table-col-special"), e.join(" ")
}() + '">', '<div class="layui-table-cell laytable-cell-' + function () {
var e = i.index + "-" + t.key;
return "normal" === t.type ? e : e + " laytable-cell-" + t.type
}() + '">' + function () {
var e = t.totalRowText || "";
return t.totalRow ? parseFloat(a[n]).toFixed(2) || e : e
}(), "</div></td>"].join("");
// 如果列被隐藏,则添加隐藏类名
t.hide && e.push(y),
// 如果列没有字段名,则添加特殊列类名
t.field || e.push("layui-table-col-special"),
// 返回类名字符串
e.join(" ")
}() + '">',
// 构建单元格内容
'<div class="layui-table-cell laytable-cell-' + function () {
// 获取单元格的类名
var e = i.index + "-" + t.key;
// 根据列类型添加不同的类名
return "normal" === t.type ? e : e + " laytable-cell-" + t.type
}() + '">' + function () {
// 获取总计行文本,如果没有则使用空字符串
var e = t.totalRowText || "";
// 如果是总计行,则显示数值,否则显示文本
return t.totalRow ? parseFloat(a[n]).toFixed(2) || e : e
}(),
// 结束单元格内容并关闭单元格标签
"</div></td>"].join("");
// 将构建的单元格HTML添加到数组中
l.push(o)
}), t.layTotal.find("tbody").html("<tr>" + l.join("") + "</tr>")
}
}, F.prototype.getColElem = function (e, t) {
var i = this, a = i.config;
return e.eq(0).find(".laytable-cell-" + (a.index + "-" + t) + ":eq(0)")
}, F.prototype.renderForm = function (e) {
n.render(e, "LAY-table-" + this.index)
}, F.prototype.setThisRowChecked = function (e) {
var t = this, i = (t.config, "layui-table-click"), a = t.layBody.find('tr[data-index="' + e + '"]');
a.addClass(i).siblings("tr").removeClass(i)
}, F.prototype.sort = function (e, i, a, l) {
var n, r, c = this, s = {}, h = c.config, y = h.elem.attr("lay-filter"), f = d.cache[c.key];
"string" == typeof e && c.layHeader.find("th").each(function (i, a) {
var l = t(this), o = l.data("field");
if (o === e) return e = l, n = o, !1
});
try {
}),
// 将所有单元格HTML组合成一行并设置到总计行的tbody中
t.layTotal.find("tbody").html("<tr>" + l.join("") + "</tr>");
// F类的原型方法用于获取指定列的单元格元素
F.prototype.getColElem = function (e, t) {
var i = this, a = i.config;
// 返回指定列的单元格元素
return e.eq(0).find(".laytable-cell-" + (a.index + "-" + t) + ":eq(0)")
};
// F类的原型方法用于渲染表单
F.prototype.renderForm = function (e) {
// 渲染表单,并设置表单的唯一标识
n.render(e, "LAY-table-" + this.index)
};
// F类的原型方法用于设置当前行的选中状态
F.prototype.setThisRowChecked = function (e) {
var t = this, i = "layui-table-click", a = t.layBody.find('tr[data-index="' + e + '"]');
// 为当前行添加选中类,并移除其他行的选中类
a.addClass(i).siblings("tr").removeClass(i)
};
// F类的原型方法用于对表格进行排序
F.prototype.sort = function (e, i, a, l) {
var n, r, c = this, s = {}, h = c.config, y = h.elem.attr("lay-filter"), f = d.cache[c.key];
// 如果排序字段是字符串,则找到对应的列元素
"string" == typeof e && c.layHeader.find("th").each(function (i, a) {
var l = t(this), o = l.data("field");
// 如果找到匹配的列,则设置列元素和字段名
if (o === e) return e = l, n = o, !1
});
try {
var n = n || e.data("field"), p = e.data("key");
if (c.sortKey && !a && n === c.sortKey.field && i === c.sortKey.sort) return;
var v = c.layHeader.find("th .laytable-cell-" + p).find(S);
@ -603,50 +979,119 @@
i.PARENT_COL_INDEX || n.push(i)
})
});
// 定义一个函数 `r`,它接收一个参数 `e`,从后续代码看这个函数可能用于递归遍历处理一些表格相关的数据结构(比如包含子列信息的表格列数据等情况),以下是函数内部的详细逻辑代码
var r = function (e) {
// 使用 `layui.each` 方法(从前面代码推测是 layui 框架自定义的用于循环遍历对象属性或者数组元素的方法,类似原生的 `forEach` 功能)遍历传入的参数 `e`,如果 `e` 为假值(比如 `undefined`、`null` 等情况),则使用变量 `n` 作为默认的遍历对象(这里 `n` 的具体值需要看前面代码的定义情况,不过从整体逻辑推测应该是和表格列数据相关的一个数组或者对象结构),在每次遍历中,参数 `e` 表示当前遍历的索引或者键名(取决于 `e` 是数组还是对象),`t` 表示当前遍历到的元素值,以下是遍历过程中的具体逻辑判断:
layui.each(e || n, function (e, t) {
return t.CHILD_COLS ? r(t.CHILD_COLS) : void ("function" == typeof i && i(e, t))
// 判断当前元素 `t` 中是否存在 `CHILD_COLS` 属性(从属性名推测可能表示当前列是否有子列信息,如果有则意味着这是一个可以继续展开遍历的结构),如果存在 `CHILD_COLS` 属性,则递归调用 `r` 函数,并传入 `t.CHILD_COLS`(也就是子列的数据结构)继续进行遍历处理;
// 如果不存在 `CHILD_COLS` 属性,则判断 `i` 是否是函数类型(这里 `i` 的具体值需要看前面代码的定义情况,不过从整体逻辑推测应该是一个用于处理表格列数据的回调函数等情况),如果 `i` 是函数类型,则调用 `i` 函数,并传入当前遍历的索引或键名 `e` 和元素值 `t` 进行相应的数据处理操作,最后通过 `return` 语句返回相应的结果(如果有返回值的话,不过从代码逻辑看这里更多是执行一些操作而不是返回特定的值给外部),如果 `i` 不是函数类型则不做任何操作(通过 `void` 关键字表示不返回任何值)
return t.CHILD_COLS? r(t.CHILD_COLS) : void ("function" == typeof i && i(e, t))
})
};
r()
}, d.checkStatus = function (e) {
var t = 0, i = 0, a = [], l = d.cache[e] || [];
return layui.each(l, function (e, l) {
return l.constructor === Array ? void i++ : void (l[d.config.checkName] && (t++, a.push(d.clearCacheKey(l))))
}), {data: a, isAll: !!l.length && t === l.length - i}
}, d.exportFile = function (e, t, i) {
t = t || d.clearCacheKey(d.cache[e]), i = i || "csv";
var a = c.config[e] || {}, l = {csv: "text/csv", xls: "application/vnd.ms-excel"}[i],
n = document.createElement("a");
return r.ie ? o.error("IE_NOT_SUPPORT_EXPORTS") : (n.href = "data:" + l + ";charset=utf-8,\ufeff" + encodeURIComponent(function () {
var i = [], a = [];
return layui.each(t, function (t, l) {
var n = [];
"object" == typeof e ? (layui.each(e, function (e, a) {
0 == t && i.push(a || "")
}), layui.each(d.clearCacheKey(l), function (e, t) {
n.push(t)
})) : d.eachCols(e, function (e, a) {
a.field && "normal" == a.type && !a.hide && (0 == t && i.push(a.title || ""), n.push(l[a.field]))
}), a.push(n.join(","))
}), i.join(",") + "\r\n" + a.join("\r\n")
}()), n.download = (a.title || "table_" + (a.index || "")) + "." + i, document.body.appendChild(n), n.click(), void document.body.removeChild(n))
}, d.resize = function (e) {
if (e) {
var t = s(e);
if (!t) return;
c.that[e].resize()
} else layui.each(c.that, function () {
this.resize()
})
}, d.reload = function (e, i) {
i = i || {};
var a = s(e);
if (a) return i.data && i.data.constructor === Array && delete a.data, d.render(t.extend(!0, {}, a, i))
}, d.render = function (e) {
var t = new F(e);
return c.call(t)
}, d.clearCacheKey = function (e) {
return e = t.extend({}, e), delete e[d.config.checkName], delete e[d.config.indexName], e
}, d.init(), e(u, d)
});
// 调用 `r` 函数,由于没有传入参数,所以会使用默认的 `n` 对象(前面提到的和表格列数据相关的结构,具体值看前面代码定义)进行遍历处理(具体处理逻辑在 `r` 函数内部实现)
r();
// 在对象 `d` 上定义一个名为 `checkStatus` 的方法,这个方法接收一个参数 `e`,从方法名称和代码逻辑推测可能用于检查表格中某些数据的选中状态等相关信息,以下是方法内部的详细逻辑代码
d.checkStatus = function (e) {
// 初始化两个变量 `t` 和 `i`,分别赋值为 `0`,从后续代码看 `t` 可能用于记录选中的数据项数量,`i` 可能用于记录某种特定类型的数据项数量(比如非数组类型的数据项等情况,具体要结合整体逻辑确定)
var t = 0, i = 0,
// 创建一个空数组 `a`,从后续代码看这个数组用于存储经过处理后的选中的数据项(比如清除一些缓存相关的标识信息后的实际数据项)
a = [],
// 通过 `d.cache` 对象(前面代码中定义的用于存储表格相关缓存数据的对象)查找以 `e` 为键的值(也就是对应表格实例的缓存数据,如果不存在则使用空数组 `[]` 作为默认值),并赋值给变量 `l`,后续会基于这个缓存数据来判断选中状态等信息
l = d.cache[e] || [];
// 使用 `layui.each` 方法遍历 `l` 数组,在每次遍历中,参数 `e` 表示当前遍历的索引,`l` 表示当前遍历到的元素值,以下是遍历过程中的具体逻辑判断:
return layui.each(l, function (e, l) {
// 判断当前元素 `l` 的构造函数是否是 `Array`(也就是判断 `l` 是否是数组类型),如果是数组类型,则将 `i` 的值自增 `1`(可能是用于统计数组类型的数据项数量等情况),不做其他操作(通过 `void` 关键字表示不返回任何值);
// 如果 `l` 不是数组类型,则判断 `l` 对象中是否存在以 `d.config.checkName` 为名称的属性(也就是判断是否有表示选中状态的标识属性,这个属性名在前面 `d` 对象的 `config` 属性中定义过),如果存在这个选中标识属性,则将 `t` 的值自增 `1`(表示找到了一个选中的数据项),同时调用 `d.clearCacheKey` 函数(从函数名推测是用于清除数据项中缓存相关标识信息的函数,具体功能要看其内部实现)处理当前元素 `l`,并将处理后的结果添加到数组 `a` 中,同样通过 `void` 关键字表示不返回任何值,只是执行相应的操作
return l.constructor === Array? void i++ : void (l[d.config.checkName] && (t++, a.push(d.clearCacheKey(l))))
}), {
// 最后返回一个包含 `data` 和 `isAll` 属性的对象,`data` 属性的值为数组 `a`(也就是经过处理后的选中的数据项数组),`isAll` 属性的值通过判断 `l` 数组是否有长度(也就是是否有缓存数据)并且选中的数据项数量 `t` 是否等于总数据项数量减去数组类型的数据项数量(`l.length - i`)来确定是否所有非数组类型的数据项都被选中,将这个判断结果转换为布尔值(`!!` 操作符用于将值转换为布尔值,并且进行了两次取反操作,确保得到准确的布尔值表示)后作为 `isAll` 的值返回,方便外部调用这个方法获取表格数据的选中状态相关信息
data: a, isAll:!!l.length && t === l.length - i
};
};
// 在对象 `d` 上定义一个名为 `exportFile` 的方法,这个方法接收三个参数 `e`、`t` 和 `i`,从方法名称和代码逻辑推测是用于将表格数据导出为文件的功能,以下是方法内部的详细逻辑代码
d.exportFile = function (e, t, i) {
// 判断如果参数 `t` 为假值(比如 `undefined`、`null` 等情况),则调用 `d.clearCacheKey` 函数(前面提到用于清除缓存标识信息的函数)处理 `d.cache` 对象中以 `e` 为键的值(也就是对应表格实例的缓存数据),将处理后的结果作为 `t` 的值;判断如果参数 `i` 为假值,则将 `i` 的值默认设置为 `"csv"`,这里是对传入参数进行一些默认值的处理,确保后续操作有合理的数据可用
t = t || d.clearCacheKey(d.cache[e]), i = i || "csv";
// 通过 `c.config` 对象(前面定义的用于存储表格配置信息的对象,以表格实例标识为键来存储对应的配置信息)查找以 `e` 为键的配置信息对象,并赋值给变量 `a`,方便后续获取表格相关的配置信息用于导出文件操作(比如获取表格标题等信息)
var a = c.config[e] || {},
// 创建一个对象 `l`,通过查找一个包含文件类型和对应 `MIME` 类型的对象(这里硬编码了 `"csv"` 和 `"xls"` 两种文件类型对应的 `MIME` 类型),以 `i`(前面处理后的文件类型参数)为键获取对应的 `MIME` 类型,并赋值给 `l`,用于后续设置导出文件的 `MIME` 类型信息
l = {csv: "text/csv", xls: "application/vnd.ms-excel"}[i],
// 使用 `document.createElement` 方法创建一个 `<a>` 元素(也就是 HTML 中的超链接元素),并赋值给变量 `n`,后续会利用这个元素来模拟点击下载文件的操作实现文件导出功能
n = document.createElement("a");
// 判断如果当前浏览器是 Internet Explorer通过 `r.ie` 判断,这里 `r.ie` 的具体值需要看前面代码对 `r` 函数以及 `ie` 属性的定义情况,不过从逻辑推测是用于检测是否是 IE 浏览器的标识),则调用 `o.error` 函数(前面获取的用于输出错误提示信息的函数)输出提示信息表示 IE 浏览器不支持文件导出功能(从错误提示内容推测的功能限制情况),不做后续的导出文件操作(通过 `return` 语句直接返回);
// 如果不是 IE 浏览器,则执行以下代码块进行文件导出的具体操作:
return r.ie? o.error("IE_NOT_SUPPORT_EXPORTS") : (
// 设置 `<a>` 元素 `n` 的 `href` 属性,通过拼接字符串的方式构造一个 `data:` 协议的 URL格式为 `data:` 加上前面获取的文件 `MIME` 类型 `l`、`;charset=utf-8`(表示字符编码为 `utf-8`)、`,\ufeff`(可能是用于处理一些特殊的编码格式或者文件开头标识相关的内容,具体要结合导出文件的规范和要求来看)以及通过调用 `encodeURIComponent` 函数对一个匿名函数的执行结果进行编码后的内容(这个匿名函数用于生成要导出的文件内容,具体生成逻辑在匿名函数内部实现),将拼接好的字符串赋值给 `n` 的 `href` 属性,用于指定要导出文件的内容和相关格式信息
n.href = "data:" + l + ";charset=utf-8,\ufeff" + encodeURIComponent(function () {
var i = [], a = [];
return layui.each(t, function (t, l) {
var n = [];
// 判断如果 `e` 是对象类型(从代码逻辑推测 `e` 可能是包含表格列信息等相关配置的对象,不过具体要结合前面传入的参数情况确定),则使用 `layui.each` 方法遍历 `e` 对象,在每次遍历中,将当前对象的属性值(如果存在)添加到数组 `i` 中(这里可能是用于添加表头信息等情况,具体要结合整体导出文件的逻辑确定),然后再次使用 `layui.each` 方法遍历调用 `d.clearCacheKey` 函数处理后的当前数据项 `l`(也就是清除缓存标识后的实际数据内容),将每个数据值添加到数组 `n` 中(这里可能是用于添加每行的数据内容等情况);
// 如果 `e` 不是对象类型,则调用 `d.eachCols` 函数(从函数名推测是用于遍历表格列的函数,不过具体功能要结合其内部实现来看)遍历 `e`,在每次遍历中,判断如果当前列的 `field` 属性存在(也就是有对应的数据字段名)并且列类型是 `"normal"`(也就是普通类型的列,不是特殊类型的列,比如不是复选框列等情况)并且列不是隐藏状态,则将当前列的标题(`title` 属性值)添加到数组 `i` 中(同样可能是用于添加表头信息),然后将当前数据项 `l` 中对应字段的数据值(通过 `l[a.field]` 获取)添加到数组 `n` 中(用于添加每行的数据内容),最后将数组 `n` 通过 `join` 方法使用 `","` 拼接成字符串后添加到数组 `a` 中,完成一行数据的整理操作
"object" == typeof e? (layui.each(e, function (e, a) {
0 == t && i.push(a || "")
}), layui.each(d.clearCacheKey(l), function (e, t) {
n.push(t)
})) : d.eachCols(e, function (e, a) {
a.field && "normal" == a.type &&!a.hide && (0 == t && i.push(a.title || ""), n.push(l[a.field]))
}), a.push(n.join(","))
}), i.join(",") + "\r\n" + a.join("\r\n")
}()),
// 设置 `<a>` 元素 `n` 的 `download` 属性,属性值通过拼接表格的标题(从 `a` 对象中获取 `title` 属性值,如果不存在则使用默认格式 `"table_"` 加上表格的索引 `a.index`,如果 `a.index` 也不存在则为空字符串)和文件类型 `i`(前面处理后的文件类型参数),中间用 `"."` 连接,形成最终的文件名,用于指定下载文件的名称
n.download = (a.title || "table_" + (a.index || "")) + "." + i,
// 将 `<a>` 元素 `n` 添加到 `document.body` 中(也就是将这个元素插入到页面的 `body` 元素内,使其成为页面 DOM 结构的一部分,这样才能进行后续的模拟点击操作等)
document.body.appendChild(n),
// 模拟触发 `<a>` 元素的 `click` 事件,也就是模拟用户点击了这个超链接,浏览器会根据 `href` 属性的设置自动下载对应的文件内容,实现文件导出功能
n.click(),
// 将 `<a>` 元素 `n` 从 `document.body` 中移除(因为已经完成了文件导出的操作,不需要这个临时创建的元素继续留在页面中了,避免对页面结构和后续操作产生影响),通过 `void` 关键字表示不返回这个操作的结果(也就是移除操作本身不需要返回值给外部)
void document.body.removeChild(n)
);
};
// 在对象 `d` 上定义一个名为 `resize` 的方法,这个方法接收一个参数 `e`,从方法名称和代码逻辑推测是用于调整表格大小的功能,以下是方法内部的详细逻辑代码
d.resize = function (e) {
// 判断如果传入了参数 `e`(可能是表格实例的标识等相关信息),则执行以下代码块进行特定表格实例的大小调整操作:
if (e) {
// 通过调用 `s` 函数(前面定义的用于查找并返回对应表格配置信息的函数),传入参数 `e`,获取对应的表格配置信息对象,并赋值给变量 `t`,如果没有找到对应的配置信息(也就是 `s` 函数返回 `null`),则直接返回(不进行后续的大小调整操作,因为没有有效的配置信息就无法准确操作对应的表格实例)
var t = s(e);
if (!t) return;
// 通过 `c.that` 对象(前面定义的用于存储表格实例对象的对象,以表格实例标识为键来存储对应的表格实例)查找以 `e` 为键的表格实例对象,并调用其 `resize` 方法(从代码逻辑推测 `c.that[e].resize` 方法应该是对应表格实例用于实际调整大小的具体业务逻辑所在,这里通过前面获取到的有效的表格实例对象来调用这个方法),实现特定表格实例的大小调整操作
c.that[e].resize()
} else {
// 如果没有传入参数 `e`(也就是可能要对所有的表格实例进行大小调整操作),则使用 `layui.each` 方法遍历 `c.that` 对象的所有属性(也就是遍历所有的表格实例对象),对于每个表格实例对象,调用其 `resize` 方法(同样是调用每个表格实例自身的 `resize` 方法来实现大小调整功能),完成对所有表格实例的大小调整操作
layui.each(c.that, function () {
this.resize()
})
}
};
// 在对象 `d` 上定义一个名为 `reload` 的方法,这个方法接收两个参数 `e` 和 `i`,从方法名称和代码逻辑推测是用于重新加载表格数据的功能,以下是方法内部的详细逻辑代码
d.reload = function (e, i) {
// 判断如果参数 `i` 为假值(比如 `undefined`、`null` 等情况),则将 `i` 赋值为一个空对象 `{}`,确保后续操作有一个有效的用于更新表格数据的配置对象可用
i = i || {};
// 通过调用 `s` 函数(前面定义的用于查找并返回对应表格配置信息的函数),传入参数 `e`,获取对应的表格配置信息对象,并赋值给变量 `a`,如果找到了对应的配置信息对象,则执行以下代码块进行表格数据的重新加载操作:
var a = s(e);
if (a) return i.data && i.data.constructor === Array && delete a.data, d.render(t.extend(!0, {}, a, i));
};
// 在对象 `d` 上定义一个名为 `render` 的方法,这个方法接收一个参数 `e`,从方法名称和代码逻辑推测是用于渲染表格的功能,以下是方法内部的详细逻辑代码
d.render = function (e) {
// 创建一个 `F` 类(从代码上下文推测 `F` 应该是一个构造函数,用于创建表格相关的实例对象,不过具体 `F` 的定义要结合前面代码来看)的新实例对象,传入参数 `e`(可能是表格渲染相关的配置信息等),并将这个新实例对象赋值给变量 `t`,后续会基于这个实例对象进行表格的渲染等操作
var t = new F(e);
// 通过调用 `c` 函数(前面定义的用于获取或操作表格实例相关的一些配置和方法等信息的函数),并使用 `call` 方法改变函数内部的 `this` 指向为 `t`(也就是让 `c` 函数内部的 `this` 指向当前创建的表格实例对象 `t`),来获取或执行与这个表格实例相关的配置、方法等操作,最后返回 `c` 函数执行的结果(具体返回值要结合 `c` 函数的实现来看,从前面代码可知可能返回包含表格操作方法的对象等情况)
return c.call(t)
};
// 在对象 `d` 上定义一个名为 `clearCacheKey` 的方法,这个方法接收一个参数 `e`,从方法名称和代码逻辑推测是用于清除表格数据中缓存相关标识信息的功能,以下是方法内部的详细逻辑代码
d.clearCacheKey = function (e) {
// 使用 `t.extend` 方法(可能是基于 jQuery 或者 layui 自定义的扩展对象属性的方法,将两个对象的属性合并到一起)将传入的参数 `e` 与一个空对象 `{}` 进行合并,这样做的目的是创建一个 `e` 的浅拷贝(避免直接修改原对象,保证数据的独立性,同时也能获取到一份可操作的对象副本),并将合并后的结果重新赋值给变量 `e`,方便后续对其进行属性删除等操作
return e = t.extend({}, e),
// 删除 `e` 对象中以 `d.config.checkName` 为名称的属性(也就是前面在 `d` 对象的 `config` 属性中定义的用于标识选中状态等缓存相关的属性名对应的属性,通过这种方式清除这个缓存相关的标识信息)
delete e[d.config.checkName],
// 删除 `e` 对象中以 `d.config.indexName` 为名称的属性(同样是清除 `d` 对象的 `config` 属性中定义的另一个缓存相关的索引属性名对应的属性)
delete e[d.config.indexName],
// 最后返回处理后的 `e` 对象,这个对象就是清除了特定缓存标识信息后的表格数据对象,方便外部获取到干净的数据用于后续操作(比如重新渲染、保存数据等操作)
e
};
// 调用对象 `d` 的 `init` 方法(不过从前面代码来看并没有展示 `init` 方法的具体实现,推测它可能用于初始化表格相关的一些默认设置、加载必要的数据等操作,具体功能要结合其内部代码逻辑确定)
d.init();
// 调用传入的函数 `e`(从整个代码结构来看,这个 `e` 函数是作为参数传递进来的,可能是 layui 框架中用于注册模块或者对外暴露接口等功能的一个回调函数,不过具体作用要结合外层调用这段代码的逻辑来确定),传入两个参数 `u`(前面代码中定义的表示表格相关事件等操作的标识字符串 `"table"`)和 `d`(也就是当前定义了很多表格相关方法和属性的 `d` 对象),通过这样的调用可能是将表格模块相关的功能注册到 layui 框架中或者向外部暴露 `d` 对象提供的表格相关操作接口等情况(具体要根据 layui 框架整体的模块机制和调用约定来准确理解其功能)
e(u, d)
// 闭合整个 layui.define 函数调用的括号以及立即执行函数的括号,完成整个模块定义和相关逻辑的封装,确保代码在合适的模块加载机制和作用域环境下正确执行
});

@ -1,187 +1,389 @@
/** layui-v2.4.5 MIT License By https://www.layui.com */
;!function (e) {
// 使用严格模式,有助于发现代码中潜在的错误,避免一些在非严格模式下可能出现的不规范或容易出错的用法
"use strict";
var t = document, o = {modules: {}, status: {}, timeout: 10, event: {}}, n = function () {
this.v = "2.4.5"
}, r = function () {
var e = t.currentScript ? t.currentScript.src : function () {
for (var e, o = t.scripts, n = o.length - 1, r = n; r > 0; r--) if ("interactive" === o[r].readyState) {
e = o[r].src;
break
}
return e || o[n].src
}();
return e.substring(0, e.lastIndexOf("/") + 1)
}(), i = function (t) {
e.console && console.error && console.error("Layui hint: " + t)
}, a = "undefined" != typeof opera && "[object Opera]" === opera.toString(), u = {
layer: "modules/layer",
laydate: "modules/laydate",
laypage: "modules/laypage",
laytpl: "modules/laytpl",
layim: "modules/layim",
layedit: "modules/layedit",
form: "modules/form",
upload: "modules/upload",
tree: "modules/tree",
table: "modules/table",
element: "modules/element",
rate: "modules/rate",
colorpicker: "modules/colorpicker",
slider: "modules/slider",
carousel: "modules/carousel",
flow: "modules/flow",
util: "modules/util",
code: "modules/code",
jquery: "modules/jquery",
mobile: "modules/mobile",
"layui.all": "../layui.all"
};
n.prototype.cache = o, n.prototype.define = function (e, t) {
var n = this, r = "function" == typeof e, i = function () {
var e = function (e, t) {
layui[e] = t, o.status[e] = !0
};
return "function" == typeof t && t(function (n, r) {
e(n, r), o.callback[n] = function () {
t(e)
// 获取全局的 `document` 对象,并赋值给变量 `t`,方便后续代码中频繁使用 `document` 进行DOM操作等相关处理时直接引用这个变量
var t = document,
// 创建一个包含多个属性的对象 `o`,用于存储一些模块相关的配置信息、状态信息、超时时间以及事件相关的配置等内容,后续很多功能实现会依赖和修改这个对象中的属性值
o = {modules: {}, status: {}, timeout: 10, event: {}},
// 定义一个名为 `n` 的构造函数,通过 `new` 关键字实例化这个构造函数创建的对象可以用于管理layui框架的各种功能模块、配置等操作从后续代码可以看到它有很多原型方法用于不同的功能实现
n = function () {
// 在通过 `n` 构造函数创建的实例对象上添加一个属性 `v`,并赋值为 "2.4.5"从变量名推测这个可能是layui框架的版本号相关信息用于版本标识等用途
this.v = "2.4.5"
},
// 定义一个名为 `r` 的函数,用于获取当前执行脚本所在的目录路径,它会优先尝试通过 `document.currentScript.src` 获取当前正在执行的 `<script>` 元素的 `src` 属性值如果在HTML中通过 `<script>` 标签引入了layui相关脚本的话
// 如果 `document.currentScript` 不存在(例如在一些旧浏览器或者特殊环境下),则通过循环查找 `document.scripts` 集合中的 `<script>` 元素,根据其 `readyState` 属性找到合适的 `<script>` 元素的 `src` 属性值作为当前脚本的路径,最后截取路径到最后一个 `/` 字符位置(包含 `/` ),获取到所在的目录路径
r = function () {
var e = t.currentScript? t.currentScript.src : function () {
for (var e, o = t.scripts, n = o.length - 1, r = n; r > 0; r--) if ("interactive" === o[r].readyState) {
e = o[r].src;
break
}
}), this
return e || o[n].src
}();
return e.substring(0, e.lastIndexOf("/") + 1)
}(),
// 定义一个名为 `i` 的函数,它接收一个参数 `t`,用于在浏览器环境下(当 `console` 可用时)在控制台输出错误提示信息,提示信息格式为 "Layui hint: " 加上传入的具体提示内容 `t`方便在开发调试layui框架或者使用layui框架出现问题时进行错误提示展示
i = function (t) {
e.console && console.error && console.error("Layui hint: " + t)
},
// 判断当前浏览器是否是Opera浏览器通过判断 `opera` 对象是否存在以及其 `toString` 方法返回的字符串是否为 `[object Opera]` 来确定),并将结果赋值给变量 `a`,后续可能根据不同浏览器的特性来进行一些兼容性处理等操作会用到这个判断结果
a = "undefined"!= typeof opera && "[object Opera]" === opera.toString(),
// 创建一个对象 `u`用于存储layui框架中各个功能模块对应的相对路径信息键是模块名称如 `layer`、`laydate` 等值是对应的模块文件在layui框架中的相对路径方便后续根据模块名称去加载相应的模块脚本文件
u = {
layer: "modules/layer",
laydate: "modules/laydate",
laypage: "modules/laypage",
laytpl: "modules/laytpl",
layim: "modules/layim",
layedit: "modules/layedit",
form: "modules/form",
upload: "modules/upload",
tree: "modules/tree",
table: "modules/table",
element: "modules/element",
rate: "modules/rate",
colorpicker: "modules/colorpicker",
slider: "modules/slider",
carousel: "modules/carousel",
flow: "modules/flow",
util: "modules/util",
code: "modules/code",
jquery: "modules/jquery",
mobile: "modules/mobile",
"layui.all": "../layui.all"
};
return r && (t = e, e = []), layui["layui.all"] || !layui["layui.all"] && layui["layui.mobile"] ? i.call(n) : (n.use(e, i), n)
}, n.prototype.use = function (e, n, l) {
function s(e, t) {
var n = "PLaySTATION 3" === navigator.platform ? /^complete$/ : /^(complete|loaded)$/;
("load" === e.type || n.test((e.currentTarget || e.srcElement).readyState)) && (o.modules[f] = t, d.removeChild(v), function r() {
return ++m > 1e3 * o.timeout / 4 ? i(f + " is not a valid module") : void (o.status[f] ? c() : setTimeout(r, 4))
}())
}
// 在 `n` 构造函数的原型上添加一个属性 `cache`,并将前面定义的 `o` 对象赋值给它,使得通过 `n` 构造函数创建的实例对象可以通过 `cache` 属性访问和操作 `o` 对象中存储的各种配置、状态等信息
n.prototype.cache = o,
// 在 `n` 构造函数的原型上添加一个名为 `define` 的方法用于定义layui框架中的功能模块它接收两个参数 `e` 和 `t`,从后续代码逻辑来看,这个方法会根据参数的类型和情况来决定如何进行模块的定义以及模块加载完成后的回调处理等操作
n.prototype.define = function (e, t) {
var n = this,
r = "function" == typeof e,
i = function () {
var e = function (e, t) {
// 将传入的模块名称 `e` 作为属性名,模块对应的内容 `t` 作为属性值,添加到全局的 `layui` 对象上,实现将模块挂载到 `layui` 框架中,方便外部使用,
// 同时将该模块在 `o.status` 对象中的对应状态设置为 `true`,表示模块已经加载完成或者定义成功等状态
layui[e] = t, o.status[e] =!0
};
return "function" == typeof t && t(function (n, r) {
e(n, r), o.callback[n] = function () {
t(e)
}
}), this
};
return r && (t = e, e = []), layui["layui.all"] ||!layui["layui.all"] && layui["layui.mobile"]? i.call(n) : (n.use(e, i), n)
},
// 在 `n` 构造函数的原型上添加一个名为 `use` 的方法这个方法用于加载指定的layui框架功能模块它接收多个参数`e` 可以是一个模块名称字符串或者模块名称数组,表示要加载的模块列表,`n` 是模块加载完成后的回调函数,`l` 是一个用于传递参数或者存储已加载模块的数组(从后续代码逻辑可以更清晰地看到其用途),整个方法内部实现了模块加载的逻辑以及加载过程中的各种状态判断、错误处理等功能
n.prototype.use = function (e, n, l) {
// 定义一个名为 `s` 的内部函数,它接收两个参数 `e`(一个事件对象,通常是 `script` 元素加载完成触发的事件对象)和 `t`(可能是模块对应的脚本文件路径等相关信息),
// 函数内部首先根据浏览器平台判断合适的脚本加载完成的状态检测正则表达式(针对不同浏览器对 `readyState` 属性的支持差异进行处理),
// 当脚本加载完成(通过判断 `load` 事件触发或者 `readyState` 状态符合相应正则表达式条件)后,将模块信息存储到 `o.modules` 对象中(以模块名称为键,模块脚本路径等信息为值),
// 然后从DOM中移除对应的 `<script>` 元素,接着通过一个递归函数 `r` 判断模块加载是否超时(如果超过一定时间模块状态还未标记为已加载完成,则输出错误提示信息),如果模块已加载完成则执行后续的回调函数等逻辑
function s(e, t) {
var n = "PLaySTATION 3" === navigator.platform? /^complete$/ : /^(complete|loaded)$/;
("load" === e.type || n.test((e.currentTarget || e.srcElement).readyState)) && (o.modules[f] = t, d.removeChild(v), function r() {
return ++m > 1e3 * o.timeout / 4? i(f + " is not a valid module") : void (o.status[f]? c() : setTimeout(r, 4))
}())
}
// 定义一个名为 `c` 的内部函数,它主要用于处理模块加载完成后的后续逻辑,当所有要加载的模块都加载完成后(通过判断 `e` 数组长度是否大于1以及递归调用 `y.use` 方法逐步减少要加载的模块数量来确定),
// 如果传入了模块加载完成后的回调函数 `n`,则调用 `n` 函数并将已加载的模块列表 `l` 作为参数传递进去,执行相应的业务逻辑(比如使用已加载的模块进行页面渲染、功能实现等操作)
function c() {
l.push(layui[f]), e.length > 1? y.use(e.slice(1), n, l) : "function" == typeof n && n.apply(layui, l)
}
var y = this,
p = o.dir = o.dir? o.dir : r,
d = t.getElementsByTagName("head")[0];
// 判断如果传入的 `e` 参数是字符串类型,则将其转换为只包含这一个元素的数组形式(因为后续代码逻辑中统一按照数组来处理要加载的模块列表),
// 同时如果浏览器环境中已经存在 `window.jQuery` 并且 `jQuery.fn.on` 方法存在即jQuery库已经加载并且可用则遍历要加载的模块列表 `e`
// 如果模块名称是 `"jquery"`,则将其从 `e` 数组中移除可能是避免重复加载jQuery等原因并将 `layui.jquery` 和 `layui.$` 都指向已存在的 `jQuery` 对象方便在layui框架中使用jQuery的功能
e = "string" == typeof e? [e] : e, window.jQuery && jQuery.fn.on && (y.each(e, function (t, o) {
"jquery" === o && e.splice(t, 1)
}), layui.jquery = layui.$ = jQuery);
var f = e[0], m = 0;
if (l = l || [], o.host = o.host || (p.match(/\/\/([\s\S]+?)\//) || ["//" + location.host + "/"])[0], 0 === e.length || layui["layui.all"] && u[f] ||!layui["layui.all"] && layui["layui.mobile"] && u[f]) return c(), y;
if (o.modules[f])!function g() {
return ++m > 1e3 * o.timeout / 4? i(f + " is not a valid module") : void ("string" == typeof o.modules[f] && o.status[f]? c() : setTimeout(g, 4))
}(); else {
// 创建一个 `<script>` 元素,用于加载指定模块对应的脚本文件,设置其 `async` 属性为 `true` 表示异步加载(不阻塞页面其他内容的加载和执行),`charset` 属性为 `"utf-8"` 确保正确解析脚本文件中的字符编码,
var v = t.createElement("script"),
h = (u[f]? p + "lay/" : /^\{\/\}/.test(y.modules[f])? "" : o.base || "") + (y.modules[f] || f) + ".js";
h = h.replace(/^\{\/\}/, ""), v.async =!0, v.charset = "utf-8", v.src = h + function () {
var e = o.version ===!0? o.v || (new Date).getTime() : o.version || "";
return e? "?v=" + e : ""
}(), d.appendChild(v),!v.attachEvent || v.attachEvent.toString && v.attachEvent.toString().indexOf("[native code") < 0 || a? v.addEventListener("load", function (e) {
s(e, h)
},!1) : v.attachEvent("onreadystatechange", function (e) {
s(e, h)
}), o.modules[f] = h
}
return y
},
// 在 `n` 构造函数的原型上添加一个名为 `getStyle` 的方法,它接收两个参数 `t`一个DOM元素和 `o`一个CSS属性名称
// 方法内部用于获取指定DOM元素上指定CSS属性的实际计算值会根据浏览器对 `currentStyle` 和 `getComputedStyle` 方法的支持情况来选择合适的方式获取属性值并返回获取到的CSS属性值
n.prototype.link = function (e, n, r) {
// 将当前调用此方法的 `n` 构造函数实例对象自身保存到变量 `a` 中,方便后续在方法内部引用实例对象的属性和方法等
var a = this,
// 使用 `document.createElement` 方法创建一个 `<link>` 元素,用于后续加载外部 CSS 文件,将创建好的 `<link>` 元素赋值给变量 `u`
u = t.createElement("link"),
// 通过 `document.getElementsByTagName` 方法获取页面中 `<head>` 元素(返回的是类数组对象),取其第一个元素(也就是实际的 `<head>` 元素)赋值给变量 `l`,后续会把 `<link>` 元素添加到 `<head>` 元素内
l = t.getElementsByTagName("head")[0];
function c() {
l.push(layui[f]), e.length > 1 ? y.use(e.slice(1), n, l) : "function" == typeof n && n.apply(layui, l)
}
// 如果传入的参数 `n` 是字符串类型,说明可能原本作为第二个参数传入的 `n` 实际应该是第三个参数 `r` 的值,所以将 `n` 的值赋给 `r`,进行参数的调整
"string" == typeof n && (r = n);
var y = this, p = o.dir = o.dir ? o.dir : r, d = t.getElementsByTagName("head")[0];
e = "string" == typeof e ? [e] : e, window.jQuery && jQuery.fn.on && (y.each(e, function (t, o) {
"jquery" === o && e.splice(t, 1)
}), layui.jquery = layui.$ = jQuery);
var f = e[0], m = 0;
if (l = l || [], o.host = o.host || (p.match(/\/\/([\s\S]+?)\//) || ["//" + location.host + "/"])[0], 0 === e.length || layui["layui.all"] && u[f] || !layui["layui.all"] && layui["layui.mobile"] && u[f]) return c(), y;
if (o.modules[f]) !function g() {
return ++m > 1e3 * o.timeout / 4 ? i(f + " is not a valid module") : void ("string" == typeof o.modules[f] && o.status[f] ? c() : setTimeout(g, 4))
}(); else {
var v = t.createElement("script"),
h = (u[f] ? p + "lay/" : /^\{\/\}/.test(y.modules[f]) ? "" : o.base || "") + (y.modules[f] || f) + ".js";
h = h.replace(/^\{\/\}/, ""), v.async = !0, v.charset = "utf-8", v.src = h + function () {
var e = o.version === !0 ? o.v || (new Date).getTime() : o.version || "";
return e ? "?v=" + e : ""
}(), d.appendChild(v), !v.attachEvent || v.attachEvent.toString && v.attachEvent.toString().indexOf("[native code") < 0 || a ? v.addEventListener("load", function (e) {
s(e, h)
}, !1) : v.attachEvent("onreadystatechange", function (e) {
s(e, h)
}), o.modules[f] = h
}
return y
}, n.prototype.getStyle = function (t, o) {
var n = t.currentStyle ? t.currentStyle : e.getComputedStyle(t, null);
return n[n.getPropertyValue ? "getPropertyValue" : "getAttribute"](o)
}, n.prototype.link = function (e, n, r) {
var a = this, u = t.createElement("link"), l = t.getElementsByTagName("head")[0];
"string" == typeof n && (r = n);
var s = (r || e).replace(/\.|\//g, ""), c = u.id = "layuicss-" + s, y = 0;
return u.rel = "stylesheet", u.href = e + (o.debug ? "?v=" + (new Date).getTime() : ""), u.media = "all", t.getElementById(c) || l.appendChild(u), "function" != typeof n ? a : (function p() {
return ++y > 1e3 * o.timeout / 100 ? i(e + " timeout") : void (1989 === parseInt(a.getStyle(t.getElementById(c), "width")) ? function () {
n()
}() : setTimeout(p, 100))
}(), a)
}, o.callback = {}, n.prototype.factory = function (e) {
if (layui[e]) return "function" == typeof o.callback[e] ? o.callback[e] : null
}, n.prototype.addcss = function (e, t, n) {
return layui.link(o.dir + "css/" + e, t, n)
}, n.prototype.img = function (e, t, o) {
var n = new Image;
return n.src = e, n.complete ? t(n) : (n.onload = function () {
n.onload = null, "function" == typeof t && t(n)
}, void (n.onerror = function (e) {
n.onerror = null, "function" == typeof o && o(e)
}))
}, n.prototype.config = function (e) {
e = e || {};
for (var t in e) o[t] = e[t];
return this
}, n.prototype.modules = function () {
var e = {};
for (var t in u) e[t] = u[t];
return e
}(), n.prototype.extend = function (e) {
var t = this;
e = e || {};
for (var o in e) t[o] || t.modules[o] ? i("模块名 " + o + " 已被占用") : t.modules[o] = e[o];
return t
}, n.prototype.router = function (e) {
var t = this, e = e || location.hash, o = {path: [], search: {}, hash: (e.match(/[^#](#.*$)/) || [])[1] || ""};
return /^#\//.test(e) ? (e = e.replace(/^#\//, ""), o.href = "/" + e, e = e.replace(/([^#])(#.*$)/, "$1").split("/") || [], t.each(e, function (e, t) {
/^\w+=/.test(t) ? function () {
t = t.split("="), o.search[t[0]] = t[1]
}() : o.path.push(t)
}), o) : o
}, n.prototype.data = function (t, o, n) {
if (t = t || "layui", n = n || localStorage, e.JSON && e.JSON.parse) {
if (null === o) return delete n[t];
o = "object" == typeof o ? o : {key: o};
// 对传入的参数 `r`(若 `r` 不存在则用 `e`)进行处理,将其中的 `.` 和 `/` 字符替换为空字符串,目的可能是生成一个相对简洁、规范的用于作为 `<link>` 元素 `id` 属性的值,将处理后的结果赋值给变量 `s`
var s = (r || e).replace(/\.|\//g, ""),
// 为 `<link>` 元素 `u` 设置 `id` 属性,属性值格式为 `"layuicss-"` 加上前面生成的 `s` 字符串,同时把这个 `id` 值也保存到变量 `c` 中,方便后续通过 `id` 查找该元素等操作
c = u.id = "layuicss-" + s,
// 初始化一个计数器变量 `y`,用于记录一些操作执行的次数,初始值设为 0从后续代码看可能用于判断加载 CSS 文件是否超时等情况
y = 0;
// 设置 `<link>` 元素 `u` 的相关属性:
// - `rel` 属性设置为 `"stylesheet"`,表明它是用于引入样式表的链接元素;
// - `href` 属性设置为传入的 CSS 文件路径 `e`,如果 `o.debug` 为真(可能是调试模式相关配置),则在路径后面添加 `"?v="` 以及当前时间戳(通过 `(new Date).getTime()` 获取),这样可以避免浏览器缓存,每次都获取最新的 CSS 文件;
// - `media` 属性设置为 `"all"`,表示该样式表适用于所有媒体类型(如屏幕、打印等);
// 接着判断页面中是否已经存在 `id` 为 `c` 的元素(通过 `document.getElementById` 方法查找),如果不存在就把创建好的 `<link>` 元素 `u` 添加到 `<head>` 元素 `l` 中;
// 最后根据传入的参数 `n` 的类型来决定返回值:如果 `n` 不是函数类型,直接返回 `a`(也就是当前实例对象);如果 `n` 是函数类型,则执行下面的匿名函数逻辑
return u.rel = "stylesheet", u.href = e + (o.debug? "?v=" + (new Date).getTime() : ""), u.media = "all", t.getElementById(c) || l.appendChild(u), "function"!= typeof n? a : (function p() {
// 在这个匿名函数内部(也就是 `n` 为函数类型时执行的逻辑),每次执行先将计数器 `y` 的值自增 1然后进行以下判断
// 判断如果 `y` 的值大于 `o.timeout`(前面定义的超时时间配置)乘以 1000 除以 100也就是 `o.timeout` 的 10 倍,推测是用于判断加载 CSS 文件是否超时的条件),
// 如果超时了,就调用 `i` 函数(前面定义的用于输出错误提示信息的函数)并传入 `"e + " timeout"`(表示 CSS 文件加载超时的提示信息,这里 `e` 是传入的 CSS 文件路径);
// 如果没有超时,则继续判断通过 `a.getStyle` 方法获取到的已添加到页面的 `<link>` 元素(通过 `document.getElementById(c)` 找到)的 `width` 属性值(这里获取 `width` 属性值的操作从代码逻辑看可能是一种判断样式是否加载完成或者生效的方式,虽然实际不一定能准确判断样式全部加载完成,但可能是一种简单的检测手段)是否等于 1989这个值具体含义可能和 layui 内部对样式加载判断的逻辑相关),
// 如果等于 1989则执行传入的函数 `n`(也就是加载完成后的回调函数),如果不等于 1989则通过 `setTimeout` 方法设置每隔 100 毫秒再次执行这个匿名函数 `p`,继续进行上述的超时判断和样式加载完成判断逻辑
return ++y > 1e3 * o.timeout / 100? i(e + " timeout") : void (1989 === parseInt(a.getStyle(t.getElementById(c), "width"))? function () {
n()
}() : setTimeout(p, 100))
}(), a)
},
// 初始化 `o` 对象的 `callback` 属性为一个空对象,从后续代码看这个对象可能用于存储各个模块对应的回调函数相关信息
o.callback = {},
// 在 `n` 构造函数的原型上添加一个名为 `factory` 的方法,它接收一个参数 `e`,用于获取已经定义或者加载的指定模块对应的回调函数(如果存在的话),以下是该方法内部的具体逻辑代码
n.prototype.factory = function (e) {
// 首先判断在全局的 `layui` 对象上是否存在以 `e` 为名称的属性(也就是对应的模块是否已经定义或者加载了),如果存在,则继续判断该模块对应的 `o.callback` 对象中是否存在以 `e` 为名称的属性且这个属性值是函数类型(也就是判断是否有对应的回调函数且类型正确),
// 如果满足上述条件,就返回这个回调函数(也就是 `o.callback[e]`),如果不满足(比如模块不存在或者对应的回调函数不是函数类型等情况),则返回 `null`
if (layui[e]) return "function" == typeof o.callback[e]? o.callback[e] : null
},
// 在 `n` 构造函数的原型上添加一个名为 `addcss` 的方法,它接收三个参数 `e`(可能是 CSS 文件名称或者相关路径信息)、`t`(可能是加载完成后的回调函数或者其他配置信息)和 `n`(备用配置信息),以下是该方法的具体逻辑代码
n.prototype.addcss = function (e, t, n) {
// 此方法内部直接调用了前面定义的 `link` 方法,传入经过处理后的参数,用于加载位于 `o.dir + "css/" + e` 路径下的 CSS 样式文件(这里 `o.dir` 应该是 layui 框架中定义的某个基础目录路径,通过拼接 `e` 参数形成完整的 CSS 文件路径),
// 并根据传入的 `t` 和 `n` 参数情况决定是否执行回调函数等操作,相当于提供了一个快捷方式来专门加载特定目录下的 CSS 文件,最后返回 `link` 方法的执行结果
return layui.link(o.dir + "css/" + e, t, n)
},
// 在 `n` 构造函数的原型上添加一个名为 `img` 的方法,它用于加载图片资源,接收三个参数 `e`(图片的 URL 地址)、`t`(图片加载完成后的回调函数)和 `o`(图片加载出错时的回调函数),以下是该方法的具体逻辑代码
n.prototype.img = function (e, t, o) {
// 创建一个 `Image` 对象(这是 JavaScript 中用于操作图片的原生对象,类似 `<img>` 元素,但可以通过编程方式控制图片的加载等操作),并将其赋值给变量 `n`
var n = new Image;
// 设置 `Image` 对象 `n` 的 `src` 属性为传入的图片 URL 地址 `e`,这样浏览器就会开始加载对应的图片资源,然后判断 `n` 对象的 `complete` 属性(如果 `complete` 为 `true` 表示图片已经加载完成),
// 如果图片已经加载完成,则直接执行传入的加载完成后的回调函数 `t`,并将 `n` 对象作为参数传递进去;
// 如果图片还未加载完成,则绑定 `onload` 事件处理函数(当图片加载成功时会触发这个事件),在事件处理函数内部,先将 `onload` 事件处理函数置空(避免重复触发等问题),然后判断如果传入的 `t` 是函数类型,则执行 `t` 函数并将 `n` 对象作为参数传递进去,
// 同时绑定 `onerror` 事件处理函数(当图片加载出错时会触发这个事件),在事件处理函数内部,同样先将 `onerror` 事件处理函数置空,然后判断如果传入的 `o` 是函数类型,则执行 `o` 函数并将错误事件对象 `e` 作为参数传递进去,最后返回 `n` 对象(因为整个 `img` 方法的返回值就是这个 `Image` 对象相关的一些操作结果等情况)
return n.src = e, n.complete? t(n) : (n.onload = function () {
n.onload = null, "function" == typeof t && t(n)
}, void (n.onerror = function (e) {
n.onerror = null, "function" == typeof o && o(e)
}))
},
// 在 `n` 构造函数的原型上添加一个名为 `config` 的方法,它接收一个参数 `e`(一个配置对象),用于更新 `o` 对象中的配置信息,以下是该方法内部的具体逻辑代码
n.prototype.config = function (e) {
// 判断如果传入的参数 `e` 为假值(比如 `undefined`、`null` 等情况),则将 `e` 赋值为一个空对象 `{}`,确保后续操作有一个有效的对象来处理配置信息更新
e = e || {};
// 通过 `for...in` 循环遍历传入的配置对象 `e` 的所有可枚举属性,对于每个属性 `t`,将 `o` 对象中对应的属性(也就是 `o[t]`)的值更新为 `e[t]`(也就是用传入的配置对象中的属性值覆盖 `o` 对象中原有的属性值),实现配置信息的更新操作
for (var t in e) o[t] = e[t];
// 最后返回当前实例对象(也就是 `n` 构造函数的实例对象,方便进行链式调用等操作,例如可以继续调用实例对象上的其他方法等)
return this
},
n.prototype.modules = function () {
// 创建一个空对象 `e`,用于存储要返回的模块相关信息,后续会将 layui 框架中各个模块对应的路径等信息填充到这个对象中
var e = {};
// 通过 `for...in` 循环遍历前面定义的 `u` 对象(`u` 对象中存储了 layui 框架各个功能模块对应的相对路径信息),对于 `u` 对象中的每个属性 `t`(也就是模块名称),
// 将 `e` 对象中对应的属性(`e[t]`)的值设置为 `u[t]`(也就是将模块名称对应的路径信息复制到新创建的 `e` 对象中),这样 `e` 对象就存储了和 `u` 对象一样的模块路径信息结构,最后返回这个填充好的 `e` 对象
for (var t in u) e[t] = u[t];
return e
}(),
n.prototype.extend = function (e) {
// 将当前调用此方法的 `n` 构造函数实例对象自身保存到变量 `t` 中,方便后续在方法内部引用实例对象的属性和方法等
var t = this;
// 判断如果传入的参数 `e` 为假值(比如 `undefined`、`null` 等情况),则将 `e` 赋值为一个空对象 `{}`,确保后续操作有一个有效的对象来处理模块扩展相关信息
e = e || {};
// 通过 `for...in` 循环遍历传入的参数对象 `e` 的所有可枚举属性 `o`,对于每个属性 `o`,判断在当前实例对象 `t` 上是否已经存在这个属性(`t[o]`)或者在实例对象的 `modules` 属性(也就是存储模块相关信息的对象)中是否已经存在这个属性(`t.modules[o]`
// 如果已经存在,则调用 `i` 函数(前面定义的用于输出错误提示信息的函数)并传入 `"模块名 " + o + " 已被占用"`(表示模块名称已经被使用了,不能重复扩展定义该模块的提示信息),
// 如果不存在,则将实例对象 `t` 的 `modules` 属性中对应的属性(`t.modules[o]`)的值设置为 `e[o]`(也就是将传入的参数对象中对应属性的模块扩展信息添加到实例对象的 `modules` 对象中),实现模块的扩展操作,最后返回当前实例对象 `t`
for (var o in e) t[o] || t.modules[o]? i("模块名 " + o + " 已被占用") : t.modules[o] = e[o];
return t
},
n.prototype.router = function (e) {
// 将当前调用此方法的 `n` 构造函数实例对象自身保存到变量 `t` 中,方便后续在方法内部引用实例对象的属性和方法等
var t = this, e = e || location.hash, o = {path: [], search: {}, hash: (e.match(/[^#](#.*$)/) || [])[1] || ""};
// 判断如果传入的参数 `e`(可能是页面的 `hash` 值等相关信息)以 `"#/"` 开头(从代码逻辑推测是符合某种特定的路由格式要求),则执行以下代码块进行路由信息的解析和处理
return /^#\//.test(e)? (
// 先将 `e` 参数中的 `"#/"` 开头部分替换为空字符串,得到去除开头特定标识后的路由路径部分,然后将 `o` 对象的 `href` 属性设置为 `"/"` 加上处理后的路由路径
e = e.replace(/^#\//, ""), o.href = "/" + e,
// 再将处理后的路由路径按照 `/` 字符进行分割(通过 `split` 方法),得到一个路径片段的数组(如果分割失败则返回 `false`,这里代码逻辑中当作 `false` 情况也能继续处理),将分割后的数组赋值给 `e`
e = e.replace(/([^#])(#.*$)/, "$1").split("/") || [],
// 通过 `t.each` 方法(从代码逻辑推测是一个自定义的循环遍历方法,类似 `forEach` 功能)遍历分割后的路由路径片段数组 `e`,对于每个片段 `t`,判断如果片段以 `\w+=` 开头(也就是符合类似 `key=value` 的格式,从代码逻辑推测是用于解析路由中的查询参数部分),
// 则执行一个匿名函数,在函数内部将片段 `t` 按照 `=` 字符进行分割(通过 `split` 方法),得到 `key` 和 `value` 两部分,将 `key` 作为属性名,`value` 作为属性值添加到 `o` 对象的 `search` 属性(一个用于存储查询参数的对象)中,
// 如果片段不符合 `\w+=` 开头的格式,则将片段直接添加到 `o` 对象的 `path` 属性(一个用于存储路由路径片段的数组)中,最后返回处理好的 `o` 对象,这个对象包含了解析后的路由路径、查询参数以及 `hash` 值等路由相关信息
t.each(e, function (e, t) {
/^\w+=/.test(t)? function () {
t = t.split("="), o.search[t[0]] = t[1]
}() : o.path.push(t)
}), o) : o
},
n.prototype.data = function (t, o, n) {
// 判断如果传入的参数 `t` 为假值(比如 `undefined`、`null` 等情况),则将 `t` 赋值为 `"layui"`(从代码逻辑推测可能是一个默认的用于存储数据的名称或者标识等),同时判断如果 `n` 为假值,则将 `n` 赋值为 `localStorage`(可能是默认使用本地存储来保存数据),并且判断当前环境是否支持 `JSON` 对象以及 `JSON.parse` 方法(用于后续处理存储的数据是否为 JSON 格式等操作),如果满足这些条件,则执行以下代码块
if (t = t || "layui", n = n || localStorage, e.JSON && e.JSON.parse) {
// 判断如果传入的参数 `o` 为 `null`,表示可能要删除对应的数据,执行 `delete n[t]`(也就是从 `n` 对象中删除以 `t` 为键的数据,这里 `n` 可能是 `localStorage` 或者其他类似的存储对象),然后直接返回(因为这种情况下没有要返回的具体数据值了)
if (null === o) return delete n[t];
o = "object" == typeof o? o : {key: o};
try {
// 尝试使用 `JSON.parse` 方法解析存储在 `n`(存储对象)中以 `t`(名称标识)为键的数据,将解析后的结果赋值给变量 `r`,如果解析成功,`r` 就是对应的数据对象,方便后续进行数据的操作和处理
var r = JSON.parse(n[t])
} catch (i) {
// 如果在解析数据过程中出现错误(比如数据格式不符合 JSON 规范等情况),则将 `r` 赋值为一个空对象 `{}`,避免后续代码出现引用错误等问题,同时也相当于对错误数据进行了一种默认的处理方式
var r = {}
}
// 判断 `o` 对象中是否存在 `value` 属性(通过 `in` 操作符判断),如果存在,则将解析后的数据对象 `r` 中以 `o.key` 为键的属性值设置为 `o.value`,实现根据传入的参数更新数据对象中对应属性值的操作
return "value" in o && (r[o.key] = o.value),
// 判断 `o` 对象中是否存在 `remove` 属性且值为真(表示可能要删除数据对象中的某个属性),如果满足条件,则删除 `r` 对象中以 `o.key` 为键的属性,进行数据的删除操作
o.remove && delete r[o.key],
// 将处理后的 `r` 对象(更新或删除了相关属性后的数据对象)再通过 `JSON.stringify` 方法转换为 JSON 字符串格式,然后重新赋值给存储对象 `n` 中以 `t` 为键的属性,实现对存储数据的更新操作
n[t] = JSON.stringify(r),
// 判断 `o` 对象中是否存在 `key` 属性,如果存在,则返回 `r` 对象中以 `o.key` 为键的属性值,否则返回整个 `r` 对象,根据不同情况返回相应的数据内容,方便外部调用这个方法获取期望的数据
o.key? r[o.key] : r
}
},
// 在 `n` 构造函数的原型上添加一个名为 `sessionData` 的方法,它接收两个参数 `e` 和 `t`,从方法内部实现来看,它主要是调用了前面定义的 `data` 方法,并传入 `e`、`t` 以及 `sessionStorage` 作为参数,意味着这个方法是专门用于在浏览器的会话存储(`sessionStorage`)中进行数据操作的快捷方式,与 `data` 方法功能类似,只是指定了存储对象为 `sessionStorage`
n.prototype.sessionData = function (e, t) {
return this.data(e, t, sessionStorage)
},
// 在 `n` 构造函数的原型上添加一个名为 `device` 的方法,它接收一个可选参数 `t`,这个方法主要用于获取当前设备的相关信息,比如操作系统类型、是否是微信浏览器、是否是安卓或 iOS 系统等信息,以下是该方法内部的详细逻辑代码
n.prototype.device = function (t) {
// 获取浏览器的 `userAgent` 字符串并转换为小写字母形式,赋值给变量 `o``userAgent` 字符串包含了浏览器以及设备的很多相关信息,后续会通过正则表达式等方式从中提取出需要的设备相关信息
var o = navigator.userAgent.toLowerCase(),
// 定义一个内部函数 `n`,它接收一个参数 `e`,在函数内部创建一个以 `e` 加上 `"/([^\\s\\_\\-]+)"` 为模式的正则表达式对象 `t`(目的是用于从 `userAgent` 字符串中提取符合特定格式的版本号等相关信息),然后通过 `match` 方法在 `o``userAgent` 字符串)中查找匹配的内容,取匹配结果数组的第二个元素(也就是括号内捕获的内容,如果有的话)作为提取的信息,若没有匹配到则返回 `false`,这个函数主要用于提取不同软件或平台在 `userAgent` 中标识的版本号等相关信息
n = function (e) {
var t = new RegExp(e + "/([^\\s\\_\\-]+)");
return e = (o.match(t) || [])[1], e ||!1
},
// 创建一个对象 `r`,用于存储解析后的设备相关信息,对象中的每个属性通过相应的函数或逻辑来获取对应的值,以下是各个属性的具体获取逻辑
r = {
// 定义 `os` 属性,通过一个匿名函数来获取操作系统类型,函数内部使用正则表达式判断 `userAgent` 字符串中是否包含特定的操作系统标识(如 `windows`、`linux`、`ios`、`mac` 等),如果匹配到则返回对应的操作系统名称,若都不匹配则返回 `undefined`,表示无法确定操作系统类型
os: function () {
return /windows/.test(o)? "windows" : /linux/.test(o)? "linux" : /iphone|ipod|ipad|ios/.test(o)? "ios" : /mac/.test(o)? "mac" : void 0
}(),
// 定义 `ie` 属性,通过判断当前环境是否支持 `ActiveXObject`(这是 Internet Explorer 浏览器特有的对象,用于操作一些浏览器相关功能)或者 `ActiveXObject` 是否在全局对象 `e` 中存在,并且通过正则表达式从 `userAgent` 字符串中提取 Internet Explorer 的版本号(如果有的话,默认值为 `"11"`),以此来判断是否是 Internet Explorer 浏览器以及其版本信息
ie: function () {
return!!(e.ActiveXObject || "ActiveXObject" in e) && ((o.match(/msie\s(\d+)/) || [])[1] || "11")
}(),
// 定义 `weixin` 属性,通过调用前面定义的内部函数 `n` 并传入 `"micromessenger"`(微信浏览器在 `userAgent` 字符串中的标识),来判断是否是微信浏览器以及提取微信浏览器的相关版本号等信息(如果有的话)
weixin: n("micromessenger")
};
// 判断如果传入了参数 `t` 并且在 `r` 对象中不存在以 `t` 为名称的属性(也就是对应的设备信息还未获取或者不存在),则调用 `n` 函数(前面定义的提取信息的函数)并传入 `t`,将获取到的结果赋值给 `r` 对象中以 `t` 为名称的属性,实现动态获取指定的设备相关信息的功能
return t &&!r[t] && (r[t] = n(t)),
// 判断 `userAgent` 字符串中是否包含 `"android"` 标识,来确定是否是安卓设备,将判断结果赋值给 `r` 对象的 `android` 属性
r.android = /android/.test(o),
// 通过判断 `r` 对象中 `os` 属性的值是否为 `"ios"`,来确定是否是 iOS 设备,将判断结果赋值给 `r` 对象的 `ios` 属性
r.ios = "ios" === r.os,
// 最后返回包含了各种设备相关信息的 `r` 对象,方便外部调用这个方法获取设备相关的详细信息
r
},
// 在 `n` 构造函数的原型上添加一个名为 `hint` 的方法,这个方法返回一个包含 `error` 属性的对象,`error` 属性的值是前面定义的 `i` 函数(用于在控制台输出错误提示信息的函数),从方法的功能来看,可能是提供一种统一的方式让外部获取到错误提示的相关操作函数,方便在不同地方进行错误提示输出等操作
n.prototype.hint = function () {
return {error: i}
},
// 在 `n` 构造函数的原型上添加一个名为 `each` 的方法,它接收两个参数 `e` 和 `t`,这个方法类似于 JavaScript 原生的 `forEach` 方法,用于循环遍历数组或者对象的属性,根据不同的数据类型(数组或者对象)以及传入的回调函数 `t` 的逻辑来执行相应的操作,以下是该方法内部的详细逻辑代码
n.prototype.each = function (e, t) {
var o, n = this;
// 判断如果传入的第二个参数 `t` 不是函数类型,则直接返回当前实例对象 `n`,因为如果不是函数就无法执行相应的循环遍历操作中的回调逻辑了,所以直接返回不做后续处理
if ("function"!= typeof t) return n;
// 判断如果传入的第一个参数 `e` 为假值(比如 `undefined`、`null` 等情况),则将 `e` 赋值为一个空数组 `[]`,确保后续操作有一个有效的数据结构来进行循环遍历,同时判断 `e` 的构造函数是否是 `Object`(也就是判断 `e` 是否是对象类型),如果是对象类型,则执行以下代码块进行对象属性的遍历操作
if (e = e || [], e.constructor === Object) {
// 通过 `for...in` 循环遍历对象 `e` 的所有可枚举属性,对于每个属性 `o`,使用 `call` 方法调用传入的回调函数 `t`,并将属性名 `o` 和属性值 `e[o]` 作为参数传递进去,如果回调函数 `t` 的返回值为真(也就是在回调函数内部判断满足了某种自定义的条件),则使用 `break` 语句跳出循环,结束遍历操作
for (o in e) if (t.call(e[o], o, e[o])) break
} else {
// 如果 `e` 不是对象类型(也就是推测为数组类型等可迭代的数据结构),则通过一个普通的 `for` 循环进行遍历,从索引 `0` 开始,每次递增 `1`,只要索引小于 `e` 的长度(`e.length`)并且回调函数 `t` 的返回值为假(也就是还未满足回调函数内部自定义的停止循环的条件),就继续循环,在每次循环中同样使用 `call` 方法调用回调函数 `t`,并将当前索引 `o` 和对应索引位置的元素 `e[o]` 作为参数传递进去
for (o = 0; o < e.length &&!t.call(e[o], o, e[o]); o++) ;
}
// 循环遍历结束后,返回当前实例对象 `n`,方便进行链式调用等操作(比如可以继续调用实例对象上的其他方法等)
return n
},
// 在 `n` 构造函数的原型上添加一个名为 `sort` 的方法,它接收三个参数 `e`、`t` 和 `o`,这个方法用于对数据(推测为数组类型的数据)进行排序操作,并且可以根据指定的属性(通过参数 `t` 指定)以及是否逆序(通过参数 `o` 判断)等条件来进行排序,以下是该方法内部的详细逻辑代码
n.prototype.sort = function (e, t, o) {
// 首先通过 `JSON.parse` 和 `JSON.stringify` 方法对传入的第一个参数 `e`(可能是一个数组数据,也可以是其他可转换为 JSON 字符串的数据结构,不过从功能上推测主要是用于处理数组)进行深拷贝操作,将拷贝后的结果赋值给变量 `n`,这样后续对 `n` 的排序操作不会影响到原始的 `e` 数据,保证数据的完整性和独立性
var n = JSON.parse(JSON.stringify(e || []));
// 判断如果传入的第二个参数 `t` 存在(也就是有指定的用于排序的属性名称等相关信息),则执行以下代码块进行带条件的排序操作
return t? (
// 使用数组的 `sort` 方法对 `n` 数组进行排序,排序的比较函数接收两个参数 `e` 和 `o`,分别代表数组中要比较的两个元素,以下是比较函数内部的详细逻辑:
// 首先创建一个正则表达式对象 `n`,用于判断元素对应指定属性(通过 `t` 指定的属性)的值是否是整数(通过判断是否匹配 `^-?\d+$` 模式),然后分别获取两个元素 `e` 和 `o` 中以 `t` 为属性名的属性值,赋值给变量 `r` 和 `i`
// 如果 `r` 的值匹配整数的正则表达式,则将 `r` 通过 `parseFloat` 方法转换为浮点数(这样可以统一处理整数和小数的比较情况),同理如果 `i` 的值匹配整数正则表达式,也将其转换为浮点数,
// 接着进行比较判断,如果 `r` 存在且 `i` 不存在(也就是 `r` 有值而 `i` 为 `undefined` 等情况),则返回 `1`,表示 `e` 应该排在 `o` 后面;如果 `r` 不存在而 `i` 存在,则返回 `-1`,表示 `e` 应该排在 `o` 前面;
// 如果 `r` 和 `i` 都存在,则比较它们的大小,如果 `r` 大于 `i`,返回 `1`,表示 `e` 应该排在 `o` 后面,如果 `r` 小于 `i`,返回 `-1`,表示 `e` 应该排在 `o` 前面,如果 `r` 和 `i` 相等,则返回 `0`,表示它们的顺序不需要改变,通过这样的比较逻辑实现根据指定属性对数组元素的排序操作
n.sort(function (e, o) {
var n = /^-?\d+$/, r = e[t], i = o[t];
return n.test(r) && (r = parseFloat(r)), n.test(i) && (i = parseFloat(i)), r &&!i? 1 :!r && i? -1 : r > i? 1 : r < i? -1 : 0
}),
// 判断如果传入的第三个参数 `o` 为真(表示需要逆序排列),则调用 `n` 数组的 `reverse` 方法,将数组元素顺序颠倒,实现逆序排列的效果
o && n.reverse(),
// 最后返回排序(以及可能逆序后)的 `n` 数组,作为排序操作的结果返回给外部调用者
n) : n
},
// 在 `n` 构造函数的原型上添加一个名为 `stope` 的方法,它接收一个可选参数 `t`,这个方法主要用于阻止事件的冒泡传播,以下是该方法内部的详细逻辑代码
n.prototype.stope = function (t) {
// 判断如果没有传入参数 `t`,则将 `t` 赋值为全局的 `e.event`(从代码上下文推测可能是获取默认的事件对象相关信息,不过这里 `e` 具体指代什么需要看外层代码传入的情况,通常在浏览器环境下可能是 `window` 对象等情况),确保后续操作有一个有效的事件对象来进行停止冒泡的操作
t = t || e.event;
try {
var r = JSON.parse(n[t])
} catch (i) {
var r = {}
// 尝试调用事件对象 `t` 的 `stopPropagation` 方法,这个方法是 JavaScript 中用于阻止事件冒泡传播的标准方法,在支持的浏览器环境下执行这个方法就能达到阻止事件向上层元素传播的效果
t.stopPropagation()
} catch (o) {
// 如果在调用 `stopPropagation` 方法过程中出现错误(可能是在一些不支持这个方法的旧浏览器或者特殊环境下),则通过设置事件对象 `t` 的 `cancelBubble` 属性为 `true` 来模拟阻止事件冒泡的效果,这是一种旧的、兼容性的处理方式,在一些老版本浏览器中可以实现类似的功能
t.cancelBubble =!0
}
return "value" in o && (r[o.key] = o.value), o.remove && delete r[o.key], n[t] = JSON.stringify(r), o.key ? r[o.key] : r
}
}, n.prototype.sessionData = function (e, t) {
return this.data(e, t, sessionStorage)
}, n.prototype.device = function (t) {
var o = navigator.userAgent.toLowerCase(), n = function (e) {
var t = new RegExp(e + "/([^\\s\\_\\-]+)");
return e = (o.match(t) || [])[1], e || !1
}, r = {
os: function () {
return /windows/.test(o) ? "windows" : /linux/.test(o) ? "linux" : /iphone|ipod|ipad|ios/.test(o) ? "ios" : /mac/.test(o) ? "mac" : void 0
}(), ie: function () {
return !!(e.ActiveXObject || "ActiveXObject" in e) && ((o.match(/msie\s(\d+)/) || [])[1] || "11")
}(), weixin: n("micromessenger")
};
return t && !r[t] && (r[t] = n(t)), r.android = /android/.test(o), r.ios = "ios" === r.os, r
}, n.prototype.hint = function () {
return {error: i}
}, n.prototype.each = function (e, t) {
var o, n = this;
if ("function" != typeof t) return n;
if (e = e || [], e.constructor === Object) {
for (o in e) if (t.call(e[o], o, e[o])) break
} else for (o = 0; o < e.length && !t.call(e[o], o, e[o]); o++) ;
return n
}, n.prototype.sort = function (e, t, o) {
var n = JSON.parse(JSON.stringify(e || []));
return t ? (n.sort(function (e, o) {
var n = /^-?\d+$/, r = e[t], i = o[t];
return n.test(r) && (r = parseFloat(r)), n.test(i) && (i = parseFloat(i)), r && !i ? 1 : !r && i ? -1 : r > i ? 1 : r < i ? -1 : 0
}), o && n.reverse(), n) : n
}, n.prototype.stope = function (t) {
t = t || e.event;
try {
t.stopPropagation()
} catch (o) {
t.cancelBubble = !0
}
}, n.prototype.onevent = function (e, t, o) {
return "string" != typeof e || "function" != typeof o ? this : n.event(e, t, null, o)
}, n.prototype.event = n.event = function (e, t, n, r) {
var i = this, a = null, u = t.match(/\((.*)\)$/) || [], l = (e + "." + t).replace(u[0], ""), s = u[1] || "",
c = function (e, t) {
var o = t && t.call(i, n);
o === !1 && null === a && (a = !1)
};
return r ? (o.event[l] = o.event[l] || {}, o.event[l][s] = [r], this) : (layui.each(o.event[l], function (e, t) {
return "{*}" === s ? void layui.each(t, c) : ("" === e && layui.each(t, c), void (s && e === s && layui.each(t, c)))
}), a)
}, e.layui = new n
},
n.prototype.onevent = function (e, t, o) {
// 判断传入的第一个参数 `e` 是否不是字符串类型,或者传入的第三个参数 `o` 是否不是函数类型,
// 如果满足这两个条件中的任意一个,就直接返回当前的 `this`(也就是 `n` 构造函数的实例对象本身),
// 这意味着如果参数不符合要求,就不进行后续特定的事件相关操作,直接返回实例对象
return "string"!= typeof e || "function"!= typeof o? this : n.event(e, t, null, o)
},
n.prototype.event = n.event = function (e, t, n, r) {
// 将当前调用此方法的 `n` 构造函数实例对象自身保存到变量 `i` 中,方便后续在方法内部引用实例对象的属性和方法等
var i = this,
// 初始化一个变量 `a`,并赋值为 `null`,从后续代码看这个变量可能用于标记某种状态或者作为一个临时的中间变量,用于事件相关逻辑的处理
a = null,
// 使用正则表达式匹配传入的第二个参数 `t` 中是否包含括号及括号内的内容,例如像 `click()` 这样的格式,提取括号内的内容,
// 如果匹配成功,将括号内的内容作为数组返回,赋值给变量 `u`,如果匹配失败(也就是没有括号及括号内内容的情况),则返回 `false`
// 这里提取括号内内容的操作可能是为了获取事件处理函数相关的一些额外参数等信息(具体要根据 layui 框架整体对事件的设计来确定)
u = t.match(/\((.*)\)$/) || [],
// 通过将传入的第一个参数 `e`(事件名称相关的字符串,比如 `click` 等)和经过处理后的第二个参数 `t`(去掉括号及括号内内容后的字符串)进行拼接,然后再替换掉前面匹配到的括号及括号内内容(也就是 `u[0]`
// 生成一个新的字符串,用于作为唯一标识事件的一个组合字符串(例如 `click.someElement` 这样的格式,具体要根据实际传入的参数和业务逻辑确定),将这个新字符串赋值给变量 `l`,方便后续根据这个标识来查找、操作对应的事件相关信息
l = (e + "." + t).replace(u[0], ""),
// 判断如果前面通过正则表达式匹配 `t` 得到的 `u` 数组不为空(也就是有括号及括号内内容的情况),则取括号内的内容(也就是 `u[1]`)作为变量 `s` 的值,
// 如果 `u` 为空(也就是没有括号及括号内内容),则将 `s` 赋值为空字符串 `""`,这里 `s` 变量可能用于区分不同条件下的事件处理情况或者作为后续查找特定事件处理函数的一个标识等(同样要结合整体框架对事件的设计来理解)
s = u[1] || "",
// 定义一个内部函数 `c`,它接收两个参数 `e` 和 `t`,在函数内部通过 `call` 方法调用传入的第二个参数 `t`(应该是一个函数类型,从后续使用情况推测可能是事件处理回调函数),
// 并将当前实例对象 `i` 和传入的第三个参数 `n`(从参数位置推测可能是与事件相关的一些额外数据等信息)作为参数传递进去,获取函数的返回值赋值给变量 `o`
// 然后判断如果 `o` 的值为 `false` 并且变量 `a` 的值为 `null`,就将 `a` 的值设置为 `false`,从这段逻辑看可能是用于根据事件处理函数的返回值来设置某种全局或者局部的状态标记,用于控制事件后续的传播、执行等逻辑(具体要看 layui 框架对事件处理流程的设计)
c = function (e, t) {
var o = t && t.call(i, n);
o ===!1 && null === a && (a =!1)
};
// 判断如果传入的第四个参数 `r` 存在(也就是有传入对应的事件处理函数等相关信息),则执行以下代码块,用于添加或注册事件相关的处理逻辑
return r? (
// 判断在 `o.event` 对象(从前面代码上下文推测 `o` 是一个存储了很多模块相关配置、状态等信息的对象,`o.event` 可能是用于存储事件相关信息的一个子对象)中是否存在以 `l` 为名称的属性(也就是是否已经有对应的事件标识相关的记录),
// 如果不存在,就创建一个空对象作为 `o.event[l]` 的值(也就是为这个事件标识初始化一个存储相关信息的对象),然后将传入的事件处理函数 `r` 包装成一个只包含这个函数的数组,作为 `o.event[l]` 对象中以 `s` 为名称的属性的值(也就是根据 `s` 的标识将事件处理函数存储到对应的位置),最后返回当前实例对象 `this`,表示事件处理函数添加成功等情况(具体返回值的使用要结合调用这个方法的外部代码逻辑来看)
o.event[l] = o.event[l] || {}, o.event[l][s] = [r], this) : (
// 如果没有传入第四个参数 `r`(也就是可能是进行事件相关信息的查询、遍历等操作),则通过 `layui.each` 方法(从前面代码推测是 layui 框架自定义的用于循环遍历对象属性或者数组元素的方法,类似原生的 `forEach` 功能)遍历 `o.event[l]` 对象(也就是根据前面生成的事件标识 `l` 找到对应的存储事件相关信息的对象)的所有属性,
// 对于每个属性 `e` 和对应的值(是一个数组,里面存储了相关的事件处理函数等信息) `t`,进行以下判断和操作:
// 如果 `s` 的值为 `"{*}"`(从代码逻辑推测这可能是一个特殊的标识,表示要对所有的事件处理函数进行某种统一操作等情况),则通过 `layui.each` 方法再次遍历 `t` 数组中的每个事件处理函数,调用前面定义的内部函数 `c` 来执行相应的逻辑(也就是根据函数返回值等情况设置状态标记等操作);
// 如果 `s` 的值为空字符串 `""`(也就是没有特定的标识区分情况),则同样通过 `layui.each` 方法遍历 `t` 数组中的每个事件处理函数,调用 `c` 函数执行逻辑;
// 如果 `s` 有具体的值且当前遍历的属性 `e` 的值等于 `s`(也就是找到匹配特定标识的事件处理函数情况),也通过 `layui.each` 方法遍历 `t` 数组中的每个事件处理函数,调用 `c` 函数执行逻辑,
// 最后返回变量 `a` 的值(前面在 `c` 函数中根据事件处理函数返回值等情况设置的状态标记变量),从整体逻辑看这里返回 `a` 的值可能是用于向外部传递某种事件处理过程中的状态信息,方便外部根据这个状态进行进一步的操作或者判断(同样要结合 layui 框架整体对事件处理的设计来准确理解其用途)
layui.each(o.event[l], function (e, t) {
return "{*}" === s? void layui.each(t, c) : ("" === e && layui.each(t, c), void (s && e === s && layui.each(t, c)))
}), a)
},
// 将通过 `n` 构造函数创建的一个新实例对象赋值给全局的 `e.layui`(这里 `e` 通常指代全局对象,在浏览器环境下一般就是 `window` 对象,也就是将 `layui` 框架实例挂载到全局对象上,方便在其他地方通过 `layui` 这个名称来访问和使用 layui 框架提供的各种功能和属性等)
e.layui = new n
}(window);
Loading…
Cancel
Save