mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
opt: 将短信发送按钮封装成组件
This commit is contained in:
parent
72cc6f3d75
commit
1fc361242e
@ -89,6 +89,7 @@ func (h *UserHandler) Register(c *gin.Context) {
|
||||
Avatar: "/images/avatar/user.png",
|
||||
Salt: salt,
|
||||
Status: true,
|
||||
Mobile: data.Mobile,
|
||||
ChatRoles: utils.JsonEncode(roleKeys),
|
||||
ChatConfig: utils.JsonEncode(types.ChatConfig{
|
||||
Temperature: h.App.ChatConfig.Temperature,
|
||||
|
68
web/src/components/BindMobile.vue
Normal file
68
web/src/components/BindMobile.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
:title="title"
|
||||
>
|
||||
<div class="form" id="password-form">
|
||||
<el-form :model="form" label-width="120px">
|
||||
<el-form-item label="手机号码">
|
||||
<el-input v-model="form.mobile" type="password"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机验证码">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-input v-model="form.code" type="password"/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<send-msg size="large" v-model:mobile="form.mobile"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="save">
|
||||
提交绑定
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import {checkSession} from "@/action/session";
|
||||
import SendMsg from "@/components/SendMsg.vue";
|
||||
|
||||
const title = ref('绑定手机号')
|
||||
const showDialog = ref(false)
|
||||
const form = ref({
|
||||
mobile: '',
|
||||
code: ''
|
||||
})
|
||||
|
||||
checkSession().then(user => {
|
||||
if (user.mobile === '') {
|
||||
showDialog.value = true
|
||||
}
|
||||
}).catch(e => {
|
||||
console.log(e.message)
|
||||
})
|
||||
|
||||
const save = () => {
|
||||
|
||||
}
|
||||
|
||||
const sendMsg = () => {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
59
web/src/components/SendMsg.vue
Normal file
59
web/src/components/SendMsg.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<el-button type="primary" class="sms-btn" :disabled="!canSend" :size="size" @click="sendMsg" plain>{{
|
||||
btnText
|
||||
}}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 发送短信验证码组件
|
||||
import {ref} from "vue";
|
||||
import {validateMobile} from "@/utils/validate";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
|
||||
const props = defineProps({
|
||||
mobile: String,
|
||||
size: String,
|
||||
});
|
||||
const btnText = ref('发送验证码')
|
||||
const canSend = ref(true)
|
||||
|
||||
const sendMsg = () => {
|
||||
if (!canSend.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!validateMobile(props.mobile)) {
|
||||
return ElMessage.error("请输入合法的手机号")
|
||||
}
|
||||
canSend.value = false
|
||||
httpGet('/api/verify/token').then(res => {
|
||||
httpPost('/api/verify/sms', {token: res.data, mobile: props.mobile}).then(() => {
|
||||
ElMessage.success('短信发送成功')
|
||||
let time = 120
|
||||
btnText.value = time
|
||||
const handler = setInterval(() => {
|
||||
time = time - 1
|
||||
if (time <= 0) {
|
||||
clearInterval(handler)
|
||||
btnText.value = '重新发送'
|
||||
canSend.value = true
|
||||
} else {
|
||||
btnText.value = time
|
||||
}
|
||||
}, 1000)
|
||||
}).catch(e => {
|
||||
canSend.value = true
|
||||
ElMessage.error('短信发送失败:' + e.message)
|
||||
})
|
||||
}).catch(e => {
|
||||
console.log('failed to fetch token: ' + e.message)
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
11
web/src/utils/validate.js
Normal file
11
web/src/utils/validate.js
Normal file
@ -0,0 +1,11 @@
|
||||
// 正则校验工具函数
|
||||
|
||||
export function validateEmail(email) {
|
||||
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return regex.test(email);
|
||||
}
|
||||
|
||||
export function validateMobile(mobile) {
|
||||
const regex = /^1[345789]\d{9}$/;
|
||||
return regex.test(mobile);
|
||||
}
|
@ -187,6 +187,8 @@
|
||||
@update-user="updateUser"/>
|
||||
<password-dialog v-if="isLogin" :show="showPasswordDialog" @hide="showPasswordDialog = false"
|
||||
@logout="logout"/>
|
||||
|
||||
<bind-mobile/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -219,6 +221,7 @@ import Clipboard from "clipboard";
|
||||
import ConfigDialog from "@/components/ConfigDialog.vue";
|
||||
import PasswordDialog from "@/components/PasswordDialog.vue";
|
||||
import {checkSession} from "@/action/session";
|
||||
import BindMobile from "@/components/BindMobile.vue";
|
||||
|
||||
const title = ref('ChatGPT-智能助手');
|
||||
const logo = 'images/logo.png';
|
||||
|
@ -76,10 +76,7 @@
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary" class="sms-btn" :disabled="!canSend" size="large" @click="sendMsg" plain>{{
|
||||
btnText
|
||||
}}
|
||||
</el-button>
|
||||
<send-msg size="large" :mobile="formData.mobile"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
@ -107,14 +104,14 @@
|
||||
|
||||
import {ref} from "vue";
|
||||
import {Checked, Iphone, Lock, UserFilled} from "@element-plus/icons-vue";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import {httpPost} from "@/utils/http";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {useRouter} from "vue-router";
|
||||
import FooterBar from "@/components/FooterBar.vue";
|
||||
import SendMsg from "@/components/SendMsg.vue";
|
||||
|
||||
const router = useRouter();
|
||||
const title = ref('ChatGPT-PLUS 用户注册');
|
||||
const btnText = ref('发送验证码')
|
||||
const formData = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
@ -142,50 +139,6 @@ const register = function () {
|
||||
})
|
||||
}
|
||||
|
||||
// const validateEmail = function (email) {
|
||||
// const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
// return regex.test(email);
|
||||
// }
|
||||
const validateMobile = function (mobile) {
|
||||
const regex = /^1[345789]\d{9}$/;
|
||||
return regex.test(mobile);
|
||||
}
|
||||
|
||||
const canSend = ref(true)
|
||||
const sendMsg = () => {
|
||||
if (!canSend.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!validateMobile(formData.value.mobile)) {
|
||||
return ElMessage.error("请输入合法的手机号")
|
||||
}
|
||||
canSend.value = false
|
||||
httpGet('/api/verify/token').then(res => {
|
||||
httpPost('/api/verify/sms', {token: res.data, mobile: formData.value.mobile}).then(() => {
|
||||
ElMessage.success('短信发送成功')
|
||||
let time = 120
|
||||
btnText.value = time
|
||||
const handler = setInterval(() => {
|
||||
time = time - 1
|
||||
if (time <= 0) {
|
||||
clearInterval(handler)
|
||||
btnText.value = '重新发送'
|
||||
canSend.value = true
|
||||
} else {
|
||||
btnText.value = time
|
||||
}
|
||||
}, 1000)
|
||||
}).catch(e => {
|
||||
canSend.value = true
|
||||
ElMessage.error('短信发送失败:' + e.message)
|
||||
})
|
||||
}).catch(e => {
|
||||
console.log('failed to fetch token: ' + e.message)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
@ -1,165 +1,14 @@
|
||||
<template>
|
||||
<div class="role-list">
|
||||
|
||||
|
||||
<el-form :model="form1" label-width="120px" ref="formRef" :rules="rules">
|
||||
<el-form-item label="角色名称:" prop="name">
|
||||
<el-input
|
||||
v-model="form1.name"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色标志:" prop="key">
|
||||
<el-input
|
||||
v-model="form1.key"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色图标:" prop="icon">
|
||||
<el-input
|
||||
v-model="form1.icon"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="打招呼信息:" prop="hello_msg">
|
||||
<el-input
|
||||
v-model="form1.hello_msg"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="上下文信息:" prop="context">
|
||||
<template #default>
|
||||
<el-table :data="form1.context" :border="childBorder" size="small">
|
||||
<el-table-column label="对话角色" width="120">
|
||||
<template #default="scope">
|
||||
<el-input
|
||||
v-model="scope.row.role"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="对话内容">
|
||||
<template #header>
|
||||
<div class="context-msg-key">
|
||||
<span>对话内容</span>
|
||||
<span class="fr">
|
||||
<el-button type="primary" @click="addContext" size="small">
|
||||
<el-icon>
|
||||
<Plus/>
|
||||
</el-icon>
|
||||
增加一行
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #default="scope">
|
||||
<div class="context-msg-content">
|
||||
<el-input
|
||||
v-model="scope.row.content"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<span><el-icon @click="removeContext(scope.$index)"><RemoveFilled/></el-icon></span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="启用状态">
|
||||
<el-switch v-model="form1.enable"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="doUpdate">保存</el-button>
|
||||
</span>
|
||||
</div>
|
||||
<div>{{ title }}</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import {Plus, RemoveFilled} from "@element-plus/icons-vue";
|
||||
import {reactive, ref} from "vue";
|
||||
import {httpPost} from "@/utils/http";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {ref} from "vue";
|
||||
|
||||
const showDialog = ref(false)
|
||||
const childBorder = ref(true)
|
||||
const form1 = ref({context: []})
|
||||
// const form2 = ref({context: []})
|
||||
const formRef = ref(null)
|
||||
|
||||
const rules = reactive({
|
||||
name: [{required: true, message: '请输入用户名', trigger: 'change',}],
|
||||
key: [{required: true, message: '请输入角色标识', trigger: 'change',}],
|
||||
icon: [{required: true, message: '请输入角色图标', trigger: 'change',}],
|
||||
hello_msg: [{required: true, message: '请输入打招呼信息', trigger: 'change',}]
|
||||
})
|
||||
|
||||
|
||||
// 编辑
|
||||
const doUpdate = function () {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
showDialog.value = false
|
||||
httpPost('/api/admin/chat-roles/set', form1.value).then(() => {
|
||||
ElMessage.success('更新角色成功')
|
||||
// 更新当前数据行
|
||||
}).catch((e) => {
|
||||
ElMessage.error('更新角色失败,' + e.message)
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const addContext = function () {
|
||||
form1.value.context.push({role: '', content: ''})
|
||||
}
|
||||
|
||||
const removeContext = function (index) {
|
||||
form1.value.context.splice(index, 1);
|
||||
}
|
||||
const title = ref('Test Page')
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.role-list {
|
||||
.opt-box {
|
||||
padding-bottom: 10px;
|
||||
|
||||
.el-icon {
|
||||
margin-right 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.context-msg-key {
|
||||
.fr {
|
||||
float right
|
||||
|
||||
.el-icon {
|
||||
margin-right 5px
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.context-msg-content {
|
||||
display flex
|
||||
|
||||
.el-icon {
|
||||
font-size: 20px;
|
||||
margin-top 5px;
|
||||
margin-left 5px;
|
||||
cursor pointer
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user