小说小程序前端代码仓库(小程序)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

350 lines
7.8 KiB

7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
  1. <template>
  2. <view class="login">
  3. <view class="logo">
  4. <image :src="configList.logo_image" mode=""></image>
  5. </view>
  6. <view class="title">
  7. 欢迎使用{{ configList.logo_name }}
  8. </view>
  9. <view class="btn mt"
  10. @click="handleLogin">
  11. <!-- <view class="icon">
  12. <image src="../static/auth/wx.png" mode=""></image>
  13. </view> -->
  14. <view class="">
  15. 授权登录
  16. </view>
  17. </view>
  18. <view class="btn b2"
  19. @click="qux">
  20. 取消登录
  21. </view>
  22. <view class="config">
  23. <uv-checkbox-group
  24. v-model="checkboxValue"
  25. shape="circle">
  26. <view class="content">
  27. <view
  28. style="display: flex;">
  29. <uv-checkbox
  30. size="40rpx"
  31. icon-size="30rpx"
  32. activeColor="#0A2463"
  33. :name="1"
  34. ></uv-checkbox>
  35. 阅读并同意我们的<text @click="$refs.popup.open('user_xy')">"用户协议"</text>
  36. </view>
  37. <view class="">
  38. 以及<text @click="$refs.popup.open('user_ys')">隐私政策</text>
  39. </view>
  40. </view>
  41. </uv-checkbox-group>
  42. </view>
  43. <configPopup ref="popup"></configPopup>
  44. </view>
  45. </template>
  46. <script>
  47. import SignPackage from '@/utils/share.js'
  48. export default {
  49. name : 'Login',
  50. data() {
  51. return {
  52. checkboxValue : [],
  53. config : {},
  54. }
  55. },
  56. onLoad(query) {
  57. if (query.shareId) {
  58. uni.setStorageSync('shareId', query.shareId)
  59. }
  60. if(query.path){
  61. this.config = query
  62. }
  63. },
  64. // #ifdef H5
  65. mounted() {
  66. // H5环境下检查URL参数,处理微信授权回调
  67. this.checkWechatAuthCallback();
  68. },
  69. // #endif
  70. methods: {
  71. // 微信登录统一入口
  72. handleLogin() {
  73. if(!this.checkboxValue.length){
  74. return uni.showToast({
  75. title: '请先同意隐私协议',
  76. icon:'none'
  77. })
  78. }
  79. // #ifdef MP-WEIXIN
  80. // 小程序环境
  81. this.miniProgramLogin();
  82. // #endif
  83. // #ifdef H5
  84. // H5环境 - 微信公众号授权
  85. this.wechatOfficialLogin();
  86. // #endif
  87. },
  88. // 小程序登录
  89. miniProgramLogin() {
  90. uni.login({
  91. provider: 'weixin',
  92. success: async (res) => {
  93. console.log('小程序登录成功', res);
  94. await this.processLogin(res.code);
  95. },
  96. fail: (err) => {
  97. console.log('小程序登录失败', err);
  98. uni.showToast({
  99. title: '登录失败',
  100. icon: 'none'
  101. });
  102. }
  103. })
  104. },
  105. // 微信公众号授权登录
  106. wechatOfficialLogin() {
  107. console.log('开始微信公众号授权登录');
  108. // 构建微信授权URL
  109. const appId = this.configList.official_appid || 'wx3c85955875a7b099'; // 从配置中获取AppID
  110. const redirectUri = encodeURIComponent(window.location.origin + window.location.pathname + '#/pages_order/auth/wxLogin');
  111. console.log('redirectUri:', window.location.origin + window.location.pathname + '#/pages_order/auth/wxLogin');
  112. const state = Date.now().toString();
  113. // 保存当前邀请人信息
  114. if (uni.getStorageSync('shareId')) {
  115. sessionStorage.setItem('temp_shareId', uni.getStorageSync('shareId'));
  116. }
  117. const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`;
  118. console.log('跳转到微信授权页面:', authUrl);
  119. window.location.href = authUrl;
  120. },
  121. // 检查微信授权回调
  122. checkWechatAuthCallback() {
  123. const code = this.getUrlParameter('code');
  124. const state = this.getUrlParameter('state');
  125. if (code && state) {
  126. console.log('检测到微信授权回调, code:', code, 'state:', state);
  127. // 恢复邀请人信息
  128. const tempShareId = sessionStorage.getItem('temp_shareId');
  129. if (tempShareId) {
  130. uni.setStorageSync('shareId', tempShareId);
  131. sessionStorage.removeItem('temp_shareId');
  132. }
  133. // 处理登录
  134. this.processLogin(code, 'official');
  135. }
  136. },
  137. // 统一登录处理
  138. async processLogin(code, type = 'applet') {
  139. try {
  140. const loginParams = {
  141. code: code,
  142. type
  143. };
  144. // 添加邀请人信息
  145. if (uni.getStorageSync('shareId')) {
  146. loginParams.shareId = uni.getStorageSync('shareId');
  147. }
  148. console.log('登录参数:', loginParams);
  149. // 根据登录类型选择不同的API
  150. const apiName = type === 'official' ? 'officialLogin' : 'wxLogin';
  151. // 调用登录API
  152. this.$api('wxLogin', loginParams, (res) => {
  153. if (res.code == 200) {
  154. uni.setStorageSync('token', res.result.token);
  155. const userInfo = res.result.userInfo;
  156. // 存储用户信息到store
  157. this.$store.state.userInfo = userInfo;
  158. this.$store.state.isLogin = true;
  159. uni.setStorageSync('userInfo', userInfo)
  160. SignPackage()
  161. if (!userInfo.nickName || !userInfo.headImage) {
  162. uni.navigateTo({
  163. url: '/pages_order/auth/wxUserInfo'
  164. });
  165. return;
  166. } else {
  167. uni.showToast({
  168. title: '登录成功',
  169. icon: 'success'
  170. });
  171. uni.navigateBack(-1);
  172. }
  173. } else {
  174. throw new Error(res.msg || '登录失败');
  175. }
  176. });
  177. } catch (error) {
  178. console.error('登录失败:', error);
  179. uni.showToast({
  180. title: '登录失败,请重试',
  181. icon: 'none'
  182. });
  183. // #ifdef H5
  184. // H5环境下如果登录失败,清除URL参数并重新加载页面
  185. if (this.getUrlParameter('code')) {
  186. const cleanUrl = window.location.origin + window.location.pathname + window.location.hash.split('?')[0];
  187. window.history.replaceState({}, document.title, cleanUrl);
  188. }
  189. // #endif
  190. }
  191. },
  192. // 获取URL参数
  193. getUrlParameter(name) {
  194. // #ifdef H5
  195. const url = window.location.href;
  196. try {
  197. const urlParams = new URLSearchParams(window.location.search);
  198. return urlParams.get(name) || '';
  199. } catch (e) {
  200. // 兼容性处理
  201. const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
  202. const results = regex.exec(url);
  203. if (!results) return '';
  204. if (!results[2]) return '';
  205. return decodeURIComponent(results[2].replace(/\+/g, ' '));
  206. }
  207. // #endif
  208. // #ifndef H5
  209. return '';
  210. // #endif
  211. },
  212. getPhoneNumber(e){
  213. console.log(e, e.detail.code);
  214. this.wxLogin(phoneCode)
  215. },
  216. wxLogin(phoneCode){
  217. if(!this.checkboxValue.length){
  218. return uni.showToast({
  219. title: '请先同意隐私协议',
  220. icon:'none'
  221. })
  222. }
  223. this.$store.commit('login', this.config)
  224. },
  225. //打开应用配置
  226. openConfigDetail(key){
  227. this.$refs.popup.open(key)
  228. },
  229. qux(){
  230. uni.reLaunch({
  231. url: '/pages/index/index'
  232. })
  233. },
  234. }
  235. }
  236. </script>
  237. <style scoped lang="scss">
  238. .login{
  239. display: flex;
  240. justify-content: center;
  241. align-items: center;
  242. flex-direction: column;
  243. position: relative;
  244. background-color: #e5eaf9;
  245. min-height: 100vh;
  246. .logo{
  247. margin-top: 120rpx;
  248. height: 140rpx;
  249. width: 140rpx;
  250. image{
  251. height: 140rpx;
  252. width: 140rpx;
  253. border-radius: 30rpx;
  254. }
  255. margin-bottom: 20rpx;
  256. }
  257. .title{
  258. position: relative;
  259. font-weight: 900;
  260. font-size: 45rpx;
  261. &::after{
  262. content: '';
  263. position: absolute;
  264. left: 0;
  265. top: 100%;
  266. display: block;
  267. height: 8rpx;
  268. width: 210rpx;
  269. background: linear-gradient(to right,$uni-color, #fff);
  270. }
  271. }
  272. .btn{
  273. all: unset;
  274. width: 80%;
  275. height: 100rpx;
  276. background-color: $uni-color;
  277. color: #fff;
  278. display: flex;
  279. justify-content: center;
  280. align-items: center;
  281. margin: 20rpx 0;
  282. border-radius: 60rpx;
  283. border: none;
  284. &::after{
  285. }
  286. .icon{
  287. margin-right: 10rpx;
  288. image{
  289. width: 40rpx;
  290. height: 35rpx;
  291. }
  292. }
  293. }
  294. .b2{
  295. background-color: rgba($uni-color, 0.2);
  296. color: $uni-color;
  297. }
  298. .mt{
  299. margin-top: 200rpx;
  300. }
  301. .config{
  302. margin-top: 30rpx;
  303. font-size: 24rpx;
  304. text-align: center;
  305. line-height: 40rpx;
  306. text{
  307. color: $uni-color;
  308. }
  309. }
  310. }
  311. </style>