登录注册修改密码,网络请求

This commit is contained in:
2026-05-14 14:59:45 +08:00
parent 14d1969903
commit 652e10ec62
12 changed files with 455 additions and 229 deletions

View File

@@ -105,13 +105,7 @@
android:exported="false" />
<activity
android:name=".home.HomeActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
android:exported="false"/>
<activity
android:name=".login.RegisterSuccessActivity"
android:exported="false" />
@@ -129,7 +123,13 @@
android:exported="false" />
<activity
android:name=".login.LoginActivity"
android:exported="false" />
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"

View File

@@ -15,3 +15,30 @@ data class LoginBean(
val token: String,
val userId: Int
)
data class LoginRequest(
val clientId: String = "428a8310cd442757ae699df5d894f051",
val grantType: String,
val username: String? = null,
val phonenumber: String? = null,
val smsCode: String? = null,
val password: String? = null,
val userType: String = "app_user"
)
data class RegisterRequest(
val clientId: String = "428a8310cd442757ae699df5d894f051",
val grantType: String,
val smsCode: String? = null,
val username: String,
val password: String,
val userType: String = "app_user",
val idCard: String,
val inviteCode: String? = null,
val faceAddr: String
)
data class ForgotRequest(
val phonenumber: String,
val smsCode: String,
val password: String
)

View File

