项目整理–Echarts前端后台的贯通写法

注:下面所有内容建立在FH admin开源框架和eharts插件基础上,建议观看本案例者进行了解。

业务逻辑

绘制两张图表。分别显示城市空间库和其它数据仓库的信息(城市空间库单独绘制)。要求:城市空间库显示数据库的实际使用量和剩余用量。其它库显示百分比。

效果展示

默认显示状态



鼠标指向状态


实现过程

1.后台数据处理

表结构设计

数据库数据

注:此处数据为显示数据,并不是项目使用数据,仅作測试使用。

Mapper文件写法

注1:此处在前端页面须要绘制两个图表,因此用两条sql语句。差别为提供查询的type字段不同。此字段也可由传參带入。使用一条sql分别实现查询,此次为了展示直观,採用第一种做法。

注2:因为採用框架,此处数据为採用实体类封装,而是採用HashMap封装。能够依据自己习惯。创建实体类来存储数据库中数据。

<?

xml version="1.0" encoding="UTF-8"?

>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="SjkyxMapper"> <!-- 列表(无实际意义,为以后扩展功能用) -->
<select id="datalist" parameterType="page" resultType="pd">
SELECT
a.id,
a.dept,
a.order,
a.score
FROM
cms_yw_fwxl AS a
ORDER BY
a.order
</select> <!-- 获取城市空间库的信息 -->
<select id="getcskjcharts" parameterType="page" resultType="pd">
SELECT
c.type,
c.id,
c.`name`,
c.volume_total,
c.volume_total_unit,
c.volume_use,
c.volume_use_unit,
c.create_time,
c.creator,
c.update_time,
c.updater,
c.remark
FROM
cms_yw_sjkyx AS c
WHERE
type = 1
</select> <!-- 获取其它库的信息 -->
<select id="getothercharts" parameterType="page" resultType="pd">
SELECT
c.type,
c.id,
c.`name`,
c.volume_total,
c.volume_total_unit,
c.volume_use,
c.volume_use_unit,
c.create_time,
c.creator,
c.update_time,
c.updater,
c.remark
FROM
cms_yw_sjkyx AS c
WHERE
type = 2
</select> </mapper>

Service中写法

注1:此处採用的已有框架,使用已经提供的统一的Dao。假设使用传统的SSM写法。能够自己稍加改动,在此不做赘述。

注2:依据业务逻辑理解代码,当中封装了createData方法来实现不同的业务逻辑。

@Service("sjkyxService")
public class SjkyxService { @Resource(name = "daoSupport")
private DaoSupport dao; /*
*数据资源列表
*/
public List<PageData> list(Page page)throws Exception{
return (List<PageData>)dao.findForList("SjkyxMapper.datalist", page);
} /*
* 用来返回城市空间库使用信息
*/
public Map<String, Object> getcskjcharts(int type)throws Exception{
List<PageData> list = (List<PageData>)dao.findForList("SjkyxMapper.getcskjcharts", null);
return createData(list,type);
} /*
* 用来返回其它库所用信息
*/
public Map<String, Object> getothercharts(int type)throws Exception{
List<PageData> list = (List<PageData>)dao.findForList("SjkyxMapper.getothercharts", null);
return createData(list,type);
} /*
* 内部设计的方法。用于封装查询数据
*/
private Map<String, Object> createData(List<PageData> list,int type)throws Exception{
Map<String,Object> resultMap = new HashMap<String,Object>();
//x轴现实的信息
String[] xAxisArr = new String[list.size()];
//总量信息
Integer[] restArr = new Integer[list.size()];
//已使用信息
Integer[] usedArr = new Integer[list.size()];
if(1==type){
for(int i=0;i<list.size();i++){
xAxisArr[i] =(String) list.get(i).get("name");
usedArr[i] = Integer.parseInt(new java.text.DecimalFormat("0").format((Double) list.get(i).get("volume_use")));
double restData = (Double)list.get(i).get("volume_total")-(Double) list.get(i).get("volume_use");
restArr[i] = Integer.parseInt(new java.text.DecimalFormat("0").format(restData));
}
}else if(2==type){
for(int i=0;i<list.size();i++){
xAxisArr[i] =(String) list.get(i).get("name");
double perData = (Double) list.get(i).get("volume_use")/(Double) list.get(i).get("volume_total")*100;
usedArr[i] = Integer.parseInt(new java.text.DecimalFormat("0").format(perData));
double restData = ((Double)list.get(i).get("volume_total")-(Double) list.get(i).get("volume_use"))/(Double) list.get(i).get("volume_total")*100;
restArr[i] = Integer.parseInt(new java.text.DecimalFormat("0").format(restData));
}
}
resultMap.put("xAxisArr", xAxisArr);
resultMap.put("restArr", restArr);
resultMap.put("usedArr", usedArr);
return resultMap;
}
}

