Compare commits

..

No commits in common. 'main' and 'master' have entirely different histories.
main ... master

Binary file not shown.

@ -0,0 +1,14 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
# 数据库连接字符串
SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:mypassword12@127.0.0.1:3306/lianai"
# 创建数据库引擎
engine = create_engine(SQLALCHEMY_DATABASE_URL)
# 创建会话本地类
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 声明基类
Base = declarative_base()

@ -0,0 +1,247 @@
from faker import Faker
from sqlalchemy.orm import Session
from database import SessionLocal, Base, engine
from models import User
# 初始化 Faker 并指定中文语言
fake = Faker('zh_CN')
# 创建会话
session: Session = SessionLocal()
# 定义爱好列表
hobbies = [
"阅读", "旅行", "摄影", "音乐", "电影", "运动", "绘画", "编程", "烹饪", "园艺",
"徒步", "瑜伽", "舞蹈", "健身", "游泳", "跑步", "骑行", "攀岩", "滑雪", "冲浪",
"钓鱼", "高尔夫", "网球", "篮球", "足球", "乒乓球", "羽毛球", "台球", "棋类", "象棋",
"围棋", "桥牌", "扑克", "桌游", "魔术", "魔术表演", "魔术制作", "手工艺", "编织", "刺绣",
"陶艺", "木工", "园艺设计", "园艺维护", "宠物护理", "宠物训练", "宠物摄影", "宠物美容",
"汽车修理", "汽车驾驶", "摩托车驾驶", "赛车", "飞行", "潜水", "跳伞", "攀冰", "攀岩",
"皮划艇", "独木舟", "帆船", "帆板", "冲浪", "滑水", "滑雪", "雪板", "滑翔伞", "热气球",
"徒步旅行", "背包旅行", "露营", "野餐", "烧烤", "音乐会", "戏剧", "歌剧", "芭蕾舞", "舞蹈",
"戏剧表演", "歌唱", "乐器演奏", "吉他", "钢琴", "小提琴", "长笛", "萨克斯", "", "打击乐",
"写作", "小说创作", "诗歌创作", "散文创作", "剧本创作", "博客写作", "新闻写作", "翻译",
"播客制作", "视频制作", "电影制作", "摄影", "航拍", "剪辑", "后期制作", "游戏开发",
"软件开发", "编程", "数据分析", "机器学习", "人工智能", "网络安全", "区块链", "云计算",
"虚拟现实", "增强现实", "机器人技术", "自动化", "电子工程", "机械工程", "生物工程",
]
university = [
"北京大学",
"清华大学",
"浙江大学",
"上海交通大学",
"复旦大学",
"南京大学",
"中国科学技术大学",
"哈尔滨工业大学",
"天津大学",
"华中科技大学",
"中山大学",
"华南理工大学",
"武汉大学",
"四川大学",
"西安交通大学",
"东南大学",
"同济大学",
"北京航空航天大学",
"北京理工大学",
"西北工业大学",
"中国人民大学",
"北京师范大学",
"南开大学",
"厦门大学",
"山东大学",
"吉林大学",
"湖南大学",
"重庆大学",
"大连理工大学",
"电子科技大学",
"兰州大学",
"东北大学",
"中国农业大学",
"国防科技大学",
"中南大学",
"中国海洋大学",
"中央民族大学",
"华东师范大学",
"北京工业大学",
"北京化工大学",
"北京邮电大学",
"北京林业大学",
"北京中医药大学",
"北京外国语大学",
"对外经济贸易大学",
"中国政法大学",
"中央财经大学",
"中国传媒大学",
"中央音乐学院",
"中央美术学院",
"北京体育大学",
"华北电力大学",
"北京科技大学",
"北京交通大学",
"中国地质大学",
"中国矿业大学",
"中国石油大学",
"北京语言大学",
"北京信息科技大学",
"首都医科大学",
"首都师范大学",
"首都经济贸易大学",
"外交学院",
"国际关系学院",
"北京电影学院",
"中国戏曲学院",
"中央戏剧学院",
"中国科学院大学",
"中国社会科学院大学",
"中国人民公安大学",
"中国刑事警察学院",
"中国消防救援学院",
"中央司法警官学院",
"南京航空航天大学",
"南京理工大学",
"河海大学",
"南京农业大学",
"南京师范大学",
"苏州大学",
"江南大学",
"南京信息工程大学",
"南京邮电大学",
"南京林业大学",
"南京中医药大学",
"南京医科大学",
"南京艺术学院",
"南京体育学院",
"南京审计大学",
"江苏大学",
"扬州大学",
"江苏师范大学",
"常州大学",
"南通大学",
"苏州科技大学",
"徐州医科大学",
"江苏科技大学",
"南京晓庄学院",
"金陵科技学院",
"南京工程学院",
"南京特殊教育师范学院",
"苏州科技大学",
"江苏理工学院",
"淮阴工学院",
"盐城工学院",
"江苏海洋大学",
"江苏师范大学",
"徐州工程学院",
"宿迁学院",
"无锡太湖学院",
"常州工学院",
"南京森林警察学院",
"江苏警官学院",
"江苏第二师范学院",
"江苏卫生健康职业学院",
"江苏经贸职业技术学院",
"南京工业职业技术大学",
"南京铁道职业技术学院",
"江苏食品药品职业技术学院",
"江苏农林职业技术学院",
"江苏建筑职业技术学院",
"江苏城市职业学院",
"江苏信息职业技术学院",
"江苏航运职业技术学院",
"江苏旅游职业学院",
"江苏护理职业学院",
"江苏财经职业技术学院",
"江苏安全技术职业学院",
"江苏商贸职业学院",
"江苏工程职业技术学院",
"江苏农牧科技职业学院",
"江苏医药职业学院",
"江苏电子信息职业学院",
"江苏海事职业技术学院",
"江苏航空职业技术学院",
"江苏交通职业技术学院",
"江苏联合职业技术学院",
"江苏开放大学",
"江苏广播电视大学",
"江苏远程教育中心",
'福州大学',
]
middle_school = [
"第一中学",
"第二中学",
"第三中学",
"实验中学",
"育才中学",
"光明中学",
"希望中学",
"胜利中学",
"友谊中学",
"和平中学"
]
img_url=[
"img/thought-balloon.f04a98df.png",
"img/ghost.e931ffda.png",
"img/rainbow.f269a036.png",
"",
]
# 生成大量模拟数据
def generate_fake_users(num_users):
fake_users = []
existing_usernames = set(user.username for user in session.query(User.username).all())
while len(fake_users) < num_users:
location = fake.city() # 生成市级地址
education = fake.random_element(elements=('初中', '高中', '本科', '研究生', '博士')) # 生成学历
if education in ['初中', '高中']:
# 从 middle_school 中随机选择一个中学,并结合 location
middle_school_name = fake.random_element(elements=middle_school)
graduation_school = f"{location}{middle_school_name}"
else:
# 从 university 中随机选择一个大学
graduation_school = fake.random_element(elements=university)
user = User(
username=fake.unique.user_name(), # 生成唯一用户名
password=fake.password(length=10), # 生成密码
head_img=fake.random_element(elements=img_url), # 生成头像链接
sex=fake.random_element(elements=('', '')), # 生成性别
age=fake.random_int(min=18, max=40), # 生成年龄
height=f"{fake.random_int(min=150, max=200)} cm", # 生成身高并添加 cm 后缀
weight=f"{fake.random_int(min=40, max=150)} kg", # 生成体重并添加 kg 后缀
hobby=fake.random_element(elements=hobbies), # 从预定义列表中随机选择爱好
tips=fake.sentence(nb_words=10), # 生成个人签名
location=location, # 使用生成的市级地址
education=education, # 使用生成的学历
graduation_school=graduation_school, # 根据学历生成的毕业院校
work_place=fake.company(), # 生成工作单位
job=fake.job()[:15], # 生成职位并限制长度
monthly_income=str(fake.random_int(min=3000, max=30000)), # 生成月收入
house=fake.random_element(elements=('没有', '贷款买房', '有房')), # 生成买房情况
car=fake.random_element(elements=('没有', '有车')) # 生成买车情况
)
if user.username not in existing_usernames:
fake_users.append(user)
existing_usernames.add(user.username)
return fake_users
# 插入模拟数据
num_users_to_generate = 1000 # 生成 1000 个用户
fake_users = generate_fake_users(num_users_to_generate)
# 批量插入数据
session.bulk_save_objects(fake_users)
session.commit()
print(f"成功插入 {num_users_to_generate} 个模拟用户")
# 关闭会话
session.close()

