diff --git a/api/public.js b/api/public.js index 9d780a2..795d170 100644 --- a/api/public.js +++ b/api/public.js @@ -1,13 +1,14 @@ import { get } from "@/utils/storeInfo"; import require from "@/utils/require"; import { Toast } from "antd-mobile"; +import { JSEncrypt } from "jsencrypt"; //关注和取关功能 export const handleLogout = async () => { const account = get("account"); try { const data = await require("POST", `/api/login/logout`, { body: { - mid:account.mid + mid: account.mid, }, }); if (data.ret === -1) { @@ -55,19 +56,22 @@ export const handleFollow = async (isFollowed, followedID, callback) => { }; //点赞和取消点赞功能 -export const thumbsUp = async (id, times, callback,isZone) => { - +export const thumbsUp = async (id, times, callback, isZone) => { try { - const body = isZone?{ - zone_moment_id: id, - times: times == 1 ? -1 : 1, - }:{ - moment_id: id, - times: times == 1 ? -1 : 1, - }; + const body = isZone + ? { + zone_moment_id: id, + times: times == 1 ? -1 : 1, + } + : { + moment_id: id, + times: times == 1 ? -1 : 1, + }; console.log("body", body); - const data = await require("POST", `/api/${isZone?"zone_moment":"moment"}/thumbs_up`, { + const data = await require("POST", `/api/${ + isZone ? "zone_moment" : "moment" + }/thumbs_up`, { body, }); if (data.ret === -1) { @@ -136,8 +140,7 @@ export async function checkRelation(subMid, objMid, predicate) { // 获取用户信息 export async function getUserInfo() { try { - const data = - await require("POST", `/api/account/list_by_mid`, null, true); + const data = await require("POST", `/api/account/list_by_mid`, null, true); if (data.ret === -1) { Toast.show({ icon: "fail", @@ -230,4 +233,33 @@ export const createOrder = async (type = "alipay_h5") => { } finally { setIsLoading(false); } -}; \ No newline at end of file +}; + +//点击获取验证码 +export const handleVerification = async (mobilePhone="",regionCode) => { + console.log("mobilePhone",mobilePhone.toString()) + //手机号校验 + if (!mobilePhone.toString().match(/^1[3456789]\d{9}$/)) { + Toast.show({ + icon: "fail", + content: "手机号码格式错误", + position: "top", + }); + return; + } + //对手机号进行RSA加密 + const encrypt = new JSEncrypt(); + encrypt.setPublicKey(process.env.EXPO_PUBLIC_RSA_KEY); + const mobile_phone = encrypt.encrypt(mobilePhone); + //发送短信验证码 + try { + await require("POST", `/api/veri_code/send`, { + body: { + mobile_phone: mobile_phone, + region_code: regionCode, + }, + }); + } catch (error) { + console.error(error); + } +}; diff --git a/app/my/setting/editPassword/page.js b/app/my/setting/editPassword/page.js index 15f092c..580210d 100644 --- a/app/my/setting/editPassword/page.js +++ b/app/my/setting/editPassword/page.js @@ -1,13 +1,19 @@ "use client"; -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Button, Input, Divider } from "antd-mobile"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faAngleLeft } from "@fortawesome/free-solid-svg-icons"; import { useRouter } from "next/navigation"; +import { get } from "@/utils/storeInfo"; import UploadImgs from "@/components/UploadImgs"; +import { handleVerification } from "@/api/public"; +import { JSEncrypt } from "jsencrypt"; +import { cryptoPassword } from "@/utils/crypto"; +import require from "@/utils/require"; +import { signOut } from "@/utils/auth"; export default function EditPassword() { - const [regionCode, setRegionCode] = useState(""); + const [regionCode, setRegionCode] = useState("86"); const [mobilePhone, setMobilePhone] = useState(""); const [veriCode, setVeriCode] = useState(""); const [newPassword, setNewPassword] = useState(""); @@ -15,6 +21,125 @@ export default function EditPassword() { const [isCounting, setIsCounting] = useState(false); const [seconds, setSeconds] = useState(60); const router = useRouter(); + // useEffect(() => { + // const mobile_phone = get("mobile_phone"); + // console.log("mobile_phone",mobile_phone) + // setMobilePhone(mobile_phone); + // }, []); + //获取之前缓存的用户的手机号 + useEffect(() => { + const mobile_phone = get("mobile_phone"); + const region_code = get("region_code"); + if (mobile_phone && region_code) { + setMobilePhone(mobile_phone); + setRegionCode(region_code); + } + }, []); + useEffect(() => { + let interval; + if (isCounting && seconds > 0) { + interval = setInterval(() => { + setSeconds(seconds - 1); + }, 1000); + } else { + setIsCounting(false); + setSeconds(60); + clearInterval(interval); + } + return () => { + clearInterval(interval); + }; + }, [isCounting, seconds]); + const getVerification = async () => { + //开始倒计时 + setIsCounting(true); + handleVerification(mobilePhone, regionCode); + }; + //点击修改密码 + const handleUpdatePassword = async () => { + //验证数据格式 + if (!mobilePhone.match(/^1[3456789]\d{9}$/)) { + Toast.show({ + icon: "fail", + content: "手机号码格式错误", + position: "top", + }); + return; + } + if (!veriCode) { + Toast.show({ + icon: "fail", + content: "请输入验证码", + position: "top", + }); + return; + } + if (!confirmPassword) { + Toast.show({ + icon: "fail", + content: "请再次输入您的密码", + position: "top", + }); + return; + } + if (newPassword != confirmPassword) { + Toast.show({ + icon: "fail", + content: "两次输入密码不一致", + position: "top", + }); + return; + } + if (newPassword.length < 8) { + Toast.show({ + icon: "fail", + content: "新密码不得小于8位", + position: "top", + }); + return; + } + if (newPassword.length > 15) { + Toast.show({ + icon: "fail", + content: "新密码不得大于15位", + position: "top", + }); + return; + } + //对手机号进行RSA加密 + const encrypt = new JSEncrypt(); + encrypt.setPublicKey(process.env.NEXT_PUBLIC_RSA_KEY); + const mobile_phone = encrypt.encrypt(mobilePhone); + //MD5加密新旧密码 + const encryptedNewPassword = cryptoPassword(newPassword); + //发送修改密码请求 + try { + const data = await require("POST", `/api/login/logout`, { + body: { + mobile_phone: mobile_phone, + region_code: regionCode, + veri_code: veriCode, + new_password: encryptedNewPassword, + }, + }); + if (data.ret === -1) { + Toast.show({ + icon: "fail", + content: data.msg, + position: "top", + }); + return; + } + Toast.show({ + icon: "success", + content: "修改成功,请重新登录", + position: "top", + }); + signOut(); + } catch (error) { + console.error(error); + } + }; return (
@@ -43,24 +168,29 @@ export default function EditPassword() { maxLength={11} onChangeText={(value) => setMobilePhone(value)} value={mobilePhone} - style={{"--color":"#FFFFFF","--font-size":"16px"}} + style={{ "--color": "#FFFFFF", "--font-size": "16px" }} />
-

验证码

+

+ 验证码 +

setVeriCode(value)} value={veriCode} type="number" - style={{"--placeholder-color":"#FFFFFF80","--font-size":"16px"}} + style={{ + "--placeholder-color": "#FFFFFF80", + "--font-size": "16px", + }} />
-

