unicloud个人全栈项目

啊洋秃头之路

项目源码:洋盘

技术栈

全程手撕组件,目前写过的全栈项目中最满意的项目

响应式官网响应式官网
官网:APP官网
API接口文档:APP端接口文档

app端: Version:1.0.43

​ 前端:uniapp

​ 后端:unicloud

H5端:https://static-1d54e049-f81e-427d-a517-62137322ac07.bspapp.com/

管理端 :

​ element+ unicloud + 部分node接口

App图片展示

码云里看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6sCd4lDi-1604919142309)(")]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HchymZrM-1604919142314)(https://cdnforspeed.oss-cn-beijing.aliyuncs.com/Img/Gitee/YangPan/night2.jpg “night2.jpg”)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aqdes5un-1604919142316)(https://cdnforspeed.oss-cn-beijing.aliyuncs.com/Img/Gitee/YangPan/night3.jpg “night3.jpg”)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZcTBD78-1604919142319)(https://cdnforspeed.oss-cn-beijing.aliyuncs.com/Img/Gitee/YangPan/night4.jpg “night4.jpg”)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T4ZqUkS0-1604919142320)(https://cdnforspeed.oss-cn-beijing.aliyuncs.com/Img/Gitee/YangPan/night5.jpg “night5.jpg”)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7n961VY-1604919142322)(https://cdnforspeed.oss-cn-beijing.aliyuncs.com/Img/Gitee/YangPan/night_6.jpg “night6.jpg”)]
杂:

0.vuex+axios

1.vue的过渡动画,监听器,计算,页面通信多种方法,

2.canvas,plus的下载器,文件管理,

3.逻辑:短信登录/注册,账号登录(第三方)注册修改信息,评论系统逻辑(到二评论),非对称加密

4.oss的文件上传下载,文件批量/单个删除,sts鉴权

5.unicloud的常操,双/多连表,模糊,排序,正则过滤

6.即时通信的业务逻辑

有个app逻辑md文件

运行配置

需要创建的表及字段标明在table文件夹内

你需要改oss配置文件的

region: 'oss-cn-hangzhou',
bucket: 'XXXXXXXXXXXXXXX',
accessKeyId: 'XXXXXXXXXXXXXXX',
accessKeySecret: 'XXXXXXXXXXXXXXX',
host: "XXXXXXXXXXXXXXX"

const sts = new STS({ // RAM账号
	accessKeyId: 'XXXXXXXXXXXXXXX',
	accessKeySecret: 'XXXXXXXXXXXXXXX'
});


​ 临时sts权限的 策略
​ StsToken = await sts.assumeRole(
​ ‘acs🐏:XXXXXXXXXXXXXXX’, {
​ “Statement”: [{
​ “Action”: [
​ “oss:"
​ ],
​ “Effect”: “Allow”,
​ “Resource”: ["acs:oss:
::xxxxxxxxxxx/”]
​ }],
​ “Version”: “1”
​ }, ‘3600’, ‘666’);

你需要改SMS配置文件的

exports.SMSConfig = {
	register: {
		smsKey: 'XXXXXXXXXXXXXXX',
		smsSecret: 'XXXXXXXXXXXXXXX',
		templateId: 'XXXXXXXXXXXXXXX'
	},
	login: {
		smsKey: 'XXXXXXXXXXXXXXX',
		smsSecret: 'XXXXXXXXXXXXXXX',
		templateId: 'XXXXXXXXXXXXXXX'
	}
}

文件目录

├─cloudfunctions-tcb   // 后端目录
│  ├─common	// 公共模块
│  ├─test		// app端接口汇总
│  │  ├─model	// 数据封装(废弃)
│  │  ├─oss	// oss文件配置表
│  │  ├─router	// 路由
│  │  │  ├─community	// 社区模块接口汇总
│  │  │  ├─file		// 文件模块接口汇总
│  │  │  ├─home		// 我的模块接口汇总
│  │  │  └─Update		// 更新插件模块接口汇总
│  │  ├─SMS		// 短信验证码配置表
│  │  └─tools		// 工具类
│  └─YangPanAdmin	// admin管理端汇总
│      ├─model		// 
│      ├─oss		//
│      ├─router		//
│      └─tools		//
├─common		
│  ├─API		
│  │  └─utils		// 请求封装
│  ├─components		// 封装组件
│  │  ├─AppHeader
│  │  ├─AppHeaderNvue
│  │  ├─u-message-input
│  │  ├─update
│  │  └─w-picker
│  │      └─city-data
│  ├─LocalStorage
│  ├─public
│  ├─Tools
│  └─verify
├─components
│  ├─loadImg
│  ├─tki-qrcode
│  ├─uni-popup
│  └─uni-pullRefresh
├─pages
│  ├─community		// 社区
│  │  └─conpoment
│  ├─file			// 文件
│  │  ├─content
│  │  └─header
│  ├─home		// 我的模块
│  │  ├─FnBlock
│  │  ├─header
│  │  ├─info
│  │  ├─LoginOut
│  │  └─OperateBar
│  ├─index
│  │  ├─header
│  │  └─main
│  ├─other
│  │  ├─dialogs
│  │  │  └─newFolder
│  │  ├─FileTypeList
│  │  ├─guide
│  │  ├─ImgView
│  │  ├─login
│  │  │  ├─form
│  │  │  ├─header
│  │  │  └─thirdLogin
│  │  ├─myCollect
│  │  ├─myFans
│  │  ├─myPublish
│  │  │  └─components
│  │  ├─myVisitor
│  │  ├─register
│  │  │  ├─form
│  │  │  ├─header
│  │  │  └─thirdLogin
│  │  ├─Setting
│  │  │  └─myInfoSet
│  │  ├─SMSCodeLogin
│  │  ├─UploadUrlManager
│  │  └─VideoView
│  └─public
│      ├─map
│      ├─pullRefresh
│      ├─QRcode
│      └─TransferPopup
├─tables
│  ├─adminVersion		// app版本表
│  ├─Article			// 社区
│  ├─common				// 评论表
│  ├─ModelList			// 模型表
│  ├─notice				// 通知表
│  ├─SMSCache			// 短信表
│  ├─UploadImg			// 上传图片表
│  ├─UploadRecord		// 上传记录表
│  ├─User				// 用户表

APP端问题汇总

文件夹路径的

文件上传

文件的下载,多线程并发

删除改文件夹下的所有文件(遍历查询删除)

阿里的SDK无法做到批量删除 只能自己写算法递归删除

递归添加文件夹到文件夹数组
文件要先删除,然后文件夹目录必须得从最里层开始删除(计算),否则会删除不了
文件夹排序做算法(代码内)

获取指定目录下的指定文件

exports.getSpecifyTypeFile = async (body_data)=>{
	let RES = { code:200,msg:"操作成功~"}
	let {UserInfo,FileType,pageNum,pageSize} = body_data
	
	if(FileType!='ImgTypes' && FileType!='ViodeoTypes' && FileType!='AudioTypes') return {code:204,msg:"参数错误"}
	let skips = pageNum * pageSize
	let OSSRes = await alioss.FolderList(UserInfo.account+'/')
	let FolederList =  OSSRes.prefixes // 文件夹路径 
	let FileArray = [...(OSSRes.objects.slice(1))] // 返回的所有文件数组
	
	
	// 根据跟目录拿出该文件下的所有文件类型
	let digui = async(list)=>{
		for(let i=0;i<list.length;i++){
			let RRR =  await alioss.FolderList(list[i])
			if(RRR.objects && RRR.objects.length>0){
				RRR.objects.forEach( (item,index)=>{
					index ==0 ? "":FileArray.push(item)
				})
			}
			if(RRR.prefixes && RRR.prefixes.length>0){
				digui(RRR.prefixes)
			}
		}
		
	}
	await digui(FolederList)
	let resultArray = [] // 要返回出去的数据
	FileArray.forEach(i=>{
		if(FileTypeTest[`${FileType}`]().includes(i.name.match(/[^\.]\w*$/)[0])){
			resultArray.push(i)
		}
	})
	RES.data = resultArray
	return RES
}

社区模块

发布文章模块

用户表关联文章表 文章表关联评论表 评论表做二级评论

// 文章表
{
    "_id":"文章ID",
    "contents":"文章文字内容",
    "ImgList":{ // "图片数组"
        id:"",
        url:""
    },
    PublishTime:"", // 发布时间
    likeCount:"", // 点赞次数
    commonCount:"", // 评论人数
    shareCount:"", // 转发人数
    viewCount:"", // 阅读人数
}

联表查询

// 返回文章列表信息
let result = await transaction.collection('Article').aggregate().lookup({
    from:'User',
    localField:'UserId',
    foreignField:'_id',
    as:"UserInfo"
}).lookup({
    from:'common',
    localField:'_id',
    foreignField:'articleId',
    as:"CommonList"
}).sort({PublishTime:-1}).limit(pageSize).skip(Skips).end()

三联表查询

// 返回评论列表信息	 // parentId:null是找出所有的一级评论
let result = await db.collection('common').aggregate().match({
    articleId,parentId:null
}).lookup({
    from:'User',
    localField:'UserId',
    foreignField:'_id',
    as:"UserInfo"
}).lookup({
    from:'common',
    localField:'_id',
    foreignField:'parentId',
    as:"SecondList"
}).sort({commonTime:-1}).limit(pageSize).skip(Skips).end()

找出当前文档下的对象数组下某个字段与传入字段是否匹配的数据

//  查询被点赞过的数据
let IsLike = await db.collection('common').aggregate().match({_id}).project({
    likeList: $.filter({
      input: '$likeList',
      as: 'item',
      cond: $.eq(['$$item.UserId', UserId])
    })
}).end()

admin端问题汇总

条件查询模糊查询

let result = await db.collection('User').where(Object.assign(
    SelJson,{
        Nickname:new RegExp(`${Nickname}`),
        account:new RegExp(`${account}`)
    })
).limit(pageSize).skip(Skips).get()

条件查询日期范围

let like_Json = {}
like_Json['registerTime'] = dbCmd.and([
  dbCmd.gte(new Date(registerTimeBeginTime)),
  dbCmd.lte(new Date(registerTimeEndTime))
])

let result = await db.collection('User').where(Object.assign(
    SelJson,like_Json
).limit(pageSize).skip(Skips).get()

数据库的删除(事务)

admin管理端删除 用户 删除oss对象和数据的用户信息

exports.DelUser = async function(body_data) {
	let res = {
		code:200,
		msg:"成功~"
	}
	let {UserInfo,_id} = body_data
	if (!_id.toString()) {return {msg: "_id必传"}}
	
	try {
		const result = await db.runTransaction(async transaction => {
			let SelRes = await transaction.collection('User').doc(_id).get()
			if (SelRes.data) {
				try {
					let ossRes = null
					let DelRes = await db.collection('User').doc(_id).remove()		// 删除用户信息
					if(DelRes.deleted>0){
						ossRes = await digui_del(SelRes.data.account+'/')		// 删除oss的数据 (app端的文件数据)
						if(ossRes===200){
							ossRes = await digui_del('uploadImg/'+SelRes.data.account+'/')		// 删除oss的数据(uploadImg下该用户的所有信息)
						}
					}
					console.log(`事务全部成功~`)
					return{
						ossRes,
						DelRes
					}
				} catch (e) {
					// 会作为 runTransaction reject 的结果出去
					await transaction.rollback('oss,remove')
				}
			} else {
				// 会作为 runTransaction reject 的结果出去
				await transaction.rollback('查询User')
			}
		})
	
		return {
			code:200,
			msg:'删除成功~',
			data:{
				ossRes:result.ossRes,
				DelRes:result.DelRes
			}
		}
	} catch (e) {
		console.error(`事务失败`,e)
		return {
			msg:'内部错误~',
			code:500
		}
	}
}

app端社区模块接口

评论排序(CommonSort)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"CommonSort",
        SortType:"String",
        articleId:"String",	
        pageSize:"Number",
        pageNum:"Number",	
        UserId:"String"		
    }
}

