如何将屏幕截图附加到Java Selenium中的Extent报告

huangapple go评论92阅读模式
英文:

How to attach screenshot to Extent Report in java selenium

问题

以下是翻译好的代码部分:

package com.qa.ExtentReportListener;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.testng.IReporter;
import org.testng.IResultMap;
import org.testng.ISuite;
import org.testng.ISuiteResult;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.xml.XmlSuite;

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.aventstack.extentreports.reporter.configuration.ChartLocation;
import com.aventstack.extentreports.reporter.configuration.Theme;
import com.crm.qa.util.TestUtil;

public class ExtentTestNGIReporterListener implements IReporter {

    private static final String OUTPUT_FOLDER = "test-output/";
    private static final String FILE_NAME = "Extent.html";

    private ExtentReports extent;
    private ExtentTest test;

    public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
        init();

        for (ISuite suite : suites) {
            Map<String, ISuiteResult> result = suite.getResults();

            for (ISuiteResult r : result.values()) {
                ITestContext context = r.getTestContext();

                buildTestNodes(context.getFailedTests(), Status.FAIL);
                buildTestNodes(context.getSkippedTests(), Status.SKIP);
                buildTestNodes(context.getPassedTests(), Status.PASS);
            }
        }

        for (String s : Reporter.getOutput()) {
            extent.setTestRunnerOutput(s);
        }

        extent.flush();
    }

    private void init() {
        ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
        htmlReporter.config().setDocumentTitle("ExtentReports - Created by TestNG Listener");
        htmlReporter.config().setReportName("ExtentReports - Created by TestNG Listener");
        htmlReporter.config().setTestViewChartLocation(ChartLocation.BOTTOM);
        htmlReporter.config().setTheme(Theme.STANDARD);

        extent = new ExtentReports();
        extent.attachReporter(htmlReporter);
        extent.setReportUsesManualConfiguration(true);
    }

    private void buildTestNodes(IResultMap tests, Status status) {
        if (tests.size() > 0) {
            for (ITestResult result : tests.getAllResults()) {
                test = extent.createTest(result.getMethod().getMethodName());

                for (String group : result.getMethod().getGroups())
                    test.assignCategory(group);

                if (result.getThrowable() != null) {
                    test.log(status, result.getThrowable());
                } else {
                    test.log(status, "Test " + status.toString().toLowerCase() + "ed");
                }

                test.getModel().setStartTime(getTime(result.getStartMillis()));
                test.getModel().setEndTime(getTime(result.getEndMillis()));
            }
        }
    }

    // ...(略去了下面的 down 方法以及日期处理函数 getTime)
}
// 在另一个类中
public static String takeScreenshotAtEndOfTest() throws IOException {
    String dateName = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
    TakesScreenshot ts = (TakesScreenshot) driver;
    File source = ts.getScreenshotAs(OutputType.FILE);
    String destination = System.getProperty("user.dir") + "/screenshots/" + dateName + ".png";
    File finalDestination = new File(destination);
    FileHandler.copy(source, finalDestination);
    return destination;
}

请注意,以上只是对你提供的代码的翻译,其中可能包含代码注释和一些特定于代码功能的术语。如果需要进一步的解释或有任何问题,请随时提问。

英文:

I am trying to attach screenshot for failed testcases from my path to Extent Report but somehow i am not able to attach into it.

I have tried my possible solution but it fails .
I have used extent report version 3

here is mine full code in separate extenreport class :

	package com.qa.ExtentReportListener;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.testng.IReporter;
