2024-05-07 15:06:36 +08:00
|
|
|
|
#include "TcpRequestHandler.h"
|
2024-03-04 16:22:40 +08:00
|
|
|
|
#include "Channel.h"
|
|
|
|
|
#include "Constant.h"
|
2024-01-25 09:57:08 +08:00
|
|
|
|
#include "Json.h"
|
2024-03-04 16:22:40 +08:00
|
|
|
|
#include "Log.h"
|
|
|
|
|
#include "Tool.h"
|
2024-01-18 15:41:43 +08:00
|
|
|
|
#include <QDir>
|
2024-01-25 09:57:08 +08:00
|
|
|
|
#include <QProcess>
|
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
extern const QList<Channel*> channelList;
|
2024-01-18 15:41:43 +08:00
|
|
|
|
|
2024-05-07 15:06:36 +08:00
|
|
|
|
TcpRequestHandler::TcpRequestHandler(QObject* parent)
|
2024-01-18 15:41:43 +08:00
|
|
|
|
: QObject(parent)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::service(TcpRequest* request, TcpResponse* response)
|
2024-01-18 15:41:43 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QString url = request->getUrl();
|
|
|
|
|
response->setUrl(url);
|
|
|
|
|
if (url == "/set_ip_addr") {
|
|
|
|
|
this->setIpaddr(request, response);
|
|
|
|
|
} else if (url == "/set_name") {
|
|
|
|
|
this->setName(request, response);
|
|
|
|
|
} else if (url == "/get_name") {
|
|
|
|
|
this->getName(request, response);
|
|
|
|
|
} else if (url == "/set_video_enc") {
|
|
|
|
|
this->setVideoEnc(request, response);
|
|
|
|
|
} else if (url == "/get_video_enc") {
|
|
|
|
|
this->getVideoEnc(request, response);
|
|
|
|
|
} else if (url == "/get_file_list") {
|
|
|
|
|
this->getFileList(request, response);
|
|
|
|
|
} else if (url == "/delete_file") {
|
|
|
|
|
this->deleteFile(request, response);
|
|
|
|
|
} else if (url == "/set_record_mode") {
|
|
|
|
|
this->setRecordMode(request, response);
|
|
|
|
|
} else if (url == "/set_playback_mode") {
|
|
|
|
|
this->setPlaybackMode(request, response);
|
|
|
|
|
} else if (url == "/reboot") {
|
|
|
|
|
this->reboot(request, response);
|
|
|
|
|
} else if (url == "/set_current_time") {
|
|
|
|
|
this->setCurrentTime(request, response);
|
|
|
|
|
} else {
|
|
|
|
|
response->error("访问路径未找到");
|
|
|
|
|
}
|
2024-01-18 15:41:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-03-04 16:22:40 +08:00
|
|
|
|
* @brief 设置盒子的ip
|
2024-01-18 15:41:43 +08:00
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::setIpaddr(TcpRequest* request, TcpResponse* reponse)
|
2024-01-18 15:41:43 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QVariantMap netMap = Json::loadFile(Constant::NetConfigPath).toMap();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
|
|
|
|
|
if (params.contains("ip"))
|
|
|
|
|
netMap["ip"] = params.value("ip");
|
|
|
|
|
if (params.contains("mask"))
|
|
|
|
|
netMap["mask"] = params.value("mask");
|
|
|
|
|
if (params.contains("gateway"))
|
|
|
|
|
netMap["gateway"] = params.value("gateway");
|
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Json::saveFile(netMap, Constant::NetConfigPath);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Tool::writeCom(Constant::NetScriptPath);
|
2024-01-18 15:41:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-03-04 16:22:40 +08:00
|
|
|
|
* @brief 设置盒子的名称
|
2024-01-18 15:41:43 +08:00
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::setName(TcpRequest* request, TcpResponse* reponse)
|
2024-01-25 09:57:08 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
if (params.isEmpty() || !params.contains("name")) {
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Log::error("setName params error, missing param \"name\"");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("名称不能为空");
|
2024-01-25 09:57:08 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QVariantMap cfg = Json::loadFile(Constant::ConfigurationPath).toMap();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
cfg["name"] = params.value("name");
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Json::saveFile(cfg, Constant::ConfigurationPath);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief 获取盒子名称
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::getName(TcpRequest* request, TcpResponse* reponse)
|
2024-01-18 15:41:43 +08:00
|
|
|
|
{
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QVariantMap config = Json::loadFile(Constant::ConfigurationPath).toMap();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
QString name = config["name"].toString();
|
|
|
|
|
QString data = QString("url=get_name\r\nstatus=success\r\nname=%1").arg(name);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("", name);
|
2024-01-18 15:41:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-03-04 16:22:40 +08:00
|
|
|
|
* @brief 设置视频录制参数
|
2024-01-18 15:41:43 +08:00
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::setVideoEnc(TcpRequest* request, TcpResponse* reponse)
|
2024-01-18 15:41:43 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
if (params.isEmpty() || !params.contains("interface")) {
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Log::error("setVideoEncode params error, missing param \"interface\"");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("缺少接口参数");
|
2024-01-25 09:57:08 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString interface = params.value("interface").toString();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Channel* chn = nullptr;
|
|
|
|
|
for (Channel* c : channelList) {
|
|
|
|
|
if (c->channelName == interface)
|
|
|
|
|
chn = c;
|
|
|
|
|
}
|
|
|
|
|
if (chn) {
|
|
|
|
|
// 修改分辨率和帧率
|
2024-05-07 15:06:36 +08:00
|
|
|
|
// chn->videoEncoder->setData(params);
|
2024-03-04 16:22:40 +08:00
|
|
|
|
// 更新配置文件
|
|
|
|
|
QVariantMap cfg = Json::loadFile(Constant::ConfigurationPath).toMap();
|
|
|
|
|
QVariantList interfaces = cfg.value("interface").toList();
|
|
|
|
|
for (int i = 0; i < interfaces.length(); i++) {
|
|
|
|
|
QVariantMap item = interfaces.at(i).toMap();
|
|
|
|
|
if (item.value("name").toString() == interface) {
|
|
|
|
|
QVariantMap encV = item.value("encV").toMap();
|
|
|
|
|
if (params.contains("width"))
|
|
|
|
|
encV["width"] = params.value("width");
|
|
|
|
|
if (params.contains("height"))
|
|
|
|
|
encV["height"] = params.value("height");
|
|
|
|
|
if (params.contains("framerate"))
|
|
|
|
|
encV["framerate"] = params.value("framerate");
|
|
|
|
|
item["encV"] = encV;
|
|
|
|
|
interfaces.replace(i, item);
|
|
|
|
|
}
|
2024-01-25 09:57:08 +08:00
|
|
|
|
}
|
2024-03-04 16:22:40 +08:00
|
|
|
|
cfg["interface"] = interfaces;
|
|
|
|
|
Json::saveFile(cfg, Constant::ConfigurationPath);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("修改录制参数成功,重启后生效");
|
2024-03-04 16:22:40 +08:00
|
|
|
|
} else {
|
|
|
|
|
Log::error("set video encode params error, no such interface {}", interface.toStdString());
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error(QString("无对应接口: %1").arg(interface));
|
2024-01-25 09:57:08 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief 获取视频录制参数
|
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::getVideoEnc(TcpRequest* request, TcpResponse* reponse)
|
2024-01-25 09:57:08 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
|
|
|
|
|
if (params.contains("interface")) {
|
|
|
|
|
QString interface = params.value("interface").toString();
|
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QVariantMap cfg = Json::loadFile(Constant::ConfigurationPath).toMap();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
QVariantList interfaces = cfg.value("interface").toList();
|
|
|
|
|
|
|
|
|
|
QVariantMap targetInterfaceCfg;
|
|
|
|
|
for (int i = 0; i < interfaces.length(); i++) {
|
|
|
|
|
QVariantMap item = interfaces.at(i).toMap();
|
|
|
|
|
if (item.value("name").toString() == interface) {
|
|
|
|
|
targetInterfaceCfg = item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QVariantMap encodeV = targetInterfaceCfg.value("encV").toMap();
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("", encodeV);
|
2024-01-25 09:57:08 +08:00
|
|
|
|
} else {
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Log::error("getVideoEnc params error, missing param \"interface\"");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("缺少接口参数");
|
2024-01-18 15:41:43 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-03-04 16:22:40 +08:00
|
|
|
|
* @brief 获取文件列表
|
2024-01-18 15:41:43 +08:00
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::getFileList(TcpRequest* request, TcpResponse* reponse)
|
2024-01-18 15:41:43 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
if (params.isEmpty() || !params.contains("interface")) {
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Log::error("getFileList params error, missing param \"interface\"");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("缺少接口参数");
|
2024-01-18 15:41:43 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-25 09:57:08 +08:00
|
|
|
|
QString interface = params.value("interface").toString();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QString videoPath = QString("%1/%2").arg(Constant::VideoPath).arg(interface);
|
2024-01-25 09:57:08 +08:00
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QStringList videoList = Tool::getFileList(videoPath);
|
2024-01-18 15:41:43 +08:00
|
|
|
|
|
2024-05-07 15:06:36 +08:00
|
|
|
|
// 复制两份测试用
|
|
|
|
|
QStringList copy = videoList;
|
|
|
|
|
QStringList copy1 = videoList;
|
|
|
|
|
videoList.append(copy);
|
|
|
|
|
videoList.append(copy1);
|
|
|
|
|
reponse->success("获取文件成功", videoList);
|
2024-01-18 15:41:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-03-04 16:22:40 +08:00
|
|
|
|
* @brief 删除文件
|
2024-01-18 15:41:43 +08:00
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::deleteFile(TcpRequest* request, TcpResponse* reponse)
|
2024-01-18 15:41:43 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
if (!params.contains("interface") || !params.contains("filename")) {
|
|
|
|
|
Log::error("deleteFile params error, missing params \"interface\" or \"filename\"");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("缺少端口或文件名");
|
2024-01-25 09:57:08 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString interface = params.value("interface").toString();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QString fileName = params.value("filename").toString();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
// xxx.mp4 ==> xxx.jpg
|
|
|
|
|
QString snapName = fileName.split(".")[0] + ".jpg";
|
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QString filePath = QString("%1/%2/%3").arg(Constant::VideoPath).arg(interface).arg(fileName);
|
2024-01-25 09:57:08 +08:00
|
|
|
|
QFile video(filePath);
|
|
|
|
|
if (video.exists()) {
|
|
|
|
|
video.remove();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Log::info("remove video {}", filePath.toStdString());
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("删除成功");
|
2024-01-25 09:57:08 +08:00
|
|
|
|
} else {
|
2024-03-04 16:22:40 +08:00
|
|
|
|
Log::error("error, file: {} dont exist", filePath.toStdString());
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("文件不存在");
|
2024-01-25 09:57:08 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief 设置录制模式,一路录制/两路录制,只修改配置文件,重启之后生效
|
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::setRecordMode(TcpRequest* request, TcpResponse* reponse)
|
2024-01-25 09:57:08 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
if (!params.contains("recordMode")) {
|
|
|
|
|
Log::error("setRecordMode params error, missing param \"recordMode\"");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("缺少录制模式参数");
|
2024-03-04 16:22:40 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int recordMode = params.value("recordMode").toInt();
|
|
|
|
|
if (recordMode != Constant::OneChannelRecord
|
|
|
|
|
&& recordMode != Constant::TwoChannelRecord
|
|
|
|
|
&& recordMode != Constant::NoChannelRecord) {
|
|
|
|
|
Log::error("setRecordMode params error, unkown param \"recordMode\": {}", recordMode);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("录制参数错误");
|
2024-03-04 16:22:40 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-05-07 15:06:36 +08:00
|
|
|
|
|
2024-03-04 16:22:40 +08:00
|
|
|
|
QVariantMap cfg = Json::loadFile(Constant::ConfigurationPath).toMap();
|
|
|
|
|
int mode = cfg["recordMode"].toInt();
|
|
|
|
|
if (recordMode == mode) {
|
|
|
|
|
Log::info("record mode has not changed, there is nothing need to do");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("录制参数无需改变");
|
2024-03-04 16:22:40 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 更新配置文件
|
|
|
|
|
cfg["recordMode"] = recordMode;
|
|
|
|
|
Json::saveFile(cfg, Constant::ConfigurationPath);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("设置录制参数成功, 重启后生效");
|
2024-03-04 16:22:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 设置回放模式, 一路回放/两路同时回放,只修改配置文件,重启之后生效
|
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::setPlaybackMode(TcpRequest* request, TcpResponse* reponse)
|
2024-03-04 16:22:40 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
QVariantMap params = request->getBodyParams();
|
2024-03-04 16:22:40 +08:00
|
|
|
|
if (!params.contains("playbackMode")) {
|
|
|
|
|
Log::error("setPlaybackMode params error, missing param \"playbackmode\"");
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("缺少回放模式参数");
|
2024-03-04 16:22:40 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int playbackMode = params.value("playbackMode").toInt();
|
|
|
|
|
if (playbackMode != Constant::OneChannelPlayback
|
|
|
|
|
&& playbackMode != Constant::TwoChannelPlayback) {
|
|
|
|
|
Log::error("setPlayBack params error, unkown param \"playbackMode\": {}", playbackMode);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->error("回放模式参数错误");
|
|
|
|
|
return;
|
2024-03-04 16:22:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariantMap cfg = Json::loadFile(Constant::ConfigurationPath).toMap();
|
2024-05-07 15:06:36 +08:00
|
|
|
|
int mode = cfg["playbackMode"].toInt();;
|
|
|
|
|
if (playbackMode == mode) {
|
|
|
|
|
Log::info("record mode has not changed, there is nothing need to do");
|
|
|
|
|
reponse->success("回放参数无需改变");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 跟新配置文件
|
2024-03-04 16:22:40 +08:00
|
|
|
|
cfg["playbackMode"] = playbackMode;
|
|
|
|
|
Json::saveFile(cfg, Constant::ConfigurationPath);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("修改回放模式成功,重启后生效");
|
2024-01-18 15:41:43 +08:00
|
|
|
|
}
|
2024-03-05 13:47:32 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 重启程序
|
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void TcpRequestHandler::reboot(TcpRequest* request, TcpResponse* reponse)
|
2024-03-05 13:47:32 +08:00
|
|
|
|
{
|
|
|
|
|
// 先停止所有的录制
|
|
|
|
|
for (Channel* chn : channelList) {
|
|
|
|
|
chn->stopRecord();
|
|
|
|
|
}
|
2024-05-07 15:06:36 +08:00
|
|
|
|
reponse->success("重启成功");
|
2024-03-05 13:47:32 +08:00
|
|
|
|
|
|
|
|
|
// 退出程序,等待后台运行的shell脚本重启程序
|
|
|
|
|
exit(0);
|
2024-05-07 15:06:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 设置当前开发板时间,进行时间同步
|
|
|
|
|
* @param socket
|
|
|
|
|
*/
|
|
|
|
|
void TcpRequestHandler::setCurrentTime(TcpRequest* request, TcpResponse* reponse)
|
|
|
|
|
{
|
|
|
|
|
QVariantMap params = request->getBodyParams();
|
|
|
|
|
if (!params.contains("time")) {
|
|
|
|
|
Log::error("setCurrentTime params error, missing params \"time\"");
|
|
|
|
|
reponse->error("缺少时间参数");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString time = params.value("time").toString();
|
|
|
|
|
QString cmd = QString("/link/bin/rtc -s time %1").arg(time);
|
|
|
|
|
QString result = Tool::writeCom(cmd);
|
|
|
|
|
// 修改成功会返回类似信息, "Tue Mar 5 15:51:18 CST 2024"
|
|
|
|
|
if (result.isEmpty()) {
|
|
|
|
|
reponse->error("时间同步失败");
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
reponse->success("时间同步成功");
|
|
|
|
|
}
|
2024-03-05 13:47:32 +08:00
|
|
|
|
}
|