邃芒智像(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.
 
 
 
 

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