初次提交
This commit is contained in:
738
src/views/Register.vue
Normal file
738
src/views/Register.vue
Normal file
@@ -0,0 +1,738 @@
|
||||
<template>
|
||||
<div class="register-page">
|
||||
<div class="register-container">
|
||||
<div class="register-card">
|
||||
<div class="register-header">
|
||||
<h2>用户注册</h2>
|
||||
<p>创建你的账号,开始使用前端H5系统</p>
|
||||
</div>
|
||||
|
||||
<el-form
|
||||
ref="registerFormRef"
|
||||
:model="registerForm"
|
||||
:rules="registerRules"
|
||||
class="register-form"
|
||||
@submit.prevent="handleRegister"
|
||||
>
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
v-model="registerForm.username"
|
||||
placeholder="请输入用户名"
|
||||
size="large"
|
||||
:prefix-icon="User"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="phone">
|
||||
<el-input
|
||||
v-model="registerForm.phone"
|
||||
placeholder="请输入手机号"
|
||||
size="large"
|
||||
:prefix-icon="Message"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="smsCode">
|
||||
<div class="sms-code-group">
|
||||
<el-input
|
||||
v-model="registerForm.smsCode"
|
||||
placeholder="请输入短信验证码"
|
||||
size="large"
|
||||
:prefix-icon="ChatDotRound"
|
||||
clearable
|
||||
class="sms-input"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!canSendSMS || smsCountdown > 0"
|
||||
:loading="sendingSMS"
|
||||
@click="sendSMSCode"
|
||||
class="sms-button"
|
||||
>
|
||||
{{ smsCountdown > 0 ? `${smsCountdown}s后重发` : '发送验证码' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="registrationCode">
|
||||
<el-input
|
||||
v-model="registerForm.registrationCode"
|
||||
placeholder="请输入激活码"
|
||||
size="large"
|
||||
:prefix-icon="Ticket"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="registerForm.password"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
:prefix-icon="Lock"
|
||||
show-password
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="confirmPassword">
|
||||
<el-input
|
||||
v-model="registerForm.confirmPassword"
|
||||
type="password"
|
||||
placeholder="请确认密码"
|
||||
size="large"
|
||||
:prefix-icon="Lock"
|
||||
show-password
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="captcha">
|
||||
<Captcha
|
||||
ref="captchaRef"
|
||||
v-model="registerForm.captcha"
|
||||
placeholder="请输入验证码"
|
||||
size="large"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="agreement">
|
||||
<el-checkbox v-model="registerForm.agreement">
|
||||
我已阅读并同意
|
||||
<el-link type="primary" @click="showAgreement">
|
||||
《用户协议》
|
||||
</el-link>
|
||||
和
|
||||
<el-link type="primary" @click="showPrivacy">
|
||||
《隐私政策》
|
||||
</el-link>
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
class="register-button"
|
||||
:loading="userStore.loading"
|
||||
@click="handleRegister"
|
||||
>
|
||||
{{ userStore.loading ? '注册中...' : '立即注册' }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="register-footer">
|
||||
<p>
|
||||
已有账号?
|
||||
<el-link type="primary" @click="$router.push('/login')">
|
||||
立即登录
|
||||
</el-link>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="features-preview">
|
||||
<el-divider>注册后你可以</el-divider>
|
||||
<div class="features-list">
|
||||
<div class="feature-item">
|
||||
<el-icon><User /></el-icon>
|
||||
<span>个性化用户中心</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon><CreditCard /></el-icon>
|
||||
<span>积分商城购物</span>
|
||||
</div>
|
||||
<div class="feature-item">
|
||||
<el-icon><ChatDotRound /></el-icon>
|
||||
<span>积分转账功能</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 背景装饰 -->
|
||||
<div class="background-decoration">
|
||||
<div class="decoration-shape shape-1"></div>
|
||||
<div class="decoration-shape shape-2"></div>
|
||||
<div class="decoration-shape shape-3"></div>
|
||||
<div class="decoration-shape shape-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { User, Lock, Message, Edit, ChatDotRound, CreditCard, Ticket } from '@element-plus/icons-vue'
|
||||
import Captcha from '@/components/Captcha.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 表单引用
|
||||
const registerFormRef = ref()
|
||||
const captchaRef = ref()
|
||||
|
||||
// 表单数据
|
||||
const registerForm = reactive({
|
||||
username: '',
|
||||
phone: '',
|
||||
registrationCode: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
captcha: '',
|
||||
smsCode: '',
|
||||
agreement: false
|
||||
})
|
||||
|
||||
// 短信验证码相关状态
|
||||
const sendingSMS = ref(false)
|
||||
const smsCountdown = ref(0)
|
||||
const canSendSMS = computed(() => {
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
return phoneRegex.test(registerForm.phone)
|
||||
})
|
||||
|
||||
// 自定义验证函数
|
||||
const validateUsername = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请输入用户名'))
|
||||
} else if (value.length < 3) {
|
||||
callback(new Error('用户名至少3个字符'))
|
||||
} else if (value.length > 20) {
|
||||
callback(new Error('用户名不能超过20个字符'))
|
||||
} else if (!/^[a-zA-Z0-9_\u4e00-\u9fa5]+$/.test(value)) {
|
||||
callback(new Error('用户名只能包含字母、数字、下划线和中文'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const validatePassword = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请输入密码'))
|
||||
} else if (value.length < 6) {
|
||||
callback(new Error('密码至少6个字符'))
|
||||
} else if (value.length > 20) {
|
||||
callback(new Error('密码不能超过20个字符'))
|
||||
} else if (!/(?=.*[a-zA-Z])(?=.*\d)/.test(value)) {
|
||||
callback(new Error('密码必须包含字母和数字'))
|
||||
} else {
|
||||
// 如果确认密码已输入,重新验证确认密码
|
||||
if (registerForm.confirmPassword) {
|
||||
registerFormRef.value?.validateField('confirmPassword')
|
||||
}
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const validateConfirmPassword = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请确认密码'))
|
||||
} else if (value !== registerForm.password) {
|
||||
callback(new Error('两次输入的密码不一致'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const validateAgreement = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请阅读并同意用户协议和隐私政策'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const registerRules = {
|
||||
username: [{ validator: validateUsername, trigger: 'blur' }],
|
||||
phone: [
|
||||
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
||||
],
|
||||
registrationCode: [
|
||||
{ required: true, message: '请输入激活码', trigger: 'blur' },
|
||||
{ min: 6, message: '激活码长度不能少于6位', trigger: 'blur' }
|
||||
],
|
||||
smsCode: [
|
||||
{ required: true, message: '请输入短信验证码', trigger: 'blur' },
|
||||
{ pattern: /^\d{6}$/, message: '短信验证码为6位数字', trigger: 'blur' }
|
||||
],
|
||||
|
||||
password: [{ validator: validatePassword, trigger: 'blur' }],
|
||||
confirmPassword: [{ validator: validateConfirmPassword, trigger: 'blur' }],
|
||||
captcha: [
|
||||
{ required: true, message: '请输入验证码', trigger: 'blur' },
|
||||
{ min: 4, max: 4, message: '验证码长度为4位', trigger: 'blur' }
|
||||
],
|
||||
agreement: [{ validator: validateAgreement, trigger: 'change' }]
|
||||
}
|
||||
|
||||
// 发送短信验证码
|
||||
const sendSMSCode = async () => {
|
||||
if (!canSendSMS.value || sendingSMS.value || smsCountdown.value > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
sendingSMS.value = true
|
||||
|
||||
const response = await fetch('/api/sms/send', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
phone: registerForm.phone
|
||||
})
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
if (result.success) {
|
||||
ElMessage.success('验证码发送成功,请查收短信')
|
||||
// 开始倒计时
|
||||
startCountdown()
|
||||
} else {
|
||||
ElMessage.error(result.message || '发送失败,请重试')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送短信验证码失败:', error)
|
||||
ElMessage.error('发送失败,请检查网络连接')
|
||||
} finally {
|
||||
sendingSMS.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 开始倒计时
|
||||
const startCountdown = () => {
|
||||
smsCountdown.value = 60
|
||||
const timer = setInterval(() => {
|
||||
smsCountdown.value--
|
||||
if (smsCountdown.value <= 0) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 处理注册
|
||||
const handleRegister = async () => {
|
||||
if (!registerFormRef.value || !captchaRef.value) return
|
||||
|
||||
try {
|
||||
// 先验证表单
|
||||
const valid = await registerFormRef.value.validate()
|
||||
if (!valid) return
|
||||
|
||||
// 验证验证码
|
||||
const captchaValid = await captchaRef.value.verifyCaptcha(registerForm.captcha)
|
||||
if (!captchaValid) {
|
||||
registerForm.captcha = ''
|
||||
return
|
||||
}
|
||||
|
||||
// 获取验证码信息
|
||||
const captchaInfo = captchaRef.value.getCaptchaInfo()
|
||||
|
||||
// 提交注册请求(包含验证码信息)
|
||||
const registerData = {
|
||||
username: registerForm.username,
|
||||
phone: registerForm.phone,
|
||||
registrationCode: registerForm.registrationCode,
|
||||
password: registerForm.password,
|
||||
smsCode: registerForm.smsCode,
|
||||
captchaId: captchaInfo.captchaId,
|
||||
captchaText: captchaInfo.captchaText
|
||||
}
|
||||
|
||||
const result = await userStore.register(registerData)
|
||||
|
||||
if (result.success) {
|
||||
ElMessage.success('注册成功!请登录')
|
||||
router.push('/login')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('注册失败:', error)
|
||||
// 注册失败后刷新验证码
|
||||
if (captchaRef.value) {
|
||||
await captchaRef.value.refreshCaptcha()
|
||||
}
|
||||
registerForm.captcha = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 显示用户协议
|
||||
const showAgreement = () => {
|
||||
ElMessageBox.alert(
|
||||
`<div style="text-align: left; line-height: 1.6;">
|
||||
<h3>用户协议</h3>
|
||||
<p>1. 用户应当遵守法律法规,不得发布违法违规内容。</p>
|
||||
<p>2. 用户对自己发布的内容承担全部责任。</p>
|
||||
<p>3. 平台有权对违规内容进行删除或限制。</p>
|
||||
<p>4. 用户应当保护好自己的账号安全。</p>
|
||||
<p>5. 平台保留修改本协议的权利。</p>
|
||||
</div>`,
|
||||
'用户协议',
|
||||
{
|
||||
confirmButtonText: '我已了解',
|
||||
dangerouslyUseHTMLString: true,
|
||||
customClass: 'agreement-dialog'
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 显示隐私政策
|
||||
const showPrivacy = () => {
|
||||
ElMessageBox.alert(
|
||||
`<div style="text-align: left; line-height: 1.6;">
|
||||
<h3>隐私政策</h3>
|
||||
<p>1. 我们重视用户隐私保护。</p>
|
||||
<p>2. 我们只收集必要的用户信息。</p>
|
||||
<p>3. 用户信息仅用于提供服务。</p>
|
||||
<p>4. 我们不会向第三方泄露用户信息。</p>
|
||||
<p>5. 用户有权查看、修改或删除个人信息。</p>
|
||||
</div>`,
|
||||
'隐私政策',
|
||||
{
|
||||
confirmButtonText: '我已了解',
|
||||
dangerouslyUseHTMLString: true,
|
||||
customClass: 'privacy-dialog'
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 图片上传成功处理
|
||||
const handleUploadSuccess = (response, field) => {
|
||||
ElMessage.success('图片上传成功')
|
||||
}
|
||||
|
||||
// 图片上传失败处理
|
||||
const handleUploadError = (error) => {
|
||||
ElMessage.error('图片上传失败,请重试')
|
||||
}
|
||||
|
||||
// 组件挂载时的处理
|
||||
onMounted(() => {
|
||||
// 如果已经登录,直接跳转
|
||||
if (userStore.isAuthenticated) {
|
||||
const redirectPath = route.query.redirect || '/'
|
||||
router.push(redirectPath)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.register-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.register-container {
|
||||
width: 100%;
|
||||
max-width: 450px;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.register-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 16px;
|
||||
padding: 40px 30px;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.register-header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.register-header h2 {
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.register-header p {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.register-button {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.register-footer {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.register-footer p {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.document-upload-section {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.document-upload-section .el-divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.document-upload-section .el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.document-upload-section .el-form-item .el-form-item__label {
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.features-preview {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.features-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.feature-item .el-icon {
|
||||
color: #409eff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.upload-preview {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.upload-preview img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.upload-demo {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.background-decoration {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.decoration-shape {
|
||||
position: absolute;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
animation: float 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.shape-1 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 50%;
|
||||
top: 15%;
|
||||
left: 15%;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.shape-2 {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 20px;
|
||||
top: 70%;
|
||||
right: 20%;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.shape-3 {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
bottom: 25%;
|
||||
left: 25%;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
.shape-4 {
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
border-radius: 20px;
|
||||
top: 40%;
|
||||
right: 10%;
|
||||
animation-delay: 6s;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0px) rotate(0deg);
|
||||
opacity: 0.7;
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-15px) rotate(180deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 480px) {
|
||||
.register-container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.register-card {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
|
||||
.features-list {
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Element Plus 组件样式覆盖 */
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-button) {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-divider__text) {
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
:deep(.el-checkbox__label) {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
/* 输入框聚焦效果 */
|
||||
:deep(.el-input__wrapper:hover),
|
||||
:deep(.el-input__wrapper.is-focus) {
|
||||
box-shadow: 0 0 0 1px #409eff inset;
|
||||
}
|
||||
|
||||
/* 加载状态样式 */
|
||||
.register-button.is-loading {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
.register-card {
|
||||
animation: slideInUp 0.6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 错误状态样式 */
|
||||
:deep(.el-form-item.is-error .el-input__wrapper) {
|
||||
box-shadow: 0 0 0 1px #f56c6c inset;
|
||||
}
|
||||
|
||||
/* 成功状态样式 */
|
||||
:deep(.el-form-item.is-success .el-input__wrapper) {
|
||||
box-shadow: 0 0 0 1px #67c23a inset;
|
||||
}
|
||||
|
||||
/* 协议对话框样式 */
|
||||
:deep(.agreement-dialog),
|
||||
:deep(.privacy-dialog) {
|
||||
.el-message-box__content {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* 密码强度指示器 */
|
||||
.password-strength {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.strength-weak {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.strength-medium {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.strength-strong {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
/* 短信验证码样式 */
|
||||
.sms-code-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sms-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sms-button {
|
||||
flex-shrink: 0;
|
||||
min-width: 120px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.sms-button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user