login.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  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('https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/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="https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/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://yujin-szyy.oss-cn-chengdu.aliyuncs.com/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://yujin-szyy.oss-cn-chengdu.aliyuncs.com/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://yujin-szyy.oss-cn-chengdu.aliyuncs.com/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://yujin-szyy.oss-cn-chengdu.aliyuncs.com/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="https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/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="https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/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="https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/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="https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/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="https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/plant/loginBottomBg.png" mode="widthFix" />
  114. </z-paging>
  115. </template>
  116. <script setup>
  117. import { ref, getCurrentInstance } from 'vue';
  118. import { useInfoStore } from '@/store';
  119. import config from '@/config';
  120. import { debounce } from 'uview-plus';
  121. import { onLoad } from '@dcloudio/uni-app';
  122. import { recursiveDecodeURIComponent } from '@/utils/ruoyi';
  123. import { useClientRequest } from '@/utils/request';
  124. const pages = ref(getCurrentPages());
  125. const infoStore = useInfoStore();
  126. const paging = ref(null);
  127. const redirect = ref('');
  128. // 判断是否绑定手机号
  129. const isBindPhone = ref(0);
  130. // 判断是否展示手机号登录
  131. const isShowPhoneLogin = ref(false);
  132. const form = ref({
  133. aloneChecked: false,
  134. phoneCode: '',
  135. xcxcode: '',
  136. grantType: 'xcx',
  137. clientId: config.clientId,
  138. // tenantId: config.tenantId,
  139. });
  140. const clickAgree = () => {
  141. form.value.aloneChecked = !form.value.aloneChecked;
  142. };
  143. const checkUserRegist = (data) => {
  144. return useClientRequest.post('/plt-api/auth/checkUserRegist', data, false);
  145. };
  146. const getPhoneNumber = (e) => {
  147. console.log(e);
  148. // 判读是否获取成功
  149. if (!e.detail.code) {
  150. uni.showToast({
  151. title: '获取手机号失败',
  152. icon: 'none',
  153. });
  154. return;
  155. }
  156. form.value.phoneCode = e.detail.code;
  157. // 判断是否勾选隐私协议
  158. if (!form.value.aloneChecked) {
  159. uni.showToast({
  160. title: '请阅读并同意用户协议和隐私政策',
  161. icon: 'none',
  162. });
  163. return;
  164. }
  165. // 手机号登录方法
  166. handleLogin();
  167. };
  168. const handleLogin = () => {
  169. // 判断是否勾选隐私协议
  170. if (!form.value.aloneChecked) {
  171. uni.showToast({
  172. title: '请阅读并同意用户协议和隐私政策',
  173. icon: 'none',
  174. });
  175. return;
  176. }
  177. // 微信小程序登录获取的code
  178. uni.login({
  179. provider: 'weixin',
  180. success: function (loginRes) {
  181. // 获取用户信息
  182. if (loginRes.errMsg === 'login:ok') {
  183. form.value.xcxcode = loginRes.code;
  184. // 请求登录接口
  185. weixinLogin();
  186. }
  187. },
  188. });
  189. };
  190. const weixinLogin = async () => {
  191. try {
  192. // 请求登录接口
  193. uni.showLoading({
  194. title: '登录中...',
  195. mask: true,
  196. });
  197. //判断是什么类型的登录
  198. if (isShowPhoneLogin) {
  199. console.log(form.value, 'form.value');
  200. await infoStore.wxLogin(form.value);
  201. } else {
  202. await infoStore.wxLogin(forms.value);
  203. }
  204. // 调用获取用户信息接口
  205. infoStore.getUserInfo();
  206. console.log('调用获取用户信息接口');
  207. infoStore.getCompanyInfo();
  208. uni.hideLoading();
  209. // 重定向或跳转首页
  210. // 获取redirect参数
  211. const redirectUrl = redirect.value || '/pages/plant/base/index';
  212. // switchTab 页面
  213. const switchTabs = ['/pages/plant/base/index', '/pages/plant/port/index', '/pages/plant/processing/index', '/pages/plant/more/index'];
  214. if (switchTabs.includes(redirectUrl)) {
  215. uni.$u.route({
  216. type: 'switchTab',
  217. url: redirectUrl,
  218. });
  219. return;
  220. }
  221. uni.$u.route({
  222. type: 'redirect',
  223. url: redirectUrl,
  224. });
  225. } catch (error) {
  226. console.log(error);
  227. uni.showToast({
  228. title: error.msg || '登录失败,请稍后重试',
  229. icon: 'none',
  230. });
  231. }
  232. };
  233. // 判断用户是否绑定手机号
  234. const hasBindPhone = async () => {
  235. // 微信小程序登录获取的code
  236. uni.login({
  237. provider: 'weixin',
  238. success: function (loginRes) {
  239. // 获取用户信息
  240. if (loginRes.errMsg === 'login:ok') {
  241. console.log(loginRes, 'loginRes');
  242. checkUserRegist({
  243. code: loginRes.code,
  244. clientId: config.clientId,
  245. }).then((res) => {
  246. if (res.code === 200) {
  247. isBindPhone.value = +res.data;
  248. }
  249. });
  250. }
  251. },
  252. });
  253. };
  254. const homeBack = () => {
  255. const pages = getCurrentPages();
  256. if (pages.length > 1) {
  257. uni.navigateBack();
  258. } else {
  259. const redirectUrl = redirect.value || '/pages/list/index';
  260. const switchTabs = ['/pages/plant/base/index', '/pages/plant/port/index', '/pages/plant/processing/index', '/pages/plant/more/index'];
  261. if (switchTabs.includes(redirectUrl)) {
  262. uni.$u.route({
  263. type: 'switchTab',
  264. url: redirectUrl,
  265. });
  266. return;
  267. } else {
  268. uni.$u.route({
  269. type: 'switchTab',
  270. url: '/pages/list/index',
  271. });
  272. }
  273. }
  274. };
  275. //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  276. const codeText = ref('获取验证码');
  277. const countDown = ref(null);
  278. const upFormRef = ref(null);
  279. const timeData = ref({});
  280. const disabled = ref(false);
  281. const finish = (e) => {
  282. disabled.value = false;
  283. codeText.value = '重新发送';
  284. };
  285. const forms = ref({
  286. phonenumber: '',
  287. smsCode: '',
  288. clientId: config.clientId,
  289. grantType: 'app_sms',
  290. aloneChecked: false,
  291. mverify: false,
  292. });
  293. const rules = reactive({
  294. phonenumber: [
  295. { required: true, message: '请输入手机号', trigger: 'blur' },
  296. { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' },
  297. ],
  298. smsCode: [
  299. { required: true, message: '请输入验证码', trigger: 'blur' },
  300. { pattern: /^[0-9]*$/, message: '验证码格式不正确', trigger: 'blur' },
  301. ],
  302. });
  303. const onChange = (e) => {
  304. timeData.value = e;
  305. if (+e.seconds) {
  306. codeText.value = `重新发送(${e.seconds + 1})`;
  307. }
  308. };
  309. const customStyle = reactive({
  310. padding: '0 50rpx',
  311. backgroundColor: '#F6F6F6',
  312. height: '98rpx',
  313. });
  314. const prefixIconStyle = reactive({
  315. // flex上下居中
  316. display: 'flex',
  317. alignItems: 'center',
  318. marginRight: '20rpx',
  319. });
  320. const clickAgrees = () => {
  321. forms.value.aloneChecked = !forms.value.aloneChecked;
  322. };
  323. const sendCode = () => {
  324. debounce(async () => {
  325. upFormRef.value?.validateField('phonenumber', (errorsRes) => {
  326. if (!errorsRes.length) {
  327. getCode();
  328. }
  329. });
  330. }, 500);
  331. };
  332. // 获取验证码
  333. const getCode = async () => {
  334. const res = await useClientRequest.get('/app/auth/sendVercode', { phone: forms.value.phonenumber }, false);
  335. if (res.code === 200) {
  336. uni.showToast({
  337. title: '验证码发送成功',
  338. icon: 'none',
  339. });
  340. countDown.value?.start();
  341. disabled.value = true;
  342. }
  343. };
  344. const save = () => {
  345. debounce(async () => {
  346. upFormRef.value
  347. ?.validate()
  348. .then((res) => {
  349. if (res) {
  350. // 判断是否勾选隐私协议
  351. if (!forms.value.aloneChecked) {
  352. uni.showToast({
  353. title: '请阅读并同意用户协议和隐私政策',
  354. icon: 'none',
  355. });
  356. return;
  357. }
  358. weixinLogin();
  359. }
  360. })
  361. .catch((error) => {});
  362. }, 500);
  363. };
  364. //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  365. onLoad((options) => {
  366. // 获取redirect参数
  367. const redirectStr = options.redirect ? recursiveDecodeURIComponent(options.redirect) : '';
  368. console.log(redirectStr, 'redirectStr');
  369. redirect.value = redirectStr;
  370. // 判断用户是否绑定手机号
  371. hasBindPhone();
  372. });
  373. </script>
  374. <style lang="scss" scoped>
  375. .login-logo-wrap {
  376. width: 750rpx;
  377. height: 550rpx;
  378. margin: auto;
  379. box-sizing: border-box;
  380. }
  381. .bg-circle {
  382. position: absolute;
  383. left: 0;
  384. top: 0;
  385. bottom: 0;
  386. right: 0;
  387. margin: auto;
  388. width: 770rpx;
  389. height: 770rpx;
  390. // 360度旋转
  391. // animation: rotate 10s linear infinite;
  392. }
  393. @keyframes rotate {
  394. from {
  395. transform: rotate(0deg);
  396. }
  397. to {
  398. transform: rotate(360deg);
  399. }
  400. }
  401. .login-logo {
  402. width: 493rpx;
  403. height: 284rpx;
  404. }
  405. .login-form {
  406. // background: linear-gradient(to bottom, #d5f7d6 0%, #daf7da 5px, #def7e0 15px, #fff 20px, #fff 100%);
  407. background-color: #fff;
  408. }
  409. .login-bttom-bg {
  410. position: absolute;
  411. left: 0;
  412. right: 0;
  413. bottom: 0;
  414. width: 687rpx;
  415. margin: auto;
  416. // 不能有事件
  417. pointer-events: none;
  418. }
  419. </style>