邃芒智像(Uniapp : WX、TT、H5)
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

781 行
20 KiB

  1. <template>
  2. <view :class="pageClass">
  3. <!-- mode="aspectFit" -->
  4. <image class="bgImg" src="../../assets/img/homeImg.jpg" />
  5. <!-- 视频,已废弃 -->
  6. <view v-show="false" class="videoBox">
  7. <!-- <video
  8. src="https://video.metavatar.cc/sv/d51a6f6-187fa2dff79/d51a6f6-187fa2dff79.mp4"
  9. autoplay
  10. muted
  11. loop
  12. :controls="false"
  13. /> -->
  14. <!-- <video
  15. src="https://wenlian.wenzhou.gov.cn//upload/video/2021-01-14%E3%80%8A%E7%93%AF%E8%B6%8A%E4%B9%8B%E5%8D%8E%E3%80%8B%E6%B8%A0%E5%B7%9D%EF%BC%9A%E8%B5%B0%E7%AC%94%E5%86%99%E4%BA%BA%E7%94%9F.mp4"
  16. autoplay
  17. loop
  18. :controls="false"
  19. /> -->
  20. </view>
  21. <view class="bottomBox">
  22. <button
  23. v-if="!checkboxValue[0] && userInfoModulesPinia.platForm == 2"
  24. class="bottomBtn"
  25. type="default"
  26. id="getPhoneNumber"
  27. @click="toCreate"
  28. >
  29. 开始制作我的数字写真
  30. </button>
  31. <button
  32. v-if="checkboxValue[0] && userInfoModulesPinia.platForm == 2"
  33. class="bottomBtn"
  34. open-type="getPhoneNumber"
  35. type="default"
  36. id="getPhoneNumber"
  37. @getphonenumber="toCreate"
  38. >
  39. 开始制作我的数字写真
  40. </button>
  41. <!-- 抖音获取手机号 -->
  42. <!-- <button
  43. v-if="userInfoModulesPinia.platForm == 3"
  44. class="bottomBtn"
  45. open-type="getPhoneNumber"
  46. type="default"
  47. id="getPhoneNumber"
  48. @getphonenumber="dogetphonenumber"
  49. >
  50. 开始制作我的数字分身
  51. </button> -->
  52. <!-- 手机号登录 -->
  53. <button
  54. v-if="userInfoModulesPinia.platForm == 3"
  55. class="bottomBtn"
  56. type="default"
  57. id="getPhoneNumber"
  58. @click="phoneLogin"
  59. >
  60. 开始制作我的数字分身
  61. </button>
  62. <!-- <view class="bottomBtn" @click="toCreate"> 开始制作我的数字写真 </view> -->
  63. <!-- 同意协议 -->
  64. <u-checkbox-group
  65. v-if="userInfoModulesPinia.platForm == 2"
  66. v-model="checkboxValue"
  67. placement="row"
  68. @change="changedCheckbox"
  69. >
  70. <u-checkbox
  71. labelColor="white"
  72. activeColor="red"
  73. v-for="(item, index) in checkboxList"
  74. :name="item.name"
  75. :key="index"
  76. >
  77. </u-checkbox>
  78. <text class="checkPro"
  79. >同意<text class="goPro" @click="goPro">《智像用户使用协议》</text>
  80. </text>
  81. </u-checkbox-group>
  82. </view>
  83. <!-- 手机号验证码登录 -->
  84. <view class="phoneLoginForm" v-show="userInfoModulesPinia.platForm == 3">
  85. <u--form
  86. labelPosition="left"
  87. :model="formData"
  88. :rules="rules"
  89. ref="formRef"
  90. >
  91. <u-form-item
  92. labelWidth="80"
  93. label="手机号"
  94. prop="phoneNum"
  95. borderBottom
  96. ref="form1"
  97. >
  98. <u--input
  99. type="number"
  100. v-model="formData.phoneNum"
  101. border="none"
  102. ></u--input>
  103. </u-form-item>
  104. <!-- 获取验证码 -->
  105. <!-- 验证码 -->
  106. <view class="getCodeBtn" @click="getCode">
  107. {{ backwardsNum < 60 ? backwardsNum + "s" : "发送验证码" }}
  108. </view>
  109. <!-- <view v-if="backwardsNums <= 0" class="getCodeBtn">{{
  110. backwardsNum
  111. }}</view> -->
  112. <u-form-item labelWidth="80" label="验证码 " borderBottom ref="form2">
  113. <u--input
  114. type="number"
  115. v-model="formData.codeNum"
  116. border="none"
  117. ></u--input>
  118. </u-form-item>
  119. </u--form>
  120. <view class="loginBtn" @click="loginByCode">登录</view>
  121. </view>
  122. <view class="outSide" v-if="showPrivacy">
  123. <view class="showPrivacy">
  124. <view class="title">隐私协议更新</view>
  125. <view class="content">
  126. 感谢您一直以来对我们的信任和支持。为了更好地保护您的个人信息安全我们已经更新了隐私协议。如您继续使用我们的服务即表示同意并接受更新后的隐私协议。如您有任何疑问或意见,欢迎您联系我们的客户服务团队。
  127. </view>
  128. <button
  129. class="agree"
  130. type="primary"
  131. open-type="agreePrivacyAuthorization"
  132. @agreeprivacyauthorization="handleAgreePrivacyAuthorization"
  133. >
  134. 同意
  135. </button>
  136. <button class="check" @click="handleOpenPrivacyContract">
  137. 查看《隐私保护指引》
  138. </button>
  139. <image
  140. @click="closePrivacy"
  141. class="delete"
  142. src="../../assets/icon/delete.png"
  143. mode=""
  144. />
  145. </view>
  146. </view>
  147. </view>
  148. </template>
  149. <script setup>
  150. //#region 导入
  151. import { ref, reactive, computed } from "vue";
  152. import { onLoad } from "@dcloudio/uni-app";
  153. import {
  154. loginApi,
  155. loginPhoneApi,
  156. getCodeApi,
  157. loginByCodeApi,
  158. } from "../../api/login.js";
  159. import { userInfoModules } from "@/store/modules/userInfo";
  160. //#endregion
  161. const userInfoModulesPinia = userInfoModules();
  162. const showPrivacy = ref(false);
  163. const pageClass = computed(() => {
  164. if (userInfoModulesPinia.platForm == 1) {
  165. return "page pageH5";
  166. } else {
  167. return "page";
  168. }
  169. });
  170. //#region 勾选和手机号授权
  171. const checkboxValue = ref([]);
  172. const checkboxList = ref([
  173. {
  174. name: "同意智像相机用户使用协议",
  175. },
  176. ]);
  177. function changedCheckbox(e) {
  178. console.log(e);
  179. }
  180. async function dogetphonenumber(e) {
  181. console.log(e, "e");
  182. if (e.detail.errMsg.includes("ok")) {
  183. // if (e.detail.errMsg.includes("fail")) {
  184. //用户授权了手机号
  185. const data = {
  186. appId: userInfoModulesPinia.getAppId(),
  187. openId: userInfoModulesPinia.openId,
  188. encryptedData: e.detail.encryptedData,
  189. iv: e.detail.iv,
  190. uid: urlUid.value,
  191. };
  192. try {
  193. const res2 = await loginPhoneApi(data);
  194. uni.showToast({
  195. icon: "none",
  196. title: "获取成功",
  197. });
  198. userInfoModulesPinia.token = res2.data.token;
  199. uni.switchTab({
  200. url: "/pages/uploadPhoto/uploadPhoto",
  201. });
  202. } catch (error) {
  203. uni.showToast({
  204. icon: "none",
  205. title: "获取手机号失败",
  206. });
  207. }
  208. } else {
  209. uni.showToast({
  210. icon: "none",
  211. title: "获取手机号失败",
  212. });
  213. //code已过期 重新拿code再授权
  214. }
  215. }
  216. async function toCreate(e) {
  217. console.log();
  218. if (checkboxValue.value[0]) {
  219. // await handleLogin();
  220. await dogetphonenumber(e);
  221. } else {
  222. uni.showModal({
  223. title: "提示",
  224. content: "同意智像相机用户使用协议?",
  225. success: function (res) {
  226. if (res.confirm) {
  227. checkboxValue.value = ["同意智像相机用户使用协议"];
  228. // handleLogin();
  229. dogetphonenumber(e);
  230. } else if (res.cancel) {
  231. }
  232. },
  233. fail: (err) => {},
  234. });
  235. }
  236. }
  237. const userInfo = ref(null);
  238. async function handleLogin() {
  239. // uni.getUserInfo({});
  240. // getPhoneNumber
  241. // getUserProfile
  242. uni.getUserProfile({
  243. desc: "用于完善用户信息",
  244. success: async (res1) => {
  245. console.log(res1);
  246. userInfo.value = res1.userInfo;
  247. userInfoModulesPinia.userInfo = res1.userInfo;
  248. console.log(userInfoModulesPinia.openId, "拿出openid");
  249. const data = {
  250. appId: "wx75cf14e3a0d45821",
  251. openId: userInfoModulesPinia.openId,
  252. encryptedData: res1.encryptedData,
  253. iv: res1.iv,
  254. };
  255. try {
  256. const res2 = await loginPhoneApi(data);
  257. uni.showToast({
  258. icon: "none",
  259. title: "获取成功",
  260. });
  261. } catch (error) {
  262. uni.showToast({
  263. icon: "none",
  264. title: "获取失败",
  265. });
  266. }
  267. },
  268. fail: (err) => {
  269. console.log(err);
  270. uni.showToast({
  271. icon: "none",
  272. title: "用户拒绝获取",
  273. });
  274. },
  275. });
  276. }
  277. const goPro = () => {
  278. uni.navigateTo({
  279. url: "/pages/protocol/user",
  280. });
  281. };
  282. //#endregion ---------------------
  283. //#region 抖音手机号登录
  284. const formData = ref({
  285. phoneNum: null,
  286. codeNum: null,
  287. });
  288. const rules = {
  289. phoneNum: [
  290. {
  291. required: true,
  292. message: "请填写手机号",
  293. trigger: ["blur"],
  294. },
  295. {
  296. // 自定义验证函数,见上说明
  297. validator: (rule, value, callback) => {
  298. // 上面有说,返回true表示校验通过,返回false表示不通过
  299. // uni.$u.test.mobile()就是返回true或者false的
  300. return uni.$u.test.mobile(value);
  301. },
  302. message: "手机号码不正确",
  303. // 触发器可以同时用blur和change
  304. trigger: ["blur"],
  305. },
  306. ],
  307. };
  308. const formRef = ref(null);
  309. const form1 = ref(null);
  310. const backwardsNum = ref(60);
  311. const countdownTimer = ref(null); // 倒计时的计时器
  312. const timerFlag = ref(false);
  313. function getCode() {
  314. if (timerFlag.value) {
  315. return; // 如果倒计时尚未结束,不执行倒计时操作
  316. }
  317. timerFlag.value = true;
  318. formRef.value
  319. .validate()
  320. .then(async (res) => {
  321. try {
  322. uni.showLoading({
  323. title: "请稍后",
  324. mask: true,
  325. });
  326. const res = await getCodeApi(formData.value.phoneNum);
  327. console.log(res.code, "duanxing");
  328. uni.hideLoading();
  329. if (res.code != 200) {
  330. uni.showToast({
  331. title: res.message,
  332. icon: "none",
  333. });
  334. }
  335. console.log(res);
  336. // 表单验证通过后开始倒计时
  337. countdownTimer.value = setInterval(() => {
  338. if (backwardsNum.value > 0) {
  339. backwardsNum.value--;
  340. } else {
  341. clearInterval(countdownTimer.value);
  342. countdownTimer.value = null;
  343. backwardsNum.value = 60;
  344. timerFlag.value = false;
  345. }
  346. }, 1000);
  347. } catch (error) {
  348. uni.hideLoading();
  349. uni.$u.toast("短信验证码获取失败");
  350. clearInterval(countdownTimer.value);
  351. countdownTimer.value = null;
  352. backwardsNum.value = 5;
  353. timerFlag.value = false;
  354. }
  355. })
  356. .catch((errors) => {
  357. console.log(errors);
  358. });
  359. }
  360. async function loginByCode() {
  361. uni.showLoading({
  362. title: "请稍后",
  363. mask: true,
  364. });
  365. const data = {
  366. appId: userInfoModulesPinia.getAppId(),
  367. openId: userInfoModulesPinia.openId,
  368. phone: formData.value.phoneNum,
  369. code: formData.value.codeNum,
  370. };
  371. try {
  372. const res = await loginByCodeApi(data);
  373. console.log(res);
  374. uni.hideLoading();
  375. userInfoModulesPinia.token = res.data.token;
  376. console.log(res.code, "denglu");
  377. if (res.code != 200) {
  378. uni.showToast({
  379. title: res.message,
  380. icon: "none",
  381. });
  382. } else {
  383. // uni.switchTab({
  384. // url: "/pages/uploadPhoto/uploadPhoto",
  385. // });
  386. }
  387. } catch (error) {
  388. uni.hideLoading();
  389. uni.showToast({
  390. title: "登录失败,请重试",
  391. icon: "none",
  392. });
  393. }
  394. }
  395. //#endregion ---------------------
  396. //#region 隐私协议
  397. const getPrivacySetting = (num) => {
  398. const canIUsePrivacy = wx.canIUse("getPrivacySetting");
  399. // console.log(canIUsePrivacy, "canIUse getPrivacySetting");
  400. if (canIUsePrivacy) {
  401. wx.getPrivacySetting({
  402. success: (res) => {
  403. // console.log(res, "getPrivacySetting"); // 返回结果为: res = { needAuthorization: true/false, privacyContractName: '《xxx隐私保护指引》' }
  404. if (res.needAuthorization) {
  405. // 需要弹出隐私协议
  406. showPrivacy.value = true;
  407. } else {
  408. // 用户已经同意过隐私协议,所以不需要再弹出隐私协议,也能调用已声明过的隐私接口
  409. if (num == 1) {
  410. // 返回token,直接跳转首页
  411. // uni.switchTab({
  412. // url: "/pages/uploadPhoto/uploadPhoto",
  413. // });
  414. } else if (num == 2) {
  415. // 没有返回token,无事发生
  416. }
  417. }
  418. },
  419. fail: () => {},
  420. complete: () => {},
  421. });
  422. }
  423. };
  424. // 关闭弹框直接退出小程序,仅对微信小程序生效
  425. const closePrivacy = () => {
  426. wx.exitMiniProgram();
  427. };
  428. const handleAgreePrivacyAuthorization = () => {
  429. // console.log("Privacy Agreed!");
  430. showPrivacy.value = false;
  431. // 用户同意隐私协议事件回调
  432. // 用户点击了同意,之后所有已声明过的隐私接口和组件都可以调用了
  433. };
  434. const handleOpenPrivacyContract = () => {
  435. // 打开隐私协议页面
  436. wx.openPrivacyContract({
  437. success: () => {}, // 打开成功
  438. fail: () => {}, // 打开失败
  439. complete: () => {},
  440. });
  441. };
  442. //#endregion ---------------------------------
  443. //#region 初始化
  444. const urlUid = ref(""); //通过邀请来的会携带邀请人ID参数
  445. onLoad((options) => {
  446. // 二维码扫描进入时
  447. if (options.scene) {
  448. const str = decodeURIComponent(options.scene);
  449. const regex = /_u:(\d+)/; // 正则表达式匹配_u:后面的数字
  450. const match = str.match(regex);
  451. urlUid.value = match[1];
  452. }
  453. // 分享链接进入时
  454. else if (options.userId) {
  455. urlUid.value = options.userId;
  456. } else {
  457. urlUid.value = null;
  458. }
  459. console.log(urlUid.value, "邀请人id");
  460. uni.hideHomeButton();
  461. // workId.value = options.id;
  462. if (options.type == "tokenFfalse") {
  463. uni.showToast({
  464. title: "登录失效,请重新登录",
  465. icon: "none",
  466. });
  467. }
  468. if (userInfoModulesPinia.platForm == 2) {
  469. uni.login({
  470. provider: "weixin", // 使用微信登录授权
  471. success: async (res) => {
  472. if (res.code) {
  473. try {
  474. uni.showLoading({
  475. title: "加载中...",
  476. mask: true,
  477. });
  478. const data = {
  479. appId: userInfoModulesPinia.getAppId(),
  480. code: res.code,
  481. };
  482. const res2 = await loginApi(data);
  483. userInfoModulesPinia.openId = res2.data.openId;
  484. if (res2.data.token) {
  485. userInfoModulesPinia.token = res2.data.token;
  486. // uni.setStorageSync("token", userInfoModulesPinia.token);
  487. console.log(userInfoModulesPinia.openId, "获取openid");
  488. // 获取头像和金币
  489. // const res3 = await findImageApi();
  490. // userInfoModulesPinia.myAvatar =
  491. // res3.data && res3.data.image ? res3.data.image : "";
  492. // const res4 = await findGlodApi();
  493. // if (!res4.data) {
  494. // userInfoModulesPinia.myGlod = 0;
  495. // } else {
  496. // userInfoModulesPinia.myGlod = res4.data.digitalAvatarResidueGlod
  497. // ? res4.data.digitalAvatarResidueGlod
  498. // : 0;
  499. // }
  500. uni.hideLoading();
  501. if (res2.data.token) {
  502. getPrivacySetting(1);
  503. } else {
  504. console.log("error1");
  505. uni.showToast({
  506. title: "登录失败,请重试",
  507. icon: "none",
  508. });
  509. }
  510. } else {
  511. getPrivacySetting(2);
  512. }
  513. uni.hideLoading();
  514. } catch (error) {
  515. // uni.redirectTo({
  516. // url: "pages/index/index",
  517. // });
  518. console.log(error, "error2");
  519. uni.showToast({
  520. title: "登录失败,请重试",
  521. icon: "none",
  522. });
  523. }
  524. } else {
  525. // uni.redirectTo({
  526. // url: "pages/index/index",
  527. // });
  528. console.log("error3");
  529. uni.showToast({
  530. title: "登录失败,请重试",
  531. icon: "none",
  532. });
  533. }
  534. },
  535. fail: (err) => {
  536. // uni.redirectTo({
  537. // url: "pages/index/index",
  538. // });
  539. console.log("error4");
  540. uni.showToast({
  541. title: "登录失败,请重试",
  542. icon: "none",
  543. });
  544. },
  545. });
  546. }
  547. // 抖音头条授权
  548. else if (userInfoModulesPinia.platForm == 3) {
  549. uni.login({
  550. provider: "toutiao", // 使用微信登录授权
  551. success: async (res) => {
  552. if (res.code) {
  553. try {
  554. uni.showLoading({
  555. title: "加载中...",
  556. mask: true,
  557. });
  558. const data = {
  559. appId: userInfoModulesPinia.getAppId(),
  560. code: res.code,
  561. };
  562. const res2 = await loginApi(data);
  563. userInfoModulesPinia.openId = res2.data.openId;
  564. if (res2.data.token) {
  565. userInfoModulesPinia.token = res2.data.token;
  566. // uni.setStorageSync("token", userInfoModulesPinia.token);
  567. console.log(userInfoModulesPinia.openId, "获取openid");
  568. uni.hideLoading();
  569. } else {
  570. uni.hideLoading();
  571. // uni.redirectTo({
  572. // url: "/pages/login/index",
  573. // });
  574. console.log("error1");
  575. uni.showToast({
  576. title: "登录失败,请重试",
  577. icon: "none",
  578. });
  579. }
  580. uni.hideLoading();
  581. } catch (error) {
  582. uni.hideLoading();
  583. console.log(error, "error2");
  584. uni.showToast({
  585. title: "登录失败,请重试",
  586. icon: "none",
  587. });
  588. }
  589. } else {
  590. console.log("error3");
  591. uni.showToast({
  592. title: "登录失败,请重试",
  593. icon: "none",
  594. });
  595. }
  596. },
  597. fail: (err) => {
  598. console.log("error4");
  599. uni.showToast({
  600. title: "登录失败,请重试",
  601. icon: "none",
  602. });
  603. },
  604. });
  605. }
  606. });
  607. //#endregion ---------------------------------
  608. //#region
  609. //#endregion ---------------------------------
  610. </script>
  611. <style lang="scss">
  612. .page {
  613. position: relative;
  614. padding: 0;
  615. min-height: 100vh;
  616. }
  617. .bgImg {
  618. width: 750rpx;
  619. height: 100vh;
  620. }
  621. .videoBox {
  622. width: 750rpx;
  623. height: 1120rpx;
  624. // aspect-ratio: 9/12;
  625. video {
  626. width: 100%;
  627. height: 100%;
  628. // aspect-ratio: 9/12;
  629. }
  630. }
  631. .bottomBox {
  632. position: absolute;
  633. bottom: 0;
  634. width: 100%;
  635. height: 345rpx;
  636. display: flex;
  637. flex-direction: column;
  638. align-items: center;
  639. background-color: rgba(0, 0, 0, 0.8);
  640. color: #fff !important;
  641. .bottomBtn {
  642. margin-top: 55rpx;
  643. margin-bottom: 65rpx;
  644. width: 520rpx;
  645. height: 100rpx;
  646. border-radius: 50rpx;
  647. line-height: 100rpx;
  648. text-align: center;
  649. color: #fff;
  650. background-color: rgba(255, 79, 0, 1);
  651. font-size: 30rpx;
  652. font-weight: 900;
  653. }
  654. .checkPro {
  655. display: inline-block;
  656. height: 27rpx;
  657. line-height: 54rpx;
  658. .goPro {
  659. color: #ff4f00;
  660. }
  661. }
  662. }
  663. .phoneLoginForm {
  664. position: absolute;
  665. top: 20%;
  666. left: 30rpx;
  667. width: 690rpx;
  668. z-index: 9;
  669. background-color: #fff;
  670. padding: 30rpx;
  671. .u-code {
  672. width: 100%;
  673. height: 50rpx;
  674. background-color: green;
  675. color: #ff4f00;
  676. }
  677. .getCodeBtn {
  678. background-color: green;
  679. text-align: center;
  680. line-height: 50rpx;
  681. }
  682. .loginBtn {
  683. background-color: #ff4f00;
  684. text-align: center;
  685. line-height: 50rpx;
  686. }
  687. }
  688. .outSide {
  689. position: fixed;
  690. top: 0;
  691. left: 0;
  692. width: 100%;
  693. height: 100%;
  694. color: #000000;
  695. background-color: #00000059;
  696. .showPrivacy {
  697. position: fixed;
  698. width: 520rpx;
  699. background-color: #fff;
  700. left: 50%;
  701. top: 50%;
  702. transform: translate(-50%, -50%);
  703. padding: 60rpx 50rpx;
  704. border-radius: 20rpx;
  705. box-shadow: #00000047 2px 1px 2px 2px;
  706. .title {
  707. text-align: center;
  708. font-size: 30rpx;
  709. font-weight: 600;
  710. }
  711. .content {
  712. text-indent: 2em;
  713. margin: 40rpx 0;
  714. }
  715. button {
  716. width: 350rpx;
  717. &.agree {
  718. margin-bottom: 25rpx;
  719. background-color: #ff4f00;
  720. }
  721. &.check {
  722. background-color: #ffffff00;
  723. font-size: 21rpx;
  724. text-decoration: underline;
  725. padding: 0;
  726. &::after {
  727. border: none;
  728. }
  729. }
  730. }
  731. .delete {
  732. position: absolute;
  733. top: 15rpx;
  734. right: 15rpx;
  735. width: 65rpx;
  736. height: 65rpx;
  737. }
  738. }
  739. }
  740. </style>