feat(.): Achieve the sms code send
This commit is contained in:
parent
d834378c1c
commit
8a04c4e72e
@ -1,24 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<client-only>
|
<client-only>
|
||||||
<el-menu
|
<el-menu
|
||||||
:default-active="activeIndex"
|
:default-active="activeIndex"
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
:ellipsis="false"
|
:ellipsis="false"
|
||||||
@select="handleSelect"
|
@select="handleSelect"
|
||||||
>
|
>
|
||||||
<el-menu-item index="/">
|
<el-menu-item index="/">
|
||||||
<img
|
<img style="width: 50px" src="/logo.svg" alt="Element logo" />
|
||||||
style="width: 50px;"
|
</el-menu-item>
|
||||||
src="/logo.svg"
|
<el-menu-item index="/apply">立即申请</el-menu-item>
|
||||||
alt="Element logo"
|
<el-menu-item index="/about" disabled>关于我们</el-menu-item>
|
||||||
/>
|
<el-menu-item index="/status" disabled>设备监控</el-menu-item>
|
||||||
</el-menu-item>
|
<el-sub-menu index="/area" disabled>
|
||||||
<el-menu-item index="/apply">立即申请</el-menu-item>
|
|
||||||
<el-menu-item index="/about">关于我们</el-menu-item>
|
|
||||||
<el-menu-item index="/status" disabled>设备监控</el-menu-item>
|
|
||||||
<el-sub-menu index="/area" disabled>
|
|
||||||
<template #title>区域服务</template>
|
<template #title>区域服务</template>
|
||||||
<!-- <el-menu-item index="/area/ln1">辽宁一区</el-menu-item>
|
<!-- <el-menu-item index="/area/ln1">辽宁一区</el-menu-item>
|
||||||
<el-menu-item index="/area/ln2">辽宁二区</el-menu-item>
|
<el-menu-item index="/area/ln2">辽宁二区</el-menu-item>
|
||||||
<el-menu-item index="/area/jx1">江西一区</el-menu-item>
|
<el-menu-item index="/area/jx1">江西一区</el-menu-item>
|
||||||
<el-sub-menu index="/area/jx2">
|
<el-sub-menu index="/area/jx2">
|
||||||
@ -27,27 +23,25 @@
|
|||||||
<el-menu-item index="/area/jx2/web">网页服务器</el-menu-item>
|
<el-menu-item index="/area/jx2/web">网页服务器</el-menu-item>
|
||||||
<el-menu-item index="/area/jx2/game">游戏服务器</el-menu-item>
|
<el-menu-item index="/area/jx2/game">游戏服务器</el-menu-item>
|
||||||
</el-sub-menu> -->
|
</el-sub-menu> -->
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-menu-item index="/forum" disabled>论坛</el-menu-item>
|
<el-menu-item index="/forum" disabled>论坛</el-menu-item>
|
||||||
<el-menu-item index="/host" disabled>托管</el-menu-item>
|
<el-menu-item index="/host" disabled>托管</el-menu-item>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<el-menu-item index="/login">登录</el-menu-item>
|
<el-menu-item index="/login">登录</el-menu-item>
|
||||||
<el-menu-item index="register">注册</el-menu-item>
|
<el-menu-item index="register">注册</el-menu-item>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</client-only>
|
</client-only>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
const activeIndex = ref("1");
|
||||||
const activeIndex = ref('1')
|
|
||||||
const handleSelect = (key: string, keyPath: string[]) => {
|
const handleSelect = (key: string, keyPath: string[]) => {
|
||||||
console.log(key, keyPath)
|
console.log(key, keyPath);
|
||||||
navigateTo(key)
|
navigateTo(key);
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
modules: [
|
runtimeConfig: {
|
||||||
"@element-plus/nuxt",
|
apiSecret: "",
|
||||||
'@vueform/nuxt'
|
apiOpenid: "",
|
||||||
],
|
apiApikey: "",
|
||||||
})
|
apiSmsId: 0,
|
||||||
|
},
|
||||||
|
modules: ["@element-plus/nuxt", "@vueform/nuxt"],
|
||||||
|
});
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"element-plus": "^2.7.4",
|
"element-plus": "^2.7.4",
|
||||||
"nuxt": "^3.11.2",
|
"nuxt": "^3.11.2",
|
||||||
"prisma": "^5.15.0",
|
"prisma": "^5.15.0",
|
||||||
|
"quanmsms": "^1.0.2",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"vue": "^3.4.27",
|
"vue": "^3.4.27",
|
||||||
"vue-router": "^4.3.2"
|
"vue-router": "^4.3.2"
|
||||||
|
78
pages/admin/index.vue
Normal file
78
pages/admin/index.vue
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<Head>
|
||||||
|
<Title>管理界面</Title>
|
||||||
|
<Meta name="description" />
|
||||||
|
</Head>
|
||||||
|
<client-only>
|
||||||
|
<el-table :data="tableData" style="width: 100%">
|
||||||
|
<el-table-column prop="appid" label="AppID" width="180" />
|
||||||
|
<el-table-column prop="name" label="申请人" width="180" />
|
||||||
|
<el-table-column prop="phone" label="手机号" width="180" />
|
||||||
|
<el-table-column label="配置" width="300">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-icon color="blue"><ElIcon-Cpu /></el-icon>
|
||||||
|
{{ scope.row.resource.cpu }} Core
|
||||||
|
<el-icon color="green"><ElIcon-Stopwatch /></el-icon
|
||||||
|
>{{ scope.row.resource.ram }} GB
|
||||||
|
<el-icon color="gray"><ElIcon-Memo /></el-icon>
|
||||||
|
{{ scope.row.resource.disk }} GB
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="usage" label="用途" width="360" />
|
||||||
|
<el-table-column label="状态" width="300">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-icon :color="scope.row.apply ? 'green' : 'orange'"
|
||||||
|
><ElIcon-Stamp
|
||||||
|
/></el-icon>
|
||||||
|
{{ scope.row.apply ? "通过" : "待审核" }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
type="success"
|
||||||
|
@click="ElMessage({ message: '同意', type: 'success' })"
|
||||||
|
>
|
||||||
|
同意
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
type="danger"
|
||||||
|
@click="ElMessage({ message: '拒绝', type: 'warning' })"
|
||||||
|
>
|
||||||
|
拒绝
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</client-only>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
const tableData = [
|
||||||
|
{
|
||||||
|
appid: "1",
|
||||||
|
name: "漩葵",
|
||||||
|
phone: 1922949224,
|
||||||
|
usage: "用于开展服务",
|
||||||
|
resource: {
|
||||||
|
cpu: 1,
|
||||||
|
ram: 2,
|
||||||
|
disk: 10,
|
||||||
|
},
|
||||||
|
apply: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
appid: "2",
|
||||||
|
name: "BrianLing",
|
||||||
|
phone: 1922949224,
|
||||||
|
usage: "用于开展服务",
|
||||||
|
resource: {
|
||||||
|
cpu: 1,
|
||||||
|
ram: 2,
|
||||||
|
disk: 10,
|
||||||
|
},
|
||||||
|
apply: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
@ -1,76 +1,123 @@
|
|||||||
<template>
|
<template>
|
||||||
<!--立即申请页面-->
|
<!--立即申请页面-->
|
||||||
<Head>
|
<Head>
|
||||||
<Title>立即申请</Title>
|
<Title>立即申请</Title>
|
||||||
<Meta name="description"/>
|
<Meta name="description" />
|
||||||
</Head>
|
</Head>
|
||||||
<div style="width:50%;margin:auto;" :style="{
|
<div
|
||||||
boxShadow: `var(--el-box-shadow-light)`,
|
style="width: 50%; margin: auto"
|
||||||
}">
|
:style="{
|
||||||
<ClientOnly >
|
boxShadow: `var(--el-box-shadow-light)`,
|
||||||
<Vueform endpoint="/api/test" method="POST" view="tabs" style="padding:30px" >
|
}"
|
||||||
<StaticElement tag="h4" align="center" content="个人信息" name="static" />
|
>
|
||||||
<TextElement name="username" label="昵称" placeholder="昵称" :columns="{ container: 4, label: 3, wrapper: 12 }" rules="required|min:3"/>
|
<ClientOnly>
|
||||||
<PhoneElement name="phone" allow-incomplete unmask default="+86" :include="['cn']" label="手机号" placeholder="+86" :columns="{ container: 12, label: 1, wrapper: 4 }" rules="required"/>
|
<Vueform
|
||||||
<TextElement name="code" label="验证码" placeholder="xxxxxx" :columns="{ container: 4, label: 3, wrapper: 12 }" rules="required"/>
|
endpoint="/api/test"
|
||||||
<ButtonElement name="button" :columns="{ container: 8, label: 3, wrapper: 12 }" button-label="发送验证码"/>
|
method="POST"
|
||||||
<StaticElement tag="h4" align="center" content="项目详情" name="static" />
|
view="tabs"
|
||||||
<TextElement name="name" label="项目名称" placeholder="项目名称" :columns="{ container: 4, label: 4, wrapper: 12 }" rules="required"/>
|
style="padding: 30px"
|
||||||
<SelectElement
|
>
|
||||||
name="select"
|
<StaticElement
|
||||||
default="辽宁一区"
|
tag="h4"
|
||||||
label="地区"
|
align="center"
|
||||||
:native="false"
|
content="个人信息"
|
||||||
:items="[
|
name="static"
|
||||||
'辽宁一区',
|
/>
|
||||||
'辽宁二区',
|
<TextElement
|
||||||
'江西一区',
|
name="username"
|
||||||
]"
|
label="昵称"
|
||||||
:columns="{ container: 4, label: 3, wrapper: 12 }"
|
placeholder="昵称"
|
||||||
rules="required"
|
:columns="{ container: 4, label: 3, wrapper: 12 }"
|
||||||
/>
|
rules="required|min:3"
|
||||||
<RadiogroupElement
|
/>
|
||||||
default="2 Core"
|
<PhoneElement
|
||||||
label="CPU核心数"
|
name="phone"
|
||||||
name="cpu"
|
allow-incomplete
|
||||||
:items="['2 Core', '4 Core', '6 Core','More']"
|
unmask
|
||||||
view="tabs"
|
default="+86"
|
||||||
/>
|
:include="['cn']"
|
||||||
<RadiogroupElement
|
label="手机号"
|
||||||
|
placeholder="+86"
|
||||||
|
:columns="{ container: 12, label: 1, wrapper: 4 }"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="code"
|
||||||
|
label="验证码"
|
||||||
|
placeholder="xxxxxx"
|
||||||
|
:columns="{ container: 4, label: 4, wrapper: 12 }"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<ButtonElement
|
||||||
|
name="button"
|
||||||
|
:columns="{ container: 8, label: 3, wrapper: 12 }"
|
||||||
|
button-label="发送验证码"
|
||||||
|
/>
|
||||||
|
<StaticElement
|
||||||
|
tag="h4"
|
||||||
|
align="center"
|
||||||
|
content="项目详情"
|
||||||
|
name="static"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="name"
|
||||||
|
label="项目名称"
|
||||||
|
placeholder="项目名称"
|
||||||
|
:columns="{ container: 4, label: 4, wrapper: 12 }"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<SelectElement
|
||||||
|
name="select"
|
||||||
|
default="辽宁一区"
|
||||||
|
label="地区"
|
||||||
|
:native="false"
|
||||||
|
:items="['辽宁一区', '辽宁二区', '江西一区']"
|
||||||
|
:columns="{ container: 4, label: 3, wrapper: 12 }"
|
||||||
|
rules="required"
|
||||||
|
/>
|
||||||
|
<RadiogroupElement
|
||||||
|
default="2 Core"
|
||||||
|
label="CPU核心数"
|
||||||
|
name="cpu"
|
||||||
|
:items="['2 Core', '4 Core', '6 Core', 'More']"
|
||||||
|
view="tabs"
|
||||||
|
/>
|
||||||
|
<RadiogroupElement
|
||||||
default="2 GB"
|
default="2 GB"
|
||||||
label="RAM容量"
|
label="RAM容量"
|
||||||
name="ram"
|
name="ram"
|
||||||
:items="['2 GB', '4 GB', '6 GB','More']"
|
:items="['2 GB', '4 GB', '6 GB', 'More']"
|
||||||
view="tabs"
|
view="tabs"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SliderElement
|
<SliderElement
|
||||||
name="disk"
|
name="disk"
|
||||||
label="磁盘容量"
|
label="磁盘容量"
|
||||||
:default="5"
|
:default="5"
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="40"
|
:max="40"
|
||||||
:format="(v: number) => v > 1 ? `${Math.round(v)} GB` : '1 GB'"
|
:format="(v: number) => v > 1 ? `${Math.round(v)} GB` : '1 GB'"
|
||||||
:add-classes="{
|
:add-classes="{
|
||||||
ElementLayout: {
|
ElementLayout: {
|
||||||
innerWrapper: 'mt-12'
|
innerWrapper: 'mt-12',
|
||||||
}
|
},
|
||||||
}"
|
}"
|
||||||
/>
|
|
||||||
|
|
||||||
<EditorElement
|
|
||||||
name="usage"
|
|
||||||
label="用途说明"
|
|
||||||
rules="required|max:500"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ButtonElement name="submit" button-label="提交申请" align="center" size="lg" submits/>
|
<EditorElement name="usage" label="用途说明" rules="required|max:500" />
|
||||||
</Vueform>
|
|
||||||
</ClientOnly>
|
<ButtonElement
|
||||||
|
name="submit"
|
||||||
</div>
|
button-label="提交申请"
|
||||||
|
align="center"
|
||||||
|
size="lg"
|
||||||
|
submits
|
||||||
|
/>
|
||||||
|
</Vueform>
|
||||||
|
</ClientOnly>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import PhoneElemen from '@vueform/vueform'
|
import PhoneElemen from "@vueform/vueform";
|
||||||
const form = ref()
|
const form = ref();
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,15 +1,63 @@
|
|||||||
<template>
|
<template>
|
||||||
<!--登录界面-->
|
<!--登录界面-->
|
||||||
<Head>
|
<Head>
|
||||||
<Title>登录界面</Title>
|
<Title>登录界面</Title>
|
||||||
<Meta name="description"/>
|
<Meta name="description" />
|
||||||
</Head>
|
</Head>
|
||||||
<div>
|
<div
|
||||||
<el-text class="mx-1" type="primary" >
|
style="width: 25%; margin: auto"
|
||||||
Primary
|
:style="{
|
||||||
</el-text>
|
boxShadow: `var(--el-box-shadow-light)`,
|
||||||
</div>
|
}"
|
||||||
|
>
|
||||||
|
<ClientOnly>
|
||||||
|
<Vueform
|
||||||
|
endpoint="/api/test"
|
||||||
|
method="POST"
|
||||||
|
view="tabs"
|
||||||
|
style="padding: 30px"
|
||||||
|
>
|
||||||
|
<StaticElement tag="h4" align="center" content="登录" name="static" />
|
||||||
|
<PhoneElement
|
||||||
|
input-type="number"
|
||||||
|
name="phone"
|
||||||
|
allow-incomplete
|
||||||
|
unmask
|
||||||
|
default="+86"
|
||||||
|
:include="['cn']"
|
||||||
|
label="手机号"
|
||||||
|
placeholder="+86"
|
||||||
|
:columns="{ container: 12, label: 3, wrapper: 10 }"
|
||||||
|
rules="required|min:14|max:14"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
input-type="password"
|
||||||
|
name="password"
|
||||||
|
label="密码"
|
||||||
|
rules="required|min:8|max:16|confirmed"
|
||||||
|
:columns="{ container: 12, label: 3, wrapper: 10 }"
|
||||||
|
/>
|
||||||
|
<CheckboxElement
|
||||||
|
name="policy"
|
||||||
|
label="用户协议"
|
||||||
|
rules="required"
|
||||||
|
message="您必须同意用户政策才能继续"
|
||||||
|
>
|
||||||
|
已阅读并同意<ElLink href="/" target="_blank">《用户协议》</ElLink>
|
||||||
|
</CheckboxElement>
|
||||||
|
<CheckboxElement name="news"> 希望获取最新资讯 </CheckboxElement>
|
||||||
|
<ButtonElement
|
||||||
|
name="submit"
|
||||||
|
button-label="登录"
|
||||||
|
align="center"
|
||||||
|
size="lg"
|
||||||
|
submits
|
||||||
|
/>
|
||||||
|
</Vueform>
|
||||||
|
</ClientOnly>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import PhoneElemen from "@vueform/vueform";
|
||||||
</script>
|
const form = ref();
|
||||||
|
</script>
|
||||||
|
@ -1,34 +1,211 @@
|
|||||||
<template>
|
<template>
|
||||||
<!--注册页面-->
|
<!--注册页面-->
|
||||||
<Head>
|
<Head>
|
||||||
<Title>注册页面</Title>
|
<Title>注册页面</Title>
|
||||||
<Meta name="description"/>
|
<Meta name="description" />
|
||||||
</Head>
|
</Head>
|
||||||
<div style="width:50%;margin:auto;" :style="{
|
<div
|
||||||
boxShadow: `var(--el-box-shadow-light)`,
|
style="width: 25%; margin: auto"
|
||||||
}">
|
:style="{
|
||||||
<ClientOnly >
|
boxShadow: `var(--el-box-shadow-light)`,
|
||||||
<Vueform endpoint="/api/test" method="POST" view="tabs" style="padding:30px" >
|
}"
|
||||||
<StaticElement tag="h4" align="center" content="个人信息" name="static" />
|
>
|
||||||
<TextElement name="username" allow-incomplete label="昵称" placeholder="昵称" :columns="{ container: 4, label: 3, wrapper: 8 }" rules="required|min:3|max:64"/>
|
<ClientOnly>
|
||||||
<PhoneElement input-type="number" name="phone" allow-incomplete unmask default="+86" :include="['cn']" label="手机号" placeholder="+86" :columns="{ container: 12, label: 1, wrapper: 4 }" rules="required|max:6|min:6"/>
|
<Vueform
|
||||||
<TextElement name="code" label="验证码" placeholder="xxxxxx" :columns="{ container: 4, label: 3, wrapper: 12 }" rules="required"/>
|
endpoint="/api/test"
|
||||||
<ButtonElement name="button" :columns="{ container: 8, label: 3, wrapper: 12 }" button-label="发送验证码"/>
|
method="POST"
|
||||||
<TextElement input-type="password" name="password" label="密码" rules="required|min:8|max:16|confirmed"/>
|
view="tabs"
|
||||||
<TextElement input-type="password" name="password_confirmation" label="确认密码" rules="required|min:8|max:16"/>
|
:model-value="form"
|
||||||
<CheckboxElement name="policy" label="用户协议" rules="required" message="您必须同意用户政策才能继续">
|
@update:model-value="form = $event"
|
||||||
已阅读并同意<ElLink href="/" target="_blank">《用户协议》</ElLink>
|
validate-on="change"
|
||||||
</CheckboxElement>
|
style="padding: 30px"
|
||||||
<CheckboxElement name="news">
|
>
|
||||||
希望获取最新资讯
|
<StaticElement tag="h4" align="center" content="注册" name="static" />
|
||||||
</CheckboxElement>
|
<TextElement
|
||||||
<ButtonElement name="submit" button-label="提交申请" align="center" size="lg" submits/>
|
ref="username$"
|
||||||
</Vueform>
|
name="username"
|
||||||
</ClientOnly>
|
allow-incomplete
|
||||||
|
label="昵称"
|
||||||
</div>
|
placeholder="昵称"
|
||||||
</template>
|
:columns="{ container: 12, label: 3, wrapper: 8 }"
|
||||||
<script setup lang="ts">
|
rules="required|min:3|max:64"
|
||||||
import PhoneElemen from '@vueform/vueform'
|
@blur="Check()"
|
||||||
const form = ref()
|
/>
|
||||||
</script>
|
<PhoneElement
|
||||||
|
ref="phone$"
|
||||||
|
input-type="number"
|
||||||
|
name="phone"
|
||||||
|
allow-incomplete
|
||||||
|
unmask
|
||||||
|
default="+86"
|
||||||
|
:include="['cn']"
|
||||||
|
label="手机号"
|
||||||
|
placeholder="+86"
|
||||||
|
:columns="{ container: 12, label: 3, wrapper: 10 }"
|
||||||
|
rules="required|min:14|max:14"
|
||||||
|
@blur="Check()"
|
||||||
|
:disabled="phoneChecked"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
name="code"
|
||||||
|
label="验证码"
|
||||||
|
placeholder="xxxxxx"
|
||||||
|
rules="required|max:6|min:6"
|
||||||
|
:columns="{ container: 8, label: 5, wrapper: 12 }"
|
||||||
|
@blur="CheckCode()"
|
||||||
|
:disabled="!codeBtnRef.disabled || phoneChecked"
|
||||||
|
ref="code$"
|
||||||
|
/>
|
||||||
|
<ButtonElement
|
||||||
|
name="button"
|
||||||
|
:columns="{ container: 4, label: 3, wrapper: 12 }"
|
||||||
|
@click="Send()"
|
||||||
|
:button-label="codeBtnRef.text"
|
||||||
|
:disabled="codeBtnRef.disabled || phoneChecked"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
input-type="password"
|
||||||
|
name="password"
|
||||||
|
label="密码"
|
||||||
|
rules="required|min:8|max:16|confirmed"
|
||||||
|
:columns="{ container: 12, label: 3, wrapper: 10 }"
|
||||||
|
/>
|
||||||
|
<TextElement
|
||||||
|
input-type="password"
|
||||||
|
name="password_confirmation"
|
||||||
|
label="确认密码"
|
||||||
|
rules="required|min:8|max:16"
|
||||||
|
:columns="{ container: 12, label: 3, wrapper: 10 }"
|
||||||
|
/>
|
||||||
|
<CheckboxElement
|
||||||
|
name="policy"
|
||||||
|
label="用户协议"
|
||||||
|
rules="required"
|
||||||
|
message="您必须同意用户政策才能继续"
|
||||||
|
>
|
||||||
|
已阅读并同意<ElLink href="/" target="_blank">《用户协议》</ElLink>
|
||||||
|
</CheckboxElement>
|
||||||
|
<CheckboxElement name="news"> 希望获取最新资讯 </CheckboxElement>
|
||||||
|
<ButtonElement
|
||||||
|
:disabled="canSubmit"
|
||||||
|
name="submit"
|
||||||
|
button-label="注册"
|
||||||
|
align="center"
|
||||||
|
size="lg"
|
||||||
|
submits
|
||||||
|
/><ButtonElement
|
||||||
|
name="reset"
|
||||||
|
danger
|
||||||
|
button-label="重置"
|
||||||
|
resets
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</Vueform>
|
||||||
|
</ClientOnly>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import PhoneElemen from "@vueform/vueform";
|
||||||
|
const form = ref({});
|
||||||
|
const phoneChecked = ref(false);
|
||||||
|
const codeBtnRef = ref({ text: "发送验证码", color: "", disabled: false });
|
||||||
|
const username$ = ref(null);
|
||||||
|
const phone$ = ref(null);
|
||||||
|
const code$ = ref(null);
|
||||||
|
const canSubmit = ref(false);
|
||||||
|
function Check() {
|
||||||
|
const query = {
|
||||||
|
username: form.value.username,
|
||||||
|
phone: form.value.phone.replace("+86", ""),
|
||||||
|
};
|
||||||
|
if (!/^(?!1(4|7)\d{9})1[3-9]\d{9}$/.test(query.phone)) {
|
||||||
|
phone$.value.messageBag.clear("errors");
|
||||||
|
phone$.value.messageBag.append("手机号格式错误" + query.phone);
|
||||||
|
canSubmit.value = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
phone$.value.messageBag = [];
|
||||||
|
}
|
||||||
|
$fetch("/api/test/reg", {
|
||||||
|
method: "POST",
|
||||||
|
body: query,
|
||||||
|
}).then((res) => {
|
||||||
|
if (!res.phone) {
|
||||||
|
phone$.value.messageBag.append("手机号已经注册");
|
||||||
|
canSubmit.value = true;
|
||||||
|
} else {
|
||||||
|
canSubmit.value = false;
|
||||||
|
}
|
||||||
|
if (!res.username) {
|
||||||
|
username$.value.messageBag.append("昵称已存在");
|
||||||
|
canSubmit.value = true;
|
||||||
|
} else {
|
||||||
|
canSubmit.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function Send() {
|
||||||
|
Check();
|
||||||
|
if (!canSubmit.value) {
|
||||||
|
$fetch("/api/test/sms", {
|
||||||
|
method: "POST",
|
||||||
|
body: {
|
||||||
|
phone: form.value.phone.replace("+86", ""),
|
||||||
|
},
|
||||||
|
}).then((res) => {
|
||||||
|
switch (res.code) {
|
||||||
|
case 0:
|
||||||
|
ElMessage({ message: res.msg + "\n" + res.error, type: "error" });
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ElMessage({ message: res.msg, type: "success" });
|
||||||
|
codeBtnRef.value.disabled = true;
|
||||||
|
codeBtnRef.value.text = "请查收";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ElMessage({ message: res.msg, type: "warning" });
|
||||||
|
codeBtnRef.value.disabled = true;
|
||||||
|
codeBtnRef.value.text = "请查收";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.info(form.value.phone.replace("+86", ""));
|
||||||
|
}
|
||||||
|
function CheckCode() {
|
||||||
|
if (!code$.value.invalid) {
|
||||||
|
$fetch("/api/test/code", {
|
||||||
|
method: "POST",
|
||||||
|
body: {
|
||||||
|
phone: form.value.phone.replace("+86", ""),
|
||||||
|
code: form.value.code,
|
||||||
|
},
|
||||||
|
}).then((res) => {
|
||||||
|
switch (res.code) {
|
||||||
|
case 0:
|
||||||
|
ElMessage({
|
||||||
|
message: res.msg,
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ElMessage({ message: res.msg, type: "success" });
|
||||||
|
codeBtnRef.value.disabled = true;
|
||||||
|
codeBtnRef.value.text = "已验证";
|
||||||
|
phoneChecked.value = ture;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ElMessage({ message: res.msg, type: "warning" });
|
||||||
|
codeBtnRef.value.disabled = false;
|
||||||
|
codeBtnRef.value.text = "发送验证码";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ElMessage({ message: res.msg, type: "warning" });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
6
pages/user/index.vue
Normal file
6
pages/user/index.vue
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<template>
|
||||||
|
<Head>
|
||||||
|
<Title>用户信息</Title>
|
||||||
|
<Meta name="description" />
|
||||||
|
</Head>
|
||||||
|
</template>
|
@ -18,6 +18,11 @@ model User {
|
|||||||
applications Application[]
|
applications Application[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Adminer {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
adminId Int
|
||||||
|
}
|
||||||
|
|
||||||
model Application {
|
model Application {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String
|
name String
|
||||||
@ -30,3 +35,9 @@ model Application {
|
|||||||
applicant User @relation(fields: [applicantId], references: [id])
|
applicant User @relation(fields: [applicantId], references: [id])
|
||||||
applicantId Int
|
applicantId Int
|
||||||
}
|
}
|
||||||
|
model Register {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
phone String
|
||||||
|
deadline DateTime
|
||||||
|
code String
|
||||||
|
}
|
27
server/api/test/code.ts
Normal file
27
server/api/test/code.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
const db = new PrismaClient();
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody(event);
|
||||||
|
const register = (await db.register.findFirst({
|
||||||
|
where: {
|
||||||
|
phone: body.phone,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
deadline: "desc", // 'asc' 表示升序,'desc' 表示降序
|
||||||
|
},
|
||||||
|
})) || {
|
||||||
|
deadline: new Date(),
|
||||||
|
};
|
||||||
|
const deadlineDate = new Date(register.deadline);
|
||||||
|
const now = new Date();
|
||||||
|
if (now > deadlineDate) {
|
||||||
|
return { code: 2, msg: "验证码超时了,请重新发送" };
|
||||||
|
} else if (register.code != body.code) {
|
||||||
|
console.log(body.code + " phone " + register.phone + " " + register.code);
|
||||||
|
return { code: 0, msg: "验证码错误" };
|
||||||
|
} else if (register.code == body.code) {
|
||||||
|
return { code: 1, msg: "验证码正确" };
|
||||||
|
} else {
|
||||||
|
return { code: -1, msg: "未知错误" };
|
||||||
|
}
|
||||||
|
});
|
@ -1,9 +1,38 @@
|
|||||||
import { PrismaClient } from "@prisma/client"
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
|
||||||
const db = new PrismaClient()
|
const db = new PrismaClient();
|
||||||
|
|
||||||
export default defineEventHandler(async(event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const body = await readBody(event)
|
const body = await readBody(event);
|
||||||
console.info(body)
|
console.info(body);
|
||||||
return body
|
let isSend =
|
||||||
})
|
(await db.register.findFirst({
|
||||||
|
where: {
|
||||||
|
phone: body.phone,
|
||||||
|
},
|
||||||
|
})) != null;
|
||||||
|
if (isSend) {
|
||||||
|
const register = (await db.register.findFirst({
|
||||||
|
where: {
|
||||||
|
phone: body.phone,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
deadline: "desc", // 'asc' 表示升序,'desc' 表示降序
|
||||||
|
},
|
||||||
|
})) || {
|
||||||
|
deadline: new Date(),
|
||||||
|
};
|
||||||
|
const deadlineDate = new Date(register.deadline);
|
||||||
|
const now = new Date();
|
||||||
|
if (now <= deadlineDate) {
|
||||||
|
return { code: 2, msg: "三分钟内请勿重发送" };
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
code: -1,
|
||||||
|
msg:
|
||||||
|
"发送成功" + now + "<=" + deadlineDate + ":" + (now <= deadlineDate),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isSend;
|
||||||
|
});
|
||||||
|
19
server/api/test/reg.ts
Normal file
19
server/api/test/reg.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
const db = new PrismaClient();
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody(event);
|
||||||
|
return {
|
||||||
|
username:
|
||||||
|
(await db.user.findFirst({
|
||||||
|
where: {
|
||||||
|
username: body.username,
|
||||||
|
},
|
||||||
|
})) == null,
|
||||||
|
phone:
|
||||||
|
(await db.user.findFirst({
|
||||||
|
where: {
|
||||||
|
phone: body.phone,
|
||||||
|
},
|
||||||
|
})) == null,
|
||||||
|
};
|
||||||
|
});
|
93
server/api/test/sms.ts
Normal file
93
server/api/test/sms.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
import qmAPI from "quanmsms";
|
||||||
|
|
||||||
|
const config = useRuntimeConfig();
|
||||||
|
const smsApi = new qmAPI(config.apiOpenid.toString(), {
|
||||||
|
sms: {
|
||||||
|
apiKey: config.apiApikey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const db = new PrismaClient();
|
||||||
|
function generateRandomCode(length: number) {
|
||||||
|
let code = "";
|
||||||
|
//const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';复杂验证码
|
||||||
|
const possible = "0123456789";
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
code += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
function generateDeadline() {
|
||||||
|
const now = new Date(); // 获取当前时间
|
||||||
|
const threeMinutesLater = new Date(now.getTime() + 3.5 * 60 * 1000); // 加上3分钟
|
||||||
|
return threeMinutesLater.toISOString(); // 转换为ISO格式字符串
|
||||||
|
}
|
||||||
|
|
||||||
|
function send(telstr: string) {
|
||||||
|
let tel = parseInt(telstr);
|
||||||
|
const code = generateRandomCode(6);
|
||||||
|
let param = {
|
||||||
|
tel: tel,
|
||||||
|
model_id: config.apiSmsId.toString(),
|
||||||
|
model_args: {
|
||||||
|
//模板id对应的变量key值,object格式,内部自动处理成平台要求的str
|
||||||
|
code: code,
|
||||||
|
// 如果你的模板没变量,该值可为空
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return smsApi
|
||||||
|
.sendSMS(param)
|
||||||
|
.then((response: { code: number; state: number }) => {
|
||||||
|
if (response.state == 200) {
|
||||||
|
db.register
|
||||||
|
.create({
|
||||||
|
data: {
|
||||||
|
phone: telstr,
|
||||||
|
deadline: generateDeadline(),
|
||||||
|
code: code,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((reg) => {
|
||||||
|
if (reg.phone == telstr) {
|
||||||
|
console.info(telstr + "发送成功");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { code: 1, msg: "发送成功" };
|
||||||
|
} else {
|
||||||
|
console.info(tel);
|
||||||
|
return { code: 0, msg: "发送失败", error: response };
|
||||||
|
}
|
||||||
|
// 你的业务代码
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody(event);
|
||||||
|
let isSend =
|
||||||
|
(await db.register.findFirst({
|
||||||
|
where: {
|
||||||
|
phone: body.phone,
|
||||||
|
},
|
||||||
|
})) != null;
|
||||||
|
if (isSend) {
|
||||||
|
const register = (await db.register.findFirst({
|
||||||
|
where: {
|
||||||
|
phone: body.phone,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
deadline: "desc", // 'asc' 表示升序,'desc' 表示降序
|
||||||
|
},
|
||||||
|
})) || {
|
||||||
|
deadline: new Date(),
|
||||||
|
};
|
||||||
|
const deadlineDate = new Date(register.deadline);
|
||||||
|
const now = new Date();
|
||||||
|
if (now <= deadlineDate) {
|
||||||
|
return { code: 2, msg: "三分钟内请勿重发送" };
|
||||||
|
} else {
|
||||||
|
return send(body.phone);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return send(body.phone);
|
||||||
|
}
|
||||||
|
});
|
@ -4858,6 +4858,11 @@ proxy-from-env@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
|
quanmsms@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/quanmsms/-/quanmsms-1.0.2.tgz#8e7748329f87fd5f5550fe8eb94b6ab11a54ff90"
|
||||||
|
integrity sha512-wY4A2tz5ZANlgJw4t3fTgmcRpXO6FkyAxSfipdWa8DZxtfbItjQ4BErlugiEmL0sB2cTwJG9P3w5NT7i56T11Q==
|
||||||
|
|
||||||
queue-microtask@^1.2.2:
|
queue-microtask@^1.2.2:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||||
|
Loading…
Reference in New Issue
Block a user