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

387 lines
9.6 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. <image
  30. class="showImg"
  31. v-show="showImgUrl"
  32. :src="showImgUrl"
  33. alt=""
  34. @click.prevent="chooseImage"
  35. mode="aspectFit"
  36. />
  37. </view>
  38. <view @click="toCloseStyle" class="uploadBtn">
  39. <text>上传我的照片</text>
  40. <view class="free">
  41. <image src="../../assets/icon/blackBG.png" mode="aspectFit" />
  42. <text>新用户免费制作</text>
  43. </view>
  44. </view>
  45. <!-- 底部盒子 -->
  46. <view class="bottomBox">
  47. <view class="tips2">请按照样片上传您五官清晰的正面照片</view>
  48. <view class="demoImgBox">
  49. <view class="imgBox">
  50. <image src="../../assets/img/img1.png" mode="aspectFit" />
  51. <view class="icon">
  52. <image src="../../assets/icon/error.png" mode="aspectFit" />
  53. </view>
  54. </view>
  55. <view class="imgBox">
  56. <image
  57. class="rightImg"
  58. src="../../assets/img/img2.png"
  59. mode="aspectFit"
  60. />
  61. <view class="icon">
  62. <image src="../../assets/icon/correct.png" mode="aspectFit" />
  63. </view>
  64. </view>
  65. <view class="imgBox">
  66. <image src="../../assets/img/img3.png" mode="aspectFit" />
  67. <view class="icon">
  68. <image src="../../assets/icon/error.png" mode="aspectFit" />
  69. </view>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </template>
  75. <script setup>
  76. //#region 导入
  77. import { ref, reactive } from "vue";
  78. import { addImageApi } from "../../api/uploadphoto.js";
  79. import { userInfoModules } from "@/store/modules/userInfo";
  80. import imageCompression from "browser-image-compression"; //压缩图片插件
  81. //#endregion
  82. const userInfoModulesPinia = userInfoModules();
  83. //#region 选择图片
  84. const uploadState = ref(1); //上传状态
  85. const showImgUrl = ref(userInfoModulesPinia.myAvatar); //回显路径 压缩
  86. const showImgUrl2 = ref(null); //回显路径 未压缩
  87. const showImgData = ref(null); //上传数据
  88. function chooseImage() {
  89. // 调用uni.chooseImage方法选择图片
  90. uni.chooseImage({
  91. count: 1, // 最多可以选择的图片张数,这里设置为1,只选择一张图片
  92. success: async (res) => {
  93. uploadState.value = 2;
  94. // 图片压缩
  95. console.log(res.tempFiles[0].size);
  96. showImgUrl2.value = res.tempFiles[0];
  97. if (userInfoModulesPinia.platForm != 1) {
  98. uni.compressImage({
  99. src: res.tempFilePaths[0],
  100. quality: 40,
  101. success: (res2) => {
  102. showImgUrl.value = res2.tempFilePath;
  103. },
  104. });
  105. } else {
  106. const options = {
  107. maxSizeMB: 2, // 最大压缩大小为 4MB
  108. useWebWorker: true, // 使用 Web Worker 进行压缩,提高性能
  109. };
  110. const compressedFile = await imageCompression(
  111. res.tempFiles[0],
  112. options
  113. );
  114. //compressedFile是一个blob对象
  115. showImgUrl.value = URL.createObjectURL(compressedFile);
  116. showImgData.value = compressedFile;
  117. }
  118. },
  119. fail: (err) => {
  120. console.error("选择图片失败", err);
  121. },
  122. });
  123. }
  124. //#endregion ---------------------
  125. //#region 上传图片
  126. // console.log(userInfoModulesPinia.token, "token");
  127. async function toCloseStyle() {
  128. if (!showImgUrl.value) {
  129. uni.showToast({
  130. title: "请先上传图片",
  131. icon: "none",
  132. });
  133. return;
  134. }
  135. uploadState.value = 3;
  136. console.log(showImgUrl.value);
  137. console.log(showImgUrl2.value.path);
  138. // 人脸识别接口
  139. uni.uploadFile({
  140. url: "https://test.metavatar.cc/C/api/userDigital/checkPhoto", //上传图片api
  141. filePath: showImgUrl2.value.path,
  142. name: "file",
  143. formData: {
  144. user: "test",
  145. },
  146. header: {
  147. // Authorization: userInfoModulesPinia.token,
  148. token: userInfoModulesPinia.token,
  149. },
  150. success: (res) => {
  151. if (JSON.parse(res.data).code != 200) {
  152. uploadState.value = 4;
  153. return;
  154. }
  155. // 上传接口
  156. uni.uploadFile({
  157. url: "https://test.metavatar.cc/C/api/upload/awsImgUpload", //上传图片api
  158. filePath: showImgUrl2.value.path,
  159. name: "file",
  160. formData: {
  161. user: "test",
  162. },
  163. header: {
  164. "Content-Type": "multipart/form-data",
  165. token: userInfoModulesPinia.token,
  166. },
  167. success: async (res2) => {
  168. if (JSON.parse(res2.data).code != 200) {
  169. uploadState.value = 5;
  170. uni.showToast({
  171. title: "网络被数字人偷走了, 请稍后重试",
  172. icon: "none",
  173. });
  174. return;
  175. }
  176. // 保存接口
  177. const res3 = await addImageApi({
  178. image: JSON.parse(res2.data).data.url,
  179. });
  180. if (res3.code == 200) {
  181. uni.redirectTo({
  182. url: "/pages/uploadPhoto/success",
  183. });
  184. } else {
  185. uni.showToast({
  186. title: "网络被数字人偷走了, 请稍后重试",
  187. icon: "none",
  188. });
  189. }
  190. },
  191. fail: () => {
  192. uploadState.value = 5;
  193. },
  194. });
  195. },
  196. fail: () => {
  197. uploadState.value = 1;
  198. uni.showToast({
  199. title: "网络被数字人偷走了, 请稍后重试",
  200. icon: "none",
  201. });
  202. },
  203. });
  204. }
  205. //#endregion ---------------------
  206. //#region
  207. //#endregion ---------------------
  208. </script>
  209. <style lang="scss">
  210. .page {
  211. position: relative;
  212. min-height: 100vh;
  213. background-color: #222527;
  214. // background-color: rgba(0, 0, 0, 0.8);
  215. .bgc {
  216. position: absolute;
  217. width: 750rpx;
  218. height: 750rpx;
  219. transform: scale(1.5);
  220. top: 187rpx;
  221. left: 0;
  222. object-fit: cover;
  223. z-index: -2;
  224. backdrop-filter: blur(3px);
  225. }
  226. }
  227. .title {
  228. margin-bottom: 40rpx;
  229. .tips {
  230. margin-top: 20rpx;
  231. color: #fff;
  232. font-size: 44rpx;
  233. font-weight: 900;
  234. }
  235. }
  236. .uploadBox {
  237. position: relative;
  238. width: 420rpx;
  239. height: 560rpx;
  240. background-color: rgba(255, 255, 255, 0.1);
  241. border-radius: 50rpx;
  242. .scan-border {
  243. position: absolute;
  244. top: 50%;
  245. left: 50%;
  246. transform: translate(-50%, -50%);
  247. width: 360rpx;
  248. height: 480rpx;
  249. }
  250. .addImg {
  251. width: 80rpx;
  252. height: 80rpx;
  253. }
  254. .showImg {
  255. max-width: 90%;
  256. max-height: 90%;
  257. }
  258. .u-upload {
  259. position: absolute;
  260. top: 0;
  261. left: 0;
  262. width: 600rpx;
  263. height: 600rpx;
  264. opacity: 0;
  265. }
  266. }
  267. // 扫描
  268. .scan {
  269. overflow: hidden;
  270. .scan-line {
  271. position: absolute;
  272. top: 0;
  273. left: 0;
  274. width: 100%;
  275. height: 40%;
  276. background: linear-gradient(180deg, rgba(0, 255, 51, 0) 50%, #00ff33 300%);
  277. border-bottom: 2px solid #00ff33;
  278. animation: scanAnimation 2s linear infinite;
  279. z-index: 9;
  280. }
  281. @keyframes scanAnimation {
  282. 0% {
  283. transform: translateY(-150%);
  284. }
  285. 100% {
  286. transform: translateY(150%);
  287. }
  288. }
  289. }
  290. // 上传
  291. .uploadBtn {
  292. position: relative;
  293. margin-top: 75rpx;
  294. width: 520rpx;
  295. height: 100rpx;
  296. line-height: 100rpx;
  297. text-align: center;
  298. background: #ff4f00;
  299. border-radius: 50rpx;
  300. font-size: 30rpx;
  301. color: #fff;
  302. font-weight: 900;
  303. .free {
  304. position: absolute;
  305. top: -25rpx;
  306. right: -80rpx;
  307. width: 185rpx;
  308. height: 50rpx;
  309. image {
  310. position: absolute;
  311. top: 0;
  312. left: 0;
  313. width: 100%;
  314. height: 100%;
  315. z-index: 1;
  316. }
  317. text {
  318. position: absolute;
  319. top: -25rpx;
  320. left: 50%;
  321. transform: translate(-50%, 0);
  322. width: 100%;
  323. height: 100%;
  324. font-size: 22rpx;
  325. font-weight: 900;
  326. z-index: 2;
  327. }
  328. }
  329. }
  330. // 底部盒子
  331. .bottomBox {
  332. flex: 1;
  333. width: 100%;
  334. display: flex;
  335. flex-direction: column;
  336. align-items: center;
  337. justify-content: flex-end;
  338. padding: 0 0 90rpx 0;
  339. .tips2 {
  340. margin-top: 20rpx;
  341. margin-bottom: 15rpx;
  342. font-size: 22rpx;
  343. }
  344. .demoImgBox {
  345. display: flex;
  346. justify-content: space-between;
  347. align-items: flex-end;
  348. padding: 0 20rpx;
  349. width: 100%;
  350. .imgBox {
  351. position: relative;
  352. image {
  353. width: 180rpx;
  354. height: 180rpx;
  355. }
  356. .rightImg {
  357. width: 200rpx;
  358. height: 200rpx;
  359. }
  360. .icon {
  361. position: absolute;
  362. top: -8rpx;
  363. right: -8rpx;
  364. width: 36rpx;
  365. height: 36rpx;
  366. image {
  367. width: 100%;
  368. height: 100%;
  369. }
  370. }
  371. }
  372. }
  373. }
  374. </style>