login.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <template>
  2. <z-paging ref="paging" bgColor="#fff">
  3. <template #top>
  4. <up-navbar :fixed="true" title="登录注册" bgColor="transparent">
  5. <template #left>
  6. <up-icon @click="homeBack()" name="arrow-left" color="#333" size="40rpx"></up-icon>
  7. </template>
  8. </up-navbar>
  9. </template>
  10. <view class="h-620 w-100%" style="background: url('/static/images/plant/loginTopBg.png'); background-size: auto 100%; background-repeat: no-repeat; position: absolute; top: 0; left: 0; z-index: -1"> </view>
  11. <view class="login-centent">
  12. <view class="login-logo-wrap p-rtv d-flex j-c a-c b-radius"></view>
  13. <view v-if="!isShowPhoneLogin" class="login-form pl-20 pd-25 b-radius p-rtv">
  14. <image class="w-100%" src="/static/images/plant/loginMidBg.png" mode="widthFix" style="position: absolute; top: 0; left: 0" />
  15. <view class="pd-40"></view>
  16. <template v-if="isBindPhone">
  17. <up-button class="mb-40" @click="handleLogin" color="#28A94B" type="primary" shape="circle">
  18. <view class="d-flex a-c j-c">
  19. <image class="w-45 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/login/weixin_logo.png" mode="widthFix" />
  20. 一键登录
  21. </view>
  22. </up-button>
  23. </template>
  24. <template v-else>
  25. <up-button class="mb-40" color="#28A94B" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber" type="primary" shape="circle">
  26. <view class="d-flex a-c j-c">
  27. <image class="w-45 mr-10" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/login/weixin_logo.png" mode="widthFix" />
  28. 一键登录
  29. </view>
  30. </up-button>
  31. </template>
  32. <view class="d-flex a-c pd-10 mb-20" @click="clickAgree">
  33. <up-checkbox activeColor="#2A6D52" size="32rpx" name="agree" usedAlone v-model:checked="form.aloneChecked"></up-checkbox>
  34. <view class="d-flex a-c f-s-24">
  35. <text class="c-999">我已阅读并同意</text>
  36. <text class="c-primary" @click="$u.route({ url: '/views/tool/agreement/agreement' })">《用户协议》</text>
  37. <text class="c-666">和</text>
  38. <text class="c-primary" @click="$u.route({ url: '/views/tool/privacy/privacy' })">《隐私政策》</text>
  39. </view>
  40. </view>
  41. <official-account></official-account>
  42. </view>
  43. <view v-if="isShowPhoneLogin" class="login-form pl-20 pd-25 b-radius">
  44. <up-form :model="forms" :rules="rules" ref="upFormRef" labelWidth="auto" labelPosition="top">
  45. <up-form-item prop="phonenumber">
  46. <up-input v-model="forms.phonenumber" fontSize="28rpx" :prefixIconStyle="prefixIconStyle" placeholderClass="placeholder" :customStyle="customStyle" maxlength="11" placeholder="请输入您的手机号" border="none" clearable shape="circle">
  47. <template #prefix>
  48. <view class="d-flex a-c mr-20">
  49. <image class="small-icon" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/login-phone/tel_icon.png" mode="widthFix" />
  50. </view>
  51. </template>
  52. </up-input>
  53. </up-form-item>
  54. <up-form-item prop="smsCode">
  55. <up-input v-model="forms.smsCode" fontSize="28rpx" :prefixIconStyle="prefixIconStyle" placeholderClass="placeholder" :customStyle="customStyle" placeholder="请输入验证码" border="none" clearable shape="circle">
  56. <template #prefix>
  57. <view class="d-flex a-c mr-20">
  58. <image class="small-icon" src="https://ta.zycpzs.cn/oss-file/smart-trace/szyy/images/login-phone/sms_code_icon.png" mode="widthFix" />
  59. </view>
  60. </template>
  61. <template #suffix>
  62. <up-button :disabled="disabled" @click="sendCode" style="color: #2a6d52" type="primary" color="#F6F6F6">
  63. <up-count-down ref="countDown" @change="onChange" :autoStart="false" :time="60 * 1000" format="(ss)" millisecond @finish="finish">
  64. <text>{{ codeText }}</text>
  65. </up-count-down>
  66. </up-button>
  67. </template>
  68. </up-input>
  69. </up-form-item>
  70. <view class="pd-40"></view>
  71. <up-button type="primary" @click="save" shape="circle">登录</up-button>
  72. <up-form-item prop="aloneChecked">
  73. <view class="d-flex a-c pd-10" @click="clickAgrees">
  74. <up-checkbox activeColor="#2A6D52" size="32rpx" name="agree" usedAlone v-model:checked="forms.aloneChecked"></up-checkbox>
  75. <view class="d-flex a-c f-s-24">
  76. <text class="c-999">我已阅读并同意</text>
  77. <text class="c-primary" @click="$u.route({ url: '/views/tool/agreement/agreement' })">《用户协议》</text>
  78. <text class="c-666">、</text>
  79. <text class="c-primary" @click="$u.route({ url: '/views/tool/privacy/privacy' })">《隐私政策》</text>
  80. </view>
  81. </view>
  82. </up-form-item>
  83. </up-form>
  84. </view>
  85. <up-divider text="更多登录方式" class="pd-30"></up-divider>
  86. <view class="d-flex j-sa pl-20 pr-20">
  87. <view v-if="!isShowPhoneLogin" class="d-flex flex-cln j-c a-c" @click="isShowPhoneLogin = true">
  88. <view class="bc-#f2f2f2 d-flex j-c a-c">
  89. <image class="w-95 h-95" src="/static/images/plant/accountNumber.png" mode="widthFix" />
  90. </view>
  91. <view class="c-#ccc f-s-24 pt-10">账号密码</view>
  92. </view>
  93. <view v-if="isShowPhoneLogin" class="d-flex flex-cln j-c a-c" @click="isShowPhoneLogin = false">
  94. <view class="bc-#f2f2f2 d-flex j-c a-c">
  95. <image class="w-95 h-95" src="/static/images/plant/QuickLogin.png" mode="widthFix" />
  96. </view>
  97. <view class="c-#ccc f-s-24 pt-10">一键登录</view>
  98. </view>
  99. <view class="d-flex flex-cln j-c a-c">
  100. <view class="bc-#f2f2f2 d-flex j-c a-c">
  101. <image class="w-95 h-95" src="/static/images/plant/SZYYLogo.png" mode="widthFix" />
  102. </view>
  103. <view class="c-#ccc f-s-24 pt-10">数字云药</view>
  104. </view>
  105. <view class="d-flex flex-cln j-c a-c">
  106. <view class="bc-#f2f2f2 d-flex j-c a-c">
  107. <image class="w-95 h-95" src="/static/images/plant/cxlmLogo.png" mode="widthFix" />
  108. </view>
  109. <view class="c-#ccc f-s-24 pt-10">中药材创新联盟</view>
  110. </view>
  111. </view>
  112. </view>
  113. <image class="login-bttom-bg" src="/static/images/plant/loginBottomBg.png" mode="widthFix" />
  114. </z-paging>
  115. </template>
  116. <script setup>
  117. import { ref, getCurrentInstance } from 'vue';
  118. import { useInfoStore, useSwitchStore } from '@/store';
  119. import config from '@/config';
  120. import { debounce } from 'uview-plus';
  121. import { onLoad } from '@dcloudio/uni-app';
  122. import { goToSwitchPage } from '@/utils/public';
  123. import { recursiveDecodeURIComponent } from '@/utils/ruoyi';
  124. import { useClientRequest } from '@/utils/request';
  125. const pages = ref(getCurrentPages());
  126. const infoStore = useInfoStore();
  127. const paging = ref(null);
  128. const redirect = ref('');
  129. // 判断是否绑定手机号
  130. const isBindPhone = ref(0);
  131. // 判断是否展示手机号登录
  132. const isShowPhoneLogin = ref(false);
  133. const form = ref({
  134. aloneChecked: false,
  135. phoneCode: '',
  136. xcxcode: '',
  137. grantType: 'xcx',
  138. clientId: config.clientId,
  139. // tenantId: config.tenantId,
  140. });
  141. const clickAgree = () => {
  142. form.value.aloneChecked = !form.value.aloneChecked;
  143. };
  144. const checkUserRegist = (data) => {
  145. return useClientRequest.post('/auth/checkUserRegist', data, false);
  146. };
  147. const getPhoneNumber = (e) => {
  148. console.log(e);
  149. // 判读是否获取成功
  150. if (!e.detail.code) {
  151. uni.showToast({
  152. title: '获取手机号失败',
  153. icon: 'none',
  154. });
  155. return;
  156. }
  157. form.value.phoneCode = e.detail.code;
  158. // 判断是否勾选隐私协议
  159. if (!form.value.aloneChecked) {
  160. uni.showToast({
  161. title: '请阅读并同意用户协议和隐私政策',
  162. icon: 'none',
  163. });
  164. return;
  165. }
  166. // 手机号登录方法
  167. handleLogin();
  168. };
  169. const handleLogin = () => {
  170. // 判断是否勾选隐私协议
  171. if (!form.value.aloneChecked) {
  172. uni.showToast({
  173. title: '请阅读并同意用户协议和隐私政策',
  174. icon: 'none',
  175. });
  176. return;
  177. }
  178. // 微信小程序登录获取的code
  179. uni.login({
  180. provider: 'weixin',
  181. success: function (loginRes) {
  182. // 获取用户信息
  183. if (loginRes.errMsg === 'login:ok') {
  184. form.value.xcxcode = loginRes.code;
  185. // 请求登录接口
  186. weixinLogin();
  187. }
  188. },
  189. });
  190. };
  191. const weixinLogin = async () => {
  192. try {
  193. // 请求登录接口
  194. uni.showLoading({
  195. title: '登录中...',
  196. mask: true,
  197. });
  198. //判断是什么类型的登录
  199. if (isShowPhoneLogin) {
  200. console.log(form.value, 'form.value');
  201. await infoStore.wxLogin(form.value);
  202. } else {
  203. await infoStore.wxLogin(forms.value);
  204. }
  205. // 调用获取用户信息接口
  206. infoStore.getUserInfo();
  207. console.log('调用获取用户信息接口');
  208. infoStore.getCompanyInfo();
  209. uni.hideLoading();
  210. // 重定向或跳转首页
  211. // 获取redirect参数
  212. const redirectUrl = redirect.value || '/pages/switch/index1';
  213. // switchTab 页面
  214. const switchTabs = ['/pages/switch/index1'];
  215. if (switchTabs.includes(redirectUrl)) {
  216. //从缓存中获取参数,然后跳转
  217. const switchStore = useSwitchStore();
  218. const params = switchStore.getAndClearParamsForPage(redirectUrl);
  219. // 使用公共函数跳转到switch页面并传递参数
  220. goToSwitchPage(redirectUrl, params);
  221. return;
  222. }
  223. uni.$u.route({
  224. type: 'redirect',
  225. url: redirectUrl,
  226. });
  227. } catch (error) {
  228. console.log(error);
  229. uni.showToast({
  230. title: error.msg || '登录失败,请稍后重试',
  231. icon: 'none',
  232. });
  233. }
  234. };
  235. // 判断用户是否绑定手机号
  236. const hasBindPhone = async () => {
  237. // 微信小程序登录获取的code
  238. uni.login({
  239. provider: 'weixin',
  240. success: function (loginRes) {
  241. // 获取用户信息
  242. if (loginRes.errMsg === 'login:ok') {
  243. console.log(loginRes, 'loginRes');
  244. checkUserRegist({
  245. code: loginRes.code,
  246. clientId: config.clientId,
  247. }).then((res) => {
  248. if (res.code === 200) {
  249. isBindPhone.value = +res.data;
  250. }
  251. });
  252. }
  253. },
  254. });
  255. };
  256. const homeBack = () => {
  257. const pages = getCurrentPages();
  258. if (pages.length > 1) {
  259. uni.navigateBack();
  260. } else {
  261. const redirectUrl = redirect.value || '/pages/list/index';
  262. const switchTabs = ['/pages/index/index', '/pages/find/index/index', '/pages/cart/index', '/pages/list/index', '/pages/user/index'];
  263. if (switchTabs.includes(redirectUrl)) {
  264. uni.$u.route({
  265. type: 'switchTab',
  266. url: redirectUrl,
  267. });
  268. return;
  269. } else {
  270. uni.$u.route({
  271. type: 'switchTab',
  272. url: '/pages/list/index',
  273. });
  274. }
  275. }
  276. };
  277. //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  278. const codeText = ref('获取验证码');
  279. const countDown = ref(null);
  280. const upFormRef = ref(null);
  281. const timeData = ref({});
  282. const disabled = ref(false);
  283. const finish = (e) => {
  284. disabled.value = false;
  285. codeText.value = '重新发送';
  286. };
  287. const forms = ref({
  288. phonenumber: '',
  289. smsCode: '',
  290. clientId: config.clientId,
  291. grantType: 'app_sms',
  292. aloneChecked: false,
  293. mverify: false,
  294. });
  295. const rules = reactive({
  296. phonenumber: [
  297. { required: true, message: '请输入手机号', trigger: 'blur' },
  298. { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' },
  299. ],
  300. smsCode: [
  301. { required: true, message: '请输入验证码', trigger: 'blur' },
  302. { pattern: /^[0-9]*$/, message: '验证码格式不正确', trigger: 'blur' },
  303. ],
  304. });
  305. const onChange = (e) => {
  306. timeData.value = e;
  307. if (+e.seconds) {
  308. codeText.value = `重新发送(${e.seconds + 1})`;
  309. }
  310. };
  311. const customStyle = reactive({
  312. padding: '0 50rpx',
  313. backgroundColor: '#F6F6F6',
  314. height: '98rpx',
  315. });
  316. const prefixIconStyle = reactive({
  317. // flex上下居中
  318. display: 'flex',
  319. alignItems: 'center',
  320. marginRight: '20rpx',
  321. });
  322. const clickAgrees = () => {
  323. forms.value.aloneChecked = !forms.value.aloneChecked;
  324. };
  325. const sendCode = () => {
  326. debounce(async () => {
  327. upFormRef.value?.validateField('phonenumber', (errorsRes) => {
  328. if (!errorsRes.length) {
  329. getCode();
  330. }
  331. });
  332. }, 500);
  333. };
  334. // 获取验证码
  335. const getCode = async () => {
  336. const res = await useClientRequest.get('/app/auth/sendVercode', { phone: forms.value.phonenumber }, false);
  337. if (res.code === 200) {
  338. uni.showToast({
  339. title: '验证码发送成功',
  340. icon: 'none',
  341. });
  342. countDown.value?.start();
  343. disabled.value = true;
  344. }
  345. };
  346. const save = () => {
  347. debounce(async () => {
  348. upFormRef.value
  349. ?.validate()
  350. .then((res) => {
  351. if (res) {
  352. // 判断是否勾选隐私协议
  353. if (!forms.value.aloneChecked) {
  354. uni.showToast({
  355. title: '请阅读并同意用户协议和隐私政策',
  356. icon: 'none',
  357. });
  358. return;
  359. }
  360. weixinLogin();
  361. }
  362. })
  363. .catch((error) => {});
  364. }, 500);
  365. };
  366. //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  367. onLoad((options) => {
  368. // 获取redirect参数
  369. const redirectStr = options.redirect ? recursiveDecodeURIComponent(options.redirect) : '';
  370. console.log(redirectStr, 'redirectStr');
  371. redirect.value = redirectStr;
  372. // 判断用户是否绑定手机号
  373. hasBindPhone();
  374. });
  375. </script>
  376. <style lang="scss" scoped>
  377. .login-logo-wrap {
  378. width: 750rpx;
  379. height: 550rpx;
  380. margin: auto;
  381. box-sizing: border-box;
  382. }
  383. .bg-circle {
  384. position: absolute;
  385. left: 0;
  386. top: 0;
  387. bottom: 0;
  388. right: 0;
  389. margin: auto;
  390. width: 770rpx;
  391. height: 770rpx;
  392. // 360度旋转
  393. // animation: rotate 10s linear infinite;
  394. }
  395. @keyframes rotate {
  396. from {
  397. transform: rotate(0deg);
  398. }
  399. to {
  400. transform: rotate(360deg);
  401. }
  402. }
  403. .login-logo {
  404. width: 493rpx;
  405. height: 284rpx;
  406. }
  407. .login-form {
  408. // background: linear-gradient(to bottom, #d5f7d6 0%, #daf7da 5px, #def7e0 15px, #fff 20px, #fff 100%);
  409. background-color: #fff;
  410. }
  411. .login-bttom-bg {
  412. position: absolute;
  413. left: 0;
  414. right: 0;
  415. bottom: 0;
  416. width: 687rpx;
  417. margin: auto;
  418. // 不能有事件
  419. pointer-events: none;
  420. }
  421. </style>