@ -0,0 +1,427 @@
from datetime import datetime
from fastapi import FastAPI, Depends, Request
from database import engine, SessionLocal
from models import User
from sqlalchemy.orm import Session
import uvicorn
from models import User ,ChatMessage,Friend
from sqlalchemy import and_
from sqlalchemy import or_
from recommend1 import recommend
app = FastAPI()
# 创建所有表
User.metadata.create_all(bind=engine)
ChatMessage.metadata.create_all(bind=engine)
Friend.metadata.create_all(bind=engine)
# 依赖注入:获取数据库会话
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# 登录
@app.post("/login")
async def login(request: Request, db: Session = Depends(get_db)):
user_data =await request.json()
print(user_data)
user=db.query(User).filter(User.username==user_data['username']).first()
if user:
if user.password==user_data['password']:
return {"code":200,"msg":"登录成功","user":user.username}
else:
return {"code":400,"msg":"密码错误"}
return {"code":501,"msg":"账号不存在"}
# 注册
@app.post("/register")
async def register(request: Request, db: Session = Depends(get_db)):
user_data =await request.json()
users=db.query(User).filter(User.username==user_data['username']).first()
if users:
return {"code":501,"msg":"账号已存在"}
elif user_data['password']!=user_data['password2']:
return {"code":400,"msg":"两次密码不一致"}
else:
new_user=User(username=user_data['username'],password=user_data['password'])
db.add(new_user)
db.commit()
db.refresh(new_user)
print(new_user)
return {"code":200,"msg":"注册成功"}
#获取头像
@app.get("/get_headimg")
async def get_headimg(request: Request, db: Session = Depends(get_db)):
username = request.query_params.get('username')
if not username:
return {"code": 501, "msg": "未提供用户名"}
user = db.query(User).filter(User.username == username).first()
if not user:
return {"code": 501, "msg": "用户不存在"}
headimg=user.head_img
return headimg
#推荐页面
import random
@app.post("/get_recomusers")
async def get_recomusers(request: Request, db: Session = Depends(get_db)):
user_data = await request.json()
username = user_data['username']
if not username:
return {"code": 501, "msg": "未登录"}
elif not db.query(User).filter(User.username == username).first():
return {"code": 501, "msg": "账号不存在"}
user = db.query(User).filter(User.username == username).first()
if user.age==None or user.height==None or user.weight==None or user.monthly_income==None or user.education==None or user.graduation_school==None or user.work_place==None or user.house==None or user.car==None or user.tips==None or user.hobby==None or user.location==None:
user_sex = user.sex
friendlist = db.query(Friend).filter(Friend.username == username).all()
# 提取所有朋友的用户名
friend_usernames = [friend.friend_username for friend in friendlist]
users = db.query(User).filter(
User.username != username,
User.sex != user_sex,
~User.username.in_(friend_usernames)
).all()
# 随机选择100个用户如果用户数量少于100则选择所有用户
recommended_users = random.sample(users, min(12, len(users)))
userList = []
for user in recommended_users:
userList.append({
'name': user.username,
'age': user.age,
'hobby': user.hobby,
'city': user.location,
'description': user.tips,
'height': user.height,
'job': user.job,
'avatar': user.head_img,
})
return {"code": 200, "response": "ok", "data": userList}
else :
result = recommend(username)
return result
#搜索页面
#获得用户列表
@app.post("/get_users")
async def get_users(request: Request, db: Session = Depends(get_db)):
user_data = await request.json()
username = user_data['username']
query=user_data['query']
print(query)
if not username:
return {"code": 501, "msg": "未登录"}
elif not db.query(User).filter(User.username == username).first():
return {"code": 501, "msg": "账号不存在"}
user = db.query(User).filter(User.username == username).first()
user_sex = user.sex
friendlist = db.query(Friend).filter(Friend.username == username).all()
# 提取所有朋友的用户名
friend_usernames = [friend.friend_username for friend in friendlist]
if query:
users = db.query(User).filter(
User.username != username,
User.sex != user_sex,
~User.username.in_(friend_usernames),
or_(User.location.like(f"%{query}%"),
User.hobby.like(f"%{query}%"),
User.job.like(f"%{query}%"),
User.username.like(f"%{query}%")),
).all()
else:
users = db.query(User).filter(
User.username != username,
User.sex != user_sex,
~User.username.in_(friend_usernames),
).all()
userList = []
for user in users:
userList.append({
'name': user.username,
'age': user.age,
'hobby': user.hobby,
'city': user.location,
'description': user.tips,
'height': user.height,
'job': user.job,
'avatar': user.head_img,
})
return {"code": 200, "response": "ok", "data": userList}
#添加好友
@app.post("/make_friend")
async def make_friend(request: Request, db: Session = Depends(get_db)):
try:
data = await request.json()
print(data)
if not data['username']:
return {"code":501,"msg":"未登录"}
if not db.query(User).filter(User.username==data['friendname']).first():
return {"code":501,"msg":"对象不存在"}
new_friend=Friend(username=data['username'],friend_username=data['friendname'])
db.add(new_friend)
db.commit()
db.refresh(new_friend)
new_friend2=Friend(username=data['friendname'],friend_username=data['username'])
db.add(new_friend2)
db.commit()
db.refresh(new_friend2)
return {"code":200,"msg":"成功添加好友"}
except Exception as e:
return {"code":501,"msg":'服务器出错'}
# 修改密码和用户名
@app.post("/changecp")
async def change_cp(request: Request, db: Session = Depends(get_db)):
user_data =await request.json()
if not user_data['username'] :
return {"code":501,"msg":"未登录"}
if not user_data['newusername'] and not user_data['password'] and not user_data['password2']:
return {"code":501,"msg":"未作修改"}
else:
if user_data['password']!=user_data['password2']:
return {"code":501,"msg":"两次密码不一致"}
if user_data['newusername']==user_data['username']:
return {"code":501,"msg":"新旧用户名一致"}
elif db.query(User).filter(User.username==user_data['newusername']).first():
return {"code":501,"msg":"用户已存在"}
user=db.query(User).filter(User.username==user_data['username']).first()
if user_data['password']:
user.password=user_data['password']
if user_data['newusername']:
user.username=user_data['newusername']
db.commit()
db.refresh(user)
return {"code":200,"msg":"修改成功"}
# 获取好友列表
@app.post("/friend/friendList")
async def friendlist(request: Request, db: Session = Depends(get_db)):
user_data =await request.json()
username=user_data['username']
if not username:
return {"code":501,"msg":"未登录"}
elif db.query(User).filter(User.username==username).first()==None:
return {"code":501,"msg":"账号不存在"}
friends=db.query(Friend).filter(Friend.username==username).all()
friendList=[]
for friend in friends:
friendList.append({
"img": "",
"name": friend.friend_username,
"detail": "",
"lastMsg": friend.last_message,
"id": friend.friend_username,
"headImg": friend.friend.head_img,
})
return friendList
# 获取聊天记录
@app.post("/friend/chatMsg")
async def chatmsg(request: Request, db: Session = Depends(get_db)):
data=await request.json()
if not data['username']:
return {"code":501,"msg":"未登录"}
chatmessage = db.query(ChatMessage).filter(
(ChatMessage.sender_username == data['username']) & (ChatMessage.receiver_username == data['frinedId']) |
(ChatMessage.sender_username == data['frinedId']) & (ChatMessage.receiver_username == data['username'])
).order_by(ChatMessage.timestamp.asc()).all()
chatMsg=[]
for message in chatmessage:
if message.chatType==0:
chatMsg.append({
"headImg": message.sender.head_img,
"name": message.sender_username,
"time": message.timestamp,
"msg": message.message_text,
"chatType": message.chatType,
"uid": message.sender_username,
})
elif message.chatType==1:# 图片
chatMsg.append({
"headImg": message.sender.head_img,
"name": message.sender_username,
"time": message.timestamp,
"msg": message.image_content,
"chatType": message.chatType,
"uid": message.sender_username,
"extend":{
"imgType": message.image_type,
},
})
return chatMsg
# 获取用户信息
@app.post("/user/userInfo")
async def get_userinfo(request: Request, db: Session = Depends(get_db)):
user_data =await request.json()
if not user_data['username']:
return {"code":501,"msg":"未登录"}
user_data=db.query(User).filter(User.username==user_data['username']).first()
userInfo={
"img": "",
"name": user_data.username,
"detail": "666",
"lastMsg": "",
"id": user_data.username,
"headImg": user_data.head_img,
}
print(userInfo)
return userInfo
#接收聊天的数据
@app.post("/friend/updateChatMsg")
async def get_userinfo(request: Request, db: Session = Depends(get_db)):
data=await request.json()
if not data['username']:
return {"code":501,"msg":"未登录"}
if db.query(User).filter(User.username==data['frinedId']).first()==None:
return {"code":501,"msg":"聊天对象不存在"}
if data['newMsg']['chatType']==0: # 文本
if data['newMsg']['name']==data['username']: # 发送方是用户
new_message=ChatMessage(sender_username=data['username'],receiver_username=data['frinedId'],message_text=data['newMsg']['msg'],chatType=data['newMsg']['chatType'],timestamp=datetime.now())
elif data['newMsg']['name']==data['friendId']: # 发送方是好友
new_message=ChatMessage(sender_username=data['friendId'],receiver_username=data['username'],message_text=data['newMsg']['msg'],chatType=data['newMsg']['chatType'],timestamp=datetime.now())
elif data['newMsg']['chatType']==1: # 图片
if data['newMsg']['name']==data['username']: # 发送方是用户
new_message=ChatMessage(sender_username=data['username'],receiver_username=data['frinedId'],image_content=data['newMsg']['msg'],chatType=data['newMsg']['chatType'],image_type=int(data['newMsg']['extend']['imgType']),timestamp=datetime.now())
db.add(new_message)
db.commit()
db.refresh(new_message)
#print(data)
return {"success": True, "message": "Message added successfully"}
# 获取用户详细信息
@app.get("/get_userinformation")
async def get_userinformation(request: Request, db: Session = Depends(get_db)):
username = request.query_params.get('username')
#print(f"Received username: {username}")
if not username:
return {"code": 501, "msg": "未提供用户名"}
user = db.query(User).filter(User.username == username).first()
if not user:
return {"code": 501, "msg": "用户不存在"}
userInfo = {
"avatarUrl": user.head_img,
"nickname": user.username,
"gender": user.sex,
"age": user.age,
"residence": user.location,
"height": user.height,
"weight": user.weight,
"education": user.education,
"graduateSchool": user.graduation_school,
"workUnit": user.work_place,
"currentPosition": user.job,
"monthlyIncome": user.monthly_income,
"hobit": user.hobby,
"tips": user.tips,
"house": user.house,
"car": user.car,
}
return userInfo
#更新用户信息
@app.post("/update_userinfo")
async def update_userinformation(request: Request, db: Session = Depends(get_db)):
try:
data = await request.json()
print(data)
if not data['username']:
return {"code":501,"msg":"未登录"}
user=db.query(User).filter(User.username==data['username']).first()
print(user)
user.head_img=data['user_info']['avatarUrl']
user.sex=data['user_info']['gender']
user.age=data['user_info']['age']
user.location=data['user_info']['residence']
user.height=data['user_info']['height']
user.weight=data['user_info']['weight']
user.education=data['user_info']['education']
user.graduation_school=data['user_info']['graduateSchool']
user.work_place=data['user_info']['workUnit']
user.job=data['user_info']['currentPosition']
user.monthly_income=data['user_info']['monthlyIncome']
user.hobby=data['user_info']['hobit']
user.tips=data['user_info']['tips']
user.house=data['user_info']['house']
user.car=data['user_info']['car']
db.commit()
db.refresh(user)
return {"code":200,"msg":"更新成功"}
except Exception as e:
return {"code":501,"msg":'更新失败'}
#上传头像
@app.post("/update_headimg")
async def upload_headimg(request: Request, db: Session = Depends(get_db)):
try:
data = await request.json()
#print(data)
if not data['username']:
return {"code":501,"msg":"未登录"}
user=db.query(User).filter(User.username==data['username']).first()
user.head_img=data['newheadimg']
db.commit()
db.refresh(user)
return {"code":200,"msg":"更新成功"}
except Exception as e:
return {"code":501,"msg":'图片过大'}
from fastapi.middleware.cors import CORSMiddleware
# 配置 CORS
origins = [
"http://localhost:8081", # 允许的源,必须要指定
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
if __name__ == '__main__':
# 运行fastapi程序
uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True)

