uniapp,h5

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <template>
  2. <view class="page">
  3. <view class="logo">
  4. <image src="../../../static/logo.png"></image>
  5. </view>
  6. <template v-if="type === 0">
  7. <view class="input">
  8. <input v-model="form_username" placeholder="请输入用户名" />
  9. </view>
  10. <view class="input">
  11. <input v-model="form_password" type="password" placeholder="请输入密码" />
  12. </view>
  13. </template>
  14. <template v-if="type === 1">
  15. <view class="input">
  16. <input v-model="form_tel" type="tel" maxlength="11" placeholder="请输入手机号" />
  17. </view>
  18. <view class="input">
  19. <input v-model="form_code" placeholder="请输入验证码" />
  20. <view class="send_button" @click="sendCode()">
  21. <text v-if="!send_count_down">发送验证码</text>
  22. <text v-else>重新发送 {{send_count_down}} S</text>
  23. </view>
  24. </view>
  25. </template>
  26. <view class="underlinecontainer">
  27. <view class="typeleft" @click="changeType()">
  28. <text v-if="type === 0">短信验证码登录</text>
  29. <text v-else>用户名密码登录</text>
  30. </view>
  31. <view class="typeright" @click="registerUserInfo()">
  32. <text class="a">没有用户名?点击注册</text>
  33. </view>
  34. </view>
  35. <view class="button">
  36. <button @click="login()">登录</button>
  37. </view>
  38. <view class="tip">
  39. <checkbox-group @change="privacyChange">
  40. <checkbox value="privacy" color="#0068B7" style="transform:scale(0.7)" />
  41. </checkbox-group>
  42. <text>
  43. 我已阅读并同意<text class="a">《隐私政策》</text>和<text class="a">《服务协议》</text>
  44. </text>
  45. </view>
  46. </view>
  47. </template>
  48. <script>
  49. import { storeJwtInfo2User } from '@/utils/storage.js';
  50. // 引入解析JWT的库
  51. export default {
  52. data() {
  53. return {
  54. type: 0, // 0 用户密码 , 1验证码登录
  55. form_username: '',
  56. form_password: '',
  57. form_tel: '',
  58. form_code: '',
  59. send_count_down: 0, // 验证码重新发送等待倒计时
  60. checked: false
  61. }
  62. },
  63. onLoad() {
  64. },
  65. methods: {
  66. changeType() {
  67. this.type = this.type ? 0 : 1
  68. },
  69. sendCode() {
  70. if (this.send_count_down === 0) {
  71. // 验证手机号规则 调用发送验证码接口
  72. let countDown = 60
  73. this.send_count_down = countDown
  74. let timer = setInterval(() => {
  75. countDown--
  76. this.send_count_down = countDown
  77. if (countDown === 0) {
  78. clearInterval(timer)
  79. }
  80. }, 1000)
  81. }
  82. },
  83. async login() {
  84. if (!this.checked) {
  85. return uni.showToast({
  86. icon: 'none',
  87. title: '请先同意隐私政策和服务协议'
  88. });
  89. }
  90. let loginUrl = this.type === 0 ?
  91. 'https://afanai.top:8089/v1/user/pwdlogin' :
  92. 'https://afanai.top:8089/v1/user/codeLogin';
  93. let loginData = {};
  94. if (this.type === 0) {
  95. // 用户密码登录
  96. loginData = {
  97. username: this.form_username,
  98. password: this.form_password
  99. };
  100. } else {
  101. // 验证码登录
  102. loginData = {
  103. tel: this.form_tel,
  104. code: this.form_code
  105. };
  106. }
  107. uni.showLoading({
  108. title: '登录中...'
  109. });
  110. try {
  111. // 调用登录接口
  112. const res = await uni.request({
  113. url: loginUrl,
  114. method: 'POST',
  115. data: loginData,
  116. header: {
  117. 'content-type': 'application/json'
  118. }
  119. });
  120. // 关闭加载提示
  121. uni.hideLoading();
  122. // 成功响应处理
  123. if (res.statusCode === 200) {
  124. const jwt = res.data.token; // 后端返回的JWT字段名为token
  125. // // 存储JWT,例如存入本地存储
  126. // console.log(jwt);
  127. uni.setStorageSync('jwt', jwt);
  128. storeJwtInfo2User(jwt);
  129. // 存储JWT到Vuex
  130. // this.$store.commit('setToken', {
  131. // token: jwt,
  132. // expiry: new Date().getTime() + 3600 * 1000
  133. // }); // 假设token有效期为1小时,具体时间根据业务调整
  134. // 或者使用dispatch
  135. // this.$store.dispatch('setToken', jwt);
  136. uni.showToast({
  137. title: "登录成功",
  138. icon: 'succeed'
  139. });
  140. // 跳转到主页面
  141. uni.reLaunch({
  142. url: '../tabbar-1/tabbar-1'
  143. });
  144. } else {
  145. try {
  146. // 确保 res.data 是一个对象且包含 error 键
  147. if (res.data && typeof res.data === 'object' && 'error' in res.data) {
  148. uni.showToast({
  149. title: res.data.error,
  150. duration: 2000,
  151. icon: 'none'
  152. });
  153. }
  154. } catch (e) {
  155. // 如果尝试处理 res.data 时出错,显示默认错误信息
  156. uni.showToast({
  157. title: '处理服务器响应时出错',
  158. duration: 2000,
  159. icon: 'none'
  160. });
  161. console.error('Error processing response data:', e);
  162. }
  163. }
  164. } catch (error) {
  165. // 关闭加载提示
  166. uni.hideLoading();
  167. // 错误处理
  168. uni.showToast({
  169. title: '网络错误,请检查网络',
  170. duration: 2000,
  171. icon: 'none'
  172. });
  173. console.error('登录请求出错:', error);
  174. }
  175. },
  176. registerUserInfo() {
  177. uni.navigateTo({
  178. url: "./register"
  179. });
  180. },
  181. privacyChange(e) {
  182. this.checked = e.detail.value.length ? true : false
  183. }
  184. }
  185. }
  186. </script>
  187. <style lang="scss" scoped>
  188. .page {
  189. display: flex;
  190. flex-direction: column;
  191. align-items: center;
  192. min-height: 100vh;
  193. background: #f5f5f5;
  194. .logo {
  195. padding-top: 12vh;
  196. margin-bottom: 30rpx;
  197. image {
  198. width: 280rpx;
  199. height: 280rpx;
  200. }
  201. }
  202. .input {
  203. width: 660rpx;
  204. margin-bottom: 30rpx;
  205. position: relative;
  206. input {
  207. box-sizing: border-box;
  208. width: 660rpx;
  209. height: 80rpx;
  210. border-radius: 40rpx;
  211. padding: 0 40rpx;
  212. background: #fff;
  213. font-size: 14px;
  214. }
  215. .send_button {
  216. position: absolute;
  217. right: 0;
  218. top: 0;
  219. height: 80rpx;
  220. width: 220rpx;
  221. text-align: center;
  222. line-height: 80rpx;
  223. font-size: 12px;
  224. color: #777;
  225. z-index: 99;
  226. }
  227. }
  228. .underlinecontainer {
  229. display: flex;
  230. /* 使用flex布局 */
  231. justify-content: space-between;
  232. /* 使子元素一个靠左,一个靠右 */
  233. .typeleft {
  234. width: 330rpx;
  235. font-size: 12px;
  236. color: #777;
  237. margin-bottom: 30rpx;
  238. text-align: left;
  239. &:active {
  240. color: #333;
  241. }
  242. }
  243. .typeright {
  244. width: 330rpx;
  245. font-size: 12px;
  246. color: #777;
  247. margin-bottom: 30rpx;
  248. text-align: right;
  249. &:active {
  250. color: #333;
  251. }
  252. }
  253. }
  254. .button {
  255. margin-bottom: 30rpx;
  256. button {
  257. width: 660rpx;
  258. height: 80rpx;
  259. line-height: 80rpx;
  260. border-radius: 40rpx;
  261. background: #0068B7;
  262. color: #fff;
  263. font-size: 14px;
  264. &:active {
  265. background: #005694;
  266. }
  267. }
  268. }
  269. .tip {
  270. width: 660rpx;
  271. height: 40rpx;
  272. font-size: 12px;
  273. color: #777;
  274. display: flex;
  275. align-items: center;
  276. .a {
  277. color: #0068B7;
  278. }
  279. }
  280. }
  281. </style>