新密码

+

+ 新密码 +

setNewPassword(value)} value={newPassword} - style={{"--placeholder-color":"#FFFFFF80","--font-size":"16px"}} + style={{ + "--placeholder-color": "#FFFFFF80", + "--font-size": "16px", + }} />
-

确认密码

+

+ 确认密码 +

setConfirmPassword(value)} value={confirmPassword} - style={{"--placeholder-color":"#FFFFFF80","--font-size":"16px"}} + style={{ + "--placeholder-color": "#FFFFFF80", + "--font-size": "16px", + }} />
diff --git a/app/my/setting/feedback/page.js b/app/my/setting/feedback/page.js index c827fce..8982dd5 100644 --- a/app/my/setting/feedback/page.js +++ b/app/my/setting/feedback/page.js @@ -1,18 +1,62 @@ "use client"; import React, { useState } from "react"; -import { Button, TextArea } from "antd-mobile"; +import { Button, TextArea,Toast } from "antd-mobile"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { - faAngleLeft, -} from "@fortawesome/free-solid-svg-icons"; +import { faAngleLeft } from "@fortawesome/free-solid-svg-icons"; import { useRouter } from "next/navigation"; import UploadImgs from "@/components/UploadImgs"; +import { get } from "@/utils/storeInfo"; export default function Feedback() { const [value, setValue] = useState(); const [assets, setAssets] = useState([]); const [isSubmitting, setIsSubmitting] = useState(false); const router = useRouter(); + //提交反馈 + const handleSubmit = async () => { + if (!value) { + Toast.show({ + icon: "fail", + content: "反馈内容不能为空", + position: "top", + }); + return; + } + // const media = await multiUpload(assets); + console.log("media",{image_ids:assets,video_ids:[]}) + // //提交数据 + // setIsSubmitting(true); + // const media = await multiUpload(assets); + // const account = await get("account"); + // try { + // const data = await require("POST", `/api/feedback/create`, { + // body: { + // mid: account.mid, + // discription: value, + // credentials: media, + // }, + // }); + // if (data.ret === -1) { + // Toast.show({ + // icon: "fail", + // content: data.msg, + // position: "top", + // }); + // return; + // } + // //提交成功后显示Toast并返回上一页 + // Toast.show({ + // icon: "success", + // content: "反馈提交成功", + // position: "top", + // }); + // router.goBack(); + // } catch (error) { + // console.error(error); + // } finally { + // setIsSubmitting(false); + // } + }; return (
@@ -40,14 +84,15 @@ export default function Feedback() {

截图或录屏(最多9张)

- +
)} diff --git a/app/space/setting/page.js b/app/space/setting/page.js index c0d85bf..462f892 100644 --- a/app/space/setting/page.js +++ b/app/space/setting/page.js @@ -1,6 +1,6 @@ "use client"; -import React, { useEffect, useState, useRef } from "react"; +import React, { useEffect, useState, useCallback } from "react"; import { Image, Avatar, Divider, Dialog, Toast } from "antd-mobile"; import { useRouter, useSearchParams } from "next/navigation"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -18,38 +18,81 @@ export default function Setting() { let data = JSON.parse(decodeURIComponent(searchParams.get("data"))); setStreamerInfo(data); }, []); - const handleShowVideo = () => { - Dialog.className = "videoMask"; - Dialog.show({ + const handleShowDialog = () => { + const result = Dialog.show({ title: "是否确认退出空间?", - content: ( -
- 一旦退出,您的空间成员身份将会被取消,若当前空间为付费空间,下次加入时,需要再次付费。请确保知晓以上内容后谨慎选择退出。 -
- ), + content: + "一旦退出,您的空间成员身份将会被取消,若当前空间为付费空间,下次加入时,需要再次付费。请确保知晓以上内容后谨慎选择退出。", bodyStyle: { - // background: "none", maxHeight: "none", width: "80vw", - position: "absolute", - top: "calc(50% - 50px)", + position: "fixed", + top: "200px", left: "10vw", + "--text-color": "#fff", + color: "#fff", }, + // cancelText:"确认", + // confirmText:"取消", + style: { + "--text-color": "#fff", + }, + closeOnAction: true, actions: [ - { - key: "submit", - text: "确定", - onClick: () => { - i; + [ + { + key: "submit", + text: "确认", + style: { color: "#ffffff80" }, + onClick: handleExitSpace, }, - }, - { - key: "cancel", - text: "取消", - onClick: () => {}, - }, + { + key: "close", + text: "取消", + bold: true, + style: { color: "#fff" }, + onClick: () => { + Dialog?.close(); + }, + }, + ], ], }); + if (result) { + Toast.show({ content: "点击了确认", position: "bottom" }); + } + }; + //格式化时间 + const formatDate = useCallback((timestamp) => { + const date = new Date(timestamp * 1000); + const year = date.getFullYear(); + const month = date.getMonth() + 1; // 月份从0开始,所以需要加1 + const day = date.getDate(); + return `${year}/${month}/${day}`; + }, []); + const handleExitSpace = async () => { + try { + const _data = + await require("POST", "/api/account_relation/count", {body:{ + zid: streamerInfo?.id, + }}); + if (_data.ret === -1) { + Toast.show({ + icon: "fail", + content: _data.msg, + position: "top", + }); + return; + } + Toast.show({ + icon: "success", + content: "退出空间成功", + position: "top", + }); + setTimeout(() => router.replace("HomeTab"), 500); + } catch (error) { + console.error(error); + } }; return (
@@ -98,7 +141,7 @@ export default function Setting() { router.back(); }} /> - {streamerInfo?.user_id} + {formatDate(streamerInfo?.ct)}
@@ -110,45 +153,14 @@ export default function Setting() { className="flex justify-between" > 分享空间 - { - router.back(); - }} - /> +
-
  • { - const result = await Dialog.confirm({ - title: "是否确认退出空间?", - content: "一旦退出,您的空间成员身份将会被取消,若当前空间为付费空间,下次加入时,需要再次付费。请确保知晓以上内容后谨慎选择退出。", - bodyStyle: { - maxHeight: "none", - width: "80vw", - position: "fixed", - top: "200px", - left: "10vw", - }, - }); - if (result) { - Toast.show({ content: "点击了确认", position: "bottom" }); - } - }} - > +
  • 退出空间 - { - router.back(); - }} - /> +
  • diff --git a/components/UploadImgs/index.js b/components/UploadImgs/index.js index 20559a0..86ecf28 100644 --- a/components/UploadImgs/index.js +++ b/components/UploadImgs/index.js @@ -1,23 +1,105 @@ import React, { useState } from "react"; -import {ImageUploader,Toast} from "antd-mobile"; -export default function UploadImgs(props) { +import { DotLoading, Image, ImageViewer } from "antd-mobile"; +import { uploadImage, uploadVideo } from "@/utils/upload"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faAdd, faClose } from "@fortawesome/free-solid-svg-icons"; +export default function UploadImgs({ getImgs }) { const maxCount = 6; - const [fileList, setFileList] = useState([ - ]); + const [fileList, setFileList] = useState([]); + const [loading, setLoading] = useState(false); + const handleUploadImage = async (e) => { + let file = e.target.files[0]; + console.log("ddddd", file.type); + if (!file) return; + setLoading(true); + if (file.type.indexOf("image/")!=-1) { + const image = await uploadImage(file); + getImgs((old) => [...old, image.id]); + setFileList((old) => [...old, image]); + }else if(file.type.indexOf("video/")!=-1){ + const video = await uploadVideo(file); + getImgs((old) => [...old, video.id]); + setFileList((old) => [...old, video]); + } + setLoading(false); + }; + const handleRemoveItem = (index) => { + console.log(index); + let newArr = [...fileList]; + newArr.splice(index, 1); + setFileList(newArr); + }; + const showPhotos = (images, index) => { + ImageViewer.Multi.show({ + images: images.map( + (item) => "https://file.wishpaldev.tech/" + item?.src_id + ), + defaultIndex: index, + }); + }; return ( - { - Toast.show(`最多选择 ${maxCount} 张图片,你多选了 ${exceed} 张`); - }} - > -
    +
    -
    + // { + // Toast.show(`最多选择 ${maxCount} 张图片,你多选了 ${exceed} 张`); + // }} + // > + //
    +
    + //
    +
    + {fileList.map((item, index) => { + return ( +
    + showPhotos(fileList, index)} + /> +
    handleRemoveItem(index)} + > + +
    +
    + ); + })} + {loading && ( +
    + +

    上传中

    +
    + )} + + +
    ); } +// export async function mockUpload(file) { +// await sleep(3000) +// return { +// url: URL.createObjectURL(file), +// } +// } diff --git a/utils/storeInfo.js b/utils/storeInfo.js index 2d12e33..b00df55 100644 --- a/utils/storeInfo.js +++ b/utils/storeInfo.js @@ -2,7 +2,7 @@ export function save(key,value){ localStorage.setItem(key,value) } export function get(key){ - let data = localStorage.getItem("account"); + let data = localStorage.getItem(key); // console.log(key,data) return data ? JSON.parse(data) : {}; diff --git a/utils/upload.js b/utils/upload.js index a424b11..e6f3c65 100644 --- a/utils/upload.js +++ b/utils/upload.js @@ -90,8 +90,43 @@ async function calculateFileMetadata(file) { }); } +//获取上传失败时返回的id +async function getFailId() { + const base = await baseRequest(); + const signature = await generateSignature({ + ...base, + }); + try { + const response = await fetch( + `/api/upload_media_fail_config/list?signature=${signature}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + ...base, + }), + } + ); + const data = await response.json(); + if (data.ret === -1) { + Toast.show({ + type: "error", + text1: data.msg, + topOffset: 60, + }); + return; + } + return data.data; + } catch (e) { + console.warn(e); + } +} + //上传单张图片 export async function uploadImage(asset) { + console.log("uploadResponse",asset) const auth = await getAuth(1); try { const formData = new FormData(); @@ -107,7 +142,6 @@ export async function uploadImage(asset) { method: "POST", body: formData, }); - if (uploadResponse.status === 200) { // console.log(asset); // debugger @@ -119,14 +153,11 @@ export async function uploadImage(asset) { w: info.width, fmt: asset.type, }; + + const base = baseRequest(); - const signature = generateSignature({ - mtype: 1, - item: item, - ...base, - }); const response = await fetch( - `/api/media/c_upload?signature=${signature}`, + `/api/media/c_upload`, { method: "POST", headers: { @@ -146,7 +177,7 @@ export async function uploadImage(asset) { }); return; } - return data.data.ret_item.id; + return data.data.ret_item; } else { Toast.show({ content: "上传图片失败", @@ -157,14 +188,108 @@ export async function uploadImage(asset) { } } +//上传单个视频 +export async function uploadVideo(asset) { + const auth = await getAuth(2); + const fileType = "video"; + const generateThumbnail = async () => { + try { + const videoCover = await VideoThumbnails.getThumbnailAsync(asset?.uri); + return videoCover; + } catch (e) { + console.warn(e); + } + }; + try { + const formData = new FormData(); + formData.append("name", auth.filename); + formData.append("policy", auth.policy); + formData.append("OSSAccessKeyId", auth.access_key_id); + formData.append("success_action_status", "200"); + formData.append("signature", auth.signature); + formData.append("key", auth.directory + "/" + auth.filename); + formData.append("file", { + uri: asset?.uri, + name: asset?.filename, + type: fileType, + }); + + const uploadResponse = await fetch(auth.host, { + method: "POST", + body: formData, + }); + + if (uploadResponse.status === 200) { + const md5 = uploadResponse.headers.map.etag.substring( + 1, + uploadResponse.headers.map.etag.length - 1 + ); + const videoCover = await generateThumbnail(); + const videoCoverId = await uploadImage(videoCover); + const item = { + src_id: auth.directory + "/" + auth.filename, + cover_id: videoCoverId, + md5: md5, + dur: asset?.duration, + fmt: fileType, + }; + const base = baseRequest(); + const response = await fetch( + `/api/media/c_upload`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + mtype: 2, + item: item, + ...base, + }), + } + ); + const data = await response.json(); + if (data.ret === -1) { + Toast.show({ + type: "error", + text1: data.msg, + topOffset: 60, + }); + return; + } + return data.data.ret_item.id; + } else { + Toast.show({ + type: "error", + text1: "上传视频失败", + topOffset: 60, + }); + const failId = await getFailId(); + return failId?.video_id_for_upload_fail; + } + } catch (error) { + console.log("Error occurred while getting or uploading data:", error); + Toast.show({ + type: "error", + text1: "上传视频失败", + topOffset: 60, + }); + const failId = await getFailId(); + return failId?.video_id_for_upload_fail; + } +} + + //上传多个图片 export async function multiUploadImage(assets) { + console.log("assets",assets) let ids = { image_ids: [], video_ids: [] }; await Promise.all( - assets.map(async (asset) => { + assets.forEach(async (asset) => { const id = await uploadImage(asset); ids.image_ids.push(id); }) ); + return ids; }