@ -0,0 +1,49 @@
from sqlalchemy import Column, Integer, String, ForeignKey, LargeBinary, DateTime, Text
from sqlalchemy.orm import relationship
from database import Base
from datetime import datetime
from sqlalchemy.dialects.mysql import LONGTEXT
class User(Base):
__tablename__ = "users"
username = Column(String(30),index=True,primary_key=True)
password = Column(String(100), index=True,nullable=False)
head_img = Column(LONGTEXT) # 头像
sex=Column(String(30)) # 性别
age=Column(Integer) # 年龄
height=Column(String(30)) # 身高
weight=Column(String(30)) # 体重
hobby=Column(Text) # 爱好
tips=Column(Text) # 个人签名
location=Column(Text) # 居住地
education=Column(String(30)) # 学历
graduation_school=Column(String(30))# 毕业院校
work_place=Column(String(30)) # 工作单位
job=Column(String(100)) # 职位
monthly_income=Column(String(30)) # 月收入
house=Column(String(40)) # 买房情况
car=Column(String(40)) # 买车情况
class ChatMessage(Base):
__tablename__ = "chat_messages"
id = Column(Integer, primary_key=True, index=True)
sender_username = Column(String(30), ForeignKey('users.username', onupdate='CASCADE'), nullable=False)
receiver_username = Column(String(30), ForeignKey('users.username', onupdate='CASCADE'), nullable=False)
message_text = Column(String(500)) # 文字消息
image_content = Column(LONGTEXT) # 图片内容
image_type=Column(Integer) #0
timestamp = Column(DateTime) # 使用 DateTime 类型
chatType = Column(Integer) # 0 文字消息1 文件消息2 图片消息
sender = relationship("User", foreign_keys=[sender_username])
receiver = relationship("User", foreign_keys=[receiver_username])
class Friend(Base):
__tablename__ = "friends"
username = Column(String(30), ForeignKey('users.username', onupdate='CASCADE'), primary_key=True)
friend_username = Column(String(30), ForeignKey('users.username', onupdate='CASCADE'), primary_key=True)
last_message=Column(String(500))
user = relationship("User", foreign_keys=[username])
friend = relationship("User", foreign_keys=[friend_username])