request:

// 打星号必传

*SortType:"String"		// 排序种类   (SortNew,SortMoreLike,SortHot)
*articleId:"String"		// 文章ID
*pageSize:"Number"		// 分页大小
*pageNum:"Number"		// 当前页数
*UserId:"String"		// 用户ID

respone:

[{
	SecondList: []
	UserId: "e656fa635f64c1790014f3077b54ae5a"
	UserInfo: [{_id: "e656fa635f64c1790014f3077b54ae5a", account: "13067271903", pwd: "1203523342zyw",}]
	articleId: "e373396c5f71f75100a607e52e317e73"
	commonIp: "211.97.131.82"
	commonTime: 1601394532379
	commonValue: "🐮🍺"
	iSlike: true
	likeList: [{UserId: "e656fa635f64c1790014f3077b54ae5a", UpdateTime: 1601513089441, Ip: "211.97.128.95"},]
	_id: "1b64dd7b5f73576400b78cb93a6d3562"
},{
	SecondList: []
	UserId: "e656fa635f64c1790014f3077b54ae5a"
	UserInfo: [{_id: "e656fa635f64c1790014f3077b54ae5a", account: "13067271903", pwd: "1203523342zyw",}]
	articleId: "e373396c5f71f75100a607e52e317e73"
	commonIp: "211.97.131.82"
	commonTime: 1601394532379
	commonValue: "🐮🍺"
	iSlike: true
	likeList: [{UserId: "e656fa635f64c1790014f3077b54ae5a", UpdateTime: 1601513089441, Ip: "211.97.128.95"},]
	_id: "1b64dd7b5f73576400b78cb93a6d3562"
}]