Controller中写法

主要用于跳转页面和Ajax传递数据,涉及权限管理的部分能够不用看。

package com.bonc.dgioc.portal.web.controller.portal.operate;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import javax.annotation.Resource; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView; import com.bonc.dgioc.portal.common.utils.Const;
import com.bonc.dgioc.portal.common.utils.PageData;
import com.bonc.dgioc.portal.domain.entity.Page;
import com.bonc.dgioc.portal.service.portal.operate.FwxlService;
import com.bonc.dgioc.portal.service.portal.operate.SjkyxService;
import com.bonc.dgioc.portal.service.portal.operate.SjzyService;
import com.bonc.dgioc.portal.web.controller.base.BaseController; /**
* 功 能:运维首页数据库执行情况
* 类名称:SjkyxController
* 创建人:@author Xiaoqi
* 创建时间:2016-03-29
*/ @Controller
@RequestMapping(value="/operate/sjkyx")
public class SjkyxController extends BaseController { @Resource(name="sjkyxService")
private SjkyxService sjkyxService; /**
* 获取sjkyx列表
* @author Xiaoqi
* @date 2016-03-30
*/
@RequestMapping(value="/getsjkyxlist")
public ModelAndView list(Page page){
logBefore(logger, "列表sjkyx信息");
ModelAndView mv = this.getModelAndView();
PageData pd = new PageData();
try{
pd = this.getPageData();
page.setPd(pd);
List<PageData> varList = sjkyxService.list(page); //列出sjkyx列表
mv.setViewName("portal/operate/sjkyx_list");
mv.addObject("varList", varList);
mv.addObject("pd", pd);
mv.addObject(Const.SESSION_QX,this.getHC()); //button权限
} catch(Exception e){
logger.error(e.toString(), e);
}
return mv;
} /**
* 返回城市空间库的图表信息
* @return 返回城市空间库的图表信息
* @date 2016-04-11
*/
@ResponseBody
@RequestMapping(value="/getcskjcharts")
public Map<String,Object> getcskjcharts(){
logBefore(logger, "获取城市空间库图表信息");
Map<String,Object> resultMap = new HashMap<String,Object>();
try{
resultMap = sjkyxService.getcskjcharts(1); //获取其它库图表信息
} catch(Exception e){
logger.error(e.toString(), e);
}
return resultMap;
} /**
* 返回城市空间库之外的其它库的图表信息
* @return 返回城市空间库之外的其它库的图表信息
* @date 2016-04-11
*/
@ResponseBody
@RequestMapping(value="/getothercharts")
public Map<String,Object> getothercharts(){
logBefore(logger, "获取其它库图表信息");
Map<String,Object> data = new HashMap<String,Object>();
try{
data = sjkyxService.getothercharts(2); //获取其它库图表信息
} catch(Exception e){
logger.error(e.toString(), e);
}
return data;
} /* ===============================权限================================== */
public Map<String, String> getHC(){
Subject currentUser = SecurityUtils.getSubject(); //shiro管理的session
Session session = currentUser.getSession();
return (Map<String, String>)session.getAttribute(Const.SESSION_QX);
}
/* ===============================权限================================== */ @InitBinder
public void initBinder(WebDataBinder binder){
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(format,true));
} }

