login.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. <template>
  2. <view id="login" class="section">
  3. <!-- <u-loading-page :loading="true" loading-text="loading..." loading-mode="spinner"></u-loading-page> -->
  4. <view class="bg">
  5. <image class="bgImage" :src="bg" v-if="bg" />
  6. <!-- <image class="bgImage" src="@/static/images/wt/bg.png" v-else /> -->
  7. </view>
  8. <view class="middle">
  9. <view class="top">
  10. <image class="logo" mode="heightFix" :src="logo" v-if="logo" />
  11. <image class="logo" mode="heightFix" src="@/static/logo200.png" v-else />
  12. <text class="title" v-if="title">{{ title }}</text>
  13. <text class="title" v-else>移动端登录</text>
  14. </view>
  15. <view class="content">
  16. <text class="title">请登录</text>
  17. <!-- #ifdef APP-PLUS -->
  18. <view id="okay" v-if="!linkUrl">首次账号登录请先配置服务器</view>
  19. <!-- <u-icon class="icons" name="scan" color="gray" size="22"></u-icon> -->
  20. <view class="setting" @tap="goSeverConfig"> 配置服务器 </view>
  21. <!--#endif-->
  22. </view>
  23. <view id="login-input" v-if="switchText == '账号密码登录'">
  24. <u-input v-model="phone" prefixIcon="phone" placeholder="请输入手机号码" />
  25. </view>
  26. <view id="login-input" v-if="switchText == '账号密码登录'">
  27. <u-input v-model="verify" prefixIcon="email" placeholder="请输入验证码" :maxlength="6">
  28. <template #suffix>
  29. <u-button @click="getVerifyCode">{{ !codeTime ? "获取验证码" : codeTime + "s" }}</u-button>
  30. </template>
  31. </u-input>
  32. </view>
  33. <view id="login-input" v-if="switchText == '验证码登录'">
  34. <u-input type="text" v-model="username" prefixIcon="account" placeholder="请输入账号" />
  35. <u-input v-model="password" prefixIcon="lock" placeholder="请输入密码" :password="inputIconBool">
  36. <template #suffix>
  37. <text :class="!inputIconBool ? 'iconfont ucicon-eye' : 'iconfont ucicon-eye-close'" @click="inputIconBool = !inputIconBool"></text>
  38. </template>
  39. </u-input>
  40. </view>
  41. <!-- -->
  42. <button class="submit" @click="submitRes">登 录</button>
  43. <view class="switchText" @click="switchMode">
  44. <text>{{ switchText }}</text>
  45. </view>
  46. <!-- #ifdef APP-PLUS -->
  47. <view class="xieyi text-center">
  48. <u-checkbox-group>
  49. <u-checkbox v-model="userChecked" shape="circle" inactiveColor="#0081ff" size="13"></u-checkbox>
  50. </u-checkbox-group>
  51. <text>我已阅读并同意</text>
  52. <text @click="handleUserAgrement" class="text-blue">用户协议</text>
  53. <text>和</text>
  54. <text @click="handlePrivacy" class="text-blue">隐私协议</text>
  55. </view>
  56. <!--#endif-->
  57. </view>
  58. <view class="bottom">
  59. <div class="title">{{ bottomTitle }}</div>
  60. </view>
  61. </view>
  62. </template>
  63. <script setup>
  64. import { onLoad, onShow, onHide, onLaunch, onReady } from "@dcloudio/uni-app";
  65. import { reactive, getCurrentInstance, toRefs, inject, watchEffect } from "vue";
  66. import { getToken, setToken, removeToken } from "@/utils/auth";
  67. import { getCodeImg, getMobileTenantConfig } from "@/api/login";
  68. import publicStore from "@/store/modules/public.js";
  69. import useStores from "@/store/modules/user.js";
  70. const useStore = useStores();
  71. const newPublicStore = publicStore();
  72. const { proxy } = getCurrentInstance();
  73. const data = reactive({
  74. /** saas数据 */
  75. bg: "",
  76. logo: "",
  77. title: "",
  78. bottomTitle: "",
  79. /** login数据 */
  80. phone: undefined,
  81. verify: undefined,
  82. codeTime: 0,
  83. switchText: "验证码登录",
  84. tenantId: undefined,
  85. username: undefined,
  86. password: undefined,
  87. inputIconBool: true,
  88. /** 服务器配置数据 */
  89. linkUrl: uni.getStorageSync("serveUrl"),
  90. /** 用户隐私协议数据 */
  91. userChecked: false,
  92. // VerificationCodeOne
  93. });
  94. const { title, bg, bottomTitle, logo, phone, verify, codeTime, switchText, username, password, tenantId, inputIconBool, linkUrl, userChecked } = toRefs(data);
  95. function goSeverConfig() {
  96. proxy.$tab.navigateTo("/pages/serveConfig");
  97. }
  98. /**登录方式切换 */
  99. function switchMode() {
  100. if (switchText.value == "验证码登录") {
  101. switchText.value = "账号密码登录";
  102. } else {
  103. switchText.value = "验证码登录";
  104. }
  105. }
  106. /** 点击发送验证码 */
  107. function getVerifyCode() {
  108. //#ifdef APP-PLUS
  109. if (!uni.getStorageSync("serveUrl")) {
  110. proxy.$modal.msg("首次登录请先进行服务器配置");
  111. return;
  112. }
  113. //#endif
  114. if (!phone.value) {
  115. proxy.$modal.msg("请输入手机号码");
  116. return;
  117. }
  118. if (!/^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/.test(phone.value)) {
  119. proxy.$modal.msg("请输入正确的手机号码");
  120. return;
  121. }
  122. //#ifdef APP-PLUS
  123. if (userChecked.value) {
  124. proxy.$modal.msg("请在阅读并同意 用户协议和隐私协议后登录");
  125. return;
  126. }
  127. //#endif
  128. verify.value = undefined;
  129. getCodeImg({
  130. phone: phone.value,
  131. }).then((res) => {
  132. console.log(res);
  133. });
  134. if (codeTime.value > 0) {
  135. proxy.$modal.msg("不能重复获取");
  136. return;
  137. } else {
  138. codeTime.value = 60;
  139. let timer = setInterval(() => {
  140. codeTime.value--;
  141. if (codeTime.value < 1) {
  142. clearInterval(timer);
  143. codeTime.value = 0;
  144. }
  145. }, 1000);
  146. }
  147. }
  148. /**
  149. * 判断运行环境
  150. */
  151. function env() {
  152. // const u = navigator.userAgent
  153. // //https://blog.csdn.net/weixin_42659644/article/details/126294231
  154. // if(u.indexOf('saas')>-1){ //指定app内 获取app识别号
  155. // }else{
  156. // }
  157. console.log(window.location.host);
  158. //#ifdef H5
  159. linkUrl.value = window.location.host;
  160. // linkUrl.value = window.location.host;
  161. // linkUrl.value='ces.cn';
  162. // linkUrl.value='172.16.120.165:13203'
  163. getMobileTenantConfigApi({ url: linkUrl.value });
  164. //#endif
  165. // uni.showToast({
  166. // title: '服务器链接地址为'+linkUrl,
  167. // icon: "none",
  168. // })
  169. // let port = uni.getSystemInfoSync().platform;
  170. // switch (port) {
  171. // case "android":
  172. // getMobileTenantConfigApi({ url: window.location.host });
  173. // console.log("Android"); //android
  174. // break;
  175. // case "ios":
  176. // console.log("iOS"); //ios
  177. // getMobileTenantConfigApi({ url: window.location.host });
  178. // break;
  179. // case "windows":
  180. // getMobileTenantConfigApi({ url: window.location.host });
  181. // break;
  182. // default: //devtools
  183. // console.log("小程序");
  184. // break;
  185. // }
  186. }
  187. /** 点击提交按钮 */
  188. function submitRes() {
  189. //#ifdef APP-PLUS
  190. if (!uni.getStorageSync("serveUrl")) {
  191. proxy.$modal.msg("首次登录请先进行服务器配置");
  192. return;
  193. }
  194. //#endif
  195. //#ifdef APP-PLUS
  196. if (userChecked.value) {
  197. proxy.$modal.msg("请在阅读并同意 用户协议和隐私协议后登录");
  198. return;
  199. }
  200. //#endif
  201. if (switchText.value == "账号密码登录") {
  202. if (!phone.value) {
  203. proxy.$modal.msg("请输入手机号码");
  204. return;
  205. }
  206. if (!/^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/.test(phone.value)) {
  207. proxy.$modal.msg("请输入正确的手机号码");
  208. return;
  209. }
  210. if (!verify.value) {
  211. proxy.$modal.msg("请输入验证码");
  212. return;
  213. }
  214. login({
  215. phone: phone.value,
  216. verify: verify.value,
  217. tenantId: tenantId.value,
  218. });
  219. } else {
  220. if (!username.value) {
  221. proxy.$modal.msg("请输入账户");
  222. return;
  223. }
  224. if (!password.value) {
  225. proxy.$modal.msg("请输入密码");
  226. return;
  227. }
  228. login({
  229. username: username.value,
  230. password: password.value,
  231. tenantId: tenantId.value,
  232. });
  233. }
  234. }
  235. /** 获取登录数据 */
  236. function login(data) {
  237. proxy.$modal.loading("登录中,请耐心等待...");
  238. useStore.Login(data).then(() => {
  239. /** 获取用户信息 */
  240. proxy.$modal.closeLoading();
  241. useStore.GetInfo().then((res) => {
  242. proxy.$tab.reLaunch("/pages/index");
  243. });
  244. });
  245. }
  246. /** 获取登录页数据 */
  247. function getMobileTenantConfigApi(params) {
  248. getMobileTenantConfig(params).then((res) => {
  249. if (res.data.length > 0) {
  250. let data = res.data[0];
  251. title.value = data.loginTitle;
  252. bottomTitle.value = data.loginFooter;
  253. tenantId.value = data.tenantId;
  254. bg.value = data.loginBackUrl;
  255. logo.value = data.loginLogo;
  256. uni.setStorageSync("homeTitle", data.loginTitle);
  257. }
  258. });
  259. }
  260. // 用户协议
  261. function handleUserAgrement() {
  262. let site = getApp().globalData.config.appInfo.agreements[0];
  263. proxy.$tab.navigateTo(`/pages/common/textview/index1?title=${site.title}&content=${site.content}`);
  264. }
  265. // 隐私协议
  266. function handlePrivacy() {
  267. let site = getApp().globalData.config.appInfo.agreements[1];
  268. proxy.$tab.navigateTo(`/pages/common/textview/index1?title=${site.title}&content=${site.content}`);
  269. }
  270. watchEffect(() => {
  271. //#ifdef APP-PLUS
  272. if (uni.getStorageSync("serveUrl")) {
  273. linkUrl.value = uni.getStorageSync("serveUrl");
  274. getMobileTenantConfigApi({ url: linkUrl.value });
  275. }
  276. //#endif
  277. });
  278. /**
  279. * @onLoad
  280. */
  281. onLoad(() => {
  282. env();
  283. const token = getToken();
  284. //需要登录
  285. if (token) {
  286. uni.switchTab({
  287. url: "/pages/index",
  288. });
  289. }
  290. });
  291. // onReady(() => {
  292. // //动态修改状态栏的颜色
  293. // uni.setNavigationBarColor({
  294. // frontColor: "#000000",
  295. // backgroundColor: "#ff0000",
  296. // });
  297. // });
  298. </script>
  299. <style>
  300. page {
  301. background-color: #ffffff;
  302. }
  303. </style>
  304. <style lang="scss" scoped>
  305. .section {
  306. display: flex;
  307. width: 100%;
  308. height: 100%;
  309. .bg {
  310. width: 100%;
  311. height: 100%;
  312. position: fixed;
  313. top: 0;
  314. left: 0;
  315. right: 0;
  316. z-index: 0;
  317. .bgImage {
  318. width: 100%;
  319. height: 100%;
  320. }
  321. }
  322. .middle {
  323. position: relative;
  324. z-index: 1;
  325. width: 100%;
  326. padding: 0 40px;
  327. margin: auto;
  328. margin-top: 30%;
  329. #login-input {
  330. .u-input {
  331. height: 45px;
  332. border-radius: 8px;
  333. padding: 5px 12px !important;
  334. border: 0 !important;
  335. // border-color: #000 !important;
  336. // border-color: gray !important;
  337. // background-color: rgba(255, 255, 255, 0.1) !important;
  338. background-color: #f5f6fa !important;
  339. margin-bottom: 20px;
  340. }
  341. :deep(.input-placeholder) {
  342. color: #96a6b5 !important;
  343. }
  344. :deep(.uni-input-wrapper) {
  345. font-size: 16px;
  346. }
  347. :deep(.u-icon__icon) {
  348. font-size: 24px !important;
  349. line-height: 24px !important;
  350. color: gray !important;
  351. }
  352. :deep(.iconfont) {
  353. color: gray !important;
  354. }
  355. :deep(:-webkit-autofill) {
  356. caret-color: #000; // 设置光标颜色
  357. // -webkit-text-fill-color: gray !important;
  358. -webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
  359. background-color: transparent;
  360. background-image: none;
  361. transition: background-color 50000s ease-in-out 0s; //背景色透明 生效时长 过渡效果 启用时延迟的时间
  362. }
  363. :deep(.u-button) {
  364. color: #2a98ff;
  365. font-size: 16px !important;
  366. white-space: nowrap;
  367. border: 0;
  368. border-color: #2a98ff !important;
  369. background-color: rgba(255, 255, 255, 0) !important;
  370. &:before {
  371. opacity: 0;
  372. }
  373. }
  374. }
  375. .top {
  376. display: flex;
  377. align-items: center;
  378. justify-content: center;
  379. margin-bottom: 60px;
  380. :deep(uni-image) {
  381. height: 40px;
  382. // width:40px;
  383. width: auto;
  384. }
  385. .logo {
  386. margin-right: 10px;
  387. }
  388. .title {
  389. font-size: 20px;
  390. color: #000;
  391. max-width: 50%;
  392. white-space: nowrap;
  393. }
  394. }
  395. .content {
  396. display: flex;
  397. position: relative;
  398. margin: 30px 0 30px 0;
  399. .title {
  400. margin: auto auto auto 0;
  401. color: #000;
  402. font-size: 18px;
  403. }
  404. .icons {
  405. margin: auto 5px auto 0;
  406. }
  407. .setting {
  408. color: #2a98ff;
  409. margin: auto 0;
  410. }
  411. #okay {
  412. position: absolute;
  413. top: -35px;
  414. right: 0px;
  415. background-color: #2a98ff;
  416. text-align: center;
  417. line-height: 25px;
  418. display: inline-block;
  419. color: #fff;
  420. padding: 3px 5px;
  421. border-radius: 3px;
  422. }
  423. #okay::after {
  424. content: "";
  425. position: absolute;
  426. border: 5px solid transparent;
  427. transform: rotate(90deg);
  428. right: 5px;
  429. bottom: -9px;
  430. border-left-color: #2a98ff;
  431. }
  432. }
  433. .switchText {
  434. color: #96a6b5;
  435. width: 100%;
  436. display: block;
  437. margin-top: 20px;
  438. }
  439. .submit {
  440. height: 45px;
  441. line-height: 45px;
  442. border-radius: 24px;
  443. background: #2a98ff;
  444. color: #fff;
  445. border: 0px;
  446. }
  447. .xieyi {
  448. color: #96a6b5;
  449. margin-top: 30px;
  450. display: flex;
  451. justify-content: center;
  452. > uni-view {
  453. margin: auto 0;
  454. }
  455. > uni-text {
  456. margin: auto 0;
  457. }
  458. // animation: roundRule 0.5s linear infinite;
  459. }
  460. @keyframes roundRule {
  461. 0% {
  462. transform: translateX(0);
  463. }
  464. 50% {
  465. transform: translateX(-5px);
  466. }
  467. 100% {
  468. transform: translateX(0);
  469. }
  470. }
  471. }
  472. .bottom {
  473. position: absolute;
  474. width: 100%;
  475. bottom: 10px;
  476. .title {
  477. text-align: center;
  478. color: #000;
  479. font-size: 14px;
  480. }
  481. }
  482. .iconfont {
  483. color: #999;
  484. }
  485. }
  486. </style>