评论点赞(CommonLike)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"CommonLike",
        _id:"String",
        UserId:"String"	
    }
}

request:

// 打星号必传

*_id:"String"		//  该条评论的id
*UserId:"String"		//  用户id

文章点赞(onLike)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"onLike",
        _id:"String",
        UserId:"String"	
    }
}

request

// 打星号必传

*_id:"String"			//	该篇文章的_id
*UserId:"String"		//  用户id

发布文章(PushArticle)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"PushArticle",
        pageSize:"Number",
        pageNum:"Number"
    }
}

request:

// 打星号必传
*_id:"String"			// 	用户id  	字段写错	add({UserId:_id})
*contents:"Number"		//  发布内容
*imgList:"String"		//  发布的图片数组	

文章列表(SelArticleList)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"SelArticleList",
        pageSize:"Number",
        pageNum:"Number"
    }
}

request:

// 打星号必传
*pageSize:"Number"		// 	分页大小
*pageNum:"Number"		//  当前页数
UserId:"String"			//  用户id	用来判断是否点赞过	

单文章详细信息(SelArticleDetail)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"SelArticleDetail",
        articleId:"String",
        UserId:"String"	
    }
}

request:

// 打星号必传

*articleId:"String"		//  文章的_id  参数写错了  // 但是转化了where({_id:articleId})
UserId:"String"		//  用户id