2.前端页面处理

下面为分部代码解读,最下方有前端页面所有代码。

引入echarts和jQuery文件

注:此处bootstrap为前端框架,此处知道当中含有jQuery文件就可以。

<!-- 引入 -->
<%@ include file="../../common/bootstrap_js.jsp"%>
<script type="text/javascript" src="<%=basePath%>/resources/module/echarts/echarts.js"></script><!-- 引入echarts -->

建立div存放不同的图表

注:echarts中一个div仅仅能绘制一张图表

<div>
<div id="chkj" style="height:160px;width:20%;text-align:right;float:left;">
</div>
<div id="other" style="height:160px;width:80%;text-align:right;float:right;">
</div>
</div>

echarts代码解读

引入echarts的主题和各种组件,调用绘制图表的方法drawotherCharts和drawchkjCharts

 require.config({
paths:{
echarts:'<%=basePath%>/resources/module/echarts'
}
}); require(
['echarts',
'echarts/theme/macarons',
'echarts/chart/line', //使用折线图,就须要加载line模块,按需加载(柱图:bar;饼图:pie;地图:map;)
'echarts/chart/bar',
'echarts/chart/pie'
],
function (ec,theme) {
drawotherCharts(ec,theme),
drawchkjCharts(ec,theme)
});

绘制图表:

function drawotherCharts(ec,theme){
var myChart = ec.init(document.getElementById("other"),theme);
option = {
tooltip : {
trigger: 'axis',
axisPointer : { // 坐标轴指示器,坐标轴触发有效
type : 'shadow' // 默觉得直线,可选为:'line' | 'shadow'
},
formatter: function (params){ //用来编辑鼠标指向时的文字信息
return params[0].name + '<br/>'
+ params[0].seriesName + ' : ' + params[0].value + '<br/>'
+ params[1].seriesName + ' : ' + (params[1].value + params[0].value);
}
},
legend: { //此处为图例
selectedMode:false,
data:['已使用', '未使用']
},
grid:{ //此处控制图表在div中的位置 x:20,
y:60,
x2:0,
y2:35
},
toolbox: { //此处为控制图表的工具栏,设置show选项为false,能够将show的false改为true来查看效果。
show : false,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
restore : {show: true},
saveAsImage : {show: true}
}
},
calculable : false, //取消加载时的动态效果
xAxis : [ //x轴现实信息配置
{
type : 'category',
data : [],
splitLine:{
show:false
},
axisTick:false,
axisLine:false,
axisLabel:{
rotate:0,
margin:10,
textStyle:{
fontSize : '2px',
fontFamily : '微软雅黑',
color: '#00A3D1'
}
},
}
],
yAxis : [ //y轴数据配置
{
type : 'value',
axisLine:false,
splitLine:{
show:false
},
axisTick:false,
boundaryGap: [0, 0.1],
axisLabel:{
show:false
}
}
],
series : [
{
name:'已使用',
type:'bar',
stack: 'sum',
barCategoryGap: '50%',
barWidth:45,
itemStyle: {
normal: {
color: '#00A3D1',
barBorderColor: '#00A3D1',
barBorderWidth: 4,
barBorderRadius:0,
label : {
show: true, position: 'insideTop'
}
}
},
data:[]
},
{
name:'未使用',
type:'bar',
stack: 'sum',
itemStyle: {
normal: {
color: '#fff',
barBorderColor: '#00A3D1',
barBorderWidth: 3,
barBorderRadius:0,
label : {
show: true,
position: 'top',
textStyle: {
fontSize : '10',
fontFamily : '微软雅黑',
color: '#00A3D1'
}
}
}
},
data:[]
}
]
}; myChart.showLoading({
text: "图表数据正在努力加载..."
});
//通过ajax向后台发送请求。传递数据。
$.ajax({
type: 'GET',
url : '<%=path %>/operate/sjkyx/getothercharts',
dataType: 'json',
success:function(data){
debugger;
option.xAxis[0]['data']=data.xAxisArr;
option.series[0]['data']=data.usedArr;
option.series[1]['data']=data.restArr;
myChart.setOption(option);
},
error:function(){
debugger;
},
complete:function(){
//无论数据接口成功或异常,都最终加载提示
myChart.hideLoading();//停止动画加载提示
}
}) }

