小说小程序前端代码仓库(小程序)
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.

351 lines
7.8 KiB

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