修改用户默认头像为用户名前两位,增加粘贴图片功能,更改充值默认金额为30,优化了一些方法名称

pull/361/head
HXY 2 years ago
parent 485584c011
commit 74692b05b3

@ -24,7 +24,7 @@ type OssCreateService interface {
PersistObject(objectKey string) error
}
// OssCreateService Object Storage System Object Delete service
// OssDeleteService Object Storage System Object Delete service
type OssDeleteService interface {
DeleteObject(objectKey string) error
DeleteObjects(objectKeys []string) error

@ -62,6 +62,7 @@ func (s *localossCreateServant) PutObject(objectKey string, reader io.Reader, ob
return "", err
}
if written != objectSize {
fmt.Print("这里发生了错误.......")
os.Remove(savePath)
return "", errors.New("put object not complete")
}

@ -10,6 +10,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/rocboss/paopao-ce/internal/core"
"image/color"
"image/png"
"io/ioutil"
@ -45,6 +46,8 @@ const (
type pubSrv struct {
api.UnimplementedPubServant
*base.DaoServant
oss core.ObjectStorageService
}
type ThirdPartyUserDataVo struct {
@ -214,12 +217,17 @@ func (s *pubSrv) Register(req *web.RegisterReq) (*web.RegisterResp, mir.Error) {
logrus.Errorf("scheckPassword err: %v", err)
return nil, web.ErrUserRegisterFailed
}
avatarURL := s.getRandomAvatarByUsername(req.Username)
if len(avatarURL) == 0 {
fmt.Println("头像生成失败或为空")
}
password, salt := encryptPasswordAndSalt(req.Password)
user := &ms.User{
Nickname: req.Username,
Username: req.Username,
Password: password,
Avatar: getRandomAvatar(),
Avatar: avatarURL,
Salt: salt,
Status: ms.UserStatusNormal,
}
@ -314,8 +322,9 @@ func (s *pubSrv) validUsername(username string) mir.Error {
return nil
}
func newPubSrv(s *base.DaoServant) api.Pub {
func newPubSrv(s *base.DaoServant, oss core.ObjectStorageService) api.Pub {
return &pubSrv{
DaoServant: s,
oss: oss,
}
}

@ -5,7 +5,19 @@
package web
import (
"bytes"
"fmt"
"github.com/golang/freetype"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font"
"hash/fnv"
"image"
"image/color"
"image/draw"
"image/png"
"io"
"io/ioutil"
"log"
"math/rand"
"strings"
"time"
@ -79,6 +91,122 @@ func getRandomAvatar() string {
return defaultAvatars[rand.Intn(len(defaultAvatars))]
}
func (s *pubSrv) getRandomAvatarByUsername(username string) string {
// 获取前两个字
runes := []rune(username)
showName := string(runes[:2])
//转换为大写
showName = strings.ToUpper(showName)
// 获取随机颜色作为头像底色
finalColor := getRandomColor(username)
//生成随机头像文件
// 生成头像图片
imageSize := 50 // 设置头像图片大小
avatar := createAvatar(imageSize, finalColor, showName)
//avatarFilename := username + ".png"
// 保存头像图片到文件
avatarBuffer := &bytes.Buffer{}
err := saveImageToBuffer(avatar, avatarBuffer)
if err != nil {
fmt.Println("保存头像到缓冲区失败:", err)
return "注册失败"
}
if avatarBuffer.Len() == 0 {
fmt.Println("头像缓冲区为空")
return "注册失败"
}
// 生成随机路径
randomPath := uuid.Must(uuid.NewV4()).String()
ossSavePath := "public/avatar/" + generatePath(randomPath[:8]) + "/" + randomPath[9:] + ".png"
if ossSavePath == "" {
fmt.Println("ossSavePath为空")
return "注册失败"
}
//fmt.Print(ossSavePath + "\n" + avatarBuffer.String() + "\n" + strconv.Itoa(imageSize) + "\n" + "image/png" + "\n" + "false")
objectUrl, err := s.oss.PutObject(ossSavePath, avatarBuffer, int64(avatarBuffer.Len()), "image/png", false)
if err != nil {
logrus.Errorf("oss.PutObject err: %s", err)
return "失败"
}
fmt.Print(objectUrl)
return objectUrl
}
// 生成随机颜色
func getRandomColor(username string) color.RGBA {
hasher := fnv.New32()
hasher.Write([]byte(username))
hash := hasher.Sum32()
return color.RGBA{
R: 150 + uint8(hash>>16)%106,
G: 150 + uint8((hash>>8)%106),
B: 150 + uint8(hash%106),
A: 255,
}
}
// 创建头像
func createAvatar(size int, bgColor color.RGBA, text string) image.Image {
avatar := image.NewRGBA(image.Rect(0, 0, size, size))
draw.Draw(avatar, avatar.Bounds(), &image.Uniform{bgColor}, image.Point{}, draw.Src)
// 在头像上绘制文字
textColor := color.RGBA{255, 255, 255, 255} // 白色文字
fontBytes, err := ioutil.ReadFile("internal/servants/web/typeface/TTF/SourceSans3-Black.ttf")
if err != nil {
log.Println("unable to read font file:", err)
return avatar
}
fontParsed, err := truetype.Parse(fontBytes)
if err != nil {
log.Println("unable to parse font file:", err)
return avatar
}
// 使用 freetype 作为字体渲染器
c := freetype.NewContext()
c.SetDPI(72)
c.SetFont(fontParsed)
c.SetFontSize(float64(size / 2)) // 设置字体大小
c.SetClip(avatar.Bounds())
c.SetDst(avatar)
c.SetSrc(image.NewUniform(textColor))
c.SetHinting(font.HintingFull)
// 创建字体面以计算字符串大小
opts := truetype.Options{}
opts.Size = float64(size) / 2
face := truetype.NewFace(fontParsed, &opts)
// 获取文本的宽度和高度
textWidth := font.MeasureString(face, text).Round()
textHeight := face.Metrics().Height.Round()
// 计算绘制文本的起点,以使其居中
x := (size - textWidth) / 2
y := (size + textHeight/2) / 2
pt := freetype.Pt(x, y)
_, err = c.DrawString(text, pt)
if err != nil {
log.Println("failed to draw string:", err)
}
return avatar
}
func saveImageToBuffer(img image.Image, buffer io.Writer) error {
return png.Encode(buffer, img)
}
// checkPassword 密码检查
func checkPassword(password string) mir.Error {
// 检测用户是否合规

@ -31,7 +31,7 @@ func RouteWeb(e *gin.Engine) {
api.RegisterCoreServant(e, newCoreSrv(ds, oss))
api.RegisterLooseServant(e, newLooseSrv(ds))
api.RegisterPrivServant(e, newPrivSrv(ds, oss))
api.RegisterPubServant(e, newPubSrv(ds))
api.RegisterPubServant(e, newPubSrv(ds, oss))
api.RegisterKeyQueryServant(e, NewShareKeyServant(ds))
api.RegisterRankServant(e, NewRankServant(ds))
api.RegisterFollowshipServant(e, newFollowshipSrv(ds))

@ -304,3 +304,19 @@ export const unfollowTopic = (
data,
});
};
export const uploadImage = (
data: NetParams.UploadImageReq,
uploadToken: string // 添加一个参数来传递 Authorization 头的值
): Promise<NetReq.UploadImageResp> => {
return request({
method: 'post',
url: '/v1/attachment',
data,
headers: {
'Authorization': uploadToken, // 设置 Authorization 头,使用传递的 uploadToken
'Content-Type': 'multipart/form-data', // 设置请求头,表明发送的是 FormData
},
});
};

@ -3,11 +3,7 @@
<div class="compose-wrap" v-if="store.state.userInfo.id > 0">
<div class="compose-line">
<div class="compose-user">
<n-avatar
round
:size="30"
:src="store.state.userInfo.avatar"
/>
<n-avatar round :size="30" :src="store.state.userInfo.avatar" />
</div>
<n-mention
type="textarea"
@ -21,6 +17,7 @@
@search="handleSearch"
@update:value="changeContent"
placeholder="讲讲今天和AiMo AI聊天的新发现吧"
@paste="handlePaste"
/>
</div>
@ -49,8 +46,7 @@
<n-upload-trigger #="{ handleClick }" abstract>
<n-button
:disabled="
(fileQueue.length > 0 &&
uploadType === 'public/video') ||
(fileQueue.length > 0 && uploadType === 'public/video') ||
fileQueue.length === 9
"
@click="
@ -64,10 +60,7 @@
type="primary"
>
<template #icon>
<n-icon
size="20"
color="var(--primary-color)"
>
<n-icon size="20" color="var(--primary-color)">
<image-outline />
</n-icon>
</template>
@ -76,11 +69,12 @@
<n-upload-trigger
v-if="allowTweetVideo"
#="{ handleClick }" abstract>
#="{ handleClick }"
abstract
>
<n-button
:disabled="
(fileQueue.length > 0 &&
uploadType !== 'public/video') ||
(fileQueue.length > 0 && uploadType !== 'public/video') ||
fileQueue.length === 9
"
@click="
@ -94,10 +88,7 @@
type="primary"
>
<template #icon>
<n-icon
size="20"
color="var(--primary-color)"
>
<n-icon size="20" color="var(--primary-color)">
<videocam-outline />
</n-icon>
</template>
@ -134,12 +125,7 @@
</n-button>
</n-upload-trigger> -->
<n-button
quaternary
circle
type="primary"
@click.stop="switchLink"
>
<n-button quaternary circle type="primary" @click.stop="switchLink">
<template #icon>
<n-icon size="20" color="var(--primary-color)">
<compass-outline />
@ -276,10 +262,10 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useStore } from 'vuex';
import { debounce } from 'lodash';
import { getSuggestUsers, getSuggestTags } from '@/api/user';
import { ref, onMounted } from "vue";
import { useStore } from "vuex";
import { debounce } from "lodash";
import { getSuggestUsers, getSuggestTags } from "@/api/user";
import {
ImageOutline,
@ -287,19 +273,17 @@ import {
AttachOutline,
CompassOutline,
EyeOutline,
} from '@vicons/ionicons5';
import { createPost } from '@/api/post';
import { parsePostTag } from '@/utils/content';
import { isZipFile } from '@/utils/isZipFile';
import type { MentionOption, UploadFileInfo, UploadInst } from 'naive-ui';
import { VisibilityEnum, PostItemTypeEnum } from '@/utils/IEnum';
import { userLogin, userRegister, userInfo } from '@/api/auth';
} from "@vicons/ionicons5";
import { createPost, uploadImage } from "@/api/post";
import { parsePostTag } from "@/utils/content";
import { isZipFile } from "@/utils/isZipFile";
import type { MentionOption, UploadFileInfo, UploadInst } from "naive-ui";
import { VisibilityEnum, PostItemTypeEnum } from "@/utils/IEnum";
import { userLogin, userRegister, userInfo } from "@/api/auth";
import { useRouter } from "vue-router";
const emit = defineEmits<{
(e: 'post-success', post: Item.PostProps): void;
(e: "post-success", post: Item.PostProps): void;
}>();
const store = useStore();
@ -310,44 +294,56 @@ const loading = ref(false);
const submitting = ref(false);
const showLinkSet = ref(false);
const showEyeSet = ref(false);
const content = ref('');
const content = ref("");
const links = ref([]);
const uploadRef = ref<UploadInst>();
const attachmentPrice = ref(0);
const uploadType = ref('public/image');
const uploadType = ref("public/image");
const fileQueue = ref<UploadFileInfo[]>([]);
const imageContents = ref<Item.CommentItemProps[]>([]);
const videoContents = ref<Item.CommentItemProps[]>([]);
const attachmentContents = ref<Item.AttachmentProps[]>([]);
const visitType = ref<VisibilityEnum>(VisibilityEnum.FRIEND);
const defaultVisitType = ref<VisibilityEnum>(VisibilityEnum.FRIEND)
const defaultVisitType = ref<VisibilityEnum>(VisibilityEnum.FRIEND);
const visibilities = [
{value: VisibilityEnum.PUBLIC, label: "公开"}
, {value: VisibilityEnum.PRIVATE, label: "私密"}
, {value: VisibilityEnum.FRIEND, label: "好友可见"}
{ value: VisibilityEnum.PUBLIC, label: "公开" },
{ value: VisibilityEnum.PRIVATE, label: "私密" },
{ value: VisibilityEnum.FRIEND, label: "好友可见" },
];
const defaultTweetMaxLength = Number(import.meta.env.VITE_DEFAULT_TWEET_MAX_LENGTH)
const allowUserRegister = ref(import.meta.env.VITE_ALLOW_USER_REGISTER.toLowerCase() === 'true')
const allowTweetVideo = ref(import.meta.env.VITE_ALLOW_TWEET_VIDEO.toLowerCase() === 'true')
const allowTweetAttachment = ref(import.meta.env.VITE_ALLOW_TWEET_ATTACHMENT.toLowerCase() === 'true')
const allowTweetAttachmentPrice = ref(import.meta.env.VITE_ALLOW_TWEET_ATTACHMENT_PRICE.toLowerCase() === 'true')
const allowTweetVisibility = ref(import.meta.env.VITE_ALLOW_TWEET_VISIBILITY.toLowerCase() === 'true')
const uploadGateway = import.meta.env.VITE_HOST + '/v1/attachment';
const defaultTweetMaxLength = Number(
import.meta.env.VITE_DEFAULT_TWEET_MAX_LENGTH
);
const allowUserRegister = ref(
import.meta.env.VITE_ALLOW_USER_REGISTER.toLowerCase() === "true"
);
const allowTweetVideo = ref(
import.meta.env.VITE_ALLOW_TWEET_VIDEO.toLowerCase() === "true"
);
const allowTweetAttachment = ref(
import.meta.env.VITE_ALLOW_TWEET_ATTACHMENT.toLowerCase() === "true"
);
const allowTweetAttachmentPrice = ref(
import.meta.env.VITE_ALLOW_TWEET_ATTACHMENT_PRICE.toLowerCase() === "true"
);
const allowTweetVisibility = ref(
import.meta.env.VITE_ALLOW_TWEET_VISIBILITY.toLowerCase() === "true"
);
const uploadGateway = import.meta.env.VITE_HOST + "/v1/attachment";
const uploadToken = ref();
const switchLink = () => {
showLinkSet.value = !showLinkSet.value;
if (showLinkSet.value && showEyeSet.value) {
showEyeSet.value = false
showEyeSet.value = false;
}
};
const switchEye = () => {
showEyeSet.value = !showEyeSet.value;
if (showEyeSet.value && showLinkSet.value) {
showLinkSet.value = false
showLinkSet.value = false;
}
};
@ -398,7 +394,7 @@ const handleSearch = (k: string, prefix: string) => {
return;
}
loading.value = true;
if (prefix === '@') {
if (prefix === "@") {
loadSuggestionUsers(k);
} else {
loadSuggestionTags(k);
@ -418,10 +414,15 @@ const setUploadType = (type: string) => {
const updateUpload = (list: UploadFileInfo[]) => {
for (let i = 0; i < list.length; i++) {
var name = list[i].name;
var basename: string = name.split('.').slice(0, -1).join('.');
var ext: string = name.split('.').pop()!;
var basename: string = name.split(".").slice(0, -1).join(".");
var ext: string = name.split(".").pop()!;
if (basename.length > 30) {
list[i].name = basename.substring(0, 18) + "..." + basename.substring(basename.length-9) + "." + ext;
list[i].name =
basename.substring(0, 18) +
"..." +
basename.substring(basename.length - 9) +
"." +
ext;
}
}
fileQueue.value = list;
@ -429,51 +430,46 @@ const updateUpload = (list: UploadFileInfo[]) => {
const beforeUpload = async (data: any) => {
// 图片类型校验
if (
uploadType.value === 'public/image' &&
!['image/png', 'image/jpg', 'image/jpeg', 'image/gif'].includes(
uploadType.value === "public/image" &&
!["image/png", "image/jpg", "image/jpeg", "image/gif"].includes(
data.file.file?.type
)
) {
window.$message.warning(' png/jpg/gif ');
window.$message.warning("图片仅允许 png/jpg/gif 格式");
return false;
}
if (uploadType.value === 'image' && data.file.file?.size > 10485760) {
window.$message.warning('10MB');
if (uploadType.value === "image" && data.file.file?.size > 10485760) {
window.$message.warning("图片大小不能超过10MB");
return false;
}
if(uploadType.value === 'public/image') {
if (uploadType.value === "public/image") {
const compressedFile = await compressionFile(data.file.file);
data.file.file = compressedFile;
}
// 视频类型校验
if (
uploadType.value === 'public/video' &&
!['video/mp4', 'video/quicktime'].includes(data.file.file?.type)
uploadType.value === "public/video" &&
!["video/mp4", "video/quicktime"].includes(data.file.file?.type)
) {
window.$message.warning(' mp4/mov ');
window.$message.warning("视频仅允许 mp4/mov 格式");
return false;
}
if (
uploadType.value === 'public/video' &&
data.file.file?.size > 8388608
) {
window.$message.warning('8MB');
if (uploadType.value === "public/video" && data.file.file?.size > 8388608) {
window.$message.warning("视频大小不能超过8MB");
return false;
}
// 附件类型校验
if (
uploadType.value === 'attachment' && !(await isZipFile(data.file.file))
) {
window.$message.warning(' zip ');
if (uploadType.value === "attachment" && !(await isZipFile(data.file.file))) {
window.$message.warning("附件仅允许 zip 格式");
return false;
}
if (uploadType.value === 'attachment' && data.file.file?.size > 104857600) {
window.$message.warning('100MB');
if (uploadType.value === "attachment" && data.file.file?.size > 104857600) {
window.$message.warning("附件大小不能超过100MB");
return false;
}
@ -489,14 +485,14 @@ const beforeUpload = async (data: any) => {
*/
const compressionFile = async (
file: Blob,
type: string = 'image/jpeg',
type: string = "image/jpeg",
quality: number = 0.4,
maxWidth: number = 1920, // 设置压缩后的最大宽度
maxHeight: number = 1920 // 设置压缩后的最大高度
) => {
const fileName = file.name;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d') as CanvasRenderingContext2D;
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d") as CanvasRenderingContext2D;
const base64 = await fileToDataURL(file);
const img = await dataURLToImage(base64);
@ -525,14 +521,14 @@ const compressionFile = async (
const newFile = new File([blob], fileName, { type });
return newFile;
}
};
const fileToDataURL = (file: Blob): Promise<any> => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = (e) => resolve((e.target as FileReader).result);
reader.readAsDataURL(file);
});
}
};
const dataURLToImage = (dataURL: string): Promise<HTMLImageElement> => {
return new Promise((resolve) => {
@ -540,32 +536,36 @@ const dataURLToImage = (dataURL: string): Promise<HTMLImageElement> => {
img.onload = () => resolve(img);
img.src = dataURL;
});
}
};
const canvasToFile = (canvas: HTMLCanvasElement, type: string, quality: number): Promise<Blob | null> => {
const canvasToFile = (
canvas: HTMLCanvasElement,
type: string,
quality: number
): Promise<Blob | null> => {
return new Promise((resolve) =>
canvas.toBlob((blob) => resolve(blob), type, quality)
);
}
};
const finishUpload = ({ file, event }: any): any => {
try {
let data = JSON.parse(event.target?.response);
if (data.code === 0) {
if (uploadType.value === 'public/image') {
if (uploadType.value === "public/image") {
imageContents.value.push({
id: file.id,
content: data.data.content,
} as Item.CommentItemProps);
}
if (uploadType.value === 'public/video') {
if (uploadType.value === "public/video") {
videoContents.value.push({
id: file.id,
content: data.data.content,
} as Item.CommentItemProps);
}
if (uploadType.value === 'attachment') {
if (uploadType.value === "attachment") {
attachmentContents.value.push({
id: file.id,
content: data.data.content,
@ -573,7 +573,7 @@ const finishUpload = ({ file, event }: any): any => {
}
}
} catch (error) {
window.$message.error('');
window.$message.error("上传失败");
}
};
const failUpload = ({ file, event }: any): any => {
@ -581,16 +581,16 @@ const failUpload = ({ file, event }: any): any => {
let data = JSON.parse(event.target?.response);
if (data.code !== 0) {
let errMsg = data.msg || '';
let errMsg = data.msg || "上传失败";
if (data.details && data.details.length > 0) {
data.details.map((detail: string) => {
errMsg += ':' + detail;
errMsg += ":" + detail;
});
}
window.$message.error(errMsg);
}
} catch (error) {
window.$message.error('');
window.$message.error("上传失败");
}
};
const removeUpload = ({ file }: any) => {
@ -611,7 +611,7 @@ const removeUpload = ({ file }: any) => {
// 发布动态
const submitPost = () => {
if (content.value.trim().length === 0) {
window.$message.warning('');
window.$message.warning("请输入内容哦");
return;
}
@ -668,19 +668,19 @@ const submitPost = () => {
tags: Array.from(new Set(tags)),
users: Array.from(new Set(users)),
attachment_price: +attachmentPrice.value * 100,
visibility: visitType.value
visibility: visitType.value,
})
.then((res) => {
window.$message.success('');
window.$message.success("发布成功");
submitting.value = false;
emit('post-success', res);
emit("post-success", res);
// 置空
showLinkSet.value = false;
showEyeSet.value = false;
uploadRef.value?.clear();
fileQueue.value = [];
content.value = '';
content.value = "";
links.value = [];
imageContents.value = [];
videoContents.value = [];
@ -688,7 +688,7 @@ const submitPost = () => {
visitType.value = defaultVisitType.value;
//转到初始页面
router.push({
name: 'home',
name: "home",
});
})
.catch((err) => {
@ -696,34 +696,137 @@ const submitPost = () => {
});
};
const triggerAuth = (key: string) => {
store.commit('triggerAuth', true);
store.commit('triggerAuthKey', key);
store.commit("triggerAuth", true);
store.commit("triggerAuthKey", key);
};
const generateRandomFileName = (extension: any) => {
const timestamp = new Date().getTime(); // 获取当前时间戳
const randomString = Math.random().toString(36).substring(2, 15); // 生成随机字符串
return `${timestamp}-${randomString}.${extension}`;
};
//粘贴事件监听
const handlePaste = (event: ClipboardEvent) => {
if (event && event.clipboardData) {
const items = event.clipboardData.items;
let file: File | null = null;
if (items && items.length) {
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) {
file = items[i].getAsFile();
break;
}
}
}
if (file) {
const fileExtension = file.name.split(".").pop();
const randomFileName = generateRandomFileName(fileExtension);
const fileSize = file.size;
// 以二进制形式读取文件内容
const reader = new FileReader();
reader.onload = function (event) {
if (
event &&
event.target &&
event.target.result instanceof ArrayBuffer
) {
// 获取文件内容
const fileContent = new Uint8Array(event.target.result);
// 创建 Blob
const blob = new Blob([fileContent], { type: "image/jpeg" });
// 这里可以使用 blob 了
const formData = new FormData();
// 添加文件到 FormData 对象
formData.append('type', 'public/image');
formData.append("file", blob, randomFileName);
const uploadImageReq: NetParams.UploadImageReq = {
type: formData.get('type') as string,
file: formData.get('file') as File,
};
// 声明一个 Ref 对象
// const uploadToken: Ref<string> = ref('your_upload_token_here');
// 获取 Ref 对象的值并赋给 string 类型的变量
// const token: string = uploadToken.value;
// const token = ref(uploadToken)
uploadImage(uploadImageReq, uploadToken.value)
.then((response) => {
// 处理响应
const pasteTimestamp = new Date().getTime()
const pasteFile : UploadFileInfo[] = [{
id: pasteTimestamp.toString(),
name: randomFileName,
batchId: pasteTimestamp.toString(),
percentage: 100,
status: 'finished',
url: null,
file: file,
thumbnailUrl: null,
type: "image/jpeg",
fullPath: "/" + randomFileName,
}]
const combinedFileList = fileQueue.value.concat(pasteFile);
updateUpload(combinedFileList)
imageContents.value.push({
id: pasteTimestamp.toString(),
content: response.content,
} as Item.CommentItemProps);
})
.catch((error) => {
// 处理错误
console.error('', error);
});
}
};
reader.readAsArrayBuffer(file);
}
}
};
onMounted(() => {
if (import.meta.env.VITE_DEFAULT_TWEET_VISIBILITY.toLowerCase() === 'friend') {
defaultVisitType.value = VisibilityEnum.FRIEND
} else if (import.meta.env.VITE_DEFAULT_TWEET_VISIBILITY.toLowerCase() === 'public') {
defaultVisitType.value = VisibilityEnum.PUBLIC
if (
import.meta.env.VITE_DEFAULT_TWEET_VISIBILITY.toLowerCase() === "friend"
) {
defaultVisitType.value = VisibilityEnum.FRIEND;
} else if (
import.meta.env.VITE_DEFAULT_TWEET_VISIBILITY.toLowerCase() === "public"
) {
defaultVisitType.value = VisibilityEnum.PUBLIC;
} else {
defaultVisitType.value = VisibilityEnum.PRIVATE
defaultVisitType.value = VisibilityEnum.PRIVATE;
}
visitType.value = defaultVisitType.value;
uploadToken.value = 'Bearer ' + localStorage.getItem('PAOPAO_TOKEN');
uploadToken.value = "Bearer " + localStorage.getItem("PAOPAO_TOKEN");
// 获取完整URL
const fullURL = window.location.href;
// 从完整URL中获取hash部分包括#号)
const hash = fullURL.split('#/')[1];
const hash = fullURL.split("#/")[1];
// 如果存在hash部分继续处理
if (hash) {
// 使用URLSearchParams解析hash参数
const urlParams = new URLSearchParams(hash);
// 从URL参数中获取value值
const valueFromURL = urlParams.get('share');
const contentValue = ref('');
const valueFromURL = urlParams.get("share");
const contentValue = ref("");
if (valueFromURL) {
const parts = valueFromURL.split('[52570552A939]').filter(part => part.trim() !== '');
const parts = valueFromURL
.split("[52570552A939]")
.filter((part) => part.trim() !== "");
if (store.state.userInfo.id > 0) {
// 用户已登录组装contentValue
} else {
@ -733,9 +836,9 @@ onMounted(() => {
password: "share[52570552A393]" + parts[5],
})
.then((res) => {
const token = res?.token || '';
const token = res?.token || "";
// 写入用户信息
localStorage.setItem('PAOPAO_TOKEN', token);
localStorage.setItem("PAOPAO_TOKEN", token);
return userInfo(token);
})
@ -743,21 +846,30 @@ onMounted(() => {
// window.$message.success('登录成功');
loading.value = false;
store.commit('updateUserinfo', res);
store.commit('triggerAuth', false);
store.commit('refresh')
store.commit("updateUserinfo", res);
store.commit("triggerAuth", false);
store.commit("refresh");
})
.catch((err) => {
loading.value = false;
});
}
contentValue.value = parts[0] + " \n\n" + "今天探索Aimo新发现了一端有趣的c#代码" + " \n\n" +
"名字:\n " + parts[1] + "\n" +
"介绍:\n " + parts[2] + "\n" +
"分享码:\n " + parts[3];
contentValue.value =
parts[0] +
" \n\n" +
"今天探索Aimo新发现了一端有趣的c#代码" +
" \n\n" +
"名字:\n " +
parts[1] +
"\n" +
"介绍:\n " +
parts[2] +
"\n" +
"分享码:\n " +
parts[3];
}
// 将获取的value值放入content中
content.value = contentValue.value || ''; // 如果没有参数,默认为空字符串
content.value = contentValue.value || ""; // 如果没有参数,默认为空字符串
}
});
</script>
@ -810,7 +922,7 @@ onMounted(() => {
width: 100%;
button {
margin: 0 4px;
width: 50%
width: 50%;
}
}
.login-wrap {

@ -6,7 +6,7 @@
name: 'user',
query: { s: props.reply.user.username },
}">
{{ props.reply.user.username }}
{{ props.reply.user.nickname }}
</router-link>
<span class="reply-name">
{{ props.reply.at_user_id > 0 ? '' : ':' }}
@ -16,7 +16,7 @@
name: 'user',
query: { s: props.reply.at_user.username },
}" v-if="props.reply.at_user_id > 0">
{{ props.reply.at_user.username }}
{{ props.reply.at_user.nickname }}
</router-link>
</div>
<div class="timestamp">

@ -160,6 +160,7 @@ import { useRouter } from "vue-router";
import { getDownloadRank, getHighQuailty, getTags } from "@/api/post";
import { Search } from "@vicons/ionicons5";
import { ChevronForward } from "@vicons/ionicons5";
import { Ref } from 'vue';
const hotTags = ref<Item.TagProps[]>([]);
const followTags = ref<Item.TagProps[]>([]);
@ -187,7 +188,7 @@ const DownloadPreWeekRankingList = ref<Item.RankingDataProps[]>([]);
const DownloadPreMonthRankingList = ref<Item.RankingDataProps[]>([]);
//获取排行榜数据
const locadHeighQuailtyRankingList = () => {
const loadHeighQuailtyRankingList = () => {
rankloading.value = true;
getHighQuailty()
.then((res) => {
@ -199,13 +200,13 @@ const locadHeighQuailtyRankingList = () => {
});
};
const loadDowmloadRankingByType = (type: number) => {
const loadDownloadRankingByType = (type: number) => {
rankloading.value = true;
getDownloadRank(type)
.then((res) => {
if (type === 1) allDownloadRankingList.value = res.list;
if (type === 2) DownloadPreWeekRankingList.value = res.list;
if (type === 3) DownloadPreMonthRankingList.value = res.list;
else if (type === 2) DownloadPreWeekRankingList.value = res.list;
else if (type === 3) DownloadPreMonthRankingList.value = res.list;
rankloading.value = false;
})
.catch((err) => {
@ -231,25 +232,28 @@ const toggleRankingType = () => {
NextRankingType.value = rankingTypes[(currentRankingTypeIndex + 1) % rankingTypes.length];
};
//1总 2周 3月
const rankingTypeToFunctionMap: { [key: string]: Ref<Item.RankingDataProps[]> } = {
highQuality: rankingList,
downloadAll: allDownloadRankingList,
downloadPreWeek: DownloadPreWeekRankingList,
downloadPreMonth: DownloadPreMonthRankingList
};
const rankingTypeToLoadFunctionMap: { [key: string]: () => void } = {
downloadAll: () => loadDownloadRankingByType(1),
downloadPreWeek: () => loadDownloadRankingByType(2),
downloadPreMonth: () => loadDownloadRankingByType(3)
};
const getCurrentRankingList = computed(() => {
if (currentRankingType.value === "highQuality") {
return rankingList.value;
} else if (currentRankingType.value === "downloadAll") {
if (allDownloadRankingList.value.length === 0) {
loadDowmloadRankingByType(1);
}
return allDownloadRankingList.value;
} else if (currentRankingType.value === "downloadPreWeek") {
if (DownloadPreWeekRankingList.value.length === 0) {
loadDowmloadRankingByType(2);
}
return DownloadPreWeekRankingList.value;
} else if (currentRankingType.value === "downloadPreMonth") {
if (DownloadPreMonthRankingList.value.length === 0) {
loadDowmloadRankingByType(3);
const currentType = currentRankingType.value;
const rankingValue = rankingTypeToFunctionMap[currentType as keyof typeof rankingTypeToFunctionMap]?.value;
if (rankingValue !== undefined) {
if (rankingValue.length === 0 && rankingTypeToLoadFunctionMap[currentType]) {
rankingTypeToLoadFunctionMap[currentType]();
}
return DownloadPreMonthRankingList.value;
return rankingValue;
}
return [];
});
@ -320,7 +324,7 @@ watch(
);
onMounted(() => {
loadHotTags();
locadHeighQuailtyRankingList();
loadHeighQuailtyRankingList();
});
</script>

@ -279,4 +279,11 @@ declare module NetParams {
interface PostUnfollowTopic {
topic_id: number;
}
/** 上传图片请求参数 */
interface UploadImageReq {
file: File;
type: string;
}
}

@ -203,4 +203,15 @@ declare module NetReq {
interface PostFollowTopic {}
interface PostUnfollowTopic {}
/** 上传图片响应参数 */
interface UploadImageResp {
/** 图片URL */
content: string;
file_size: number;
img_height: number;
img_width: number;
type: number;
user_id: number;
}
}

@ -158,7 +158,7 @@ import MainNav from "@/components/main-nav.vue";
const store = useStore();
const route = useRoute();
const showRecharge = ref(false);
const selectedRechargeAmount = ref(100);
const selectedRechargeAmount = ref(3000);
const recharging = ref(false);
const rechargeQrcode = ref('');
const loading = ref(false);

Loading…
Cancel
Save