修改用户默认头像为用户名前两位,增加粘贴图片功能,更改充值默认金额为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
},
});
};

File diff suppressed because it is too large Load Diff

@ -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;
if (type === 1) allDownloadRankingList.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