邃芒智像(Uniapp : WX、TT、H5)
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

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