import org.testng.IResultMap;
import org.testng.ISuite;
import org.testng.ISuiteResult;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.xml.XmlSuite;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.aventstack.extentreports.reporter.configuration.ChartLocation;
import com.aventstack.extentreports.reporter.configuration.Theme;
import com.crm.qa.util.TestUtil;
public class ExtentTestNGIReporterListener implements IReporter {
private static final String OUTPUT_FOLDER = &quot;test-output/&quot;;
private static final String FILE_NAME = &quot;Extent.html&quot;;
private ExtentReports extent;
private ExtentTest test;
public void generateReport(List&lt;XmlSuite&gt; xmlSuites, List&lt;ISuite&gt; suites, String outputDirectory) {
init();
for (ISuite suite : suites) {
Map&lt;String, ISuiteResult&gt; result = suite.getResults();
for (ISuiteResult r : result.values()) {
ITestContext context = r.getTestContext();
buildTestNodes(context.getFailedTests(), Status.FAIL);
buildTestNodes(context.getSkippedTests(), Status.SKIP);
buildTestNodes(context.getPassedTests(), Status.PASS);
}
}
for (String s : Reporter.getOutput()) {
extent.setTestRunnerOutput(s);
}
extent.flush();
}
private void init() {
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
htmlReporter.config().setDocumentTitle(&quot;ExtentReports - Created by TestNG Listener&quot;);
htmlReporter.config().setReportName(&quot;ExtentReports - Created by TestNG Listener&quot;);
htmlReporter.config().setTestViewChartLocation(ChartLocation.BOTTOM);
htmlReporter.config().setTheme(Theme.STANDARD);
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
}
private void buildTestNodes(IResultMap tests, Status status) {
if (tests.size() &gt; 0) {
for (ITestResult result : tests.getAllResults()) {
test = extent.createTest(result.getMethod().getMethodName());
for (String group : result.getMethod().getGroups())
test.assignCategory(group);
if (result.getThrowable() != null) {
test.log(status, result.getThrowable());
}
else {
test.log(status, &quot;Test &quot; + status.toString().toLowerCase() + &quot;ed&quot;);
}
test.getModel().setStartTime(getTime(result.getStartMillis()));
test.getModel().setEndTime(getTime(result.getEndMillis()));
}
}
}
public void down(ITestResult result) throws IOException{
if(result.getStatus()==ITestResult.FAILURE){
test.log(Status.FAIL, &quot;TEST CASE FAILED IS &quot;+result.getName()); //to add name in extent report
test.log(Status.FAIL, &quot;TEST CASE FAILED IS &quot;+result.getThrowable()); //to add error/exception in extent report
String screenshotPath = TestUtil.takeScreenshotAtEndOfTest();
test.fail(&quot;Test Case failed check screenshot below&quot;+test.addScreenCaptureFromPath(screenshotPath));
//extentTest.log(Status.FAIL, MediaEntityBuilder.createScreenCaptureFromPath(screenshotPath).build()); //to add screenshot in extent report
//extentTest.fail(&quot;details&quot;).addScreenCaptureFromPath(screenshotPath);
}
else if(result.getStatus()==ITestResult.SKIP){
test.log(Status.SKIP, &quot;Test Case SKIPPED IS &quot; + result.getName());
}
else if(result.getStatus()==ITestResult.SUCCESS){
test.log(Status.PASS, &quot;Test Case PASSED IS &quot; + result.getName());
}
extent.flush();
}
private Date getTime(long millis) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
return calendar.getTime();      
}
}

here is my util class which contain screenshot method:

public static String takeScreenshotAtEndOfTest() throws IOException {
String dateName = new SimpleDateFormat(&quot;yyyyMMddhhmmss&quot;).format(new Date());
TakesScreenshot ts = (TakesScreenshot)driver;
File source = ts.getScreenshotAs(OutputType.FILE);
String destination = System.getProperty(&quot;user.dir&quot;) + &quot;/screenshots/&quot; +  dateName
+ &quot;.png&quot;;
File finalDestination = new File(destination);
FileHandler.copy(source, finalDestination);
return destination;
}

答案1

得分: 1

after 方法中使用以下代码:

if (result.getStatus() == result.FAILURE || result.getStatus() == result.SKIP) {
    String screenshotPath = util.captureScreenshot(driver, result.getName());
    result.setAttribute("screenshotPath", screenshotPath); // 设置变量/属性 screenshotPath 的值为截图的路径
}

并且在 buildtestnodes 中添加以下代码:

if (result.getStatus() == result.FAILURE || result.getStatus() == result.SKIP) {
    String screenshotPath = (String) result.getAttribute("screenshotPath");
    test.log(status, test.addScreenCapture(screenshotPath));
}
英文:

Use this code in after method

if(result.getStatus()==result.FAILURE || result.getStatus()==result.SKIP) {
			String screenshotPath = util.captureScreenshot(driver, result.getName());
			result.setAttribute(&quot;screenshotPath&quot;, screenshotPath); //sets the value the variable/attribute screenshotPath as the path of the sceenshot
		}