评论列表(一级二级)(SelCommonList)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"SelCommonList",
        articleId:"String",
        pageSize:"Number",
        pageNum:"Number"
    }
}

request:

// 打星号必传

*articleId:"String"		//  文章ID 	联表用
*pageSize:"Number"		// 	分页大小
*pageNum:"Number"		//  当前页数
UserId:"String"			//  用户id	用来查询是否点赞过 无登录状态下就没有了
parentId:"String"		//  二级评论的父评论ID		用来查询二级评论

发布评论(一级二级)(onCommon)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"onCommon",
        articleId:"String",
		UserId:"String",
		commonValue:"String",
		parentId:"String"
    }
}

request:

// 打星号必传
*articleId:"String"		//  文章ID
*UserId:"String"		//  用户id
*commonValue:"String"	// 评论内容
parentId:"String"		//  二级评论的父评论ID		用来回复二级评论

app端我的模块接口

查询指定账户的个人发布列表接口(SelPersionPublish)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"SelPersionPublish",
        pageSize:"Number",
        pageNum:"Number",
        UserId:"String",
        PersionId:"String"
    }
}

request:

// 打星号必传
*pageSize:"Number"		//  分页大小
*pageNum:"Number"		//  分页的当前页数
UserId:"String"			// 当前登录用户的用户id
*PersionId:"String"		// 要查询用户的发布信息的id

app端注册/登录接口

获取短信验证码接口(getSMSInterface)

// 接口示例:
{
    url: 'https://qddscxy-16b8d1.service.tcloudbase.com/YangPan',
    method: 'post',
    data:{
        type:"getSMSInterface",
        SMSType:"Number",
        phone:"Number"
    }
}

request:

// 打星号必传
*SMSType:"Number"		//  发送短信类型 (注册/登录)
*phone:"Number"		//  发送电话

后端模块逻辑

通知模块

一个通知表 来存储通知信息

​ 通知类 :点赞插入通知信息

​ 评论插入通知信息

​ 关注插入通知信息

​ 发文章插入通知信息

​ 收藏插入通知信息

​ 分享插入通知信息

比如我点赞一篇文章:通知表插入一条数据:带有这篇文章的发布者的用户id(noticeUserId),这篇文章的文章id(noticeArticleId),通知内容(noticeType):点赞,触发这个通知的用户(SourceUserId)

然后通知该用户(noticeUserId)

评论模块

登录注册模块

文件模块

app端文件模块接口

admin端接口

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值