echarts完整代码

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Widgets - Ace Admin</title>
<base href="<%=basePath%>">
<!-- 引入 -->
<%@ include file="../../common/bootstrap_js.jsp"%>
<script type="text/javascript" src="<%=basePath%>/resources/module/echarts/echarts.js"></script><!-- 引入echarts -->
<script type="text/javascript"> require.config({
paths:{
echarts:'<%=basePath%>/resources/module/echarts'
}
}); require(
['echarts',
'echarts/theme/macarons',
'echarts/chart/line', //使用折线图,就须要加载line模块,按需加载(柱图:bar;饼图:pie;地图:map;)
'echarts/chart/bar',
'echarts/chart/pie'
],
function (ec,theme) {
drawotherCharts(ec,theme),
drawchkjCharts(ec,theme)
}); function drawotherCharts(ec,theme){
var myChart = ec.init(document.getElementById("other"),theme);
option = {
tooltip : {
trigger: 'axis',
axisPointer : { // 坐标轴指示器,坐标轴触发有效
type : 'shadow' // 默觉得直线。可选为:'line' | 'shadow'
},
formatter: function (params){ //用来编辑鼠标指向时的文字信息
return params[0].name + '<br/>'
+ params[0].seriesName + ' : ' + params[0].value + '<br/>'
+ params[1].seriesName + ' : ' + (params[1].value + params[0].value);
}
},
legend: { //此处为图例
selectedMode:false,
data:['已使用', '未使用']
},
grid:{ //此处控制图表在div中的位置 x:20,
y:60,
x2:0,
y2:35
},
toolbox: { //此处为控制图表的工具栏,设置show选项为false,能够将show的false改为true来查看效果。
show : false,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
restore : {show: true},
saveAsImage : {show: true}
}
},
calculable : false, //取消加载时的动态效果
xAxis : [ //x轴现实信息配置
{
type : 'category',
data : [],
splitLine:{
show:false
},
axisTick:false,
axisLine:false,
axisLabel:{
rotate:0,
margin:10,
textStyle:{
fontSize : '2px',
fontFamily : '微软雅黑',
color: '#00A3D1'
}
},
}
],
yAxis : [ //y轴数据配置
{
type : 'value',
axisLine:false,
splitLine:{
show:false
},
axisTick:false,
boundaryGap: [0, 0.1],
axisLabel:{
show:false
}
}
],
series : [
{
name:'已使用',
type:'bar',
stack: 'sum',
barCategoryGap: '50%',
barWidth:45,
itemStyle: {
normal: {
color: '#00A3D1',
barBorderColor: '#00A3D1',
barBorderWidth: 4,
barBorderRadius:0,
label : {
show: true, position: 'insideTop'
}
}
},
data:[]
},
{
name:'未使用',
type:'bar',
stack: 'sum',
itemStyle: {
normal: {
color: '#fff',
barBorderColor: '#00A3D1',
barBorderWidth: 3,
barBorderRadius:0,
label : {
show: true,
position: 'top',
textStyle: {
fontSize : '10',
fontFamily : '微软雅黑',
color: '#00A3D1'
}
}
}
},
data:[]
}
]
}; myChart.showLoading({
text: "图表数据正在努力加载..."
});
//通过ajax向后台发送请求。传递数据。
$.ajax({
type: 'GET',
url : '<%=path %>/operate/sjkyx/getothercharts',
dataType: 'json',
success:function(data){
debugger;
option.xAxis[0]['data']=data.xAxisArr;
option.series[0]['data']=data.usedArr;
option.series[1]['data']=data.restArr;
myChart.setOption(option);
},
error:function(){
debugger;
},
complete:function(){
//无论数据接口成功或异常。都最终加载提示
myChart.hideLoading();//停止动画加载提示
}
}) } function drawchkjCharts(ec,theme){
var myChart = ec.init(document.getElementById("chkj"),theme);
options = { tooltip : {
show:false,
trigger: 'axis',
axisPointer : { // 坐标轴指示器。坐标轴触发有效
type : 'shadow' // 默觉得直线,可选为:'line' | 'shadow'
},
formatter: function (params){
return params[0].name + '<br/>'
+ params[0].seriesName + ' : ' + params[0].value + '<br/>'
+ params[1].seriesName + ' : ' + (params[1].value + params[0].value);
}
},
grid:{ x:20,
y:50,
x2:0,
y2:35
},
toolbox: {
show : false,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
restore : {show: true},
saveAsImage : {show: true}
}
},
calculable : false,
xAxis : [
{
type : 'category',
data : [],
splitLine:{
show:false
},
axisTick:false,
axisLine:false,
axisLabel:{
rotate:0,
margin:10,
textStyle:{
fontSize : '2px',
fontFamily : '微软雅黑',
color: 'red'
}
},
}
],
yAxis : [
{
type : 'value',
axisLine:false,
splitLine:{
show:false
},
axisTick:false,
boundaryGap: [0, 0.1],
axisLabel:{
show:false
}
}
],
series : [
{
name:'已使用',
type:'bar',
stack: 'sum',
barCategoryGap: '50%',
barWidth:45,
itemStyle: {
normal: {
color: 'red',
barBorderColor: 'red',
barBorderWidth: 4,
barBorderRadius:0,
label : {
show: true, position: 'insideTop',
formatter:'{c}'+'T'
}
}
},
data:[]
},
{
name:'未使用',
type:'bar',
stack: 'sum',
itemStyle: {
normal: {
color: '#fff',
barBorderColor: 'red',
barBorderWidth: 3,
barBorderRadius:0,
label : {
show: true,
position: 'top',
formatter:'{c}'+'T',
textStyle: {
fontSize : '10',
fontFamily : '微软雅黑',
color: 'red'
}
}
}
},
data:[]
}
]
}; myChart.showLoading({
text: "图表数据正在努力加载..."
}); $.ajax({
type: 'GET',
url : '<%=path %>/operate/sjkyx/getcskjcharts',
dataType: 'json',
success:function(data){
debugger;
options.xAxis[0]['data']=data.xAxisArr;
options.series[0]['data']=data.usedArr;
options.series[1]['data']=data.restArr;
myChart.setOption(options);
},
error:function(){
debugger;
},
complete:function(){
//无论数据接口成功或异常,都最终加载提示
myChart.hideLoading();//停止动画加载提示
}
}) } </script>
</head> <body style="height:160px;width:450px;text-align:left;">
<div>
<div id="chkj" style="height:160px;width:20%;text-align:right;float:left;">
</div>
<div id="other" style="height:160px;width:80%;text-align:right;float:right;">
</div>
</div> </body> </html>