and add below code in buildtestnodes

    if(result.getStatus()==result.FAILURE || result.getStatus()==result.SKIP) {
						String screenshotPath=(String) 
     result.getAttribute(&quot;screenshotPath&quot;);
						test.log(status, test.addScreenCapture(screenshotPath));
					} 

答案2

得分: 0

Sure, here's the translated content:

如果您想为失败的测试用例拍摄屏幕截图并使用测试类名,请使用以下代码段。

如何将屏幕截图附加到Java Selenium中的Extent报告

如何将屏幕截图附加到Java Selenium中的Extent报告

英文:

If you want take screen shots for failed test cases with test class name use below code segment.

如何将屏幕截图附加到Java Selenium中的Extent报告

如何将屏幕截图附加到Java Selenium中的Extent报告

答案3

得分: 0

Extent Report已经提供了获取屏幕截图的工具。请参考以下链接:

https://extentreports.com/docs/versions/3/java/#automatic-screenshot-management

同时找到截图和相应的代码:

ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter("extent.html");
htmlReporter.config().setAutoCreateRelativePathMedia(true);

test1.fail("details", MediaEntityBuilder.createScreenCaptureFromPath("1.png").build());
test2.fail("details", MediaEntityBuilder.createScreenCaptureFromPath("2.png").build());

如何使用Extent Report进行截图

英文:

Extent Report already provide the utility to take the screenshot .Please refer the below link:

https://extentreports.com/docs/versions/3/java/#automatic-screenshot-management

also find the snapshot and code for same:

 ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(&quot;extent.html&quot;);
htmlReporter.config().setAutoCreateRelativePathMedia(true);
test1.fail(&quot;details&quot;, MediaEntityBuilder.createScreenCaptureFromPath(&quot;1.png&quot;).build());
test2.fail(&quot;details&quot;, MediaEntityBuilder.createScreenCaptureFromPath(&quot;2.png&quot;).build());

how to take Screenshot using extent report

答案4

得分: 0

尝试使用以下代码:

logger.log(Status.FAIL, logger.addScreenCaptureFromPath("YOUR PATH"));

更新:
如果这不起作用,只需使用标记将内部日志记录器转换。

import com.aventstack.extentreports.markuputils.Markup;
英文:

Try using this :

logger.log(Status.FAIL, logger.addScreenCaptureFromPath(&quot;YOUR PATH&quot;));

UPDATE :
If this doesn't work, just cast the inner logger with markup.
import com.aventstack.extentreports.markuputils.Markup;

答案5

得分: 0

package com.helper;

import org.testng.annotations.Test;

import com.aventstack.extentreports.AnalysisStrategy;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.MediaEntityBuilder;
import com.aventstack.extentreports.Status;

