修复已有问题

This commit is contained in:
al 2024-07-16 20:20:12 +08:00
parent dbdca5cb68
commit 890fd7dcba
10 changed files with 555 additions and 119 deletions

View File

@ -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) {
@ -56,18 +57,21 @@ export const handleFollow = async (isFollowed, followedID, callback) => {
//点赞和取消点赞功能
export const thumbsUp = async (id, times, callback, isZone) => {
try {
const body = isZone?{
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",
@ -231,3 +234,32 @@ export const createOrder = async (type = "alipay_h5") => {
setIsLoading(false);
}
};
//点击获取验证码
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);
}
};

View File

@ -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 (
<div>
<div className="p-4 fixed top-0 z-10 w-full">
@ -48,19 +173,24 @@ export default function EditPassword() {
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center my-4">
<p className="text-base text-white mr-4 whitespace-nowrap">验证码</p>
<p className="text-base text-white mr-4 whitespace-nowrap">
验证码
</p>
<Input
placeholder="请输入验证码"
onChangeText={(value) => setVeriCode(value)}
value={veriCode}
type="number"
style={{"--placeholder-color":"#FFFFFF80","--font-size":"16px"}}
style={{
"--placeholder-color": "#FFFFFF80",
"--font-size": "16px",
}}
/>
<Button
shape="rounded"
size="mini"
disabled={isCounting}
// onClick={handleSubmit}
onClick={getVerification}
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
className="whitespace-nowrap"
>
@ -69,24 +199,34 @@ export default function EditPassword() {
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center my-4">
<p className="text-base text-white mr-4 whitespace-nowrap">新密码</p>
<p className="text-base text-white mr-4 whitespace-nowrap">
新密码
</p>
<Input
placeholder="请输入8-15位新密码"
placeholderTextColor="#FFFFFF80"
underlineColorAndroid="transparent"
onChangeText={(value) => setNewPassword(value)}
value={newPassword}
style={{"--placeholder-color":"#FFFFFF80","--font-size":"16px"}}
style={{
"--placeholder-color": "#FFFFFF80",
"--font-size": "16px",
}}
/>
</div>
<Divider />
<div className="flex flex-row flex-nowrap items-center mt-4">
<p className="text-base text-white mr-4 whitespace-nowrap">确认密码</p>
<p className="text-base text-white mr-4 whitespace-nowrap">
确认密码
</p>
<Input
placeholder="请再次输入新密码"
onChangeText={(value) => setConfirmPassword(value)}
value={confirmPassword}
style={{"--placeholder-color":"#FFFFFF80","--font-size":"16px"}}
style={{
"--placeholder-color": "#FFFFFF80",
"--font-size": "16px",
}}
/>
</div>
</div>

View File

@ -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 (
<div>
<div className="p-4 fixed top-0 z-10 w-full">
@ -40,14 +84,15 @@ export default function Feedback() {
<p className="text-base font-medium text-white mt-4 mb-1">
截图或录屏最多9张
</p>
<UploadImgs/>
<UploadImgs getImgs={setAssets} />
<div className="mt-16">
<Button
shape="rounded"
size="middle"
block
// onClick={handleSubmit}
onClick={handleSubmit}
style={{ "--background-color": "#FF669E", color: "#FFFFFF" }}
disabled={isSubmitting}
>
{/* {isSubmitting && <ActivityIndicator size="small" color="white" />} */}
{isSubmitting ? "正在提交..." : "提交"}

View File

@ -19,7 +19,7 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faRefresh } from "@fortawesome/free-solid-svg-icons";
import PostItem from "../components/PostItem";
import { sleep } from "antd-mobile/es/utils/sleep";
// import { sleep } from "antd-mobile/es/utils/sleep";
import "./index.css";
import PostItemSkeleton from "@/components/skeletons/PostItemSkeleton";
import Link from "next/link";

View File

@ -156,7 +156,7 @@ const ZoneItem = ({ data, showMore }) => {
return (
<List.Item
className="!p-0"
onClick={() => router.push(`space/profile/${data.mid}`)}
onClick={() => router.push(`space/person_space_introduce/${data.mid}`)}
key={data.id}
arrow={false}
>

View File

@ -222,12 +222,12 @@ export default function Space() {
>
搜索空间
</Link>
<Link
{/* <Link
href="/search"
className="bg-[#FFFFFF40] px-12 py-2 rounded-full text-base text-white mt-2"
>
查看推荐
</Link>
</Link> */}
</div>
</div>
)}

View File

@ -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: (
<div className="flex flex-col gap-2">
一旦退出您的空间成员身份将会被取消若当前空间为付费空间下次加入时需要再次付费请确保知晓以上内容后谨慎选择退出
</div>
),
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;
},
text: "确认",
style: { color: "#ffffff80" },
onClick: handleExitSpace,
},
{
key: "cancel",
key: "close",
text: "取消",
onClick: () => {},
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 (
<div className="">
@ -98,7 +141,7 @@ export default function Setting() {
router.back();
}}
/>
<span>{streamerInfo?.user_id}</span>
<span>{formatDate(streamerInfo?.ct)}</span>
</li>
</ul>
</div>
@ -110,45 +153,14 @@ export default function Setting() {
className="flex justify-between"
>
<span className="text-base text-white">分享空间</span>
<FontAwesomeIcon
icon={faAngleRight}
size="xl"
className="mr-1"
onClick={() => {
router.back();
}}
/>
<FontAwesomeIcon icon={faAngleRight} size="xl" />
</div>
<Divider />
</li>
<li
onClick={async () => {
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" });
}
}}
>
<li onClick={handleShowDialog}>
<div className="flex justify-between">
<span className="text-base text-white">退出空间</span>
<FontAwesomeIcon
icon={faAngleRight}
size="xl"
className="mr-1"
onClick={() => {
router.back();
}}
/>
<FontAwesomeIcon icon={faAngleRight} size="xl" />
</div>
<Divider />
</li>

View File

@ -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 (
<ImageUploader
value={fileList}
onChange={setFileList}
// upload={mockUpload}
multiple
maxCount={9}
showUpload={fileList.length < maxCount}
onCountExceed={(exceed) => {
Toast.show(`最多选择 ${maxCount} 张图片,你多选了 ${exceed}`);
}}
// <ImageUploader
// value={fileList}
// onChange={setFileList}
// upload={handleUploadImage}
// multiple={true}
// maxCount={9}
// showUpload={fileList.length < maxCount}
// onCountExceed={(exceed) => {
// Toast.show(`最多选择 ${maxCount} 张图片,你多选了 ${exceed} 张`);
// }}
// >
// <div className="flex justify-center items-center h-[80px] w-[80px] border-2 border-gray-400 border-dashed rounded-md text-2xl text-gray-400">+</div>
// </ImageUploader>
<div className="grid grid-cols-4 gap-1">
{fileList.map((item, index) => {
return (
<div key={index} className="rounded relative">
<Image
src={"https://file.wishpaldev.tech/" + item.src_id}
width="100%"
height="100%"
className="rounded"
onClick={() => showPhotos(fileList, index)}
/>
<div
className="h-4 w-4 bg-[#33333380] absolute top-0 right-0 flex justify-center items-center"
onClick={() => handleRemoveItem(index)}
>
<div className="flex justify-center items-center h-[80px] w-[80px] border-2 border-gray-400 border-dashed rounded-md text-2xl text-gray-400">+</div>
</ImageUploader>
<FontAwesomeIcon icon={faClose} size="sm" />
</div>
</div>
);
})}
{loading && (
<div className="rounded border-[#ffffff80] text-[#ffffff80] flex flex-col justify-center items-center">
<DotLoading />
<p>上传中</p>
</div>
)}
<label htmlFor="uploadAvatarBtn">
<div
className="border-2 border-[#ffffff80] text-[#ffffff80] rounded border-dashed w-full h-full flex justify-center items-center"
style={{ minHeight: "calc(25vw - 0.75rem)" }}
>
<FontAwesomeIcon icon={faAdd} size="2xl" />
</div>
</label>
<input
type="file"
id="uploadAvatarBtn"
style={{ display: "none" }}
accept="image/png, image/jpeg, video/*"
// capture="camera"
onChange={handleUploadImage}
/>
</div>
);
}
// export async function mockUpload(file) {
// await sleep(3000)
// return {
// url: URL.createObjectURL(file),
// }
// }

View File

@ -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) : {};

View File

@ -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;
}