login.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <template>
  2. <view class="w-screen h-screen flex flex-col" :style="themeColor()">
  3. <!-- #ifdef MP-WEIXIN -->
  4. <view :style="{ height: headerHeight }">
  5. <top-tabbar :data="param" :scrollBool="topTabarObj.getScrollBool()" class="top-header" />
  6. </view>
  7. <!-- #endif -->
  8. <view class="mx-[60rpx]">
  9. <view class="pt-[140rpx] text-[44rpx] font-500 text-[#333]">账号密码登录</view>
  10. <view class="text-[26rpx] text-[#333] leading-[34rpx] mt-[24rpx] mb-[90rpx]"
  11. @click="redirect({ url: '/app/pages/auth/register', param: { type } })">
  12. <text>还没有账号,</text>
  13. <text class="text-primary">去注册</text>
  14. </view>
  15. <u-form labelPosition="left" :model="formData" errorType="toast" :rules="rules" ref="formRef">
  16. <template v-if="type == 'username'">
  17. <view class="h-[88rpx] flex w-full items-center px-[30rpx] rounded-[40rpx] box-border bg-[#F6F6F6]">
  18. <u-form-item label="" prop="username" :border-bottom="false">
  19. <u-input v-model="formData.username" border="none" maxlength="40" placeholder="请输入账号"
  20. autocomplete="off" class="!bg-transparent" :disabled="real_name_input" fontSize="26rpx"
  21. placeholderClass="!text-[var(--text-color-light9)] text-[26rpx]" />
  22. </u-form-item>
  23. </view>
  24. <view
  25. class="h-[88rpx] flex w-full items-center px-[30rpx] rounded-[40rpx] box-border bg-[#F6F6F6] mt-[40rpx]">
  26. <u-form-item label="" prop="password" :border-bottom="false">
  27. <u-input v-model="formData.password" border="none" :password="isPassword" maxlength="40"
  28. placeholder="请输入密码" autocomplete="new-password" class="!bg-transparent"
  29. :disabled="real_name_input" fontSize="26rpx"
  30. placeholderClass="!text-[var(--text-color-light9)] text-[26rpx]">
  31. <template #suffix>
  32. <view @click="changePassword" v-if="formData.password">
  33. <u-icon :name="isPassword ? 'eye-off' : 'eye-fill'" color="#b9b9b9"
  34. size="20"></u-icon>
  35. </view>
  36. </template>
  37. </u-input>
  38. </u-form-item>
  39. </view>
  40. </template>
  41. <!-- #ifdef MP-WEIXIN -->
  42. <template v-if="type == 'wx'">
  43. <button
  44. class="w-full h-[80rpx] !bg-[var(--primary-color)] text-[26rpx] rounded-[40rpx] leading-[80rpx] font-500 !text-[#fff] !mx-[0]"
  45. open-type="getPhoneNumber" @getphonenumber="getphonenumber">
  46. 授权手机号登录
  47. </button>
  48. </template>
  49. <!-- #endif -->
  50. <template v-if="type == 'mobile'">
  51. <view class="h-[88rpx] flex w-full items-center px-[30rpx] rounded-[40rpx] box-border bg-[#F6F6F6]">
  52. <u-form-item label="" prop="mobile" :border-bottom="false">
  53. <u-input v-model="formData.username" type="number" maxlength="11" border="none"
  54. placeholder="请输入手机号" autocomplete="off" class="!bg-transparent"
  55. :disabled="real_name_input" fontSize="26rpx"
  56. placeholderClass="!text-[var(--text-color-light9)] text-[26rpx]" />
  57. </u-form-item>
  58. </view>
  59. <view
  60. class="h-[88rpx] flex w-full items-center px-[30rpx] rounded-[40rpx] box-border bg-[#F6F6F6] mt-[40rpx]">
  61. <u-form-item label="" prop="mobile_code" :border-bottom="false">
  62. <u-input v-model="formData.code" type="number" maxlength="4" border="none"
  63. class="!bg-transparent" fontSize="26rpx" :disabled="real_name_input"
  64. placeholder="请输入手机验证码" placeholderClass="!text-[var(--text-color-light9)] text-[26rpx]">
  65. <template #suffix>
  66. <sms-code v-if="configStore.login.agreement_show" :mobile="formData.username"
  67. type="login" v-model="formData.mobile_key" :isAgree="isAgree"></sms-code>
  68. <sms-code v-else :mobile="formData.username" type="login"
  69. v-model="formData.mobile_key"></sms-code>
  70. </template>
  71. </u-input>
  72. </u-form-item>
  73. </view>
  74. </template>
  75. </u-form>
  76. <template v-if="type != 'wx'">
  77. <view
  78. class="h-[34rpx] text-right text-[24rpx] text-[var(--text-color-light6)] leading-[34rpx] mt-[20rpx]"
  79. @click="toResetpwd">忘记密码</view>
  80. <view class="mt-[106rpx]">
  81. <button
  82. class="w-full h-[80rpx] !bg-[var(--primary-color)] text-[26rpx] rounded-[40rpx] leading-[80rpx] font-500 !text-[#fff] !mx-[0]"
  83. loadingText="登录中" @click="handleLogin">
  84. 登录
  85. </button>
  86. </view>
  87. </template>
  88. </view>
  89. <view class="footer w-full">
  90. <view class="text-[26rpx] leading-[36rpx] text-[#666] text-center mb-[30rpx] font-400" @click="setType">
  91. {{ type == "wx" ? "短信登录" : "其他登录方式" }}
  92. </view>
  93. <view class="flex justify-center gap-[40rpx]"> </view>
  94. </view>
  95. </view>
  96. </template>
  97. <script setup lang="ts">
  98. import { ref, reactive, computed, onMounted } from "vue";
  99. import { usernameLogin, mobileLogin, clientLogin } from "@/app/api/auth";
  100. import useMemberStore from "@/stores/member";
  101. import useConfigStore from "@/stores/config";
  102. import { useLogin } from "@/hooks/useLogin";
  103. import { t } from "@/locale";
  104. import { redirect, getToken, pxToRpx, isWeixinBrowser } from "@/utils/common";
  105. import { onLoad } from "@dcloudio/uni-app";
  106. import { topTabar } from "@/utils/topTabbar";
  107. import useSystemStore from "@/stores/system";
  108. const systemStore = useSystemStore();
  109. /********* 自定义头部 - start ***********/
  110. const topTabarObj = topTabar();
  111. const param = topTabarObj.setTopTabbarParam({
  112. title: "",
  113. topStatusBar: { bgColor: "#fff", textColor: "#333" },
  114. });
  115. /********* 自定义头部 - end ***********/
  116. const headerHeight = computed(() => {
  117. return Object.keys(systemStore.menuButtonInfo).length
  118. ? pxToRpx(Number(systemStore.menuButtonInfo.height)) +
  119. pxToRpx(systemStore.menuButtonInfo.top) +
  120. pxToRpx(8) +
  121. "rpx"
  122. : "auto";
  123. });
  124. const real_name_input = ref(true);
  125. const memberStore = useMemberStore();
  126. const configStore = useConfigStore();
  127. const type = ref("");
  128. const isAgree = ref(false);
  129. const isShowQuickLogin = ref(false); // 是否显示快捷登录
  130. const popupRef = ref();
  131. const isPassword = ref(true);
  132. const changePassword = () => {
  133. isPassword.value = !isPassword.value;
  134. };
  135. const dialogClose = () => {
  136. popupRef.value.close();
  137. };
  138. const dialogConfirm = () => {
  139. isAgree.value = true;
  140. popupRef.value.close();
  141. handleLogin();
  142. };
  143. onLoad(async (option: any) => {
  144. // #ifdef H5
  145. uni.getStorageSync("openid") &&
  146. Object.assign(formData, { wx_openid: uni.getStorageSync("openid") });
  147. // #endif
  148. // #ifdef MP-WEIXIN
  149. uni.getStorageSync("openid") &&
  150. Object.assign(formData, { weapp_openid: uni.getStorageSync("openid") });
  151. // #endif
  152. type.value = option.type ? option.type : "username";
  153. // if (option.type) {
  154. // if (option.type == 'mobile') {
  155. // if (configStore.login.is_mobile) {
  156. // type.value = option.type
  157. // uni.getStorageSync('pid') && (Object.assign(formData, { pid: uni.getStorageSync('pid') }))
  158. // }
  159. // } else if (option.type == 'username' && configStore.login.is_username) {
  160. // type.value = option.type
  161. // }
  162. // } else {
  163. // if (configStore.login.is_username) {
  164. // type.value = 'username'
  165. // } else if (configStore.login.is_mobile) {
  166. // type.value = 'mobile'
  167. // }
  168. // }
  169. // // 如果只开启了账号密码登录,那么就不需要跳转到登录中间页了
  170. // // #ifdef MP-WEIXIN
  171. // if (!configStore.login.is_auth_register) {
  172. // isShowQuickLogin.value = false;
  173. // } else {
  174. // isShowQuickLogin.value = true;
  175. // }
  176. // // #endif
  177. // // #ifdef H5
  178. // if (isWeixinBrowser()) {
  179. // // 微信浏览器
  180. // if (!configStore.login.is_auth_register) {
  181. // isShowQuickLogin.value = false;
  182. // } else {
  183. // isShowQuickLogin.value = true;
  184. // }
  185. // } else {
  186. // // 普通浏览器
  187. // isShowQuickLogin.value = false;
  188. // }
  189. // // #endif
  190. });
  191. const formData = reactive({
  192. username: "",
  193. password: "",
  194. code: "",
  195. mobile_key: "",
  196. });
  197. const getphonenumber = async (res: any) => {
  198. console.log(res, "?????????????");
  199. };
  200. onMounted(() => {
  201. // 防止浏览器自动填充
  202. setTimeout(() => {
  203. real_name_input.value = false;
  204. }, 800);
  205. });
  206. const agreeChange = () => {
  207. isAgree.value = !isAgree.value;
  208. };
  209. const setType = () => {
  210. if (type.value == "username") {
  211. // #ifndef MP-WEIXIN
  212. type.value = "mobile";
  213. // #endif
  214. // #ifdef MP-WEIXIN
  215. type.value = "wx";
  216. // #endif
  217. } else if ((type.value == "wx")) {
  218. type.value = "mobile";
  219. } else {
  220. type.value = "username";
  221. }
  222. };
  223. const loading = ref(false);
  224. const rules = computed(() => {
  225. return {
  226. username: [
  227. {
  228. type: "string",
  229. required: true,
  230. message: "请输入账号",
  231. trigger: ["blur", "change"],
  232. },
  233. {
  234. validator(rule: any, value: any) {
  235. return uni.$u.test.mobile(value);
  236. },
  237. message: "请输入正确的手机号",
  238. trigger: ["change", "blur"],
  239. },
  240. ],
  241. password: {
  242. type: "string",
  243. required: true,
  244. message: "请输入密码",
  245. trigger: ["blur", "change"],
  246. },
  247. };
  248. });
  249. const formRef: any = ref(null);
  250. const handleLogin = () => {
  251. formRef.value.validate().then(() => {
  252. if (loading.value) return;
  253. let datas: any = {}
  254. if (type.value == "username") {
  255. datas.username = formData.username
  256. datas.password = formData.password
  257. }
  258. loading.value = true;
  259. clientLogin(datas)
  260. .then((res: any) => {
  261. memberStore.setToken(res.data.access_token);
  262. useLogin().handleLoginBack();
  263. })
  264. .catch(() => {
  265. loading.value = false;
  266. });
  267. });
  268. };
  269. const toLink = () => {
  270. const pages = getCurrentPages(); // 获取页面栈
  271. if (pages.length > 1) {
  272. const currentPage = pages[pages.length - 2].route;
  273. if (currentPage == "app/pages/auth/index") {
  274. // 返回上一页
  275. uni.navigateBack({
  276. delta: 1, // 默认值是1,表示返回的页面层数
  277. });
  278. } else {
  279. redirect({ url: "/app/pages/auth/index", mode: "redirectTo" });
  280. }
  281. } else {
  282. redirect({ url: "/app/pages/auth/index", mode: "redirectTo" });
  283. }
  284. };
  285. const toResetpwd = () => {
  286. uni.showToast({ title: "请联系管理员重置密码", icon: "none" });
  287. };
  288. </script>
  289. <style lang="scss" scoped>
  290. :deep(.u-input) {
  291. background-color: transparent !important;
  292. }
  293. :deep(.u-checkbox) {
  294. margin: 0 !important;
  295. }
  296. :deep(.u-form-item) {
  297. flex: 1;
  298. .u-line {
  299. display: none;
  300. }
  301. }
  302. .footer {
  303. // position: absolute;
  304. // position: fixed;
  305. margin-top: 200rpx;
  306. bottom: 0;
  307. left: 0;
  308. right: 0;
  309. padding-bottom: calc(151rpx + constant(safe-area-inset-bottom));
  310. padding-bottom: calc(151rpx + env(safe-area-inset-bottom));
  311. }
  312. </style>