import com.aventstack.extentreports.reporter.ExtentSparkReporter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class TestingEdgeDriver {
    ExtentReports extent;
    ExtentTest test;
    WebDriver driver;
    ExtentTest Parent;
    ExtentTest child1, child;

    @BeforeMethod
    public void setup() {

        DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH-mm-ss");
        String destDir = dateFormat.format(new Date());
        ExtentSparkReporter esp = new ExtentSparkReporter(System.getProperty("user.dir") +
                "/ExtentReport/ExtentReports_" + destDir + "/SwarupExtentReport.html");
        extent = new ExtentReports();
        extent.attachReporter(esp);
        extent.setAnalysisStrategy(AnalysisStrategy.SUITE);
    }

    @Test(testName = "Chrome browser Testing")
    public void chromeBrowser() throws IOException {
        Parent = extent.createTest("CMO");
        child1 = Parent.createNode("Test1");
        child = child1.createNode("Chrome browser Testing");

        System.out.println("The tread value for Chrome browser is " + Thread.currentThread().getId());
        System.setProperty("webdriver.chrome.driver", "E:\\chromedriver_win32 (2)\\chromedriver.exe");
        driver = new ChromeDriver();
        child.log(Status.PASS, "Chrome browser has opened",
                MediaEntityBuilder.createScreenCaptureFromPath(capture(driver)).build());
        driver.get("https://www.icicibank.com");

        child.log(Status.PASS, "Expected was its should open the bank website",
                MediaEntityBuilder.createScreenCaptureFromPath(capture(driver)).build());

        child.log(Status.PASS, "Need to open the URL " + "http://www.icicibank.com");
        driver.manage().window().maximize();
        child.log(Status.PASS, "Test Case is passed",
                MediaEntityBuilder.createScreenCaptureFromPath(capture(driver)).build());
    }

    @AfterMethod
    public void getResult(ITestResult result) {
        if (result.getStatus() == ITestResult.SUCCESS) {
            child.log(Status.PASS, "Test case is passed " + result.getStatus() + " " + result.getTestClass() + "  " + result.getName());
            child.log(Status.PASS, "Test case is passed " + result.getTestName());
        }
        if (result.getStatus() == ITestResult.FAILURE) {
            child.log(Status.FAIL, "Test case is failed at below location " + result.getThrowable());
        }
        extent.flush();
    }

    public static String captureBase64(WebDriver driver) throws IOException {
        String encodedBase64 = null;
        FileInputStream fileInputStream = null;
        File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        File Dest = new File("src/../BStackImages/" + System.currentTimeMillis() + ".png");
        String errflpath = Dest.getAbsolutePath();
        FileUtils.copyFile(scrFile, Dest);

        try {
            fileInputStream = new FileInputStream(Dest);
            byte[] bytes = new byte[(int) Dest.length()];
            fileInputStream.read(bytes);
            encodedBase64 = new String(Base64.encodeBase64(bytes));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return "data:image/png;base64," + encodedBase64;
    }

    public static String capture(WebDriver driver) throws IOException {
        File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        File Dest = new File("src/../BStackImages/" + System.currentTimeMillis() + ".png");
        String errflpath = Dest.getAbsolutePath();
        FileUtils.copyFile(scrFile, Dest);
        return errflpath;
    }
}
英文:
	package com.helper;
import org.testng.annotations.Test;
import com.aventstack.extentreports.AnalysisStrategy;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.MediaEntityBuilder;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.reporter.ExtentSparkReporter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.opera.OperaDriver;
import org.testng.IResultMap;
import org.testng.ITest;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
public class TestingEdgeDriver {
ExtentReports extent;
ExtentTest test;
WebDriver driver;
ExtentTest Parent;
ExtentTest child1,child;
@BeforeMethod
public void setup(){
DateFormat dateFormat = new SimpleDateFormat(&quot;yyyy.MM.dd HH-mm-ss&quot;); 
String destDir = dateFormat.format(new Date());
ExtentSparkReporter esp=new ExtentSparkReporter(System.getProperty(&quot;user.dir&quot;)+&quot;/ExtentReport/ExtentReports_&quot;+destDir+&quot;/SwarupExtentReport.html&quot;);
extent=new ExtentReports();
extent.attachReporter(esp);
extent.setAnalysisStrategy(AnalysisStrategy.SUITE);
}
@Test (testName=&quot;Chrome browser Testing&quot;)public void chromeBrowser() throws IOException{
/*extent.attachReporter(spark);
extent.createTest(&quot;chromeBrowser&quot;).log(Status.PASS	, &quot;This is logging event for the setup and it is passed&quot;);
extent.flush();*/
Parent=extent.createTest(&quot;CMO&quot;);
child1=Parent.createNode(&quot;Test1&quot;);
child=child1.createNode(&quot;Chrome browser Testing&quot;);
System.out.println(&quot;The tread value for Chrome browser is &quot;+ Thread.currentThread().getId());
System.setProperty(&quot;webdriver.chrome.driver&quot;,&quot;E:\\chromedriver_win32 (2)\\chromedriver.exe&quot;);
driver=new ChromeDriver();
child.log(Status.PASS, &quot;Chrome browser has opened&quot;,MediaEntityBuilder.createScreenCaptureFromPath(capture(driver)).build());
driver.get(&quot;https://www.icicibank.com&quot;);
child.log(Status.PASS,&quot;Expected was its should open the bank website&quot;,MediaEntityBuilder.createScreenCaptureFromPath(capture(driver)).build());
child.log(Status.PASS, &quot;Need to open the URL &quot;+&quot; http://www.icicibank.com&quot;);
driver.manage().window().maximize();
child.log(Status.PASS, &quot;Test Case is passed&quot;,MediaEntityBuilder.createScreenCaptureFromPath(capture(driver)).build());
}
@AfterMethod
public void getResult(ITestResult result){
if(result.getStatus()==ITestResult.SUCCESS){
child.log(Status.PASS, &quot;Test case is passed &quot;+result.getStatus()+&quot; &quot;+result.getTestClass()+&quot;  &quot;+result.getName());
child.log(Status.PASS, &quot;Test case is passed &quot;+result.getTestName());
}
if(result.getStatus()==ITestResult.FAILURE){
child.log(Status.FAIL, &quot;Test case is failed at below location &quot;+result.getThrowable());
}
extent.flush();
}
/*@Test public void operaTesting(){
System.out.println(&quot;The tread value for Opera browser is &quot;+ Thread.currentThread().getId());
System.setProperty(&quot;webdriver.opera.driver&quot;,&quot;E:\\operadriver_win32\\operadriver_win32\\operadriver.exe&quot;);
Reporter.log(&quot;opera driver has been set&quot;,true);
driver=new OperaDriver();
driver.manage().window().maximize();
driver.get(&quot;https://www.irctc.co.in&quot;);
}
@Test public void FirefoxTesting(){
System.out.println(&quot;The tread value for Firefox browser is &quot;+ Thread.currentThread().getId());
System.setProperty(&quot;webdriver.gecko.driver&quot;,&quot;E:\\gecodriver\\geckodriver-v0.29.0-win32\\geckodriver.exe&quot;);
Reporter.log(&quot;Gecko Driver has been set&quot;,true);
driver=new FirefoxDriver();
driver.manage().window().maximize();
Reporter.log(&quot;firefox driver has been initialsed&quot;,true);
driver.get(&quot;https://www.primevideo.com/&quot;);
}
@Test public void InternetExplorerTesting(){
System.out.println(&quot;The tread value for IE browser is &quot;+ Thread.currentThread().getId());
System.setProperty(&quot;webdriver.ie.driver&quot;,&quot;E:\\IEDriverServer_Win32_3.4.0\\IEDriverServer.exe&quot;);
Reporter.log(&quot;IE driver has been set&quot;,true);
driver=new InternetExplorerDriver();
driver.manage().window().maximize();
driver.get(&quot;https://www.hotstar.com/in&quot;);
}*/
public static String captureBase64(WebDriver driver) throws IOException {
String encodedBase64 = null;
FileInputStream fileInputStream = null;
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
File Dest = new File(&quot;src/../BStackImages/&quot; + System.currentTimeMillis()
+ &quot;.png&quot;);
String errflpath = Dest.getAbsolutePath();
FileUtils.copyFile(scrFile, Dest);
try {
fileInputStream =new FileInputStream(Dest);
byte[] bytes =new byte[(int)Dest.length()];
fileInputStream.read(bytes);
encodedBase64 = new String(Base64.encodeBase64(bytes));
}catch (FileNotFoundException e){
e.printStackTrace();
}
return &quot;data:image/png;base64,&quot;+encodedBase64;
}
public static String capture(WebDriver driver) throws IOException {
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
File Dest = new File(&quot;src/../BStackImages/&quot; + System.currentTimeMillis()
+ &quot;.png&quot;);
String errflpath = Dest.getAbsolutePath();
FileUtils.copyFile(scrFile, Dest);
return errflpath;
}
}

答案6

得分: -1

使用以下的Java示例:

WebDriver driver = new FirefoxDriver();

driver.get("http://www.google.com/");

// 将截图存储在当前项目目录中。
String screenShot = System.getProperty("user.dir") + "\\Artifacts\\FileName.png";

// 调用Webdriver来点击截图。
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);

// 保存截图。
FileUtils.copyFile(scrFile, new File(screenShot));
英文:

Use this following example is in Java

   WebDriver driver = new FirefoxDriver();
driver.get(&quot;http://www.google.com/&quot;);
// Store the screenshot in current project dir.
String screenShot = System.getProperty(&quot;user.dir&quot;)+&quot;\\Artifacts\\FileName.png&quot;;
// Call Webdriver to click the screenshot.
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
// Save the screenshot.
FileUtils.copyFile(scrFile, new File(screenShot));

huangapple
  • 本文由 发表于 2020年4月7日 12:47:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/61073005.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定