login.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <template>
  2. <CommonRoot>
  3. <FlexCol>
  4. <StatusBarSpace />
  5. <NavBar v-if="!AppCofig.requireLogin" title="登录" leftButton="back" />
  6. <FlexCol center>
  7. <Height :size="200" />
  8. <Image
  9. :width="200"
  10. :src="baseLogo"
  11. mode="widthFix"
  12. />
  13. <Height :size="60" />
  14. <Text bold :fontSize="40">您好!欢迎使用村社文化资源挖掘平台</Text>
  15. <Height :size="60" />
  16. </FlexCol>
  17. <FlexCol center v-if="type == 'mobile'" :padding="40">
  18. <Form
  19. :model="loginFormModel"
  20. :rules="loginFormRules"
  21. labelWidth="140rpx"
  22. :fieldProps="{
  23. fieldStyle: fieldStyle,
  24. }"
  25. >
  26. <Field
  27. label="用户名"
  28. name="mobile"
  29. type="text"
  30. placeholder="请输入用户名"
  31. />
  32. <Field
  33. label="密码"
  34. type="password"
  35. name="password"
  36. placeholder="请输入密码(6-16位)"
  37. />
  38. <Field
  39. label="角色"
  40. name="loginType"
  41. required
  42. :fieldStyle="{
  43. ...fieldStyle,
  44. backgroundColor: 'transparent'
  45. }"
  46. >
  47. <FlexRow align="center">
  48. <RadioGroup>
  49. <Radio :name="0" text="志愿者" />
  50. <Radio :name="1" text="管理员" />
  51. </RadioGroup>
  52. </FlexRow>
  53. </Field>
  54. </Form>
  55. <Height :size="25" />
  56. <Button type="primary" block size="large" text="登录" @click="loginMobile" />
  57. <Height :size="20" />
  58. <Button type="text" block text="返回" @click="type='wechat'" />
  59. </FlexCol>
  60. <FlexCol center v-if="type == 'wechat'" :padding="40">
  61. <!-- #ifdef MP-WEIXIN -->
  62. <Button type="primary" block size="large" text="微信登录" icon="wechat-white" :iconProps="{color: 'white'}" @click="loginWechat" />
  63. <Height :size="20" />
  64. <!-- #endif -->
  65. <Button type="default" block size="large" text="用户名密码登录" @click="type='mobile'" />
  66. <FlexRow v-if="isTestEnv" position="absolute" :left="10" :bottom="10">
  67. <CheckBox v-model="isTestCode" />
  68. </FlexRow>
  69. </FlexCol>
  70. </FlexCol>
  71. </CommonRoot>
  72. </template>
  73. <script setup lang="ts">
  74. import { useTheme } from '@/components/theme/ThemeDefine';
  75. import { useAuthStore } from '@/store/auth';
  76. import { useAppInit } from '@/common/composeabe/AppInit';
  77. import { waitTimeOut } from '@imengyu/imengyu-utils';
  78. import { onMounted, ref } from 'vue';
  79. import { showError } from '@/common/composeabe/ErrorDisplay';
  80. import { alert, closeToast, confirm, toast } from '@/components/dialog/CommonRoot';
  81. import { checkAndGoBindVolunteer } from '../dig/forms/bind';
  82. import { back } from '@/components/utils/PageAction';
  83. import AppCofig, { isTestEnv } from '@/common/config/AppCofig';
  84. import type { Rules } from 'async-validator';
  85. import FlexCol from '@/components/layout/FlexCol.vue';
  86. import Form from '@/components/form/Form.vue';
  87. import Field from '@/components/form/Field.vue';
  88. import RadioGroup from '@/components/form/RadioGroup.vue';
  89. import Radio from '@/components/form/Radio.vue';
  90. import Button from '@/components/basic/Button.vue';
  91. import Height from '@/components/layout/space/Height.vue';
  92. import baseLogo from '/static/logo.png';
  93. import FlexRow from '@/components/layout/FlexRow.vue';
  94. import CommonRoot from '@/components/dialog/CommonRoot.vue';
  95. import StatusBarSpace from '@/components/layout/space/StatusBarSpace.vue';
  96. import Image from '@/components/basic/Image.vue';
  97. import Text from '@/components/basic/Text.vue';
  98. import CheckBox from '@/components/form/CheckBox.vue';
  99. import MemoryTimeOut from '@/common/composeabe/MemoryTimeOut';
  100. import NavBar from '@/components/nav/NavBar.vue';
  101. /**
  102. * 登录页面
  103. *
  104. * 登录页面,支持微信登录和用户名密码登录
  105. */
  106. const type = ref('wechat');
  107. const authStore = useAuthStore();
  108. const themeContext = useTheme();
  109. const { init } = useAppInit();
  110. const loginFormModel = ref({
  111. mobile: '',
  112. password: '',
  113. loginType: 0,
  114. });
  115. const loginFormRules : Rules = {
  116. 'mobile': {
  117. type: 'string',
  118. required: true,
  119. message: '请填写用户名',
  120. },
  121. 'password': {
  122. type: 'string',
  123. min: 6,
  124. max: 16,
  125. required: true,
  126. message: '请填写密码(6-16位)',
  127. },
  128. };
  129. const fieldStyle = themeContext.useThemeStyle({
  130. backgroundColor: '#ececec',
  131. paddingVertical: '30rpx',
  132. paddingHorizontal: '25rpx',
  133. borderRadius: '20rpx',
  134. marginBottom: '20rpx',
  135. });
  136. const isTestCode = ref(false);
  137. const tipBindWechat = new MemoryTimeOut('TipBindWechat', 1000 * 3600 * 72);
  138. async function loginWechat() {
  139. toast({
  140. type: 'loading',
  141. content: '登录中...',
  142. })
  143. try {
  144. const res = await Promise.all([
  145. uni.login({ provider: 'weixin' }),
  146. uni.getUserProfile({ desc: '用于完善会员资料' }),
  147. ])
  148. //测试code功能
  149. if (isTestCode.value) {
  150. uni.setClipboardData({
  151. data: res[0].code,
  152. });
  153. alert({
  154. title: '测试登录',
  155. content: '已复制登录信息到剪贴板\n' + JSON.stringify(res),
  156. });
  157. return;
  158. }
  159. //登录微信
  160. await authStore.loginWechart(res[0].code, res[1]);
  161. toast({ type: 'success',content: '登录成功' });
  162. await loginAfter();
  163. } catch(e) {
  164. showError(e);
  165. } finally {
  166. closeToast();
  167. }
  168. }
  169. async function loginMobile() {
  170. toast({
  171. type: 'loading',
  172. content: '登录中...',
  173. })
  174. try {
  175. await authStore.loginMobile(
  176. loginFormModel.value.mobile,
  177. loginFormModel.value.password,
  178. loginFormModel.value.loginType,
  179. );
  180. toast({ type: 'success',content: '登录成功' });
  181. await loginAfter(true);
  182. } catch (e) {
  183. closeToast()
  184. showError(e);
  185. }
  186. }
  187. async function loginAfter(isMobileLogin = false) {
  188. await waitTimeOut(200);
  189. //检查是否有志愿者信息,跳转至不同的页面
  190. //已认领志愿者,跳转至首页
  191. //未认领志愿者,跳转至绑定账号页面
  192. if (await checkAndGoBindVolunteer())
  193. return;
  194. //刷新用户信息
  195. await init();
  196. //如果用户未绑定微信,提示用户绑定微信
  197. if (isMobileLogin && !authStore.userInfo?.openId && tipBindWechat.isTimeout()) {
  198. tipBindWechat.recordTime();
  199. if (await confirm({
  200. title: '提示',
  201. content: '绑定微信账号后登录更方便,是否前往绑定?',
  202. confirmText: '前往绑定',
  203. cancelText: '稍后绑定',
  204. width: 580,
  205. })) {
  206. uni.redirectTo({ url: '/pages/dig/sharereg/bind-wx?fromLogin=true' });
  207. return;
  208. }
  209. }
  210. redirectToIndex();
  211. }
  212. function redirectToIndex() {
  213. if (AppCofig.requireLogin)
  214. uni.redirectTo({ url: '/pages/index' });
  215. else
  216. back();
  217. }
  218. onMounted(() => {
  219. toast({
  220. type: 'loading',
  221. content: '请稍后...',
  222. });
  223. setTimeout(() => {
  224. closeToast();
  225. if (authStore.isLogged)
  226. loginAfter();
  227. }, 800);
  228. })
  229. </script>