邃芒智像(Uniapp : WX、TT、H5)
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.
 
 
 
 

608 line
16 KiB

  1. <template>
  2. <view class="page">
  3. <view class="title">
  4. <!-- 提示文字 -->
  5. <text v-show="uploadState == 1" class="tips">请添加一张正面照片</text>
  6. <text v-show="uploadState == 2" class="tips">请点击上传</text>
  7. <text v-show="uploadState == 3" class="tips">数字形象生成中</text>
  8. <text v-show="uploadState == 4" class="tips"
  9. >照片不符合规范,请重新上传</text
  10. >
  11. <text v-show="uploadState == 5" class="tips">上传失败,请重新上传</text>
  12. </view>
  13. <!-- 上传图片和展示 -->
  14. <view class="uploadBox imgContenBox scan" @click.stop="chooseImage">
  15. <!-- 扫描线 -->
  16. <view v-show="uploadState == 3" class="scan-line"></view>
  17. <image
  18. class="scan-border"
  19. src="../../assets/img/scanBorder.png"
  20. mode="aspectFit"
  21. />
  22. <!-- 上传按钮 -->
  23. <image
  24. class="addImg"
  25. v-show="!showImgUrl"
  26. src="../../assets/icon/add.png"
  27. alt=""
  28. />
  29. <!-- @click.prevent="chooseImage" -->
  30. <image
  31. class="showImg"
  32. v-show="showImgUrl"
  33. :src="showImgUrl"
  34. alt=""
  35. mode="aspectFit"
  36. />
  37. </view>
  38. <view class="uploadBtn">
  39. <view @click="toCloseStyle" class="orangeBtn">上传新头像</view>
  40. <view
  41. class="grayBtn"
  42. v-if="userInfoModulesPinia.myAvatar"
  43. @click="goOtherPage('/pages/closeStyle/closeStyle')"
  44. >已有形象,直接创作</view
  45. >
  46. <view class="grayBtn" v-if="uploadState == 4" @click="chooseImage"
  47. >重新上传</view
  48. >
  49. <view class="free">
  50. <image src="../../assets/icon/blackBG.png" mode="aspectFit" />
  51. <text>新用户免费制作</text>
  52. </view>
  53. </view>
  54. <!-- 底部盒子 -->
  55. <view class="bottomBox">
  56. <view class="tips2">请按照样片上传您五官清晰的正面照片</view>
  57. <view class="demoImgBox">
  58. <view class="imgBox">
  59. <image src="../../assets/img/img1.png" mode="aspectFit" />
  60. <view class="icon">
  61. <image src="../../assets/icon/error.png" mode="aspectFit" />
  62. </view>
  63. </view>
  64. <view class="imgBox">
  65. <image
  66. class="rightImg"
  67. src="../../assets/img/img2.png"
  68. mode="aspectFit"
  69. />
  70. <view class="icon">
  71. <image src="../../assets/icon/correct.png" mode="aspectFit" />
  72. </view>
  73. </view>
  74. <view class="imgBox">
  75. <image src="../../assets/img/img3.png" mode="aspectFit" />
  76. <view class="icon">
  77. <image src="../../assets/icon/error.png" mode="aspectFit" />
  78. </view>
  79. </view>
  80. </view>
  81. </view>
  82. </view>
  83. </template>
  84. <script setup>
  85. //#region 导入
  86. import { ref, reactive, nextTick } from "vue";
  87. import {
  88. onLoad,
  89. onShareAppMessage,
  90. onShareTimeline,
  91. onAddToFavorites,
  92. onShow,
  93. } from "@dcloudio/uni-app";
  94. import { loginApi } from "../../api/login";
  95. import { addImageApi } from "../../api/uploadphoto.js";
  96. import { userInfoModules } from "@/store/modules/userInfo";
  97. import imageCompression from "browser-image-compression"; //压缩图片插件
  98. import { findImageApi, findGlodApi } from "../../api/home";
  99. //#endregion
  100. const userInfoModulesPinia = userInfoModules();
  101. //#region 选择图片
  102. const uploadState = ref(1); //上传状态
  103. const showImgUrl = ref(""); //回显路径 压缩
  104. const showImgUrl2 = ref(null); //回显路径 未压缩
  105. const showImgData = ref(null); //上传数据
  106. // 点击上传图片
  107. function chooseImage() {
  108. console.log("chooseImage");
  109. // 检查token
  110. if (!userInfoModulesPinia.token) {
  111. uni.showModal({
  112. title: "提示",
  113. content: "登录以体验完整功能",
  114. success: function (res) {
  115. if (res.confirm) {
  116. uni.navigateTo({
  117. url: "/pages/login/index",
  118. });
  119. return;
  120. } else if (res.cancel) {
  121. console.log("用户点击取消");
  122. return;
  123. }
  124. },
  125. });
  126. } else {
  127. // 调用uni.chooseImage方法选择图片
  128. uni.chooseImage({
  129. count: 1, // 最多可以选择的图片张数,这里设置为1,只选择一张图片
  130. success: async (res) => {
  131. uploadState.value = 2;
  132. // 图片压缩
  133. console.log(res.tempFiles[0].size);
  134. showImgUrl2.value = res.tempFiles[0];
  135. if (userInfoModulesPinia.platForm != 1) {
  136. uni.compressImage({
  137. src: res.tempFilePaths[0],
  138. quality: 40,
  139. success: (res2) => {
  140. showImgUrl.value = res2.tempFilePath;
  141. toCloseStyle();
  142. },
  143. });
  144. } else {
  145. const options = {
  146. maxSizeMB: 2, // 最大压缩大小为 4MB
  147. useWebWorker: true, // 使用 Web Worker 进行压缩,提高性能
  148. };
  149. const compressedFile = await imageCompression(
  150. res.tempFiles[0],
  151. options
  152. );
  153. //compressedFile是一个blob对象
  154. showImgUrl.value = URL.createObjectURL(compressedFile);
  155. showImgData.value = compressedFile;
  156. }
  157. },
  158. fail: (err) => {
  159. console.error("选择图片失败", err);
  160. },
  161. });
  162. }
  163. }
  164. //#endregion ---------------------
  165. //#region 上传图片
  166. // console.log(userInfoModulesPinia.token, "token");
  167. async function toCloseStyle() {
  168. // 检查token
  169. if (!userInfoModulesPinia.token) {
  170. uni.showModal({
  171. title: "提示",
  172. content: "登录以体验完整功能",
  173. success: function (res) {
  174. if (res.confirm) {
  175. uni.navigateTo({
  176. url: "/pages/login/index",
  177. });
  178. return;
  179. } else if (res.cancel) {
  180. console.log("用户点击取消");
  181. return;
  182. }
  183. },
  184. });
  185. } else {
  186. if (!showImgUrl.value) {
  187. uni.showToast({
  188. title: "请先上传图片",
  189. icon: "none",
  190. });
  191. chooseImage();
  192. return;
  193. }
  194. uni.showLoading({
  195. title: "上传中...",
  196. mask: true,
  197. });
  198. uploadState.value = 3;
  199. console.log(showImgUrl.value);
  200. console.log(showImgUrl2.value.path);
  201. // 百度敏感信息检测
  202. uni.uploadFile({
  203. url: "https://test.metavatar.cc/C/api/baidu/checkPhoto", //上传图片api
  204. filePath: showImgUrl2.value.path,
  205. name: "file",
  206. formData: {
  207. user: "test",
  208. },
  209. header: {
  210. // Authorization: userInfoModulesPinia.token,
  211. token: userInfoModulesPinia.token,
  212. },
  213. success: (res0) => {
  214. if (JSON.parse(res0.data).code != 200) {
  215. uni.hideLoading();
  216. uploadState.value = 4;
  217. return;
  218. }
  219. // 人脸识别接口
  220. uni.uploadFile({
  221. url: "https://test.metavatar.cc/C/api/userDigital/checkPhoto", //上传图片api
  222. filePath: showImgUrl2.value.path,
  223. name: "file",
  224. formData: {
  225. user: "test",
  226. },
  227. header: {
  228. // Authorization: userInfoModulesPinia.token,
  229. token: userInfoModulesPinia.token,
  230. },
  231. success: (res) => {
  232. if (JSON.parse(res.data).code != 200) {
  233. uni.hideLoading();
  234. uploadState.value = 4;
  235. return;
  236. }
  237. // 上传接口
  238. uni.uploadFile({
  239. url: "https://test.metavatar.cc/C/api/upload/awsImgUpload", //上传图片api
  240. filePath: showImgUrl2.value.path,
  241. name: "file",
  242. formData: {
  243. user: "test",
  244. },
  245. header: {
  246. "Content-Type": "multipart/form-data",
  247. token: userInfoModulesPinia.token,
  248. },
  249. success: async (res2) => {
  250. let moment = res2;
  251. if (JSON.parse(res2.data).code != 200) {
  252. uni.hideLoading();
  253. uploadState.value = 5;
  254. uni.showToast({
  255. title: "网络被数字人偷走了, 请稍后重试",
  256. icon: "none",
  257. });
  258. return;
  259. }
  260. // 保存接口
  261. const res3 = await addImageApi({
  262. image: JSON.parse(res2.data).data.url,
  263. });
  264. if (res3.code == 200) {
  265. // 改变全局的头像
  266. userInfoModulesPinia.myAvatar = JSON.parse(
  267. moment.data
  268. ).data.url;
  269. uploadState.value = 1;
  270. uni.hideLoading();
  271. showImgUrl.value = null;
  272. uni.navigateTo({
  273. url: "/pages/uploadPhoto/success",
  274. });
  275. } else {
  276. uni.hideLoading();
  277. uni.showToast({
  278. title: "网络被数字人偷走了, 请稍后重试",
  279. icon: "none",
  280. });
  281. }
  282. },
  283. fail: () => {
  284. uploadState.value = 5;
  285. uni.hideLoading();
  286. uni.showToast({
  287. title: "网络被数字人偷走了, 请稍后重试",
  288. icon: "none",
  289. });
  290. },
  291. });
  292. },
  293. fail: () => {
  294. uploadState.value = 1;
  295. uni.hideLoading();
  296. uni.showToast({
  297. title: "网络被数字人偷走了, 请稍后重试",
  298. icon: "none",
  299. });
  300. },
  301. // complete: (complete) => {
  302. // uni.hideLoading();
  303. // },
  304. });
  305. },
  306. fail: () => {
  307. uploadState.value = 1;
  308. uni.hideLoading();
  309. uni.showToast({
  310. title: "网络被数字人偷走了, 请稍后重试",
  311. icon: "none",
  312. });
  313. },
  314. });
  315. }
  316. }
  317. //#endregion ---------------------
  318. //#region 页面初始化
  319. onLoad((options) => {
  320. // showImgUrl.value = userInfoModulesPinia.myAvatar;
  321. // 微信登录授权
  322. if (userInfoModulesPinia.platForm != 1) {
  323. uni.login({
  324. provider: "weixin", // 使用微信登录授权
  325. success: async (res) => {
  326. console.log(res);
  327. if (res.code) {
  328. console.log(res.code);
  329. try {
  330. uni.showLoading({
  331. title: "加载中...",
  332. mask: true,
  333. });
  334. const data = {
  335. appId: "wx75cf14e3a0d45821",
  336. code: res.code,
  337. };
  338. const res2 = await loginApi(data);
  339. userInfoModulesPinia.openId = res2.data.openId;
  340. if (res2.data.token) {
  341. userInfoModulesPinia.token = res2.data.token;
  342. // uni.setStorageSync("token", userInfoModulesPinia.token);
  343. console.log(userInfoModulesPinia.openId, "获取openid");
  344. // 获取头像和金币
  345. const res3 = await findImageApi();
  346. userInfoModulesPinia.myAvatar =
  347. res3.data && res3.data.image ? res3.data.image : "";
  348. const res4 = await findGlodApi();
  349. if (!res4.data) {
  350. userInfoModulesPinia.myGlod = 0;
  351. } else {
  352. userInfoModulesPinia.myGlod = res4.data.digitalAvatarResidueGlod
  353. ? res4.data.digitalAvatarResidueGlod
  354. : 0;
  355. }
  356. uni.hideLoading();
  357. if (res2.data.token) {
  358. // uni.redirectTo({
  359. // url: "/pages/index/index",
  360. // });
  361. } else {
  362. uni.redirectTo({
  363. url: "/pages/login/index",
  364. });
  365. console.log("error1");
  366. uni.showToast({
  367. title: "登录失败,请重试",
  368. icon: "none",
  369. });
  370. }
  371. }
  372. uni.hideLoading();
  373. } catch (error) {
  374. // uni.redirectTo({
  375. // url: "pages/index/index",
  376. // });
  377. console.log(error, "error2");
  378. uni.showToast({
  379. title: "登录失败,请重试",
  380. icon: "none",
  381. });
  382. }
  383. } else {
  384. // uni.redirectTo({
  385. // url: "pages/index/index",
  386. // });
  387. console.log("error3");
  388. uni.showToast({
  389. title: "登录失败,请重试",
  390. icon: "none",
  391. });
  392. }
  393. },
  394. fail: (err) => {
  395. // uni.redirectTo({
  396. // url: "pages/index/index",
  397. // });
  398. console.log("error4");
  399. uni.showToast({
  400. title: "登录失败,请重试",
  401. icon: "none",
  402. });
  403. },
  404. });
  405. }
  406. console.log(options);
  407. });
  408. onShow(() => {
  409. // 若来自我的页面的更换头像按钮,直接触发以下操作
  410. const action = uni.getStorageSync("action");
  411. if (action == 1) {
  412. chooseImage();
  413. uni.removeStorageSync("action");
  414. }
  415. });
  416. //#endregion ---------------------
  417. //#region 公共方法
  418. function goOtherPage(url) {
  419. uni.navigateTo({
  420. url: url,
  421. });
  422. }
  423. //#endregion ---------------------
  424. //#region
  425. //#endregion ---------------------
  426. </script>
  427. <style lang="scss">
  428. .page {
  429. position: relative;
  430. min-height: 100vh;
  431. background-color: #222527;
  432. // background-color: rgba(0, 0, 0, 0.8);
  433. .bgc {
  434. position: absolute;
  435. width: 750rpx;
  436. height: 750rpx;
  437. transform: scale(1.5);
  438. top: 187rpx;
  439. left: 0;
  440. object-fit: cover;
  441. z-index: -2;
  442. backdrop-filter: blur(3px);
  443. }
  444. }
  445. .title {
  446. margin-bottom: 40rpx;
  447. .tips {
  448. margin-top: 20rpx;
  449. color: #fff;
  450. font-size: 44rpx;
  451. font-weight: 900;
  452. }
  453. }
  454. .uploadBox {
  455. position: relative;
  456. width: 420rpx;
  457. height: 560rpx;
  458. background-color: rgba(255, 255, 255, 0.1);
  459. border-radius: 50rpx;
  460. .scan-border {
  461. position: absolute;
  462. top: 50%;
  463. left: 50%;
  464. transform: translate(-50%, -50%);
  465. width: 360rpx;
  466. height: 480rpx;
  467. }
  468. .addImg {
  469. width: 80rpx;
  470. height: 80rpx;
  471. }
  472. .showImg {
  473. max-width: 90%;
  474. max-height: 90%;
  475. }
  476. .u-upload {
  477. position: absolute;
  478. top: 0;
  479. left: 0;
  480. width: 600rpx;
  481. height: 600rpx;
  482. opacity: 0;
  483. }
  484. }
  485. // 扫描
  486. .scan {
  487. overflow: hidden;
  488. .scan-line {
  489. position: absolute;
  490. top: 0;
  491. left: 0;
  492. width: 100%;
  493. height: 40%;
  494. background: linear-gradient(180deg, rgba(0, 255, 51, 0) 50%, #00ff33 300%);
  495. border-bottom: 2px solid #00ff33;
  496. animation: scanAnimation 2s linear infinite;
  497. z-index: 9;
  498. }
  499. @keyframes scanAnimation {
  500. 0% {
  501. transform: translateY(-150%);
  502. }
  503. 100% {
  504. transform: translateY(150%);
  505. }
  506. }
  507. }
  508. // 上传
  509. .uploadBtn {
  510. position: relative;
  511. margin-top: 75rpx;
  512. width: 520rpx;
  513. // height: 100rpx;
  514. line-height: 100rpx;
  515. text-align: center;
  516. // background: #ff4f00;
  517. border-radius: 50rpx;
  518. font-size: 30rpx;
  519. color: #fff;
  520. font-weight: 900;
  521. .free {
  522. position: absolute;
  523. top: -25rpx;
  524. right: -80rpx;
  525. width: 185rpx;
  526. height: 50rpx;
  527. image {
  528. position: absolute;
  529. top: 0;
  530. left: 0;
  531. width: 100%;
  532. height: 100%;
  533. z-index: 1;
  534. }
  535. text {
  536. position: absolute;
  537. top: -25rpx;
  538. left: 50%;
  539. transform: translate(-50%, 0);
  540. width: 100%;
  541. height: 100%;
  542. font-size: 22rpx;
  543. font-weight: 900;
  544. z-index: 2;
  545. }
  546. }
  547. }
  548. // 底部盒子
  549. .bottomBox {
  550. flex: 1;
  551. width: 100%;
  552. display: flex;
  553. flex-direction: column;
  554. align-items: center;
  555. justify-content: flex-end;
  556. padding: 0 0 90rpx 0;
  557. .tips2 {
  558. margin-top: 20rpx;
  559. margin-bottom: 15rpx;
  560. font-size: 22rpx;
  561. }
  562. .demoImgBox {
  563. display: flex;
  564. justify-content: space-between;
  565. align-items: flex-end;
  566. padding: 0 20rpx;
  567. width: 100%;
  568. .imgBox {
  569. position: relative;
  570. image {
  571. width: 180rpx;
  572. height: 180rpx;
  573. }
  574. .rightImg {
  575. width: 200rpx;
  576. height: 200rpx;
  577. }
  578. .icon {
  579. position: absolute;
  580. top: -8rpx;
  581. right: -8rpx;
  582. width: 36rpx;
  583. height: 36rpx;
  584. image {
  585. width: 100%;
  586. height: 100%;
  587. }
  588. }
  589. }
  590. }
  591. }
  592. </style>