这个和前面发的Unicloud初级入门-新闻小案例,是一体的。只不过这个带图片上传功能,更完整些。
我就不啰嗦了,直接把代码全部贴出来。
项目截图
数据库
uniapp代码
artAddNews
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
let {news,picUrls} = event;
let res = await db.collection("article").add({
posttime: Date.now(),
...news,
picUrls
});
return res;
};
artDelete
'use strict';
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
//解析id
let {id} = event;
//根据条件删除
let res = await db.collection("article").where({
_id : dbCmd.eq(id)
}).remove();
//返回
return res;
};
artGetAll
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
//翻页需要过滤的的量,默认首次是0
let {skip = 0 } = event;
let res = await db.collection("article")
.limit(8) //一次取6条
.skip(skip) //过滤多少条,把前面已经展示的内容过滤掉
.orderBy("posttime","desc") //按时间倒序排序
.get();
return res;
};
artGetById
'use strict';
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
let {id} = event;
//根据id获取新闻详情
//let res = await db.collection("article").doc(id).get();
//根据id获取新闻详情
let res = await db.collection("article").where({
_id : dbCmd.eq(id)
}).get();
return res;
};
artUpdateNews
'use strict';
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
let {news,picUrls} = event;
let res = await db.collection("article").where({
_id: dbCmd.eq(news._id)
}).update({
title: news.title,
author: news.author,
content: news.content,
picUrls: picUrls
});
return res;
};
pages add add.vue
<template>
<view class="add">
<form @submit="onsubmit">
<view class="item">
<input type="text" name="title" placeholder="请输入标题" v-model="formValue.title" />
</view>
<view class="item">
<input type="text" name="author" placeholder="请输入作者" v-model="formValue.author" />
</view>
<view class="item">
<textarea value="" placeholder="请输入内容" name="content" v-model="formValue.content"/>
</view>
<view class="item">
<uni-file-picker
v-model="imageValue"
file-mediatype="image"
mode="grid"
:limit="3"
title="可以上传3张图片"
file-extname="png,jpg"
@success="uploadSuccess"
/>
</view>
<view class="item">
<button type="default" form-type="reset">重置</button>
<button type="primary" form-type="submit" :disabled="isDisabled(formValue)">提交</button>
</view>
</form>
</view>
</template>
<script>
export default {
data() {
return {
imageValue:[],
formValue:{
title: '',
author:'',
content:''
},
picUrls:[]
}
},
methods: {
//图片上传成功
uploadSuccess(e){
console.log(e)
//this.picUrls.push(...e.tempFilePaths);
},
//判断按钮是否禁用
isDisabled(obj){
let disabled = Object.keys(obj).some((key,value)=>{
//此项没有填写值时
return obj[key] == ''
})
return disabled;
},
onsubmit(e){
let obj = e.detail.value;
this.picUrls = this.imageValue.map(item=>{
return item.url
});
uniCloud.callFunction({
name:"artAddNews",
data:{
news: obj,
picUrls: this.picUrls
}
}).then(res=>{
console.log(res);
uni.showToast({
title:"发布成功",
icon:"success",
mask:true,
duration:1000
});
setTimeout(()=>{
uni.reLaunch({
url:'/pages/index/index'
})
},1200);
})
}
}
}
</script>
<style lang="scss" scoped>
.add{
padding: 30rpx;
.item{
padding-bottom: 20rpx;
input,textarea{
border: 1px solid #eee;
height: 80rpx;
padding: 0 20rpx;
}
textarea{
height: 200rpx;
width: 100%;
box-sizing: border-box;
}
button{
margin-bottom: 20rpx;
}
}
}
</style>
pages detail detail.vue
<template>
<view class="detail">
<view v-if="loading">
<view class="title">
{{detailData.title}}
</view>
<view class="info">
<text class="txt">作者:{{detailData.author}}</text>
<text>时间:</text>
<uni-dateformat
:date="detailData.posttime"
format="yyyy年MM月dd hh:mm:ss"
class="txt"/>
</view>
<view class="content">
<rich-text :nodes="detailData.content"></rich-text>
</view>
<view class="picUrls" v-if="detailData.picUrls && detailData.picUrls.length">
<image :src="item" mode="widthFix" v-for="(item,index) in detailData.picUrls" :key="index"></image>
</view>
<view class="btnGroup">
<button type="default" size="mini" class="btn" @tap="onUpdate">
<uni-icons type="compose" size="15"></uni-icons>
修改
</button>
<button type="warn" size="mini" class="btn" @tap="onDelete">
<uni-icons type="trash" size="15" color="#fff"></uni-icons>
删除
</button>
</view>
</view>
<view v-else>
<uni-load-more status="loading"></uni-load-more>
</view>
</view>
</template>
<script>
export default {
data() {
return {
id:null,
detailData:{},
loading: false
};
},
onLoad(options) {
this.id = options.id;
},
onShow() {
this.getData();
},
methods:{
//
getData(){
uniCloud.callFunction({
name:"artGetById",
data:{
id: this.id
}
}).then(res=>{
console.log(res)
this.detailData = res.result.data[0];
//加载完成,关闭提示
this.loading = true;
//修改导航栏的标题
uni.setNavigationBarTitle({
title: this.detailData.title
});
}).catch(()=>{
uni.showToast({
title:'参数有误',
icon:'none'
});
setTimeout(()=>{
uni.reLaunch({
url:'/pages/index/index'
})
},800);
})
},
//修改
onUpdate(){
uni.navigateTo({
url:'/pages/edit/edit?id=' + this.id
});
},
//调用云函数
remove(){
uniCloud.callFunction({
name:"artDelete",
data:{
id: this.id
}
}).then(res=>{
console.log(res);
//
uni.showToast({
title:'删除成功',
icon:'success',
mask:true,
duration:1000
});
//等待图标提示完毕,再跳转
setTimeout(()=>{
uni.reLaunch({
url:'/pages/index/index'
});
},1500)
})
},
//删除
onDelete(){
uni.showModal({
title:'删除提示',
content:'您确定要删除此篇文章吗?',
confirmText:'删除',
success: (res) => {
//确认删除
if(res.confirm){
this.remove();
}else{
//不删除
uni.showToast({
title:'已取消删除',
icon:'none'
});
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.detail{
padding: 30rpx;
.title{
font-size: 50rpx;
color: #333;
text-align: justify;
line-height: 1.4em;
}
.info{
font-size: 30rpx;
color: #666;
padding: 30rpx 0 60rpx;
.txt{
padding-right: 30rpx;
}
}
.content{
font-size: 36rpx;
line-height: 1.7em;
color: #333;
}
.picUrls{
padding-top: 50rpx;
image{
width: 100%;
display: block;
margin-bottom: 30rpx;
}
}
.btnGroup{
margin-top: 50rpx;
padding: 50rpx 0;
border-top: 1px solid #ccc;
.btn{
margin-right: 30rpx;
}
}
}
</style>
pages edit edit.vue
<template>
<view class="add">
<form @submit="onsubmit">
<view class="item">
<input type="text" name="title" placeholder="请输入标题" v-model="formValue.title" />
</view>
<view class="item">
<input type="text" name="author" placeholder="请输入作者" v-model="formValue.author" />
</view>
<view class="item">
<textarea value="" placeholder="请输入内容" name="content" v-model="formValue.content"/>
</view>
<view class="item">
<uni-file-picker
v-model="imageValue"
file-mediatype="image"
mode="grid"
:limit="3"
title="可以上传3张图片"
file-extname="png,jpg"
@success="uploadSuccess"
/>
</view>
<view class="item">
<button type="default" form-type="reset">重置</button>
<button type="primary" form-type="submit" :disabled="isDisabled(formValue)">提交</button>
</view>
</form>
</view>
</template>
<script>
export default {
data() {
return {
id:null,
formValue:{
title: '',
author:'',
content:''
},
imageValue:[],
picUrls:[]
}
},
onLoad(options) {
this.id = options.id;
this.getDetail();
},
methods: {
//图片上传成功
uploadSuccess(e){
console.log(e)
//this.picUrls.push(...e.tempFilePaths);
},
getDetail(){
uniCloud.callFunction({
name:"artGetById",
data:{
id: this.id
}
}).then(res=>{
console.log(res)
this.formValue = res.result.data[0];
//如果本就没有图片,不做回显
if(!this.formValue.picUrls) return;
this.picUrls = this.formValue.picUrls;
let urls = this.formValue.picUrls.map(item =>{
return {
url: item
}
})
console.log("urls",urls)
this.imageValue = urls;
});
},
//判断按钮是否禁用
isDisabled(obj){
let disabled = Object.keys(obj).some((key,value)=>{
//此项没有填写值时
return obj[key] == ''
})
return disabled;
},
onsubmit(){
//从控件中取,
this.picUrls = this.imageValue.map(item=>{
return item.url
});
uniCloud.callFunction({
name:"artUpdateNews",
data:{
news: this.formValue,
picUrls: this.picUrls
}
}).then(res=>{
console.log(res);
uni.showToast({
title:"更新成功",
icon:"success",
mask:true,
duration:1000
});
setTimeout(()=>{
uni.navigateBack({
delta:1
});
},1200);
})
}
}
}
</script>
<style lang="scss" scoped>
.add{
padding: 30rpx;
.item{
padding-bottom: 20rpx;
input,textarea{
border: 1px solid #eee;
height: 80rpx;
padding: 0 20rpx;
}
textarea{
height: 200rpx;
width: 100%;
box-sizing: border-box;
}
button{
margin-bottom: 20rpx;
}
}
}
</style>
pages index index.vue
<template>
<view class="home">
<view class="content">
<view class="item" v-for="item in newsList" :key="item._id" @tap="goDetail(item)">
<view class="txt">
<view class="title">
{{item.title}}
</view>
<view class="info">
<text class="t">{{item.author}}</text>
<uni-dateformat
:date="item.posttime"
:threshold="[60000, 7200000]"
format="MM-dd">
</uni-dateformat>
</view>
</view>
<view class="pic">
<image :src="item.picUrls[0]" mode="aspectFit" v-if="item.picUrls && item.picUrls.length"></image>
<image src="../../static/logo.png" mode="aspectFit" v-else></image>
</view>
</view>
</view>
<view class="goAdd" @tap="goAdd">
<uni-icons type="plusempty" size="30" color="#fff"></uni-icons>
</view>
<view v-if="isEnd">
<uni-load-more status="noMore"></uni-load-more>
</view>
</view>
</template>
<script>
export default {
data() {
return {
newsList:[],
isEnd: false
}
},
onLoad() {
//重置
this.isEnd = false;
//获取数据
this.getData();
},
//触底加载
onReachBottom() {
this.getData();
},
//下拉刷新
onPullDownRefresh(){
//重置状态
this.isEnd = false;
this.newsList = [];
this.getData();
},
methods: {
//前往详情页
goDetail(obj){
//
uni.navigateTo({
url:"/pages/detail/detail?id=" + obj._id
});
},
getData(){
uniCloud.callFunction({
name:"artGetAll",
data:{
//过滤的量就是,已经获取的数组长度
skip: this.newsList.length
}
}).then(res=>{
console.log(res)
//新获取的数据,解析后,追加到数组中
this.newsList.push(...res.result.data);
//下拉刷新停止
uni.stopPullDownRefresh();
//判断是否到底了
if(res.result.affectedDocs <= 0){
this.isEnd = true;
}
})
},
goAdd(){
uni.navigateTo({
url:'/pages/add/add'
});
}
}
}
</script>
<style lang="scss" scoped>
.home{
.content{
padding: 30rpx;
.item{
display: flex;
justify-content: space-between;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
.txt{
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-right: 20rpx;
.title{
font-size: 40rpx;
color: #333;
text-align: justify;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.info{
font-size: 28rpx;
color: #888;
.t{
padding-right: 20rpx;
}
}
}
.pic{
width: 260rpx;
height: 160rpx;
image{
width: 100%;
height: 100%;
}
}
}
}
.goAdd{
width: 120rpx;
height: 120rpx;
background-color: #5B89FE;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
position: fixed;
right: 30rpx;
bottom: 60rpx;
}
}
</style>
app.vue
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
:root{
box-sizing: border-box;
}
</style>
pages.json
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "文章列表",
"enablePullDownRefresh": true
}
},
{
"path" : "pages/add/add",
"style" :
{
"navigationBarTitleText" : "新增文章",
"enablePullDownRefresh" : false
}
},
{
"path" : "pages/edit/edit",
"style" :
{
"navigationBarTitleText" : "修改文章",
"enablePullDownRefresh" : false
}
},
{
"path" : "pages/detail/detail",
"style" :
{
"navigationBarTitleText" : "新闻详情",
"enablePullDownRefresh" : false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "文章管理系统",
"navigationBarBackgroundColor": "#2B9939",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}
图示