项目整理--Echarts前端后台的贯通写法的更多相关文章

  1. crm项目整理

    crm项目整理   一.开发背景 由于公司人员的增多,原来通过excel表格存取方式过于繁琐,而且对于公司人员的调配和绩效考核等不能做到精确处理,所以开发crm系统,开始开发只是针对销售人员和客户,后 ...

  2. 前端导出Excel兼容写法

    今天整理出在Web前端导出Excel的写法,写了一个工具类,对各个浏览器进行了兼容. 首先,导出的数据来源可能有两种: 1. 页面的HTML内容(一般是table) 2. 纯数据 PS:不同的数据源, ...

  3. 前端后台以及游戏中使用Google Protocol Buffer详解

    前端后台以及游戏中使用Google Protocol Buffer详解 0.什么是protoBuf protoBuf是一种灵活高效的独立于语言平台的结构化数据表示方法,与XML相比,protoBuf更 ...

  4. 使用前端后台管理模板库admin-lte(转)

    使用前端后台管理模板库admin-lte 使用前端后台管理模板库admin-lte 安装 搭建环境 安装 安装admin-lte,可以通过以下几种办法安装,下图是GitHub中admin-lte的主页 ...

  5. Ztree的简单使用和后台交互的写法(二)

    针对Ztree的简单使用和后台交互的写法(一)中的树进行改进 1.增加节点的权限 由页面的当前用户,决定树的根节点 然后动态获取树的详细节点: 初始化函数为: function init(){ //初 ...

  6. 【转】GitHub平台最火Android开源项目整理——2013-08-25 17

    http://game.dapps.net/news/developer/9199.html GitHub在中国的火爆程度无需多言,越来越多的开源项目迁移到GitHub平台上.更何况,基于不要重复造轮 ...

  7. vue项目使用echarts按需引入实现地图动态显示效果时,报错:TypeError: Cannot read property 'dataToPoint' of undefined

    vue项目使用echarts按需引入实现地图动态显示效果时,报错:TypeError: Cannot read property 'dataToPoint' of undefined 借鉴了该大神的文 ...

  8. idea启动项目连接mysql数据库后台报duplicate name异常

    自己写的sql语句在MySQL数据库中运行是没有问题的 但是在使用idea启动项目的时候,后台在运行这行sql语句的时候居然报错了,duplicate name:重复的名字,最后自己经过思考,修改了一 ...

  9. 内网 Ubuntu 20.04 搭建 docusaurus 项目(或前端项目)的环境(mobaxterm、tigervnc、nfs、node)

    内网 Ubuntu 20.04 搭建 docusaurus 项目(或前端项目)的环境 背景 内网开发机是 win7,只能安装 node 14 以下,而 spug 的文档项目采用的是 Facebook ...

随机推荐

  1. Windows环境下python3.7版本怎么安装pygame

    访问此网址 下载对应Python版本的pygame,如下图: 下载完成后,会有一个whl后缀的文件. 将此文件复制到Python根目录下的scripts目录下,打开cmd, 切换到scripts目录下 ...

  2. java 位向量

    public class BitVectory { private int count; private int[] a; private static final int BIT_LEN = 32; ...

  3. MarkdownPad 2 HTML 渲染错误解决办法

    MarkdownPad 2 HTML 渲染错误解决办法 1. 安装SDK工具包 Awesomium 1.6.6 SDK 2. 安装渲染插件Microsoft’s DirectX End-User Ru ...

  4. SQL2012 分页(最新)

    --提取分页数据,返回总记录数 ALTER procedure [dbo].[sp_Common_GetDataPaging_ReturnDataCount] ( @SqlString varchar ...

  5. 03-for循环in遍历

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. CentOS 7.0如何安装配置iptables和seLinux以及firewalld

    一.配置防火墙,开启80端口.3306端口 CentOS .0默认使用的是firewall作为防火墙,这里改为iptables防火墙. .关闭firewall: systemctl stop fire ...

  7. iOS知识列表

    Xib和StoryBoard,自动布局地图导航,实时公交,第三方地图应用本地推送通知,网络推送通知,真机调试,应用上传绘图,图表,曲线图 Xcode使用技巧多线程,runtime机制编码解码,加密设备 ...

  8. BZOJ3473 字符串 【广义后缀自动机】

    题目 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? 输入格式 第一行两个整数n,k. 接下来n行每行一个字符串. 输出格式 一行n个整数,第i个整数表 ...

  9. 常州模拟赛d1t5 遗忘口令

    就像每个人都会遇到的问题一样,贝西忘了在 cowtube 上的口令.不过,她还记着一些关于口令 的信息.首先,她确定口令由小写字母组成,长度为 L.其次,这个密码是由几个单词组合而成 的.贝西一共认识 ...

  10. cf725F Family Photos

    Alice and Bonnie are sisters, but they don't like each other very much. So when some old family phot ...