资讯动态

【微服务即时通讯】登录注册界面设计

发布时间:2026/9/12 2:08:24 来源:尧图企业网站定制
目录一.账号密码 登录注册界面设计loginwidget.cpp)1.1.登录/注册双模态的转换1.2.与邮箱注册/登录界面的切换1.3.注册/登录按钮二.邮箱注册登录界面设计emailloginwidget.cpp)2.1.登录/注册双模态的转换2.2.与 账号密码 登录界面的切换2.3.获取验证码2.4.登录/注册按钮一.账号密码 登录注册界面设计loginwidget.cpp)我们设计界面都是需要有原型图的那么我们的原型图就如下面所示我们发现它是有双模态的。也就是注册和登录两种状态。首先我们就需要先将这个界面搭建出来吧// 构造函数初始化登录/注册窗口 LoginWidget::LoginWidget(QWidget *parent) : QWidget{parent} { // 1. 设置本窗口的基本属性 this-setFixedSize(400, 350); // 固定窗口大小 this-setWindowTitle(登录); // 窗口标题 this-setWindowIcon(QIcon(:/resource/image/logo.png)); // 窗口图标 this-setStyleSheet(QWidget { background-color: rgb(255, 255, 255); }); // 白色背景 this-setAttribute(Qt::WA_DeleteOnClose); // 关闭时自动销毁窗口对象 // 2. 创建布局管理器网格布局 QGridLayout* layout new QGridLayout(); layout-setSpacing(0); // 控件间距为0 layout-setContentsMargins(50, 0, 50, 0); // 左右边距50上下边距0 this-setLayout(layout); // 3. 创建标题标签 titleLabel new QLabel(); titleLabel-setText(登录); titleLabel-setAlignment(Qt::AlignCenter); // 居中显示 titleLabel-setFixedHeight(50); // 固定高度 titleLabel-setStyleSheet(QLabel { font-size: 40px; font-weight: 600; }); // 字体样式 // 4. 创建用户名输入框 QString editStyle QLineEdit { border: none; border-radius: 10px; font-size: 20px; background-color: rgb(240, 240, 240); padding-left:5px; }; usernameEdit new QLineEdit(); usernameEdit-setFixedHeight(40); usernameEdit-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 水平伸展垂直固定 usernameEdit-setPlaceholderText(输入用户名); usernameEdit-setStyleSheet(editStyle); // 5. 创建密码输入框 passwordEdit new QLineEdit(); passwordEdit-setFixedHeight(40); passwordEdit-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); passwordEdit-setPlaceholderText(输入密码); passwordEdit-setStyleSheet(editStyle); passwordEdit-setEchoMode(QLineEdit::Password); // 密码模式显示圆点 // 6. 创建验证码输入框 verifyCodeEdit new QLineEdit(); verifyCodeEdit-setFixedHeight(40); verifyCodeEdit-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); verifyCodeEdit-setPlaceholderText(输入验证码); verifyCodeEdit-setStyleSheet(editStyle); // 7. 创建显示验证码图片的控件 // 使用自定义的 VerifyCodeWidget 来生成和显示验证码图片 verifyCodeWidget new VerifyCodeWidget(this); // 8. 创建登录按钮 submitBtn new QPushButton(); submitBtn-setText(登录); submitBtn-setFixedHeight(40); submitBtn-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); QString btnGreenStyle QPushButton { border: none; border-radius: 10px; background-color: rgb(44, 182, 61); color: rgb(255, 255, 255); }; btnGreenStyle QPushButton:pressed { background-color: rgb(240, 240, 240); }; // 按下时颜色变浅 submitBtn-setStyleSheet(btnGreenStyle); // 9. 创建切换到邮箱号登录按钮 emailModeBtn new QPushButton(); emailModeBtn-setFixedSize(100, 40); emailModeBtn-setText(邮箱号登录); QString btnWhiteStyle QPushButton { border: none; border-radius: 10px; background-color: transparent; }; btnWhiteStyle QPushButton:pressed { background-color: rgb(240, 240, 240); }; emailModeBtn-setStyleSheet(btnWhiteStyle); // 10. 创建切换模式(登录和注册)按钮 switchModeBtn new QPushButton(); switchModeBtn-setFixedSize(100, 40); switchModeBtn-setText(注册); switchModeBtn-setStyleSheet(btnWhiteStyle); // 11. 将所有控件添加到网格布局中 // 参数控件, 行, 列, 行跨度, 列跨度 layout-addWidget(titleLabel, 0, 0, 1, 5); // 标题占5列 layout-addWidget(usernameEdit, 1, 0, 1, 5); // 用户名输入框占5列 layout-addWidget(passwordEdit, 2, 0, 1, 5); // 密码输入框占5列 layout-addWidget(verifyCodeEdit, 3, 0, 1, 4); // 验证码输入框占前4列 layout-addWidget(verifyCodeWidget, 3, 4, 1, 1); // 验证码图片占第5列 layout-addWidget(submitBtn, 4, 0, 1, 5); // 登录/注册按钮占5列 layout-addWidget(emailModeBtn, 5, 0, 1, 1); // 邮箱登录按钮放在左下 layout-addWidget(switchModeBtn, 5, 4, 1, 1); // 切换模式按钮放在右下 }这样子我们就搭建出来了但是还有一些问题需要我们来进行解决。这3个都是QPushButton都是按钮那么按下这些按键会有啥效果呢我们这个时候就需要给这些按钮设置槽函数了。1.1.登录/注册双模态的转换我们先看一个按钮来那么我们将它反过来呢可以看到这个就是可以实现一个双模态的转换。因此我们给这个按钮配置一个槽函数connect(switchModeBtn, QPushButton::clicked, this, LoginWidget::switchMode);那么这个槽函数是怎么实现的这个就涉及到来注册和登录模式的一种切换了这个是借助于一个标志位来进行实现的。bool isLoginModetrue; // true 登录模式false 注册模式初始值我们在头文件中初始化为 true登录模式因为窗口标题一开始就是“登录”按钮文本也是“登录”。作用记录当前界面处于登录还是注册状态后续所有行为都依赖这个标志。我们来看看void LoginWidget::switchMode() { if (isLoginMode) { // 当前是登录模式 → 切换到注册模式 this-setWindowTitle(注册); titleLabel-setText(注册); submitBtn-setText(注册); emailModeBtn-setText(邮箱号注册); switchModeBtn-setText(登录); } else { // 当前是注册模式 → 切换到登录模式 this-setWindowTitle(登录); titleLabel-setText(登录); submitBtn-setText(登录); emailModeBtn-setText(邮箱号登录); switchModeBtn-setText(注册); } isLoginMode !isLoginMode; // 取反完成状态切换 }好像就是一个简单的显示文本的替换而已。1.2.与邮箱注册/登录界面的切换我们接下来看看这个我们发现无论在注册和登录界面都是跳转到邮箱号登录注册界面。这个其实很容易进行实现至于这个登录按钮按下去后客户端会向服务器发送登录请求如果登录成功就会切换到主界面。那么我们现在就能来配置这个槽函数了。connect(emailModeBtn, QPushButton::clicked, this, []() { // 此处还可以把 isLoginMode 这个值传到新的窗口中, 让新的窗口决定自己是登录状态还是注册状态. 大家自行尝试实现. EmailLoginWidget* emailLoginWidget new EmailLoginWidget(nullptr); emailLoginWidget-show(); // 关闭当前窗口 this-close(); });这个就是比较清晰了吧。1.3.注册/登录按钮接下来是一个重头戏。这两个的槽函数我们需要怎么进行设计我们仔细想想就能知道我们注册和登录给服务器发送的请求不一样。但是它们又是同一个按钮只能配置一个槽函数。所以我们就需要根据这个注册/登录状态标志位来做出不同的处理。// 处理登录/注册按钮的点击事件 void LoginWidget::clickSubmitBtn() { // 1. 先从输入框拿到必要的内容 const QString username usernameEdit-text(); const QString password passwordEdit-text(); const QString verifyCode verifyCodeEdit-text(); if (username.isEmpty() || password.isEmpty() || verifyCode.isEmpty()) { Toast::showMessage(用户名/密码/验证码不能为空!); // 显示提示信息 return; } // 2. 对比验证码是否正确 if (!verifyCodeWidget-checkVerifyCode(verifyCode)) { Toast::showMessage(验证码不正确!); return; } // 3. 真正去发送网络请求. DataCenter* dataCenter DataCenter::getInstance(); // 获取数据中心单例 //根据这个注册/登录状态标志位来做出不同的处理 if (isLoginMode) { // 登录模式连接登录完成信号并异步发起登录请求 connect(dataCenter, DataCenter::userLoginDone, this, LoginWidget::userLoginDone); //当服务器的响应回来并且我们获取了里面的数据并更新到数据中心之后我们设计的是会发送一个DataCenter::userLoginDone信号 dataCenter-userLoginAsync(username, password);//利用这个接口去向服务器发起登录请求这个是异步接口 } else { // 注册模式连接注册完成信号并异步发起注册请求 connect(dataCenter, DataCenter::userRegisterDone, this, LoginWidget::userRegisterDone); //当服务器的响应回来并且我们获取了里面的数据并更新到数据中心之后我们设计的是会发送一个DataCenter::userRegisterDone信号 dataCenter-userRegisterAsync(username, password);//利用这个接口去向服务器发起注册请求这个是异步接口 } }那么针对登录成功和注册成功我们又分别设置了槽函数大家自己去看看即可。// 登录完成的槽函数 void LoginWidget::userLoginDone(bool ok, const QString reason) { // 登录失败显示失败原因 if (!ok) { Toast::showMessage(登录失败! reason); return; } // 登录成功跳转到主界面 MainWidget* mainWidget MainWidget::getInstance();//主界面我们后面再说 mainWidget-show(); this-close(); // 关闭当前登录窗口 } // 注册完成的槽函数 void LoginWidget::userRegisterDone(bool ok, const QString reason) { if (!ok) { Toast::showMessage(注册失败! reason); return; } Toast::showMessage(注册成功!); // 切换到登录界面 this-switchMode(); // 输入框清空一下. // 主要是要清空用户名和密码, 验证码输入框的内容的. // 但是此处, 只清空一下验证码. 用户名密码这里的情况大概率还是同样的内容. verifyCodeEdit-clear(); // 更新验证码图片 verifyCodeWidget-refreshVerifyCode(); }我觉得思路就很简单登录成功我们就进入主界面注册成功我们就进入登录界面这个设计思想还是很清晰的。二.邮箱注册登录界面设计emailloginwidget.cpp)这个就有点像上面那个了。这个其实跟上面那个差不多。也是登录/注册双模态。那么我们现在就先把这个界面给写出来// 构造函数初始化邮箱登录/注册窗口 EmailLoginWidget::EmailLoginWidget(QWidget *parent) : QWidget{parent} { // 1. 设置窗口的基本属性 this-setFixedSize(400, 350); // 固定窗口大小 this-setWindowTitle(登录); // 窗口标题 this-setWindowIcon(QIcon(:/resource/image/logo.png)); // 窗口图标 this-setStyleSheet(QWidget { background-color: rgb(255, 255, 255); }); // 白色背景 this-setAttribute(Qt::WA_DeleteOnClose); // 关闭时自动销毁窗口对象 // 2. 创建核心布局管理器网格布局 QGridLayout* layout new QGridLayout(); layout-setSpacing(10); // 控件间距10像素 layout-setContentsMargins(50, 0, 50, 0); // 左右边距50上下边距0 this-setLayout(layout); // 3. 创建标题标签 titleLabel new QLabel(); titleLabel-setText(登录); titleLabel-setFixedHeight(50); titleLabel-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 水平拉伸垂直固定 titleLabel-setStyleSheet(QLabel { font-size: 40px; font-weight: 600; }); titleLabel-setAlignment(Qt::AlignCenter); // 4. 创建邮箱号输入框 QString editStyle QLineEdit { border: none; background-color: rgb(240, 240, 240); font-size: 20px; border-radius: 10px; padding-left: 5px;}; emailEdit new QLineEdit(); emailEdit-setPlaceholderText(输入邮箱号); emailEdit-setFixedHeight(40); emailEdit-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); emailEdit-setStyleSheet(editStyle); // 5. 创建验证码输入框 verifyCodeEdit new QLineEdit(); verifyCodeEdit-setPlaceholderText(输入邮箱验证码); verifyCodeEdit-setFixedHeight(40); verifyCodeEdit-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); verifyCodeEdit-setStyleSheet(editStyle); // 6. 创建发送验证码按钮 QString btnWhiteStyle QPushButton { border: none; border-radius: 10px; background-color: transparent; }; btnWhiteStyle QPushButton:pressed { background-color: rgb(240, 240, 240); }; sendVerifyCodeBtn new QPushButton(); sendVerifyCodeBtn-setFixedSize(100, 40); sendVerifyCodeBtn-setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); sendVerifyCodeBtn-setText(发送验证码); sendVerifyCodeBtn-setStyleSheet(btnWhiteStyle); // 7. 创建提交按钮登录/注册 submitBtn new QPushButton(); submitBtn-setFixedHeight(40); submitBtn-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); submitBtn-setText(登录); QString btnGreenStyle QPushButton { border: none; border-radius: 10px; background-color: rgb(44, 182, 61); color: rgb(255, 255, 255); }; btnGreenStyle QPushButton:pressed { background-color: rgb(240, 240, 240); }; submitBtn-setStyleSheet(btnGreenStyle); // 8. 创建 切换到用户名 模式按钮 QPushButton* userModeBtn new QPushButton(); userModeBtn-setFixedSize(100, 40); userModeBtn-setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); userModeBtn-setText(切换到用户名); userModeBtn-setStyleSheet(btnWhiteStyle); // 9. 切换登录/注册模式的按钮 switchModeBtn new QPushButton(); switchModeBtn-setFixedSize(100, 40); switchModeBtn-setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); switchModeBtn-setText(注册); switchModeBtn-setStyleSheet(btnWhiteStyle); // 10. 将所有控件添加到布局管理器中 layout-addWidget(titleLabel, 0, 0, 1, 5); layout-addWidget(emailEdit, 1, 0, 1, 5); layout-addWidget(verifyCodeEdit, 2, 0, 1, 4); layout-addWidget(sendVerifyCodeBtn, 2, 4, 1, 1); layout-addWidget(submitBtn, 3, 0, 1, 5); layout-addWidget(userModeBtn, 4, 0, 1, 1); layout-addWidget(switchModeBtn, 4, 4, 1, 1); …… }在我们这里有4个按钮。对于每一个按钮我们都要去设置槽函数。那么我们一个一个来说明。2.1.登录/注册双模态的转换我们这里跟上面一样还是借助了这个标志位来判断当前是登录还是注册模态。bool isLoginMode true; // 当前是否为登录模式true登录false注册默认情况下就是登录状态。那么这个按钮的槽函数就很好安排了// 切换登录/注册模式按钮 connect(switchModeBtn, QPushButton::clicked, this, EmailLoginWidget::switchMode);可以说跟上面的是一模一样的// 切换登录模式和注册模式的界面及状态 void EmailLoginWidget::switchMode() { if (isLoginMode) { // 当前是登录模式切换到注册模式 this-setWindowTitle(注册); titleLabel-setText(注册); submitBtn-setText(注册); switchModeBtn-setText(登录); } else { // 当前是注册模式切换到登录模式 this-setWindowTitle(登录); titleLabel-setText(登录); submitBtn-setText(登录); switchModeBtn-setText(注册); } isLoginMode !isLoginMode; // 反转模式标志 }2.2.与 账号密码 登录界面的切换这个其实就很简单没有别的啥技巧// 切换到用户名登录窗口并关闭当前窗口 connect(userModeBtn, QPushButton::clicked, this, []() { LoginWidget* loginWidget new LoginWidget(nullptr); loginWidget-show(); this-close(); });2.3.获取验证码接下来就来到一个重头戏了。我们先自己想想按下这个按钮应该发生什么首先最重要的肯定是往服务端发起发送验证码请求然后客户端再这里我们就需要来完完整整的讲清楚这整个流程了。// 发送验证码按钮 connect(sendVerifyCodeBtn, QPushButton::clicked, this, EmailLoginWidget::sendVerifyCode);我们设定的槽函数如下// 发送验证码的槽函数 void EmailLoginWidget::sendVerifyCode() { // 1. 获取到邮箱号码 const QString email this-emailEdit-text(); if (email.isEmpty()) { return; // 邮箱为空则不发送 } this-currentEmail email; // 保存当前邮箱防止用户后续修改 // 2. 发送网络请求, 获取验证码 DataCenter* dataCenter DataCenter::getInstance(); // Qt::UniqueConnection 避免重复连接 connect(dataCenter, DataCenter::getVerifyCodeDone, this, EmailLoginWidget::sendVerifyCodeDone, Qt::UniqueConnection); dataCenter-getVerifyCodeAsync(email); // 3. 开启定时器, 开始倒计时每秒触发一次 timer-start(1000); }我们在客户端收到服务器的响应并更新完数据之后会发出一个信号我们给这个信号配置一个槽函数槽函数非常简单就是弹出一个弹窗打印下面这些内容。// 验证码发送完成后的处理网络请求成功返回 void EmailLoginWidget::sendVerifyCodeDone() { Toast::showMessage(验证码已经发送); }这里其实涉及到一个全局通知设计Toast.cpp这里的Toast::showMessage其实是我们自己写的一个函数这个就是专门用于全局通知的我们就设计了一个全局通知非常简单的一个弹窗#ifndef TOAST_H #define TOAST_H #include QDialog #include QWidget class Toast : public QDialog { Q_OBJECT public: // 此处不需要指定父窗口. 全局通知的父窗口就是 桌面. Toast(const QString text); // 并不需要手动来 new 这个对象, 而是通过 showMessage 来弹出窗口 static void showMessage(const QString text); }; #endif // TOAST_H我们看看具体的实现#include toast.h #include QApplication #include QScreen #include QVBoxLayout #include QLabel #include QTimer Toast::Toast(const QString text) { // 1. 设置窗口的基本参数 this-setFixedSize(800, 150); this-setWindowTitle(消息通知); this-setWindowIcon(QIcon(:/resource/image/logo.png)); this-setAttribute(Qt::WA_DeleteOnClose); this-setStyleSheet(QDialog { background-color: rgb(255, 255, 255); }); // 去掉窗口的标题栏 this-setWindowFlags(Qt::FramelessWindowHint); // 2. 先考虑一下窗口的位置. // 获取到整个屏幕的尺寸, 通过 primaryScreen 来获取. QScreen* screen QApplication::primaryScreen(); int width screen-size().width(); int height screen-size().height(); int x (width - this-width()) / 2; int y height - this-height() - 100; // 此处的 100 是窗口底边距离屏幕底边的间隔 this-move(x, y); // 3. 添加一个布局管理器 QVBoxLayout* layout new QVBoxLayout(); layout-setSpacing(0); layout-setContentsMargins(0, 0, 0, 0); this-setLayout(layout); // 4. 创建显示文本的 Label QLabel* label new QLabel(); label-setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); label-setAlignment(Qt::AlignCenter); label-setStyleSheet(QLabel { font-size: 32px; }); label-setText(text); layout-addWidget(label); // 5. 实现 2s 之后自动关闭. QTimer* timer new QTimer(this); connect(timer, QTimer::timeout, this, []() { timer-stop(); // 核心代码, 关闭当前窗口 this-close(); }); timer-start(2000); } void Toast::showMessage(const QString text) { Toast* toast new Toast(text); toast-show(); }这个就是比较简单的一个设计。事实上在我们的槽函数的设计里面我们还会需要下面这2个成员。QTimer* timer; // 倒计时定时器 int leftTime 30; // 倒计时剩余秒数默认30秒我们回到刚刚槽函数的设计我们思考一下为什么需要下面这一句// 3. 开启定时器, 开始倒计时每秒触发一次 timer-start(1000);事实上我们给定时器也配置了一个槽函数// 倒计时定时器 timer new QTimer(this); connect(timer, QTimer::timeout, this, EmailLoginWidget::countDown);// 倒计时槽函数用于控制发送验证码按钮的禁用和文本更新 void EmailLoginWidget::countDown() { if (leftTime 1) { // 倒计时结束发送按钮设为可用恢复文本停止定时器重置剩余时间 sendVerifyCodeBtn-setEnabled(true); sendVerifyCodeBtn-setText(发送验证码); timer-stop(); leftTime 30; // 重置为默认倒计时秒数 return; } // 倒计时未结束减少剩余秒数更新按钮文本禁用按钮 leftTime - 1; sendVerifyCodeBtn-setText(QString::number(leftTime) s); if (sendVerifyCodeBtn-isEnabled()) { sendVerifyCodeBtn-setEnabled(false); // 确保按钮在倒计时期间不可点击 } }这样子这个定时器的作用就明显了。在 EmailLoginWidget::sendVerifyCode() 中timer-start(1000); 的作用是启动一个间隔为 1 秒的定时器用于实现发送验证码按钮的倒计时功能。具体意义如下1. 防止用户频繁请求验证码当用户点击“发送验证码”按钮后程序会立即请求服务器发送验证码。同时启动这个定时器让按钮进入 30 秒倒计时倒计时期间按钮变灰不可点击。倒计时结束后按钮才恢复可用从而避免用户在短时间内反复点击造成服务器压力和体验问题。2. 每 1 秒更新一次按钮上的剩余秒数定时器每隔 1000 毫秒会触发一次 countDown() 槽函数该函数会将 leftTime 减 1。更新按钮的文本例如从 30 s → 29 s → ... → 1 s。在倒计时结束前禁用按钮虽然已经禁用但再次设置确保状态。当 leftTime 1 时恢复按钮文本为 发送验证码启用按钮并调用 timer-stop() 停止计时器。2.4.登录/注册按钮那么接下来我们就来设计这个按钮的槽函数这里是进行了注册/登录双模态的设计那么我们就有必要去根据这个登录/注册标志位来判断当前是注册还是登录状态。// 点击提交按钮登录或注册的槽函数 void EmailLoginWidget::clickSubmitBtn() { // 1. 从输入框中拿到必要的内容 // 此处不要从输入框直接拿邮箱. 可能用户故意搞事情, 输入验证码的时候, 输入的是邮箱1, 点击提交的时候, 输入的是邮箱2; const QString email this-currentEmail; // 使用发送验证码时保存的邮箱 const QString verifyCode verifyCodeEdit-text(); if (email.isEmpty() || verifyCode.isEmpty()) { Toast::showMessage(邮箱或者验证码不应该为空); return; } // 2. 根据当前模式发送登录或注册请求 DataCenter* dataCenter DataCenter::getInstance(); if (isLoginMode) { // 登录模式邮箱登录 connect(dataCenter, DataCenter::emailLoginDone, this, EmailLoginWidget::emailLoginDone, Qt::UniqueConnection); dataCenter-emailLoginAsync(email, verifyCode); } else { // 注册模式邮箱注册 connect(dataCenter, DataCenter::emailRegisterDone, this, EmailLoginWidget::emailRegisterDone, Qt::UniqueConnection); dataCenter-emailRegisterAsync(email, verifyCode); } }这个可以说跟上面账号密码登录的完全一样。// 邮箱登录完成的槽函数 void EmailLoginWidget::emailLoginDone(bool ok, const QString reason) { if (!ok) { Toast::showMessage(登录失败! reason); return; } // 登录成功跳转到主窗口 MainWidget* mainWidget MainWidget::getInstance(); mainWidget-show(); // 关闭当前邮箱登录窗口 this-close(); } // 邮箱注册完成的槽函数 void EmailLoginWidget::emailRegisterDone(bool ok, const QString reason) { if (!ok) { Toast::showMessage(注册失败! reason); return; } Toast::showMessage(注册成功!); // 注册成功后自动切换到登录模式 switchMode(); // 清空验证码输入框 verifyCodeEdit-clear(); // 重置倒计时相关变量使发送验证码按钮恢复可用leftTime 设为 1 会让倒计时定时器立即重置 leftTime 1; }

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价