Index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. <template>
  2. <app-view class="register g-form g-layout">
  3. <template #header>
  4. <app-navbar :title="t('user.register.title')" :show-back-button="showBackButton" />
  5. </template>
  6. <app-switch-tab class="g-layout-block" v-model="selectedMethod" :options="openMethodList" @change="changeMethod"
  7. v-if="openMethodList.length > 1" />
  8. <Form ref="formRef" class="g-form__container g-layout-block" @submit="formSubmit">
  9. <CellGroup :inset="insetStyle" v-if="selectedMethod === 1">
  10. <Field :label="t('user.register.area')" right-icon="arrow" v-if="codeList.length">
  11. <template #input>
  12. <app-select v-model="selectedCode" :options="codeList">
  13. <span>+{{ selectedCode }}</span>
  14. <template #option="{ row }">
  15. +{{ row.value }}
  16. </template>
  17. </app-select>
  18. </template>
  19. </Field>
  20. <Field v-model="formData.mobilephone" type="digit" name="mobilephone" :label="t('user.register.mobile')"
  21. :placeholder="t('common.required')" :rules="formRules.mobilephone" />
  22. <Field v-model="formData.vcode" type="digit" name="vcode" :label="t('user.register.vcode')"
  23. :placeholder="t('common.required')" :rules="formRules.vcode">
  24. <template #button>
  25. <Button size="small" :disabled="loading" @click="sendVerifyCode">
  26. <span v-if="isCountdown">{{ t('user.register.sendagain') }}({{ currentTime }})</span>
  27. <span v-else>{{ t('user.register.getsmscode') }}</span>
  28. </Button>
  29. </template>
  30. </Field>
  31. </CellGroup>
  32. <CellGroup :inset="insetStyle" v-if="selectedMethod === 2">
  33. <Field name="email" label="邮箱地址" v-model="formData.mobilephone" :placeholder="t('common.required')"
  34. :rules="formRules.email" />
  35. <Field v-model="formData.vcode" type="digit" name="vcode" label="验证码" :placeholder="t('common.required')"
  36. :rules="formRules.vcode">
  37. <template #button>
  38. <Button size="small" :disabled="loading" @click="sendVerifyCode">
  39. <span v-if="isCountdown">{{ t('user.register.sendagain') }}({{ currentTime }})</span>
  40. <span v-else>{{ t('user.register.getsmscode') }}</span>
  41. </Button>
  42. </template>
  43. </Field>
  44. </CellGroup>
  45. <CellGroup :inset="insetStyle">
  46. <Field v-model="formData.loginpwd" name="loginpwd" type="password" :label="t('user.register.logipwd')"
  47. :placeholder="t('common.required')" :rules="formRules.loginpwd" />
  48. <Field v-model="confirmpassword" name="confirmpassword" type="password" :label="t('user.register.confirmpwd')"
  49. :placeholder="t('common.required')" :rules="formRules.confirmpassword" />
  50. <Field v-model="formData.refernum" name="refernum" :label="t('user.register.registercode')"
  51. :placeholder="registrationCodeRule ? t('common.required') : t('common.optional')" :rules="formRules.refernum"
  52. v-if="registrationCodeRule > -1">
  53. <!-- <template #button>
  54. <app-qrcode-scan @success="onScanSuccess">
  55. <Button size="small" type="danger">扫码</Button>
  56. </app-qrcode-scan>
  57. </template> -->
  58. </Field>
  59. </CellGroup>
  60. <CellGroup :inset="insetStyle">
  61. <Cell>
  62. <template #title>
  63. <div style="display: flex;align-items: center;font-size: 13px;">
  64. <Checkbox shape="square" icon-size="16px" v-model="checked">
  65. {{ t('user.register.checked') }}
  66. </Checkbox>
  67. <span @click="routerTo('rules-zcxy')" style="color:#E92020">
  68. {{ t('user.register.ruleszcxy') }}
  69. </span>
  70. <span @click="routerTo('rules-yhkhfxgzs')" style="color:#E92020" v-if="showYhkhfxgzs">
  71. {{ t('user.register.rulesfxgzs') }}
  72. </span>
  73. </div>
  74. </template>
  75. </Cell>
  76. </CellGroup>
  77. </Form>
  78. <div class="g-form__footer inset">
  79. <Button type="primary" @click="formRef?.submit" :round="insetStyle" block>
  80. {{ t('user.register.freeregister') }}
  81. </Button>
  82. </div>
  83. <app-reward :show="showReward" :value="redEnvelope" :title="t('user.register.registersuccess')"
  84. @click="routerAction" />
  85. </app-view>
  86. </template>
  87. <script lang="ts" setup>
  88. import { reactive, shallowRef, ref, computed, onMounted, useAttrs } from 'vue'
  89. import { CellGroup, Cell, Button, Field, Form, FormInstance, Checkbox, showFailToast, showToast, FieldRule, showSuccessToast } from 'vant'
  90. import { useCountDown } from '@vant/use'
  91. import { fullloading, dialog } from '@/utils/vant'
  92. import { validateRules } from '@/constants/regex'
  93. import { useFacebook } from '@/hooks/facebook'
  94. import { useAppsFlyer } from '@/hooks/appsflyer'
  95. import { useNavigation } from '@mobile/router/navigation'
  96. import { userRegister, sendRegisterVerifyCode2, queryMyRegisterMoney } from '@/services/api/common'
  97. import { i18n, useGlobalStore, useUserStore, useErrorInfoStore } from '@/stores'
  98. import { getCountryCodeList } from '@/constants/unit'
  99. import { getOpenMethodList } from '@/constants/common'
  100. import cryptojs from 'crypto-js'
  101. import plus from '@/utils/h5plus'
  102. import AppSwitchTab from '@mobile/components/base/switch-tab/index.vue'
  103. import AppReward from '@mobile/components/modules/reward/index.vue'
  104. import AppSelect from '@mobile/components/base/select/index.vue'
  105. // import AppQrcodeScan from '@mobile/components/base/qrcode-scan/index.vue'
  106. defineProps({
  107. showBackButton: {
  108. type: Boolean,
  109. default: true
  110. },
  111. showYhkhfxgzs: {
  112. type: Boolean,
  113. default: true
  114. },
  115. insetStyle: {
  116. type: Boolean,
  117. default: true
  118. }
  119. })
  120. const emit = defineEmits<{ (event: string, ...args: unknown[]): void }>()
  121. const { t } = i18n.global
  122. const { trackEvent } = useFacebook()
  123. const { logEvent } = useAppsFlyer()
  124. const attrs = useAttrs()
  125. const { router, routerTo, getQueryString } = useNavigation()
  126. const globalStore = useGlobalStore()
  127. const errorInfoStore = useErrorInfoStore()
  128. const registrationCodeRule = globalStore.getSystemInfo('registrationCodeRule')
  129. const formRef = ref<FormInstance>()
  130. const checked = ref(false) // 是否同意注册条款
  131. const loading = ref(false)
  132. const isCountdown = ref(false) // 是否正在倒计时
  133. const showReward = ref(false) // 显示红包
  134. const redEnvelope = ref(0) // 红包金额
  135. const openMethodList = getOpenMethodList() // 开户方式
  136. const selectedMethod = shallowRef(1) // 选中的开户方式
  137. const { getSystemParamValue } = useUserStore()
  138. const param1010 = getSystemParamValue('1010') ?? '1'
  139. const param1013 = getSystemParamValue('1013') ?? '30'
  140. const codeList = getCountryCodeList()
  141. const selectedCode = shallowRef(codeList[0]?.value) // 选中的区号
  142. // 用户名
  143. const accountName = computed(() => {
  144. const prefix = selectedMethod.value === 1 ? (selectedCode.value ?? '') : ''
  145. return prefix + formData.mobilephone
  146. })
  147. const confirmpassword = ref('') // 确认密码
  148. // 倒计时函数
  149. const countdown = useCountDown({
  150. time: +param1013 * 1000,
  151. onFinish: () => {
  152. countdown.reset()
  153. isCountdown.value = false
  154. loading.value = false
  155. }
  156. })
  157. // 倒计时剩余时间
  158. const currentTime = computed(() => {
  159. const { total } = countdown.current.value
  160. return (total / 1000).toFixed(0)
  161. })
  162. // 表单数据
  163. const formData = reactive<Model.RegisterReq>({
  164. mobilephone: '',
  165. loginpwd: '',
  166. vcode: '',
  167. refernum: getQueryString('code') ?? '',
  168. isaudit: 1,
  169. userinfotype: 1,
  170. usertype: 5,
  171. openmode: 4,
  172. lsitAgreementID: []
  173. })
  174. // 表单验证规则
  175. const formRules: { [key: string]: FieldRule[] } = {
  176. mobilephone: [{
  177. required: true,
  178. message: t('user.register.tips1'),
  179. validator: (val) => {
  180. /// 值为”0“ 时 只校验长度20位,不限字符
  181. if (param1010 === '0') {
  182. if (val.length <= 20) {
  183. return true
  184. }
  185. return t('banksign.tips6')
  186. } else {
  187. if (validateRules.phone.validate(val)) {
  188. return true
  189. }
  190. return validateRules.phone.message
  191. }
  192. }
  193. }],
  194. email: [{
  195. required: true,
  196. message: '请输入邮箱地址',
  197. validator: (val) => {
  198. if (validateRules.email.validate(val)) {
  199. return true
  200. }
  201. return validateRules.email.message
  202. }
  203. }],
  204. loginpwd: [{
  205. required: true,
  206. message: t('user.register.tips2'),
  207. validator: (val) => {
  208. if (globalStore.getSystemInfo('strongPassword')) {
  209. if (validateRules.password.validate(val)) {
  210. return true
  211. }
  212. return validateRules.password.message
  213. }
  214. return val?.length < 6 ? '密码长度不能小于6位' : true
  215. }
  216. }],
  217. confirmpassword: [{
  218. required: true,
  219. message: t('user.register.tips3'),
  220. validator: (val) => {
  221. if (formData.loginpwd === val) {
  222. return true
  223. }
  224. return t('user.register.tips4')
  225. }
  226. }],
  227. vcode: [{
  228. required: true,
  229. message: t('user.register.tips5'),
  230. }],
  231. refernum: [{
  232. validator: (val) => {
  233. if (!registrationCodeRule || val) {
  234. return true
  235. }
  236. return t('user.register.tips6')
  237. }
  238. }],
  239. }
  240. // 扫码成功
  241. // const onScanSuccess = (text: string) => {
  242. // formData.refernum = text
  243. // }
  244. // 选择开户方式
  245. const changeMethod = (value: number) => {
  246. formData.mobilephone = ''
  247. formData.vcode = ''
  248. selectedMethod.value = value
  249. }
  250. // 路由跳转
  251. const routerAction = () => {
  252. // 追踪注册结果
  253. trackEvent('CompleteRegistration')
  254. logEvent('af_complete_registration', {
  255. af_registration_method: 'Mobile'
  256. })
  257. if (attrs.onRouterAction) {
  258. emit('routerAction')
  259. } else {
  260. router.back()
  261. }
  262. }
  263. // 清除数据
  264. const resetData = () => {
  265. formData.mobilephone = ''
  266. formData.vcode = ''
  267. formData.loginpwd = ''
  268. confirmpassword.value = ''
  269. formData.refernum = ''
  270. checked.value = false
  271. }
  272. // 发送验证码
  273. const sendVerifyCode = () => {
  274. const field = selectedMethod.value === 1 ? 'mobilephone' : 'email'
  275. formRef.value?.validate(field).then(() => {
  276. loading.value = true
  277. sendRegisterVerifyCode2({
  278. data: {
  279. param: accountName.value
  280. }
  281. }).then(() => {
  282. isCountdown.value = true
  283. countdown.start()
  284. }).catch(() => {
  285. loading.value = false
  286. showFailToast(t('user.register.tips7'))
  287. })
  288. })
  289. }
  290. // 获取注册红包
  291. const getRegisterMoney = (accountid: number) => {
  292. const toggleDialog = () => {
  293. dialog({
  294. message: t('user.register.tips8'),
  295. confirmButtonText: t('operation.confirm')
  296. }).then(() => {
  297. routerAction()
  298. })
  299. }
  300. return queryMyRegisterMoney({
  301. data: {
  302. accountid
  303. }
  304. }).then((res) => {
  305. // 查询成功显示获得红包
  306. if (res.data.length) {
  307. redEnvelope.value = res.data[0].amount
  308. showReward.value = true
  309. } else {
  310. toggleDialog()
  311. }
  312. }).catch(() => {
  313. // 查询失败提示注册成功后返回登录页面
  314. toggleDialog()
  315. })
  316. }
  317. // 表单提交
  318. const formSubmit = () => {
  319. if (checked.value) {
  320. fullloading((hideLoading) => {
  321. const { Utf8, Base64 } = cryptojs.enc
  322. // 密码需进行两次base64加密
  323. const passwordData = Base64.stringify(Utf8.parse(formData.loginpwd))
  324. const loginpwd = Base64.stringify(Utf8.parse(passwordData))
  325. userRegister({
  326. data: {
  327. ...formData,
  328. mobilephone: accountName.value,
  329. loginpwd
  330. }
  331. }).then((res) => {
  332. if (res.code === 0) {
  333. if (res.taaccount != undefined) {
  334. // 等待3秒后查询注册红包
  335. setTimeout(() => {
  336. getRegisterMoney(res.taaccount[0].accountid).finally(() => {
  337. hideLoading()
  338. })
  339. }, 3000)
  340. } else {
  341. // 清除数据
  342. resetData()
  343. showSuccessToast(t('user.register.tips11'))
  344. }
  345. } else {
  346. const msg = errorInfoStore.getErrorInfoByCode(res.message)
  347. showFailToast(msg ?? res.message)
  348. }
  349. }).catch((err) => {
  350. const msg = errorInfoStore.getErrorInfoByCode(err)
  351. showFailToast(msg ?? err)
  352. })
  353. }, t('user.register.tips9'))
  354. } else {
  355. showToast(t('user.register.tips10'))
  356. }
  357. }
  358. onMounted(() => {
  359. const os = plus.getSystemInfo('os')
  360. if (os === 'Android') {
  361. formData.openmode = 5
  362. }
  363. if (os === 'iOS') {
  364. formData.openmode = 6
  365. }
  366. if (openMethodList.length) {
  367. selectedMethod.value = openMethodList[0].value
  368. }
  369. })
  370. </script>