@@ -4,28 +4,27 @@ import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.os.CountDownTimer
import android.text.InputType
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import bean.ForgotRequest
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ForgetPasswordActivityBinding
import com.example.defenseapplication.utils.HttpUtils
import com.google.firebase.crashlytics.buildtools.reloc.org.apache.http.util.TextUtils
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.regex.Pattern
import kotlin.random.Random
//找回密码
class ForgetPasswordActivity : AppCompatActivity() {
private lateinit var binding: ForgetPasswordActivityBinding
private var verifyCode: String? = null // 存储模拟验证码
private var countDownTimer: CountDownTimer? = null
private var isSendingCode = false // 防止重复发送验证码
private var isSendingCode = false
companion object {
private const val COUNTDOWN_DURATION = 60000L // 60秒倒计时
private const val COUNTDOWN_DURATION = 60000L
private const val COUNTDOWN_INTERVAL = 1000L
private const val MIN_PASSWORD_LENGTH = 6
private const val MAX_PASSWORD_LENGTH = 20
@@ -39,7 +38,6 @@ class ForgetPasswordActivity : AppCompatActivity() {
.statusBarDarkFont(true)
.titleBar(binding.topContainer)
.init()
// 设置渐变背景
val startColor = Color.parseColor("#CBEBFA")
val endColor = Color.parseColor("#FFF2EF")
setGradientBackground(binding.main, startColor, endColor)
@@ -47,12 +45,10 @@ class ForgetPasswordActivity : AppCompatActivity() {
}
private fun setupClickListeners() {
// 返回按钮
binding.backIcon.setOnClickListener {
finish()
}
// 发送验证码按钮
binding.sendCodeBtn.setOnClickListener {
if (!isSendingCode && countDownTimer == null) {
val phoneNumber = binding.etPhoneNumber.text.toString().trim()
@@ -66,28 +62,42 @@ class ForgetPasswordActivity : AppCompatActivity() {
}
}
// 确定按钮(重置密码)
binding.btnNext.setOnClickListener {
performResetPassword()
}
}
/**
* 手机号格式校验简单1开头的11位数字
*/
private fun isPhoneNumberValid(phone: String): Boolean {
if (TextUtils.isEmpty(phone)) return false
val pattern = Pattern.compile("^1[0-9]{10}$")
return pattern.matcher(phone).matches()
}
/**
* 发送验证码
*/
private fun sendVerificationCode(phoneNumber: String) {
isSendingCode = true
binding.sendCodeBtn.isEnabled = false
CoroutineScope(Dispatchers.IO).launch {
try {
val response = HttpUtils.api.getCode(phoneNumber)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@ForgetPasswordActivity, "验证码已发送", Toast.LENGTH_SHORT).show()
startCountDown()
} else {
Toast.makeText(this@ForgetPasswordActivity, response.msg, Toast.LENGTH_SHORT).show()
binding.sendCodeBtn.isEnabled = true
isSendingCode = false
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(this@ForgetPasswordActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
binding.sendCodeBtn.isEnabled = true
isSendingCode = false
}
}
}
}
/**
@@ -122,31 +132,20 @@ class ForgetPasswordActivity : AppCompatActivity() {
*/
private fun performResetPassword() {
val phoneNumber = binding.etPhoneNumber.text.toString().trim()
val code = binding.etSmsCode.text.toString().trim()
val smsCode = binding.etSmsCode.text.toString().trim()
val newPassword = binding.etPassword.text.toString().trim()
val confirmPassword = binding.etInviteCode.text.toString().trim()
// 1. 手机号校验
if (!isPhoneNumberValid(phoneNumber)) {
Toast.makeText(this, "手机号格式不正确", Toast.LENGTH_SHORT).show()
return
}
// 2. 验证码校验
if (TextUtils.isEmpty(code)) {
if (TextUtils.isEmpty(smsCode)) {
Toast.makeText(this, "请输入验证码", Toast.LENGTH_SHORT).show()
return
}
if (verifyCode == null) {
Toast.makeText(this, "请先获取验证码", Toast.LENGTH_SHORT).show()
return
}
if (code != verifyCode) {
Toast.makeText(this, "验证码错误", Toast.LENGTH_SHORT).show()
return
}
// 3. 密码校验
if (TextUtils.isEmpty(newPassword) || TextUtils.isEmpty(confirmPassword)) {
Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show()
return
@@ -164,19 +163,36 @@ class ForgetPasswordActivity : AppCompatActivity() {
return
}
// 禁用确定按钮,防重复提交
binding.btnNext.isEnabled = false
binding.btnNext.text = "重置中..."
val requestJson = """
{
"phone":"$phoneNumber",
"code":"$code",
"newPassword":"$newPassword"
CoroutineScope(Dispatchers.IO).launch {
try {
val forgotRequest = ForgotRequest(
phonenumber = phoneNumber,
smsCode = smsCode,
password = newPassword
)
val response = HttpUtils.api.forgotPassword(forgotRequest)
withContext(Dispatchers.Main) {
binding.btnNext.isEnabled = true
binding.btnNext.text = "确定"
if (response.code == 200) {
Toast.makeText(this@ForgetPasswordActivity, R.string.reset_success, Toast.LENGTH_SHORT).show()
finish()
} else {
Toast.makeText(this@ForgetPasswordActivity, response.msg, Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
binding.btnNext.isEnabled = true
binding.btnNext.text = "确定"
Toast.makeText(this@ForgetPasswordActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
""".trimIndent()
}
}
private fun setGradientBackground(
view: android.view.View,

View File

@@ -1,8 +1,8 @@
package com.example.defenseapplication.login
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import com.example.defenseapplication.R
import android.os.Bundle
import android.os.CountDownTimer
import android.view.View
@@ -10,9 +10,18 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import bean.LoginRequest
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ActivityLoginBinding
import com.example.defenseapplication.home.HomeActivity
import com.example.defenseapplication.utils.HttpUtils
import com.example.defenseapplication.utils.UserinfoUtil
import com.gyf.immersionbar.ImmersionBar
//登录
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
@@ -22,10 +31,18 @@ class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (UserinfoUtil.getUserInfo() != null) {
val intent = Intent(this, HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
return
}
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
// 设置渐变背景
val startColor = Color.parseColor("#CBEBFA")
val endColor = Color.parseColor("#FFF2EF")
setGradientBackground(binding.main, startColor, endColor)
@@ -64,7 +81,7 @@ class LoginActivity : AppCompatActivity() {
binding.registerText.visibility = View.VISIBLE
binding.forgetText.visibility = View.GONE
updateRegisterTextConstraints(center = true)
updateRegisterTextConstraints(center = false)
//需要正确的方法名和参数
updateLoginButtonTopConstraint(R.id.smsRowLayout)
@@ -117,13 +134,17 @@ class LoginActivity : AppCompatActivity() {
Toast.makeText(this, R.string.enter_phone_number, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
if (phone.length != 11) {
Toast.makeText(this, R.string.phone_format_invalid, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
when (currentLoginMode) {
LoginMode.SMS -> {
val code = binding.etSmsCode.text.toString()
if (code.isEmpty()) {
Toast.makeText(this, R.string.enter_verification_code_pls, Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, getString(R.string.sms_login_success, phone, code), Toast.LENGTH_SHORT).show()
smsLogin(phone, code)
}
}
LoginMode.PASSWORD -> {
@@ -131,7 +152,7 @@ class LoginActivity : AppCompatActivity() {
if (pwd.isEmpty()) {
Toast.makeText(this, R.string.password_hint, Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, getString(R.string.password_login_success, phone, pwd), Toast.LENGTH_SHORT).show()
passwordLogin(phone, pwd)
}
}
}
@@ -143,8 +164,11 @@ class LoginActivity : AppCompatActivity() {
Toast.makeText(this, R.string.phone_hint, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
Toast.makeText(this, getString(R.string.code_sent_to, phone), Toast.LENGTH_SHORT).show()
startCountDown()
if (phone.length != 11) {
Toast.makeText(this, R.string.phone_format_invalid, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
sendVerificationCode(phone)
}
binding.registerText.setOnClickListener {
@@ -173,6 +197,92 @@ class LoginActivity : AppCompatActivity() {
}.start()
}
private fun sendVerificationCode(phone: String) {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = HttpUtils.api.getCode(phone)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@LoginActivity, getString(R.string.code_sent_to, phone), Toast.LENGTH_SHORT).show()
startCountDown()
} else {
Toast.makeText(this@LoginActivity, response.msg, Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun smsLogin(phone: String, smsCode: String) {
CoroutineScope(Dispatchers.IO).launch {
try {
val loginRequest = LoginRequest(
grantType = "sms",
username = phone,
phonenumber = phone,
smsCode = smsCode
)
android.util.Log.d("LoginActivity", "短信登录请求: $loginRequest")
val response = HttpUtils.api.login(loginRequest)
android.util.Log.d("LoginActivity", "短信登录响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
UserinfoUtil.saveUserInfo(response.data)
Toast.makeText(this@LoginActivity, R.string.sms_login_success_title, Toast.LENGTH_SHORT).show()
val intent = Intent(this@LoginActivity, HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
} else {
Toast.makeText(this@LoginActivity, response.msg, Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
android.util.Log.e("LoginActivity", "短信登录异常", e)
withContext(Dispatchers.Main) {
Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun passwordLogin(phone: String, password: String) {
CoroutineScope(Dispatchers.IO).launch {
try {
val loginRequest = LoginRequest(
grantType = "password",
username = phone,
phonenumber = phone,
password = password
)
android.util.Log.d("LoginActivity", "密码登录请求: $loginRequest")
val response = HttpUtils.api.login(loginRequest)
android.util.Log.d("LoginActivity", "密码登录响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
UserinfoUtil.saveUserInfo(response.data)
Toast.makeText(this@LoginActivity, R.string.password_login_success_title, Toast.LENGTH_SHORT).show()
val intent = Intent(this@LoginActivity, HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
} else {
Toast.makeText(this@LoginActivity, response.msg, Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
android.util.Log.e("LoginActivity", "密码登录异常", e)
withContext(Dispatchers.Main) {
Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun setGradientBackground(
view: android.view.View,
startColor: Int,

View File

@@ -4,25 +4,34 @@ import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.os.CountDownTimer
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import bean.RegisterRequest
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.RegisterActivityBinding
import com.example.defenseapplication.utils.HttpUtils
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* 注册页面
* 功能:收集用户信息(手机号、身份证号、密码、邀请码),
* 进行前端格式校验,模拟注册请求并反馈结果。
*/
class RegisterActivity : AppCompatActivity() {
private lateinit var binding: RegisterActivityBinding
private var isLoading = false // 防止重复点击
private var isLoading = false
private var countDownTimer: CountDownTimer? = null
private var isSendingCode = false
companion object {
private const val COUNTDOWN_DURATION = 60000L
private const val COUNTDOWN_INTERVAL = 1000L
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = RegisterActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
// 设置渐变背景
val startColor = Color.parseColor("#CBEBFA")
val endColor = Color.parseColor("#FFF2EF")
setGradientBackground(binding.main, startColor, endColor)
@@ -33,172 +42,161 @@ class RegisterActivity : AppCompatActivity() {
.init()
setupListeners()
//setupTextWatchers()
}
private fun setupListeners() {
// 返回按钮
binding.backIcon.setOnClickListener {
finish()
}
// 下一步按钮
binding.sendCodeBtn.setOnClickListener {
if (!isSendingCode && countDownTimer == null) {
val phone = binding.etPhoneNumber.text.toString().trim()
if (phone.isEmpty()) {
Toast.makeText(this, R.string.enter_phone_number, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
if (phone.length != 11) {
Toast.makeText(this, R.string.phone_format_invalid, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
sendVerificationCode(phone)
}
}
binding.btnNext.setOnClickListener {
if (!isLoading) {
val intent= Intent(this, FaceLoginActivity::class.java)
startActivity(intent)
Toast.makeText(this, "跳转到人脸页面", Toast.LENGTH_SHORT).show()
//performRegistration()
performRegistration()
}
}
}
private fun sendVerificationCode(userName: String) {
isSendingCode = true
binding.sendCodeBtn.isEnabled = false
CoroutineScope(Dispatchers.IO).launch {
try {
val response = HttpUtils.api.getCode(userName)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@RegisterActivity, "验证码已发送", Toast.LENGTH_SHORT).show()
startCountDown()
} else {
Toast.makeText(this@RegisterActivity, response.msg, Toast.LENGTH_SHORT).show()
binding.sendCodeBtn.isEnabled = true
isSendingCode = false
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(this@RegisterActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
binding.sendCodeBtn.isEnabled = true
isSendingCode = false
}
}
}
}
private fun startCountDown() {
countDownTimer = object : CountDownTimer(COUNTDOWN_DURATION, COUNTDOWN_INTERVAL) {
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished / 1000).toInt()
binding.sendCodeBtn.text = "${secondsRemaining}秒后重试"
binding.sendCodeBtn.isEnabled = false
}
override fun onFinish() {
resetSendButton()
}
}.start()
}
private fun resetSendButton() {
countDownTimer?.cancel()
countDownTimer = null
binding.sendCodeBtn.text = getString(R.string.send_code)
binding.sendCodeBtn.isEnabled = true
isSendingCode = false
}
private fun performRegistration() {
val phone = binding.etPhoneNumber.text.toString().trim()
val smsCode = binding.etSmsCode.text.toString().trim()
val idCard = binding.etIdNumber.text.toString().trim()
val password = binding.etPassword.text.toString().trim()
val inviteCode = binding.etInviteCode.text.toString().trim()
if (phone.isEmpty()) {
Toast.makeText(this, R.string.enter_phone_number, Toast.LENGTH_SHORT).show()
return
}
if (phone.length != 11) {
Toast.makeText(this, R.string.phone_format_invalid, Toast.LENGTH_SHORT).show()
return
}
if (smsCode.isEmpty()) {
Toast.makeText(this, R.string.enter_verification_code_pls, Toast.LENGTH_SHORT).show()
return
}
if (idCard.isEmpty()) {
Toast.makeText(this, R.string.enter_id_number, Toast.LENGTH_SHORT).show()
return
}
if (idCard.length != 18) {
Toast.makeText(this, R.string.hint_input_correct_id_card, Toast.LENGTH_SHORT).show()
return
}
if (password.isEmpty()) {
Toast.makeText(this, R.string.password_hint, Toast.LENGTH_SHORT).show()
return
}
if (password.length < 6 || password.length > 20) {
Toast.makeText(this, R.string.password_requirement, Toast.LENGTH_SHORT).show()
return
}
isLoading = true
binding.btnNext.isEnabled = false
binding.btnNext.text = getString(R.string.registering)
CoroutineScope(Dispatchers.IO).launch {
try {
val registerRequest = RegisterRequest(
grantType = "password",
smsCode = smsCode,
username = phone,
password = password,
idCard = idCard,
inviteCode = if (inviteCode.isEmpty()) null else inviteCode,
faceAddr = "https://tiebapic.baidu.com/forum/pic/item/2924ab18972bd407021da3e33d899e510eb309d1.jpg?tbpicau=2026-04-22-05_44105254d24a81214177d11b72513421"
)
val response = HttpUtils.api.register(registerRequest)
withContext(Dispatchers.Main) {
isLoading = false
binding.btnNext.isEnabled = true
binding.btnNext.text = getString(R.string.next_step)
if (response.code == 200) {
Toast.makeText(this@RegisterActivity, R.string.register_success, Toast.LENGTH_SHORT).show()
val intent = Intent(this@RegisterActivity, LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
} else {
Toast.makeText(this@RegisterActivity, response.msg, Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
isLoading = false
binding.btnNext.isEnabled = true
binding.btnNext.text = getString(R.string.next_step)
Toast.makeText(this@RegisterActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
//
// /**
// * 为输入框添加文字监听,实时清除错误提示
// */
// private fun setupTextWatchers() {
// val errorClearWatcher = object : TextWatcher {
// override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
// override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
// override fun afterTextChanged(s: Editable?) {
// // 当用户开始输入时,清除该字段的错误
// when (binding.etPhoneNumber.hasFocus()) {
// true -> binding.etPhoneNumber.error = null
// else -> Unit
// }
// when (binding.etIdNumber.hasFocus()) {
// true -> binding.etIdNumber.error = null
// else -> Unit
// }
// when (binding.etPassword.hasFocus()) {
// true -> binding.etPassword.error = null
// else -> Unit
// }
// }
// }
//
// binding.etPhoneNumber.addTextChangedListener(errorClearWatcher)
// binding.etIdNumber.addTextChangedListener(errorClearWatcher)
// binding.etPassword.addTextChangedListener(errorClearWatcher)
// }
//
// /**
// * 执行注册流程:校验输入 -> 模拟网络请求
// */
// private fun performRegistration() {
// val phone = binding.etPhoneNumber.text.toString().trim()
// val idNumber = binding.etIdNumber.text.toString().trim()
// val password = binding.etPassword.text.toString().trim()
// val inviteCode = binding.etInviteCode.text.toString().trim()
//
// // 1. 校验
// val phoneValid = validatePhone(phone)
// val idValid = validateIdNumber(idNumber)
// val passwordValid = validatePassword(password)
//
// if (!phoneValid) {
// binding.etPhoneNumber.error = "请输入有效的11位手机号"
// binding.etPhoneNumber.requestFocus()
// return
// }
// if (!idValid) {
// binding.etIdNumber.error = "请输入正确的身份证号"
// binding.etIdNumber.requestFocus()
// return
// }
// if (!passwordValid) {
// binding.etPassword.error = "密码长度需为6~20位"
// binding.etPassword.requestFocus()
// return
// }
//
// // 2. 模拟注册请求(展示加载状态)
// isLoading = true
// binding.btnNext.isEnabled = false
// binding.btnNext.text = "注册中..."
//
// lifecycleScope.launch {
// // 模拟网络延迟 1.5 秒
// val registerResult = simulateRegister(phone, idNumber, password, inviteCode)
// delay(1500)
//
// isLoading = false
// binding.btnNext.isEnabled = true
// binding.btnNext.text = "下一步"
//
// if (registerResult) {
// Toast.makeText(this@RegisterActivity, "注册成功!", Toast.LENGTH_SHORT).show()
// // 实际项目中通常跳转到登录页或主页,这里简单关闭当前页面
// finish()
// } else {
// Toast.makeText(this@RegisterActivity, "注册失败,请稍后重试", Toast.LENGTH_SHORT).show()
// }
// }
// }
//
// /**
// * 模拟注册请求(实际应替换为 Retrofit/OkHttp 调用)
// */
// private suspend fun simulateRegister(
// phone: String,
// idNumber: String,
// password: String,
// inviteCode: String
// ): Boolean {
// // 模拟网络请求,此处始终返回成功(实际根据后端响应决定)
// // 您可以在这里添加真实网络请求逻辑
// return true
// }
// /**
// * 校验手机号中国大陆手机号简单校验1开头的11位数字第二位3-9
// */
// private fun validatePhone(phone: String): Boolean {
// val phoneRegex = Pattern.compile("^1[3-9]\\d{9}$")
// return phone.isNotEmpty() && phoneRegex.matcher(phone).matches()
// }
//
// /**
// * 校验身份证号支持15位和18位18位时校验最后一位校验码
// */
// private fun validateIdNumber(idNumber: String): Boolean {
// if (idNumber.isEmpty()) return false
// // 长度校验
// if (idNumber.length != 15 && idNumber.length != 18) return false
//
// // 15位全数字
// if (idNumber.length == 15) {
// return idNumber.all { it.isDigit() }
// }
//
// // 18位前17位为数字最后一位为数字或大写X
// val regex = Regex("^\\d{17}[\\dXx]$")
// if (!regex.matches(idNumber)) return false
//
// // 校验最后一位校验码(可选,提升准确性)
// return verifyIdCardChecksum(idNumber)
// }
//
// /**
// * 身份证最后一位校验码校验仅18位
// */
// private fun verifyIdCardChecksum(id18: String): Boolean {
// val weights = intArrayOf(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
// val checkCodes = charArrayOf('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2')
// var sum = 0
// for (i in 0 until 17) {
// sum += (id18[i] - '0') * weights[i]
// }
// val mod = sum % 11
// val expectedCheckCode = checkCodes[mod]
// return id18[17].uppercaseChar() == expectedCheckCode
// }
//
// /**
// * 校验密码长度6~20位
// */
// private fun validatePassword(password: String): Boolean {
// return password.length in 6..20
// }
private fun setGradientBackground(
view: android.view.View,
startColor: Int,

View File

@@ -11,7 +11,7 @@ import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.RegisterSuccessActivityBinding
import com.example.defenseapplication.home.HomeActivity
import com.gyf.immersionbar.ImmersionBar
//注册
//注册成功界面
class RegisterSuccessActivity : AppCompatActivity() {
private lateinit var binding: RegisterSuccessActivityBinding

View File

@@ -1,14 +1,27 @@
package com.example.defenseapplication.utils
import com.google.gson.Gson
import okhttp3.OkHttpClient
import bean.ForgotRequest
import com.example.defenseapplication.bean.GetCodeBean
import bean.LoginBean
import bean.LoginRequest
import bean.RegisterRequest
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Query
interface ApiService {
// 获取登录注册验证码
@GET("/resource/sms/code")
suspend fun getCode(): String
suspend fun getCode(@Query("userName") userName: String): GetCodeBean<String>
@POST("/app/login")
suspend fun login(@Body loginRequest: LoginRequest): GetCodeBean<LoginBean>
@POST("/app/register")
suspend fun register(@Body registerRequest: RegisterRequest): GetCodeBean<Any>
@PUT("/app/forgot")
suspend fun forgotPassword(@Body forgotRequest: ForgotRequest): GetCodeBean<Any>
}
}

View File

@@ -10,7 +10,7 @@ import java.util.concurrent.TimeUnit
//网络工具类
object HttpUtils {
val baseURL = "https://stem-boozy-margarine.ngrok-free.dev"
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.writeTimeout(3, TimeUnit.MINUTES)
@@ -30,7 +30,7 @@ object HttpUtils {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.baseUrl("https://stem-boozy-margarine.ngrok-free.dev")
.baseUrl(baseURL)
.build()

View File

@@ -97,6 +97,64 @@
app:layout_constraintStart_toEndOf="@+id/ivPhoneIcon"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- 验证码输入框 -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/smsRowLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/textinput_white_bg"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:layout_constraintTop_toBottomOf="@+id/phoneRowLayout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="visible">
<!-- 左侧图标 -->
<ImageView
android:id="@+id/ivSmsIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/vc"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- 验证码输入框(无背景) -->
<EditText
android:id="@+id/etSmsCode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:hint="@string/sms_code_hint"
android:textColorHint="@color/gray"
android:textColor="@android:color/black"
android:background="@null"
android:inputType="number"
android:paddingVertical="16dp"
app:layout_constraintStart_toEndOf="@+id/ivSmsIcon"
app:layout_constraintEnd_toStartOf="@+id/sendCodeBtn"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- 发送验证码按钮 -->
<android.widget.Button
android:id="@+id/sendCodeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_sms_code"
android:textSize="16sp"
android:textColor="@color/white"
android:background="@drawable/rounded_blue_bg"
android:paddingHorizontal="12dp"
android:maxWidth="120dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="12dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- 身份证号输入框 -->
@@ -110,7 +168,7 @@
android:paddingEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/phoneRowLayout">
app:layout_constraintTop_toBottomOf="@+id/smsRowLayout">
<ImageView
android:id="@+id/ivIdIcon"

View File

@@ -39,6 +39,7 @@
<string name="and"></string>
<string name="privacy_policy">隐私政策</string>
<string name="register_success">注册成功</string>
<string name="registering">注册中...</string>
<string name="register_success_message">您的账号已成功创建</string>
<string name="go_to_login">去登录</string>
@@ -320,6 +321,7 @@
<string name="determine">确定</string>
<string name="id_number">身份证号</string>
<string name="enter_id_number">请输入身份证号</string>
<string name="hint_input_correct_id_card">请输入正确的身份证号</string>
<string name="invite_code_optional">邀请码(非必填)</string>
<string name="enter_invite_code">请输入邀请码</string>
<string name="scan_add">扫描添加</string>

View File

@@ -35,6 +35,7 @@
<string name="and">and</string>
<string name="privacy_policy">Privacy Policy</string>
<string name="register_success">Registration Successful</string>
<string name="registering">Registering...</string>
<string name="register_success_message">Your account has been created successfully</string>
<string name="go_to_login">Go to Login</string>
@@ -304,6 +305,7 @@
<string name="determine">Confirm</string>
<string name="id_number">ID Number</string>
<string name="enter_id_number">Enter ID number</string>
<string name="hint_input_correct_id_card">Please enter a valid ID card number</string>
<string name="invite_code_optional">Invite Code (Optional)</string>
<string name="enter_invite_code">Enter invite code</string>
<string name="scan_add">Scan to Add</string>