@ -0,0 +1,178 @@
from fuzzywuzzy import fuzz
import numpy as np
from sqlalchemy.orm import Session
from models import User, Friend
from database import SessionLocal
import random
def get_max_n_items(arr, n): # 选出数组中最大的n个元素返回这n个数值及下标
np_arr = np.array(arr)
top_n_indices = np.argsort(np_arr)[-n:][::-1]
top_n_values = np_arr[top_n_indices]
return top_n_indices, top_n_values
def isfemale(str): # 方便相似度计算而设
if str == "": return 1
else: return -1
# 定义教育程度映射表
education_map = {
"初中": 1,
"高中": 2,
"本科": 3,
"研究生": 4,
"博士": 5
}
# recommend1.py
def recommend(username):
num_of_item = 50 # 设置推荐用户的个数
db = SessionLocal()
try:
user = db.query(User).filter(User.username == username).first()
if not user:
return {"code": 501, "msg": "账号不存在"}
user_sex = user.sex
user_age = user.age
# 清理 height 字符串并转换为浮点数
try:
if user.height is not None:
user_height = float(user.height.replace('cm', '')) # 去除单位 'cm'
else:
user_height = None
except ValueError:
return {"code": 500, "msg": "用户身高数据格式错误"}
# 清理 weight 字符串并转换为浮点数
try:
if user.weight is not None:
user_weight = float(user.weight.replace('kg', '')) # 假设 weight 的单位是 'kg'
else:
user_weight = None
except ValueError:
return {"code": 500, "msg": "用户体重数据格式错误"}
if user_height is not None and user_weight is not None:
user_bmi = user_weight * 10000 / (user_height * user_height)
else:
user_bmi = None
user_hobby = user.hobby + "aaabbbcccdd"
user_education = education_map.get(user.education, 0) # 使用映射表获取数值默认值为0
user_job = user.job + "aaabbbccc"
# 确保 user_income 是数值类型,清理单位
try:
if user.monthly_income is not None:
user_income_str = user.monthly_income.replace('', '').strip() # 去除单位 '元' 和前后空格
user_income = float(user_income_str)
else:
user_income = None
except (ValueError, TypeError):
return {"code": 500, "msg": f"用户 {username} 的月收入数据格式错误"}
# 获取朋友列表
friendlist = db.query(Friend).filter(Friend.username == username).all()
friend_usernames = [friend.friend_username for friend in friendlist]
# 获取所有用户
users = db.query(User).filter(
User.username != username,
User.sex != user_sex,
~User.username.in_(friend_usernames)
).all()
# 定义用户参数的计算权重
age_weight = 0.15 # 年龄差
hobby_weight = 0.3
bmi_weight = 0.05 # 体重指数
height_weight = 0.1 # 身高差
job_weight = 0.15
property_weight = 0.25 # 对应monthly_income、house、car三个参数的综合值
# 遍历用户,构建相似度向量
similarity = []
for i, other_user in enumerate(users):
if other_user.sex == user_sex: # 筛去同性别用户
continue
# 将其他用户的教育程度也转换为数值
other_education = education_map.get(other_user.education, 0)
if abs(other_education - user_education) > 2: # 受教育程度相差过大的样本赋予低分
similarity.append(30)
continue
# 清理其他用户的 height 和 weight 字符串并转换为浮点数
try:
if other_user.height is not None:
other_height = float(other_user.height.replace('cm', ''))
else:
continue # 如果其他用户的 height 数据为空,则跳过该用户
except ValueError:
continue # 如果其他用户的 height 数据格式错误,则跳过该用户
try:
if other_user.weight is not None:
other_weight = float(other_user.weight.replace('kg', ''))
else:
continue # 如果其他用户的 weight 数据为空,则跳过该用户
except ValueError:
continue # 如果其他用户的 weight 数据格式错误,则跳过该用户
if other_height is not None and other_weight is not None:
other_bmi = other_weight * 10000 / (other_height * other_height)
else:
other_bmi = None
# 确保 other_user.monthly_income 是数值类型,清理单位
try:
if other_user.monthly_income is not None:
other_income_str = other_user.monthly_income.replace('', '').strip() # 去除单位 '元' 和前后空格
other_income = float(other_income_str)
else:
continue # 如果其他用户的月收入数据为空,则跳过该用户
except (ValueError, TypeError):
continue # 如果其他用户的月收入数据格式错误,则跳过该用户
# 处理 house 和 car 属性
other_house = 0 if other_user.house == "没有" else (1 if other_user.house == "贷款买房" else 2)
other_car = 0 if other_user.car == "没有" else 1
# 加权平均
sim = age_weight * (600 / (6 + abs(other_user.age - user_age))) + \
hobby_weight * fuzz.ratio(user_hobby, other_user.hobby + "aaabbbcccdd") + \
bmi_weight * (400 / (4 + abs(other_bmi - user_bmi) if user_bmi is not None and other_bmi is not None else 0)) + \
height_weight * (3600 / ((isfemale(other_user.sex) * (user_height - other_height) - 12) * (isfemale(other_user.sex) * (user_height - other_height) - 12) + 36) if user_height is not None and other_height is not None else 0) + \
job_weight * fuzz.ratio(user_job, other_user.job + "aaabbbccc") + \
property_weight * (0.8 * 500000 / (5000 + abs(other_income - user_income) if user_income is not None and other_income is not None else 0) + 7.5 * other_house + 5 * other_car)
similarity.append(sim)
most_similar_indices, _ = get_max_n_items(similarity, num_of_item)
recommended_users = [users[i] for i in most_similar_indices]
recommended_users = random.sample(users, min(12, len(recommended_users)))
userList = []
for user in recommended_users:
userList.append({
'name': user.username,
'age': user.age,
'hobby': user.hobby,
'city': user.location,
'description': user.tips,
'height': user.height,
'job': user.job,
'avatar': user.head_img,
})
return {"code": 200, "response": "ok", "data": userList}
finally:
db.close()
# 示例调用
if __name__ == '__main__':
username = "example_username" # 替换为实际用户名
result = recommend(username)
print(result)

Binary file not shown.

@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

23
loveget/.gitignore vendored

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,21 @@
# chathome
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
# LOVEGET

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>666</title>
<style type="text/css">
.div1{
width: 500px;
height: 300px;
overflow-y: scroll;
margin: auto;
border: 1px solid red;
}
.div2{
width: 200px;
height: 50px;
border: 1px solid red;
}
</style>
</head>
<body>
<div class="div1">
666
</div>
<button type="button" id="btn">添加</button>
<script type="text/javascript">
var div1 = document.querySelector('.div1');
var btn = document.querySelector('#btn');
btn.addEventListener('click',function(){
console.log('66')
var k = div1.innerHTML;
div1.innerHTML = k+"<br/>66";
div1.scrollTop = div1.scrollHeight;
})
</script>
</body>
</html>

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,25 @@
{
"name": "chathome",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^1.3.1",
"core-js": "^3.8.3",
"element-ui": "^2.15.12",
"mockjs": "^1.1.0",
"sass": "^1.56.2",
"sass-loader": "^13.2.0",
"vue": "^2.6.14",
"vue-router": "^3.6.5"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"babel-plugin-component": "^1.1.1",
"vue-template-compiler": "^2.6.14"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,40 @@
<template>
<div id="app">
<Home></Home>
</div>
</template>
<script>
import Home from './view/home.vue'
export default {
name: 'App',
components: {
Home
}
}
</script>
<style lang="scss">
@import url(./assets/font/iconfont.css);
.iconfont {
font-family: "iconfont" !important;
font-style: normal;
font-size: 25px;
vertical-align: middle;
color: rgb(117,120,137);
transition: .3s;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
* {
padding: 0;
margin: 0;
}
#app {
width: 100vw;
height: 100vh;
background-color: rgb(255, 255, 255);
}
</style>

@ -0,0 +1,41 @@
<template>
<div id="app">
<Home></Home>
</div>
</template>
<script>
import Home from './view/home.vue'
export default {
name: 'App',
components: {
Home,
}
}
</script>
<style lang="scss">
@import url(./assets/font/iconfont.css);
.iconfont {
font-family: "iconfont" !important;
font-style: normal;
font-size: 25px;
vertical-align: middle;
color: rgb(117,120,137);
transition: .3s;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
* {
padding: 0;
margin: 0;
}
#app {
width: 100vw;
height: 100vh;
background-color: rgb(255, 255, 255);
}
</style>

@ -0,0 +1,61 @@
import base from './index'
let axios = base.axios
let baseUrl = base.baseUrl
//baseUrl = 'http://localhost:8080'
//获取username
const userstring=localStorage.getItem('user')
const username = JSON.parse(userstring)
// 获取好友
export const getFriend = params => {
const requestData = {
...params,
username: username
};
return axios({
method: 'post',
baseURL: `${baseUrl}/friend/friendList`,
// /frend/friendList和mock文件夹中预设的接口一致
data: requestData
}).then(res => res.data)
}
// 获取聊天信息
export const getChatMsg = params => {
const requestData = {
...params,
username: username
};
return axios({
method: 'post',
baseURL: `${baseUrl}/friend/chatMsg`,
data: requestData
}).then(res => res.data)
}
//获取用户信息
export const getuserInfo = params => {
const requestData = {
...params,
username: username
};
return axios({
method: 'post',
baseURL: `${baseUrl}/user/userInfo`,
data: requestData
}).then(res => res.data)
}
// 更新聊天信息
export function updateChatMsg(params) {
const requestData = {
...params,
username: username
};
console.log(requestData)
return axios({
method: 'post',
baseURL: `${baseUrl}/friend/updateChatMsg`,
data: requestData
})
}

@ -0,0 +1,36 @@
import axios from 'axios'
//全局参数,自定义参数可在发送请求时设置
axios.defaults.timeout = 300000000 //超时时间ms
axios.defaults.withCredentials = true
// 请求时的拦截
//回调里面不能获取错误信息
axios.interceptors.request.use(
function (config) {
return config;
},
function (error) {
// 当请求异常时做一些处理
console.log('请求异常:' + JSON.stringify(error));
return Promise.reject(error);
}
);
axios.interceptors.response.use(function (response) {
// Do something with response data
return response
}, function (error) {
// Do something with response error
console.log('响应出错:' + error)
return Promise.reject(error)
})
const base = {
axios: axios,
baseUrl: 'http://localhost:8000'
}
export default base

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke viewBox IE
normalize.css */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

@ -0,0 +1,395 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=3829178" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe646;</span>
<div class="name">snapchat</div>
<div class="code-name">&amp;#xe646;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe62e;</span>
<div class="name">文件</div>
<div class="code-name">&amp;#xe62e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe96c;</span>
<div class="name">24gf-telephone</div>
<div class="code-name">&amp;#xe96c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe610;</span>
<div class="name">图片</div>
<div class="code-name">&amp;#xe610;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe600;</span>
<div class="name">视频</div>
<div class="code-name">&amp;#xe600;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe601;</span>
<div class="name"></div>
<div class="code-name">&amp;#xe601;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe8b8;</span>
<div class="name">205设置</div>
<div class="code-name">&amp;#xe8b8;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe607;</span>
<div class="name">message</div>
<div class="code-name">&amp;#xe607;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe61b;</span>
<div class="name">闪电</div>
<div class="code-name">&amp;#xe61b;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1675406501520') format('woff2'),
url('iconfont.woff?t=1675406501520') format('woff'),
url('iconfont.ttf?t=1675406501520') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-snapchat"></span>
<div class="name">
snapchat
</div>
<div class="code-name">.icon-snapchat
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-wenjian"></span>
<div class="name">
文件
</div>
<div class="code-name">.icon-wenjian
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gf-telephone"></span>
<div class="name">
24gf-telephone
</div>
<div class="code-name">.icon-gf-telephone
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-tupian"></span>
<div class="name">
图片
</div>
<div class="code-name">.icon-tupian
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shipin"></span>
<div class="name">
视频
</div>
<div class="code-name">.icon-shipin
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shu"></span>
<div class="name">
</div>
<div class="code-name">.icon-shu
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shezhi"></span>
<div class="name">
205设置
</div>
<div class="code-name">.icon-shezhi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xinxi"></span>
<div class="name">
message
</div>
<div class="code-name">.icon-xinxi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shandian"></span>
<div class="name">
闪电
</div>
<div class="code-name">.icon-shandian
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-snapchat"></use>
</svg>
<div class="name">snapchat</div>
<div class="code-name">#icon-snapchat</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-wenjian"></use>
</svg>
<div class="name">文件</div>
<div class="code-name">#icon-wenjian</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gf-telephone"></use>
</svg>
<div class="name">24gf-telephone</div>
<div class="code-name">#icon-gf-telephone</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-tupian"></use>
</svg>
<div class="name">图片</div>
<div class="code-name">#icon-tupian</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shipin"></use>
</svg>
<div class="name">视频</div>
<div class="code-name">#icon-shipin</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shu"></use>
</svg>
<div class="name"></div>
<div class="code-name">#icon-shu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shezhi"></use>
</svg>
<div class="name">205设置</div>
<div class="code-name">#icon-shezhi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xinxi"></use>
</svg>
<div class="name">message</div>
<div class="code-name">#icon-xinxi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shandian"></use>
</svg>
<div class="name">闪电</div>
<div class="code-name">#icon-shandian</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

@ -0,0 +1,51 @@
@font-face {
font-family: "iconfont"; /* Project id 3829178 */
src: url('iconfont.woff2?t=1675406501520') format('woff2'),
url('iconfont.woff?t=1675406501520') format('woff'),
url('iconfont.ttf?t=1675406501520') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-snapchat:before {
content: "\e646";
}
.icon-wenjian:before {
content: "\e62e";
}
.icon-gf-telephone:before {
content: "\e96c";
}
.icon-tupian:before {
content: "\e610";
}
.icon-shipin:before {
content: "\e600";
}
.icon-shu:before {
content: "\e601";
}
.icon-shezhi:before {
content: "\e8b8";
}
.icon-xinxi:before {
content: "\e607";
}
.icon-shandian:before {
content: "\e61b";
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,72 @@
{
"id": "3829178",
"name": "chat",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "1080596",
"name": "snapchat",
"font_class": "snapchat",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "6714382",
"name": "文件",
"font_class": "wenjian",
"unicode": "e62e",
"unicode_decimal": 58926
},
{
"icon_id": "7568886",
"name": "24gf-telephone",
"font_class": "gf-telephone",
"unicode": "e96c",
"unicode_decimal": 59756
},
{
"icon_id": "12382329",
"name": "图片",
"font_class": "tupian",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "1283",
"name": "视频",
"font_class": "shipin",
"unicode": "e600",
"unicode_decimal": 58880
},
{
"icon_id": "1412",
"name": "树",
"font_class": "shu",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "1727422",
"name": "205设置",
"font_class": "shezhi",
"unicode": "e8b8",
"unicode_decimal": 59576
},
{
"icon_id": "5744743",
"name": "message",
"font_class": "xinxi",
"unicode": "e607",
"unicode_decimal": 58887
},
{
"icon_id": "15391349",
"name": "闪电",
"font_class": "shandian",
"unicode": "e61b",
"unicode_decimal": 58907
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@ -0,0 +1,160 @@
<template>
<div class="emoji-content">
<div class="emoji">
<div class="emoji-wrapper">
<ul class="emoji-list">
<li
class="emoji-item"
v-for="(item, index) in emojiList"
:key="index"
@click="sendEmoji(item)"
>
<img :src="item" alt="" />
</li>
</ul>
</div>
</div>
<div class="mask" @click="closeEmoji"></div>
</div>
</template>
<script>
export default {
data() {
return {
emojiList: [
require("@/assets/img/emoji/slightly-smiling-face.png"),
require("@/assets/img/emoji/smiling-face.png"),
require("@/assets/img/emoji/smiling-face-with-heart-eyes.png"),
require("@/assets/img/emoji/smiling-face-with-sunglasses.png"),
require("@/assets/img/emoji/thinking-face.png"),
require("@/assets/img/emoji/tired-face.png"),
require("@/assets/img/emoji/money-mouth-face.png"),
require("@/assets/img/emoji/loudly-crying-face.png"),
require("@/assets/img/emoji/pouting-face.png"),
require("@/assets/img/emoji/face-screaming-in-fear.png"),
require("@/assets/img/emoji/face-vomiting.png"),
require("@/assets/img/emoji/face-without-mouth.png"),
require("@/assets/img/emoji/face-with-tongue.png"),
require("@/assets/img/emoji/clown-face.png"),
require("@/assets/img/emoji/new-moon-face.png"),
require("@/assets/img/emoji/ghost.png"),
require("@/assets/img/emoji/jack-o-lantern.png"),
require("@/assets/img/emoji/money-bag.png"),
require("@/assets/img/emoji/pile-of-poo.png"),
require("@/assets/img/emoji/shamrock.png"),
require("@/assets/img/emoji/hibiscus.png"),
require("@/assets/img/emoji/lips.png"),
require("@/assets/img/emoji/sparkles.png"),
require("@/assets/img/emoji/star.png"),
require("@/assets/img/emoji/two-hearts.png"),
require("@/assets/img/emoji/rainbow.png"),
require("@/assets/img/emoji/thought-balloon.png"),
],
};
},
methods: {
sendEmoji(item) {
this.$emit("sendEmoji", item);
},
closeEmoji() {
this.$emit("closeEmoji");
}
},
};
</script>
<style lang="scss" scoped>
.emoji-content {
.emoji {
width: 400px;
height: 200px;
background-color: white;
position: absolute;
top: -220px;
left: 12px;
border-radius: 10px;
transition: 0.3s;
z-index: 3;
&::after {
content: "";
display: block;
width: 0;
height: 0;
border-top: 10px solid whitesmoke;
border-right: 10px solid transparent;
border-left: 10px solid transparent;
position: absolute;
bottom: -8px;
left: 15px;
z-index: 100;
}
.emoji-wrapper {
background-color: whitesmoke;
width: 100%;
height: 100%;
overflow-y: scroll;
padding: 10px;
box-sizing: border-box;
position: relative;
border-radius: 5px;
&::-webkit-scrollbar {
/*滚动条整体样式*/
width: 0; /* Safari,Chrome 隐藏滚动条 */
height: 0; /* Safari,Chrome 隐藏滚动条 */
display: none; /* 移动端、pad 上SafariChrome隐藏滚动条 */
}
&::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 10px;
box-shadow: inset 0 0 5px rgba(97, 184, 179, 0.1);
background: white;
}
&::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 5px rgba(87, 175, 187, 0.1);
border-radius: 10px;
background: white;
}
.emoji-list {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
margin-left: 10px;
.emoji-item {
list-style: none;
width: 50px;
height: 50px;
border-radius: 10px;
margin: 5px;
position: relative;
cursor: pointer;
&:hover {
background-color: rgba(128, 128, 128, 0.158);
}
img {
width: 35px;
height: 35px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
}
}
.mask {
width: 100%;
height: 100%;
position: fixed;
background: transparent;
left: 0;
top: 0;
z-index: 1;
}
}
</style>

@ -0,0 +1,81 @@
<template>
<div class="file-card">
<img src="@/assets/img/fileImg/unknowfile.png" alt="" v-if="fileType == 0"/>
<img src="@/assets/img/fileImg/word.png" alt="" v-else-if="fileType == 1"/>
<img src="@/assets/img/fileImg/excel.png" alt="" v-else-if="fileType == 2"/>
<img src="@/assets/img/fileImg/ppt.png" alt="" v-else-if="fileType == 3"/>
<img src="@/assets/img/fileImg/pdf.png" alt="" v-else-if="fileType == 4"/>
<img src="@/assets/img/fileImg/zpi.png" alt="" v-else-if="fileType == 5"/>
<img src="@/assets/img/fileImg/txt.png" alt="" v-else/>
<div class="word">
<span
>{{file.name || '未知'}}</span
>
<span>154kb</span>
</div>
</div>
</template>
<script>
export default {
// props: ["fileType", "file"],
props: {
fileType: Number,
file: File,
default() {
return {};
},
},
watch: {
file() {
console.log(this.file);
},
},
mounted() {
console.log(this.file);
console.log(this.fileType);
}
};
</script>
<style lang="scss" scoped>
.file-card {
width: 250px;
height: 100px;
background-color: rgb(255, 255, 255);
border-radius: 20px;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
box-sizing: border-box;
cursor: pointer;
&:hover {
background-color: rgb(8, 250, 226);
}
img {
width: 60px;
height: 60px;
}
.word {
width: 60%;
margin-left: 10px;
overflow: hidden;
span {
width: 90%;
display: inline-block;
color: #090000;
}
span:first-child {
font-size: 14px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
span:last-child {
font-size: 12px;
color: rgb(10, 0, 0);
}
}
}
</style>

@ -0,0 +1,52 @@
<template>
<div class="head-portrait">
<img :src="imgUrl || defaultAvatar" alt="">
</div>
</template>
<script>
export default {
props: {
imgUrl:{ default:require('@/assets/img/snapchat.png')},
},
data() {
return {
defaultAvatar: require('@/assets/img/snapchat.png')
};
}
}
</script>
<style lang="scss" scoped>
.head-portrait {
width: 50px;
height: 50px;
border-radius: 50%;
// border: 2px solid rgb(137,140,151);
border: 2px solid rgb(12, 12, 12);
position:relative;
&::before {
content: '';
width: 15px;
height: 15px;
z-index: 1;
display: block;
border-radius: 50%;
background-color: rgb(144,225,80);
position: absolute;
right: 0;
}
img {
width: 45px;
height: 45px;
border-radius: 50%;
// padding: 2px;
box-sizing: border-box;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
vertical-align: middle;
}
}
</style>

@ -0,0 +1,128 @@
<template>
<div class="nav">
<div class="nav-menu-wrapper">
<ul class="menu-list">
<li
v-for="(item, index) in menuList"
:key="index"
:class="{ activeNav: index == current }"
@click="changeMenu(index)"
>
<div class="block"></div>
<span class="iconfont" :class="item"></span>
</li>
</ul>
</div>
<div class="own-pic">
<HeadPortrait :imgUrl="imgUrl"></HeadPortrait>
</div>
</div>
</template>
<script>
import HeadPortrait from "./HeadPortrait.vue";
export default {
components: {
HeadPortrait,
},
data() {
return {
menuList: [
"icon-xinxi",
"icon-shipin",
"icon-shu",
"icon-shandian",
"icon-shezhi",
],
current: 0,
imgUrl: require('@/assets/img/head_portrait.jpg')
};
},
methods: {
changeMenu(index) {
switch (index) {
case 0:
this.$router.push({
name: "ChatHome",
}, () => {});
break;
case 1:
this.$message("该功能还没有开发哦,敬请期待一下吧~🥳");
break;
case 2:
this.$message("该功能还没有开发哦,敬请期待一下吧~🥳");
break;
case 3:
this.$message("该功能还没有开发哦,敬请期待一下吧~🥳");
break;
case 4:
this.$message("该功能还没有开发哦,敬请期待一下吧~🥳");
break;
default:
this.$router.push({
name: "ChatHome",
});
}
this.current = index;
},
},
};
</script>
<style lang="scss" scoped>
.nav {
width: 100%;
height: 90vh;
position: relative;
border-radius: 20px 0 0 20px;
.nav-menu-wrapper {
position: absolute;
top: 40%;
transform: translate(0, -50%);
.menu-list {
margin-left: 10px;
li {
margin: 40px 0 0 30px;
list-style: none;
cursor: pointer;
position: relative;
.block {
background-color: rgb(29, 144, 245);
position: absolute;
left: -40px;
width: 6px;
height: 25px;
transition: 0.5s;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
opacity: 0;
}
&:hover {
span {
color: rgb(29, 144, 245);
}
.block {
opacity: 1;
}
}
}
}
}
.own-pic {
position: absolute;
bottom: 10%;
margin-left: 25px;
}
}
.activeNav {
span {
color: rgb(29, 144, 245);
}
.block {
opacity: 1 !important;
}
}
</style>

@ -0,0 +1,206 @@
<template>
<nav class="navbar">
<ul class="nav-links">
<li @click="setActiveItem('recommend')" :class="{ 'active': activeItem === 'recommend' }">
<router-link to="/ReCommendtrue">推荐</router-link>
</li>
<li @click="setActiveItem('search')" :class="{ 'active': activeItem === 'search' }">
<router-link to="/ReCommend">搜索</router-link>
</li>
<li @click="setActiveItem('chat')" :class="{ 'active': activeItem === 'chat' }">
<router-link to="/ChatHome">聊天</router-link>
</li>
<li @click="setActiveItem('profile')" :class="{ 'active': activeItem === 'profile' }">
<router-link to="/LinVite1n">个人资料</router-link>
</li>
<li class="logout-button" :style="backgroundStyle" @mouseenter="toggleDropdown(true)" @mouseleave="toggleDropdown(false)">
<ul v-if="isDropdownOpen" class="dropdown-menu">
<li @click.stop="handleOptionClick('option1')">修改账户</li>
<li @click.stop="handleOptionClick('option2')">退出登录</li>
</ul>
</li>
</ul>
</nav>
</template>
<script>
import base from '@/api/index';
export default {
data() {
return {
activeItem: null,
backgroundImageUrl: '',
defaultAvatarUrl: require('@/assets/img/snapchat.png'), //
isDropdownOpen: false
};
},
computed: {
backgroundStyle() {
return {
backgroundImage: `url(${this.backgroundImageUrl || this.defaultAvatarUrl})`
};
}
},
watch: {
$route(to) {
this.setActiveItemBasedOnRoute(to.path);
}
},
mounted() {
this.setActiveItemBasedOnRoute(this.$route.path);
this.fetchBackgroundImageUrl();
},
methods: {
setActiveItem(item) {
this.activeItem = item;
},
setActiveItemBasedOnRoute(path) {
if (path === '/ReCommendtrue') {
this.activeItem = 'recommend';
} else if (path === '/ReCommend') {
this.activeItem = 'search';
} else if (path === '/ChatHome') {
this.activeItem = 'chat';
} else if (path === '/LinVite1n') {
this.activeItem = 'profile';
}
},
async fetchBackgroundImageUrl() {
try {
const userString = localStorage.getItem('user');
const username = JSON.parse(userString);
const response = await base.axios({
method: 'get',
url: `${base.baseUrl}/get_headimg`,
params: {
username: username
}
});
this.backgroundImageUrl = response.data;
console.log(this.backgroundImageUrl);
} catch (error) {
console.error('获取用户头像失败:', error);
}
},
toggleDropdown(isOpen) {
this.isDropdownOpen = isOpen;
},
logout() {
localStorage.removeItem('user');
this.$router.push('/');
},
handleOptionClick(option) {
console.log(`Clicked on ${option}`);
//
if (option === 'option2') {
this.logout();
}
if (option === 'option1') {
this.$router.push('/ChangePwd');
}
this.isDropdownOpen = false; //
}
}
};
</script>
<style scoped>
.active {
background-color: rgb(0, 0, 255); /* 你可以根据需要更改颜色 */
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.navbar {
display: flex;
flex-direction: row;
width: 100%;
background-color: #0073e6;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
font-family: 'Open Sans', sans-serif;
}
.nav-links {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
justify-content: space-around;
align-items: center;
height: 50px;
}
.nav-links li {
font-weight: 600;
height: 100%; /* 确保 li 占据整个导航栏的高度 */
display: flex;
align-items: center;
justify-content: center;
cursor: pointer; /* 添加鼠标指针样式 */
}
.nav-links li a {
text-decoration: none;
color: white;
font-size: 25px;
transition: color 0.3s;
width: 360px;
height: 100%; /* 确保 a 占据整个 li 的高度 */
display: flex;
align-items: center;
justify-content: center;
}
.nav-links li a:hover {
color: #d0e7ff;
}
.nav-links li.active {
background-color: rgb(0, 0, 255); /* 确保整个 li 的背景颜色在激活状态下改变 */
}
.nav-links li.active a {
color: white; /* 确保文字颜色在激活状态下不变 */
}
.logout-button {
margin-left: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
background-position: center;
background-size: cover;
border: none;
cursor: pointer; /* 添加鼠标指针样式 */
position: relative; /* 设置为相对定位 */
}
.dropdown-menu {
position: absolute;
top: 100%; /* 从父元素底部开始 */
left: -15px;
background-color: #1d84eb;
border: 1px solid #ccc;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
list-style-type: none;
font-size: 14.6px;
color: white;
width: 160%;
z-index: 1000;
}
.dropdown-menu li {
padding: 10px;
cursor: pointer;
transition: background-color 0.3s;
}
.dropdown-menu li:hover {
background-color: #f0f0f0;
}
</style>

@ -0,0 +1,109 @@
<template>
<div class="person-card" :class="{ activeCard: personInfo.id == current }">
<div class="info">
<HeadPortrait :imgUrl="personInfo.headImg"></HeadPortrait>
<div class="info-detail">
<div class="name">{{ personInfo.name }}</div>
<!-- <div class="detail">{{ personInfo.detail }}</div> -->
</div>
</div>
</div>
</template>
<script>
import HeadPortrait from "./HeadPortrait.vue";
export default {
props: {
personInfo: {
default: {
},
},
pcCurrent: {
default: ''
}
},
components: {
HeadPortrait,
},
data() {
return {
current: '',
}
},
watch: {
pcCurrent: function() {
this.isActive()
}
},
methods: {
isActive() {
this.current = this.pcCurrent
}
}
};
</script>
<style lang="scss" scoped>
.person-card {
width: 280px;
height: 80px;
border-radius: 0px;
background-color: white;
position: relative;
cursor: pointer;
.info {
position: absolute;
left: 50%;
top: 50%;
width: 90%;
transform: translate(-50%, -50%);
overflow: hidden;
display: flex;
.info-detail {
margin-top: 5px;
margin-left: 20px;
.name {
color: #070707;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-bottom: 5px;
}
.detail {
color: #3f5f8f;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 12px;
}
}
}
&:hover {
background-color: #1d90f5;
transition: 0.3s;
// box-shadow: 0px 0px 10px 0px rgba(0, 136, 255);
// box-shadow: 0 5px 20px rgba(251, 152, 11, .5);
.info {
.info-detail {
.detail {
color: #fff;
}
}
}
}
}
.activeCard {
background-color: #1d90f5;
transition: 0.3s;
// box-shadow: 3px 2px 10px 0px rgba(0, 136, 255);
.info {
.info-detail {
.detail {
color: #fff;
}
}
}
}
</style>

@ -0,0 +1,22 @@
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import VueRouter from 'vue-router'
import 'element-ui/lib/theme-chalk/index.css';
import router from './router/index'
import "./mock/index.js"
import api from './api/index.js'; // 导入配置好的 axios 实例
Vue.config.productionTip = false;
// 将 axios 挂载到 Vue 原型上,这样所有 Vue 实例都可以访问
Vue.prototype.$axios = api.axios;
Vue.use(VueRouter)
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
router,
render: h => h(App),
}).$mount('#app')

@ -0,0 +1,258 @@
// const Mock = require("mockjs");
// Mock.mock(/friend\/friendList/, 'post', () => { //三个参数。第一个路径第二个请求方式post/get第三个回调返回值
// return friendList
// })
// Mock.mock(/friend\/chatMsg/, 'post', (config) => { //三个参数。第一个路径第二个请求方式post/get第三个回调返回值
// let params = JSON.parse(config.body)
// if (params.frinedId == "1002")
// return chatMsg1002
// if (params.frinedId == "1003")
// return chatMsg1003
// if (params.frinedId == "1004")
// return chatMsg1004
// if (params.frinedId == "1005")
// return chatMsg1003
// })
// Mock.mock(/user\/userInfo/, 'post', () => {
// return userInfo
// })
// Mock.mock(/friend\/updateChatMsg/, 'post', (config) => {
// let params = JSON.parse(config.body);
// let frinedId = params.frinedId;
// let newMsg = params.newMsg;
// // 找到对应的聊天记录并更新
// let chatMsgKey = `chatMsg${frinedId}`;
// if (global[chatMsgKey]) {
// global[chatMsgKey].push(newMsg);
// return { success: true, message: "Message added successfully" };
// } else {
// return { success: false, message: "Friend not found" };
// }
// });
// let userInfo = Mock.mock(
// {
// img: "",
// name: "大毛是小白",
// detail: "666",
// lastMsg: "",
// id: "1001",
// headImg: require("@/assets/img/head_portrait.jpg"),
// }
// )
// let friendList = Mock.mock(
// [
// {
// img: "",
// name: "大毛",
// detail: "我是大毛",
// lastMsg: "to do",
// id: "1002",
// headImg: require("@/assets/img/head_portrait1.jpg"),
// },
// {
// img: "",
// name: "小毛",
// detail: "我是小毛",
// lastMsg: "dada dw ertgthy j uy",
// id: "1003",
// headImg: require("@/assets/img/head_portrait2.jpg"),
// },
// {
// img: "",
// name: "小王",
// detail: "我是小王",
// lastMsg: "大萨达萨达所大大萨达",
// id: "1004",
// headImg: require("@/assets/img/head_portrait3.jpg"),
// },
// {
// img: "",
// name: "小红",
// detail: "我是喜欢音乐的有趣灵魂",
// lastMsg: "to do",
// id: "1005",
// headImg: require("@/assets/img/head_portrait1.jpg"),
// },
// ]
// )
// let chatMsg1002 = Mock.mock(
// [
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: " 在吗?",
// chatType: 0, //信息类型0文字1图片
// uid: "1001", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait1.jpg"),
// name: "大毛",
// time: "0912 AM",
// msg: " 怎么了?",
// chatType: 0, //信息类型0文字1图片
// uid: "1002", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: "问你个问题",
// chatType: 0, //信息类型0文字1图片, 2文件
// uid: "1001",
// },
// {
// headImg: require("@/assets/img/head_portrait1.jpg"),
// name: "大毛",
// time: "0912 AM",
// msg: "别问",
// chatType: 0, //信息类型0文字1图片
// uid: "1002", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: require("@/assets/img/emoji/slightly-smiling-face.png"),
// chatType: 1, //信息类型0文字1图片
// extend: {
// imgType: 1, //(1表情2本地图片)
// },
// uid: "1001",
// },
// ]
// )
// let chatMsg1003 = Mock.mock(
// [
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: "在干嘛呢",
// chatType: 0, //信息类型0文字1图片
// uid: "1001", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: require("@/assets/img/emoji/slightly-smiling-face.png"),
// chatType: 1, //信息类型0文字1图片
// extend: {
// imgType: 1, //(1表情2本地图片)
// },
// uid: "1001",
// },
// {
// headImg: require("@/assets/img/head_portrait2.jpg"),
// name: "小毛",
// time: "0912 AM",
// msg: "吃饭",
// chatType: 0, //信息类型0文字1图片
// uid: "1002", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: "吃的什么饭",
// chatType: 0, //信息类型0文字1图片, 2文件
// uid: "1001",
// },
// {
// headImg: require("@/assets/img/head_portrait2.jpg"),
// name: "小毛",
// time: "0912 AM",
// msg: "蛋炒饭",
// chatType: 0, //信息类型0文字1图片
// uid: "1002", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: "加蛋了吗?",
// chatType: 0, //信息类型0文字1图片, 2文件
// uid: "1001",
// },
// {
// headImg: require("@/assets/img/head_portrait2.jpg"),
// name: "小毛",
// time: "0912 AM",
// msg: "你说呢",
// chatType: 0, //信息类型0文字1图片
// uid: "1002", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait2.jpg"),
// name: "小毛",
// time: "0912 AM",
// msg: require("@/assets/img/emoji/slightly-smiling-face.png"),
// chatType: 1, //信息类型0文字1图片
// extend: {
// imgType: 1, //(1表情2本地图片)
// },
// uid: "1002", //uid
// },
// ]
// )
// let chatMsg1004 = Mock.mock(
// [
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: " sadasdawdas sadsad sad sad as despite ofhaving so much to do",
// chatType: 0, //信息类型0文字1图片
// uid: "1001", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: require("@/assets/img/emoji/slightly-smiling-face.png"),
// chatType: 1, //信息类型0文字1图片
// extend: {
// imgType: 1, //(1表情2本地图片)
// },
// uid: "1001",
// },
// {
// headImg: require("@/assets/img/head_portrait3.jpg"),
// name: "小王",
// time: "0912 AM",
// msg: " 21312大萨达萨达",
// chatType: 0, //信息类型0文字1图片
// uid: "1002", //uid
// },
// {
// headImg: require("@/assets/img/head_portrait.jpg"),
// name: "大毛是小白",
// time: "0912 AM",
// msg: "111212",
// chatType: 0, //信息类型0文字1图片, 2文件
// uid: "1001",
// },
// {
// headImg: require("@/assets/img/head_portrait3.jpg"),
// name: "小王",
// time: "0912 AM",
// msg: "大萨达萨达所大大萨达",
// chatType: 0, //信息类型0文字1图片
// uid: "1002", //uid
// },
// ]
// )

@ -0,0 +1,82 @@
import VueRouter from 'vue-router'
import ChatHome from '../view/pages/chatHome/index.vue'
import Video from '../view/pages/video.vue'
import Lingting from '../view/pages/lingting.vue'
import Setting from '../view/pages/setting.vue'
import LinVite1n from '../view/pages/LnVite1n.vue'
import ReCommend from '../view/pages/ReCommend.vue'
import LoginPage from '@/view/LoginPage.vue'
import zhuce from '@/view/zhuce.vue'
import ChangePwd from '@/view/ChangePwd.vue'
import ImFormation from '@/view/pages/ImFormation.vue'
import ReCommendtrue from '@/view/pages/ReCommendtrue.vue'
export default new VueRouter({
mode: 'hash',
routes: [
{
path:'/',
name: 'Login',
component:LoginPage
},
{
path: "/home",
name: "Home",
redirect: '/ChatHome'
},
{
path: "/Recommendtrue",
name: "Recommendtrue",
component: ReCommendtrue
},
{
path: "/ChatHome",
name: "ChatHome",
component: ChatHome,
},
{
path: "/LinVite1n",
name: "LinVite1n",
component: LinVite1n
},
{
path: "/Recommend",
name: "Recommend",
component: ReCommend
},
{
path: "/Video",
name: "Video",
component: Video
},
{
path: "/Lingting",
name: "Lingting",
component: Lingting
},
{
path: "/Setting",
name: "Setting",
component: Setting
},
{
path: "/zhuce",
name: "zhuce",
component: zhuce
},
{
path:'/ChangePwd',
name:'ChangePwd',
component:ChangePwd
},
{
path:'/InFormation',
name:'InFormation',
component:ImFormation
},
]
})

@ -0,0 +1,88 @@
//防抖
export function debounce(fn) {
console.log(1)
let t = null //只会执行一次
debugger
return function (){
if(t){
clearTimeout(t)
}
t = setTimeout(()=>{
console.log(temp); //可以获取
// console.log(arguments[0]) //undefined
fn.apply(this,arguments)
//在这个回调函数里面的argument是这个回调函数的参数因为没有参数所以undefined可以通过外面的函数赋值来进行访问
//也可以改变成箭头函数,箭头函数的this是指向定义函数的那一层的所以访问到的arguments是上一层函数的arguments
},1000)
}
}
//节流
export function throttle(fn, delay = 200) {
let timer = null
console.log(fn);
debugger
return function () {
if(timer) return
timer = setTimeout(() => {
debugger
fn.apply(this,arguments)
timer = null
})
}
}
//下拉动画
export function animation(obj, target, fn1) {
// console.log(fn1);
// fn是一个回调函数在定时器结束的时候添加
// 每次开定时器之前先清除掉定时器
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 步长计算公式 越来越小
// 步长取整
var step = (target - obj.scrollTop) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.scrollTop >= target) {
clearInterval(obj.timer);
// 如果fn1存在调用fn
if (fn1) {
fn1();
}
} else {
// 每30毫秒就将新的值给obj.left
obj.scrollTop = obj.scrollTop + step;
}
}, 10);
}
//判断文件类型
export function judgeFileType(file) {
if (file == null||file == ""){
alert("请选择要上传的图片!");
return false;
}
if (file.lastIndexOf('.')==-1){ //如果不存在"."
alert("路径不正确!");
return false;
}
var AllImgExt=".jpg|.jpeg|.gif|.bmp|.png|";
var extName = file.substring(file.lastIndexOf(".")).toLowerCase();//(把路径中的所有字母全部转换为小写)
if(AllImgExt.indexOf(extName+"|")==-1)
{
ErrMsg="该文件类型不允许上传。请上传 "+AllImgExt+" 类型的文件,当前文件类型为"+extName;
alert(ErrMsg);
return false;
}
}
//文件类型
export function fileType() {
return {
'application/msword': 'word',
'application/pdf': 'pdf',
'application/vnd.ms-powerpoint': 'ppt',
'application/vnd.ms-excel': 'excel',
'aplication/zip': 'zpi',
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save