App开发之帖子系统(实战篇)
漂泊80
共 52316字,需浏览 105分钟
·
2020-11-23 03:05
帖子系统数据库设计
帖子表
评论表
收藏表
点赞表
点赞评论表(点赞帖子和点赞评论我用了2个表,也可以用一个表用类型字段区分)
发帖
客户端add_post_page.dart
import 'dart:convert';
import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_songbei/custom/common_bottom_sheet.dart';
import 'package:flutter_songbei/custom/griditem/add_post_images_grid_item.dart';
import 'package:flutter_songbei/custom/network_loading.dart';
import 'package:flutter_songbei/models/image_model.dart';
import 'package:flutter_songbei/models/post_model.dart';
import 'package:flutter_songbei/network/chttp.dart';
import 'package:flutter_songbei/network/params.dart';
import 'package:flutter_songbei/provider/app.dart';
import 'package:flutter_songbei/qiniu/qiniu_file.dart';
import 'package:flutter_songbei/qiniu/qiniu_scuess.dart';
import 'package:flutter_songbei/utils/qiniu.dart';
import 'package:flutter_songbei/utils/toast_util.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:provider/provider.dart';
import 'package:sy_flutter_qiniu_storage/sy_flutter_qiniu_storage.dart';
class AddPostPage extends StatefulWidget {
State
createState() { return _PageState();
}
}
class _PageState extends State<AddPostPage> {
TextEditingController _titleController = TextEditingController();
TextEditingController _controller = TextEditingController();
String specification = "";
int per_add = 0;
int image_max = 9;
String token = '';
Map
qiniuFlies = Map ();
List
images = List ();
final ImagePicker _picker = ImagePicker();
void initState() {
var image = ImageModel();
image.type = 1;
images.add(image);
_reqQiniuToken();
rootBundle.loadString('assets/data/specification.txt').then((value) => {
this.specification = value,
print('-----specification:${specification}')
});
WidgetsBinding.instance.addPostFrameCallback((_) {
_reqPrivileges();
});
super.initState();
}
void dispose() {
_controller.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'想法',
),
centerTitle: true,
actions:
[ FlatButton.icon(
onPressed: () {
_submit();
},
icon: Icon(
Icons.near_me,
size: 14,
color: Colors.white,
),
label: Text(
'发布',
style: TextStyle(color: Colors.white),
),
)
],
),
body: Container(
color: Colors.white,
padding: EdgeInsets.all(10),
child: Column(
children:
[ // TextField(
// controller: _titleController,
// minLines: 1,
// maxLines: 20,
// decoration: InputDecoration(
// contentPadding: EdgeInsets.all(5.0),
// hintText: '编辑想法标题',
// filled: true,
// fillColor: Colors.white,
// border: InputBorder.none,
// ),
// ),
// Divider(
// height: 1,
// ),
TextField(
controller: _controller,
minLines: 5,
maxLines: 20,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(5.0),
hintText: '写下你的想法',
filled: true,
fillColor: Colors.white,
border: InputBorder.none,
),
),
Flexible(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //横轴三个子widget
childAspectRatio: 1.0 //宽高比为1时,子widget
),
itemCount: images.length,
itemBuilder: (content, index) {
return AddPostGridItem(
images[index],
onAdd: (item) {
showPhotos();
},
onDel: (item) {
print('-----item:$item');
images.removeAt(index);
for (var i = images.length - 1; i >= 0; i--) {
if (images[i].id == item.id) {
images.removeAt(i);
}
}
if (images.length < image_max) {
if (images[images.length - 1].type != 1) {
var image = ImageModel();
image.type = 1;
images.add(image);
}
}
setState(() {});
},
);
}),
),
],
),
));
}
showPhotos() {
var cur_images = 0;
for (var i = 0; i < images.length; i++) {
if (images[i].type == 0) {
cur_images++;
}
}
if (cur_images < image_max) {
} else {
ToastUtil.showToast(context, '最多可上传$image_max张图片');
}
showDialog(
barrierDismissible: true, //是否点击空白区域关闭对话框,默认为true,可以关闭
context: context,
builder: (BuildContext context) {
var list = List();
list.add('相册');
list.add('相机');
return CommonBottomSheet(
list: list,
onItemClickListener: (index) async {
print('-----index:$index');
if (index == 0 || index == 2) {
var source = ImageSource.gallery;
if (index == 2) source = ImageSource.camera;
PickedFile file = await _picker.getImage(source: source);
if (file == null) {
ToastUtil.showToast(context, '选择文件失败');
return;
}
var insert_index = 0;
images.forEach((element) {
if (element.type == 0) {
insert_index += 1;
}
});
var image = ImageModel();
image.path = image.url = file.path;
image.type = 0;
image.state = 0;
images.insert(insert_index, image);
if (images.length > image_max) {
for (var i = images.length - 1; i >= 0; i--) {
if (images[i].type == 1) {
images.removeAt(i);
}
}
}
setState(() {});
// _onUpload(file);
Future future = this._onUpload(file);
future.then((qiniuScuess) {
for (var i = 0; i < images.length; i++) {
if (images[i].type == 0 &&
images[i].path == qiniuScuess.file_path) {
images[i].state = 1;
images[i].url = Qiniu.getUpUrl(qiniuScuess.qiniu_key);
print('------上传成功');
}
}
setState(() {});
});
}
Navigator.pop(context);
},
);
});
}
_submit() {
print("==============================");
// if (_titleController.text.isEmpty) {
// ToastUtil.showToast(context, '编辑想法标题');
// return;
// }
if (_controller.text.isEmpty) {
ToastUtil.showToast(context, '写下你的想法');
return;
}
List
upImages = List (); for (var i = 0; i < images.length; i++) {
if (images[i].type == 0 && images[i].state == 1) {
upImages.add(images[i]);
}
}
// if (upImages.length == 0) {
// ToastUtil.showToast(context, '请选择图片');
// return;
// }
var to_json = {};
if (upImages.length > 0) {
List
for (var i = 0; i < upImages.length; i++) {
photos.add(upImages[i].toServerJson(i));
}
// print(photos);
to_json = {'photos': photos};
}
_reqAddDiscuss(
_titleController.text, _controller.text, json.encode(to_json));
}
/**
* 用户规范
*/
showSpecification() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('用户发布内容规范'),
content: Container(
height: MediaQuery.of(context).size.height / 2,
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(10.0),
child: Text(
specification,
style: TextStyle(fontSize: 18.0),
),
),
),
),
actions:
[ FlatButton(
child: Text("同意"),
onPressed: () =>
{_reqSetPri(), Navigator.of(context).pop()}),
FlatButton(
child: Text("拒绝"),
onPressed: () => {
Navigator.of(context).pop(),
Navigator.of(context).pop()
}),
]);
});
}
void _reqAddDiscuss(title, content, extend) {
print('-----userid:${Provider.of
(context, listen: false).userid}' );showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return NetworkLoading();
});
CHttp.post(
CHttp.DISCUSS_ADD,
(data) {
Navigator.pop(context);
ToastUtil.showToast(context, '发布成功');
Navigator.pop(context, PostModel(data));
},
params: PAddPost(Provider.of
(context, listen: false).userid, title, content, 1,extend)
.toJson(),
errorCallback: (err) {
Navigator.pop(context);
ToastUtil.showToast(context, err);
},
completeCallback: () {
// Navigator.pop(context);
});
}
Future
_onUpload(PickedFile file) async { if (token == null || (token != null && token.length == 0)) {
ToastUtil.showToast(context, 'token 无效!');
return null;
}
print('---_onUpload:${token}');
QiniuScuess qiniuScuess = null;
if (token == null || (token != null && token.length == 0)) {
ToastUtil.showToast(context, 'token 无效!');
return qiniuScuess;
}
if (file == null) {
return qiniuScuess;
}
qiniuFlies[file.path] = QinuFile(file.path);
final syStorage = SyFlutterQiniuStorage();
//监听上传进度
syStorage.onChanged().listen((dynamic percent) {
double p = percent;
// setState(() {
if (qiniuFlies[file.path] != null) qiniuFlies[file.path].process = p;
// });
// print(percent);
LogUtil.e('---percent:${percent}');
// if (qiniuFlies[file.path] != null&&p >= 1.0) {
//// LogUtil.e('---qiuniu_link:${qiniu_link}');
// Qiniu.httpGetImageInfo(Qiniu.getUpUrl(qiniuFlies[file.path].qiniu_key), (data) {
// Map info_map = jsonDecode(jsonEncode(data));
//// this.myFileStorage.onUpScuess(file.path,qiniuFlies[file.path].qiniu_key,info_map);
// qiniuScuess = QiniuScuess(file.path,qiniuFlies[file.path].qiniu_key,info_map);
// this.myFileStorage.onUpScuess(qiniuScuess);
// print('-----tag qiniuScuess:${qiniuScuess}');
// setState(() {
// _controller.text = _controller.text;
// });
// }, errorCallback: (err) {
//
// });
// }
});
String key = Qiniu.getUpPath(file.path);
// LogUtil.e('---key:${key}');
// setState(() {
// qiniu_key = key;
// });
qiniuFlies[file.path].qiniu_key = key;
//上传文件
UploadResult result = await syStorage.upload(file.path, token, key);
if (result.success) {
qiniuScuess = QiniuScuess(file.path, qiniuFlies[file.path].qiniu_key);
}
print('-----result:${result} qiniuScuess:${qiniuScuess}');
return qiniuScuess;
}
void _reqQiniuToken() {
CHttp.post(CHttp.QINIU_UPTOKEN, (data) {
LogUtil.e('-----data:${data}');
setState(() {
token = data;
});
}, errorCallback: (err) {
LogUtil.e('-----err:${err}');
});
}
void _reqPrivileges() {
CHttp.post(
CHttp.USER_PRIVILEGES,
(data) {
LogUtil.e('-----data:${data}');
var temp_per_add = data['per_add'];
setState(() {
per_add = temp_per_add;
});
if (temp_per_add == 0) {
this.showSpecification();
}
},
params:
PUserid(Provider.of
(context, listen: false).userid).toJson(), errorCallback: (err) {
LogUtil.e('-----err:${err}');
});
}
void _reqSetPri() {
CHttp.post(
CHttp.USER_SETPRI,
(data) {
LogUtil.e('-----data:${data}');
var temp_per_add = data['per_add'];
setState(() {
per_add = temp_per_add;
});
if (temp_per_add == 0) {
showSpecification();
}
},
params: PSetPri(Provider.of
(context, listen: false).userid, 'per_add', true)
.toJson(),
errorCallback: (err) {
LogUtil.e('-----err:${err}');
});
}
}
服务器 discuss.js
router.post('/add', function(req, res, next) {
try {
ru.logReq(req);
var userid = req.body.userid;
var title = req.body.title;
var content = req.body.content;
var extend = req.body.extend;
var type = req.body.type;
var os = req.body.os;
if (!content || !userid ||!type) {
ru.resError(res, '参数错误');
} else {
discussDao.addDiscuss(userid, type, title, content, extend, function(err, result) {
if (err) {
ru.resError(res, err);
} else {
var poem = {};
if (result.length > 0) {
poem = result[0];
}
ru.resSuccess(res, poem);
// console.log(poem)
userDao.queryFollowMe(userid, function(err, result) {
if (err) {
logger.error(err);
} else {
if (result.length > 0) {
let messages = [];
console.log('--------------')
console.log(result);
for (var i = 0; i < result.length; i++) {
var title = poem.nickname + '发布了新讨论';
var content = poem.nickname + '发布了[' + poem.title + ']';
var addDiscussExtend = new AddDiscussExtend(poem.id, poem.userid, poem.head, poem.nickname, poem.title);
var message = new Notice(NoticeType.DADD, result[i].fansid, title, content, addDiscussExtend);
messages.push(message)
}
if (messages.length > 0) {
httputil.requstLocalPost('/psbook/message/actionmsgs', { messages: messages }, function(err, result) {
logger.debug(err);
logger.debug(result);
});
}
var app_name = appconfig.APP_NAME;
var webhook_body = "####" + app_name + "\n用户:" + userid + "发布了新的讨论[" + poem.title + "]"
+"\n系统:["+os+"]";
webhook.sendMarkdownMsg(webhook_body, function(err, result) {
if (err) {
logger.error(err);
}
});
}
}
})
}
})
}
} catch (err) {
ru.resError(res, err.message);
}
});
帖子列表
客户端发现页
import 'package:flutter/material.dart';
import 'package:flutter_songbei/custom/listitem/post_list_item.dart';
import 'package:flutter_songbei/models/post_model.dart';
import 'package:flutter_songbei/network/chttp.dart';
import 'package:flutter_songbei/network/params.dart';
import 'package:flutter_songbei/pages/post/post_page.dart';
import 'package:flutter_songbei/pages/user/login_page.dart';
import 'package:flutter_songbei/provider/app.dart';
import 'package:flutter_songbei/utils/app_util.dart';
import 'package:flutter_songbei/utils/toast_util.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import '../../app_theme.dart';
class FoundTab extends StatefulWidget {
State
createState() {return _PageState();
}
}
class _PageState extends State<FoundTab> {
List
posts = List ();
/**
* 0 下拉刷新 1 上拉刷新
*/
int pull_type = 0;
int count = 0;
RefreshController _refreshController =
RefreshController(initialRefresh: false);
void initState() {
super.initState();
pull_type = 0;
_requestNDiscuss();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('发现'),
backgroundColor: AppTheme.mainColor,
),
body: Container(
child: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
child: ListView.separated(
itemBuilder: (content, index) {
return PostListItem(
posts[index],
index,
this.onItem,
onStar: (item) {
if (AppUtil.isLogin(context) == false) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => LoginPage()));
return;
}
_reqPostStar(item);
},
onLove: (item) {
if (AppUtil.isLogin(context) == false) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => LoginPage()));
return;
}
_reqPostLove(item);
},
);
},
itemCount: posts.length,
separatorBuilder: (context, index) {
return Divider(
height: 0.5,
indent: 0,
color: Color(0xFFDDDDDD),
);
},
),
),
),
);
}
void _onRefresh() {
pull_type = 0;
_requestNDiscuss();
}
void _onLoading() {
pull_type = 1;
if (posts.length < count) {
_requestHDiscuss();
} else {
_refreshController.loadComplete();
}
}
void onItem(item) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => PostPage(item.id)))
.then((res) {
if (res != null) {
print('-----res');
print(res);
if (res['action'] == 'del') {
var id = res['id'];
var temp_discuss = posts;
for (var i = temp_discuss.length - 1; i >= 0; i--) {
if (temp_discuss[i].id == id) {
temp_discuss.removeAt(i);
}
}
this.setState(() {
posts = temp_discuss;
});
}
}
});
}
void _requestNDiscuss() {
var fromid = 0;
var forms = posts;
if (forms.length > 0) {
fromid = forms[0].id;
}
CHttp.post(
CHttp.DISCUSS_NDISCUSS,
(data) {
if (!mounted) {
return;
}
count = data['count'];
var temp_discuss = List
(); var res_discuss = data['discuss'];
for (var i = 0; i < res_discuss.length; i++) {
temp_discuss.add(PostModel(res_discuss[i]));
}
posts.insertAll(0, temp_discuss);
setState(() {
});
print(posts);
},
params:
PDiscuss(Provider.of
(context, listen: false).userid, fromid) .toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
},
completeCallback: () {
if (pull_type == 0) {
_refreshController.refreshCompleted();
} else {
_refreshController.loadComplete();
}
});
}
void _requestHDiscuss() {
var fromid = 0;
var forms = posts;
if (forms.length > 0) {
fromid = forms[forms.length - 1].id;
}
CHttp.post(
CHttp.DISCUSS_HDISCUSS,
(data) {
if (!mounted) {
return;
}
count = data['count'];
var temp_discuss = List
(); var res_discuss = data['discuss'];
for (var i = 0; i < res_discuss.length; i++) {
temp_discuss.add(PostModel(res_discuss[i]));
}
posts.addAll(temp_discuss);
setState(() {
});
print(posts);
},
params: PDiscuss(Provider.of
(context).userid, fromid).toJson(), errorCallback: (err) {
ToastUtil.showToast(context, err);
},
completeCallback: () {
if (pull_type == 0) {
_refreshController.refreshCompleted();
} else {
_refreshController.loadComplete();
}
});
}
void _reqPostStar(PostModel post) {
print(post);
var star = post.mystar != null&&post.mystar == 1 ? 0 : 1;
CHttp.post(
CHttp.STATR,
(data) {
if (!mounted) {
return;
}
post.mystar = star;
var starnum = post.starnum != null?post.starnum :0;
if (star == 1) {
starnum += 1;
} else {
if (starnum > 0) {
starnum -= 1;
}
}
post.starnum = starnum;
setState(() {});
ToastUtil.showToast(context, star == 1 ? '收藏成功' : '取消收藏');
print(data);
},
params: PStar(Provider.of
(context, listen: false).userid, 3, post.id, star)
.toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
void _reqPostLove(PostModel post) {
CHttp.post(
CHttp.LOVE_LOVE,
(data) {
if (!mounted) {
return;
}
print(data);
var love = data['love'];
var lovenum = post.lovenum;
if (love == 1) {
lovenum += 1;
} else {
if (lovenum > 0) {
lovenum -= 1;
}
}
post.lovenum = lovenum;
post.mylove = love;
setState(() {});
},
params: PPostLove(Provider.of
(context, listen: false).userid,3, post.id, post.mylove == 0 ? 1 : 0)
.toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
},
completeCallback: () {
});
}
}
服务器帖子列表
/**
* 最新帖子
*/
router.post('/ndiscuss', function(req, res, next) {
try {
ru.logReq(req);
var id = req.body.id;
var userid = req.body.userid;
discussDao.queryNDiscuss(id, userid, function(err, poems) {
if (err) {
ru.resError(res, err);
} else {
ru.resSuccess(res, poems);
}
})
} catch (err) {
ru.resError(res, err.message);
}
});
/**
* 历史帖子
*/
router.post('/hdiscuss', function(req, res, next) {
try {
ru.logReq(req);
var id = req.body.id;
var userid = req.body.userid;
discussDao.queryHDiscuss(id, userid, function(err, poems) {
if (err) {
ru.resError(res, err);
} else {
ru.resSuccess(res, poems);
}
});
} catch (err) {
ru.resError(res, err.message);
}
});
帖子详情
客户端post_page.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_songbei/custom/follow_user.dart';
import 'package:flutter_songbei/custom/listitem/comment_list_item.dart';
import 'package:flutter_songbei/custom/listitem/post_love_lits_item.dart';
import 'package:flutter_songbei/custom/loading.dart';
import 'package:flutter_songbei/manager/ui_manager.dart';
import 'package:flutter_songbei/models/comment_model.dart';
import 'package:flutter_songbei/models/follow_model.dart';
import 'package:flutter_songbei/models/love_model.dart';
import 'package:flutter_songbei/models/photo_gallery_model.dart';
import 'package:flutter_songbei/models/post_model.dart';
import 'package:flutter_songbei/network/chttp.dart';
import 'package:flutter_songbei/network/params.dart';
import 'package:flutter_songbei/pages/my/report_page.dart';
import 'package:flutter_songbei/pages/user/login_page.dart';
import 'package:flutter_songbei/pages/user/loves_page.dart';
import 'package:flutter_songbei/provider/app.dart';
import 'package:flutter_songbei/utils/app_util.dart';
import 'package:flutter_songbei/utils/toast_util.dart';
import 'package:provider/provider.dart';
import '../../app_theme.dart';
import '../photos_gallery_page.dart';
class PostPage extends StatefulWidget {
int id;
PostPage(this.id);
State
createState() { return _PageState(id);
}
}
class _PageState extends State<PostPage> {
int id;
PostModel post;
FollowModel follow;
List
comments = List (); List
loves = List ();
TextEditingController _textController = TextEditingController();
FocusNode _focusNode = FocusNode();
bool _isComposing = false;
String placeholder = '发表评论...';
String ctips = '';
int cid = 0;
String cnickname = '';
String ccomment = '';
String comment = '';
_PageState(this.id);
void initState() {
super.initState();
_requestDiscuss();
_requestNewestComment();
_requestLoves();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('想法'),
centerTitle: true,
),
body: _buildBody(),
);
}
Widget _buildBody() {
print('_buildBody');
print(post);
if (post != null) {
return Column(
children:
[ Flexible(
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(color: Colors.white),
child: ListView(
children:
[ _buildFollow(),
_buildPost(context),
_buildLoves(),
_buildMenus(),
Row(
children:
[Text('全部回复:${post.commentnum}')], ),
ListView.separated(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: comments.length,
itemBuilder: (BuildContext context, int positon) {
return CommentLstItem(comments[positon], onComment:(item) {
// print('----item:${item}');
if (AppUtil.isLogin(context) == false) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginPage()));
return;
}
_renderTips(item.id, item.nickname, item.comment);
}, onLove:(item) {
_onLoveComment(item);
}, onDel:(item) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('删除评论'),
content: Container(
child: Text('是否确认删除评论?'),
),
actions:
[ FlatButton(
child: const Text('取消'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('确认'),
onPressed: () {
_onDelComment(item);
Navigator.of(context).pop();
}),
],
);
});
});
},
separatorBuilder: (context, index) {
return Divider(
height: 0.5,
indent: 0,
color: Color(0xFFDDDDDD),
);
},
)
],
),
),
),
Divider(height: 1.0),
Container(
decoration: new BoxDecoration(color: Theme.of(context).cardColor),
child: _buildTextComposer(), //页面下方的文本输入控件
)
],
);
} else {
return Loading();
}
}
Widget _buildFollow() {
print('------_buildFollow');
print(follow);
if (follow != null) {
return Container(
child: FollowUser(1, follow, (item) {}),
);
} else {
return Container();
}
}
Widget _buildPost(BuildContext context) {
print('post.time:${post.time}');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
[ Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Text(
post.title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
post.content,
style: TextStyle(fontSize: 16),
),
),
_buildPhotos(context),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children:
[ Text(
UIManager.getTime(post.time),
style:
TextStyle(fontSize: 14,color: AppTheme.grayColor),
)
],
)
],
);
}
Widget _buildPhotos(BuildContext context) {
if (post.postExtend != null && post.postExtend.photos.length > 0) {
var photos = post.postExtend.photos;
return Container(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext content, int index) {
return InkWell(
child: Container(
constraints:
BoxConstraints(maxHeight: MediaQuery.of(context).size.width),
child: CachedNetworkImage(
imageUrl: UIManager.getHeadurl(photos[index].photo),
fit: BoxFit.cover,
width: double.infinity,
),
),
onTap: (){
List
gallery_photos = List (); photos.forEach((element) {
gallery_photos.add(PhotoGalleryModel(element.photo));
});
Navigator.push(
context, MaterialPageRoute(builder: (context) => PhotosGalleryPage(gallery_photos,index)));
},
);
},
itemCount: photos.length,
),
);
} else {
return Container();
}
}
Widget _buildLoves() {
if (post.lovenum > 0) {
return GestureDetector(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LovesPage(id)));
},
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children:
[ Container(
height: 40,
width: MediaQuery.of(context).size.width/2,
child: ListView.separated(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: loves.length,
itemBuilder: (BuildContext context, int positon) {
return PostLoveListItem(loves[positon]);
},
separatorBuilder: (context, index) {
return Divider(
height: 0.5,
indent: 0,
color: Color(0xFFDDDDDD),
);
},
),
),
Divider(
height: 5,
color: Colors.white,
),
Text(
'${post.lovenum}人赞过 >',
style: TextStyle(color: Colors.black45),
)
],
),
),
);
} else {
return Container();
}
}
Widget _buildMenus() {
print('-----_buildMenus');
print(post);
return Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children:
[ InkWell(
child: Column(
children:
[ Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20.0)),
border: Border.all(color: AppTheme.grayColor)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children:
[ Image(
image: AssetImage(
UIManager.getLoveAssetImage(post.mylove)),
width: 20,
height: 20,
color: UIManager.getLoveColor(post.mylove),
)
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Text(
UIManager.getNumStr(post.lovenum),
style: TextStyle(color: AppTheme.grayColor),
),
)
],
),
onTap: () {
_onLove();
},
),
SizedBox(
width: 40,
height: 40,
),
InkWell(
child: Column(
children:
[ Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20.0)),
border: Border.all(color: AppTheme.grayColor)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children:
[ Image(
image: AssetImage(
UIManager.getStarAssetImage(post.mystar)),
width: 20,
height: 20,
color: UIManager.getStarColor(post.mystar),
)
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Text(
UIManager.getNumStr(post.starnum),
style: TextStyle(color: AppTheme.grayColor),
),
)
],
),
onTap: () {
_onStar();
},
),
SizedBox(
width: 40,
height: 40,
),
InkWell(
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20.0)),
border: Border.all(color: AppTheme.grayColor)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children:
[ Image(
image: AssetImage('assets/post/jubao.png'),
width: 20,
height: 20,
color: AppTheme.grayColor,
)
],
),
),
onTap: () {
_onReport();
},
),
_buildDelete(),
],
),
);
}
Widget _buildDelete() {
if (post.userid == Provider.of
(context).userid) { return Row(
children:
[ SizedBox(
width: 40,
height: 40,
),
InkWell(
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20.0)),
border: Border.all(color: AppTheme.grayColor)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children:
[ Image(
image: AssetImage('assets/post/shanchu.png'),
width: 20,
height: 20,
color: AppTheme.grayColor,
)
],
),
),
onTap: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('删除想法'),
content: Container(
child: Text('是否确认删除想法?'),
),
actions:
[ FlatButton(
child: const Text('取消'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('确认'),
onPressed: () {
_onDelDiscuss();
Navigator.of(context).pop();
}),
],
);
});
},
)
],
);
} else {
return Container();
}
}
Widget _buildTextComposer() {
return IconTheme(
data: IconThemeData(color: Theme.of(context).accentColor),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children:
[ cid > 0
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:
[ Container(
width: MediaQuery.of(context).size.width / 3 * 2,
// child: Text(ctips,
// style: TextStyle(color: Colors.black45),
// maxLines: 1,
// textAlign: TextAlign.left,
// overflow: TextOverflow.ellipsis,
// softWrap: true,
// ),
child: RichText(
text: TextSpan(
text: '正在回复',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87),
children:
[ TextSpan(
text: cnickname,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.lightBlueAccent)),
TextSpan(
text: '的',
style: TextStyle(color: Colors.black87)),
TextSpan(
text: ccomment,
style: TextStyle(
color: Colors.lightBlueAccent)),
]),
textAlign: TextAlign.left,
maxLines: 1,
overflow: TextOverflow.ellipsis,
softWrap: true,
),
),
FlatButton(
child: Text('取消回复'),
onPressed: () {
_renderTips(0, '', '');
_onHideKey();
},
)
],
)
: Container(),
Row(
children:
[ Flexible(
child: TextField(
controller: _textController,
focusNode: _focusNode,
onChanged: (String text) {
//new 通过onChanged事件更新_isComposing 标志位的值
setState(() {
//new 调用setState函数重新渲染受到_isComposing变量影响的IconButton控件
_isComposing =
text.length > 0; //new 如果文本输入框中的字符串长度大于0则允许发送消息
}); //new
},
//new
onSubmitted: _handleSubmitted,
decoration:
InputDecoration.collapsed(hintText: placeholder),
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 4.0),
child: IconButton(
icon: Icon(Icons.send),
onPressed: _isComposing
? () =>
_handleSubmitted(_textController.text) //modified
: null, //modified 当没有为onPressed绑定处理函数时,IconButton默认为禁用状态
),
),
],
)
],
),
),
);
}
void _renderTips(cid, cnickname, comment) {
// print('----cnickname:${cnickname}');
var placeholder = '发表评论...';
var ctips = '';
if (cid > 0) {
placeholder = '回复...';
ctips = '正在回复[${cnickname}]的[${comment}]';
print('----${ctips}');
// this.refs.cinput.focus();
FocusScope.of(context).requestFocus(_focusNode);
} else {
this._onHideKey();
}
setState(() {
this.cid = cid;
this.cnickname = cnickname;
this.ccomment = comment;
this.placeholder = placeholder;
this.ctips = ctips;
this.comment = '';
});
}
void _onHideKey() {
if (_focusNode.hasFocus == true) {
// FocusScope.of(context).requestFocus(_focusNode);
FocusScope.of(context).requestFocus(FocusNode());
}
}
//定义发送文本事件的处理函数
void _handleSubmitted(String text) {
comment = _textController.text;
if (AppUtil.isLogin(context)) {
_onRelease();
} else {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()))
.then((perfect) {
if (perfect != null) {
_onRelease();
}
});
}
}
void _onRelease() {
if (comment.length == 0) {
ToastUtil.showToast(context, '请输入内容');
return;
}
var params = PCommentAdd(3, Provider.of
(context, listen: false).userid, id, cid, comment)
.toJson();
CHttp.post(
CHttp.COMMENT_ADD,
(data) {
if (!mounted) {
return;
}
var temp_comment = CommentModel(data);
comments.insert(0, temp_comment);
setState(() {});
_requestLoveComment();
ToastUtil.showToast(context, '评论成功');
_renderTips(0, '', '');
_textController.clear(); //清空输入框
},
params: params,
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
void _onLoveComment(CommentModel comment) {
if (!AppUtil.isLogin(context)) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()))
.then((perfect) {
if (perfect != null) {}
});
return;
}
var onlove = comment.love == 1 ? 0 : 1;
print('---comment.love:${comment.love}');
print('---onlove:${onlove}');
var params = PLoveComment(
2,
Provider.of
(context, listen: false).userid, id,
comment.id,
onlove)
.toJson();
CHttp.post(
CHttp.LOVE_LOVECOMMENT,
(data) {
var id = data['id'];
var love = data['love'];
for (var i = 0; i < comments.length; i++) {
if (comments[i].id == id) {
var lovenum = comments[i].lovenum;
if (love == 1) {
lovenum += 1;
} else {
if (lovenum > 0) lovenum -= 1;
}
comments[i].lovenum = lovenum;
comments[i].love = love;
}
}
setState(() {});
},
params: params,
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
void _onDelComment(CommentModel comment) {
if (!AppUtil.isLogin(context)) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()))
.then((perfect) {
if (perfect != null) {}
});
return;
}
var params = PDelComment(
2,
Provider.of
(context, listen: false).userid, comment.id,id,)
.toJson();
CHttp.post(
CHttp.COMMENT_DEL,
(data) {
for (var i = comments.length - 1; i >= 0; i--) {
if (comments[i].id == comment.id) {
comments.removeAt(i);
}
}
setState(() {});
},
params: params,
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
_onDelDiscuss() {
CHttp.post(
CHttp.DISCUSS_DEL,
(data) {
ToastUtil.showToast(context, '想法删除成功');
Navigator.of(context).pop({'action': 'del', 'id': post.id});
},
params:
PDiscuss(Provider.of
(context, listen: false).userid, id) .toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
void _onLove() {
if (AppUtil.isLogin(context) == false) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()));
return;
}
_reqPostLove(post);
}
void _onStar() {
if (AppUtil.isLogin(context) == false) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()));
return;
}
_reqPostStar(post);
}
void _onReport() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ReportPage('举报想法', post.userid,post.id, 3)));
}
void _requestDiscuss() {
CHttp.post(
CHttp.DISCUSS_INFO,
(data) {
if (!mounted) {
return;
}
post = PostModel(data);
setState(() {});
_requestFloow(post.userid);
},
params:
PPost(Provider.of
(context, listen: false).userid, id).toJson(), errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
void _requestFloow(String fansid){
CHttp.post(
CHttp.USER_FOLLOWINFO,
(data) {
if (!mounted) {
return;
}
follow = FollowModel(data);
setState(() {});
},
params:
PFollowUser(Provider.of
(context, listen: false).userid, fansid).toJson(), errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
/**
* 请求点单数和评论数
*/
void _requestLoveComment() {
CHttp.post(
CHttp.LOVE_LCNUM,
(data) {
if (!mounted) {
return;
}
print(data);
},
params: PCommentNum(3, id).toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
/**
* 请求评论列表
*/
void _requestNewestComment() {
var fromid = 0;
if (comments.length > 0) {
fromid = comments[0].id;
}
CHttp.post(
CHttp.COMMENT_LATEST,
(data) {
if (!mounted) {
return;
}
List
temp_comments = List (); for (var i = 0; i < data.length; i++) {
temp_comments.add(CommentModel(data[i]));
}
comments.insertAll(0, temp_comments);
setState(() {});
// print(data);
},
params: PComment(3, fromid, id).toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
void _reqPostStar(PostModel post) {
print(post);
var star = post.mystar != null&&post.mystar == 1 ? 0 : 1;
CHttp.post(
CHttp.STATR,
(data) {
if (!mounted) {
return;
}
post.mystar = star;
var starnum = post.starnum != null?post.starnum :0;
if (star == 1) {
starnum += 1;
} else {
if (starnum > 0) {
starnum -= 1;
}
}
post.starnum = starnum;
setState(() {});
ToastUtil.showToast(context, star == 1 ? '收藏成功' : '取消收藏');
print(data);
},
params: PStar(Provider.of
(context, listen: false).userid, 3, post.id, star)
.toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
void _reqPostLove(PostModel post) {
CHttp.post(
CHttp.LOVE_LOVE,
(data) {
if (!mounted) {
return;
}
print(data);
var love = data['love'];
var lovenum = post.lovenum;
if (love == 1) {
lovenum += 1;
} else {
if (lovenum > 0) {
lovenum -= 1;
}
}
post.lovenum = lovenum;
post.mylove = love;
setState(() {});
},
params: PPostLove(Provider.of
(context, listen: false).userid,3, post.id, post.mylove == 0 ? 1 : 0)
.toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
},
completeCallback: () {
});
}
_requestLoves() {
CHttp.post(
CHttp.LOVE_LOVES,
(data) {
if (!mounted) {
return;
}
List
temp_loves = List (); for (var i = 0; i < data.length; i++) {
temp_loves.add(LoveModel(data[i]));
}
setState(() {
loves = temp_loves;
});
},
params: PLoves(3, id).toJson(),
errorCallback: (err) {
ToastUtil.showToast(context, err);
});
}
}
服务器帖子详情
router.post('/info', function(req, res, next) {
ru.logReq(req);
var id = req.body.id;
var userid = req.body.userid;
if (!id) {
ru.resError(res, '参数错误')
} else {
discussDao.queryDiscussInfo(id, userid, function(err, result) {
if (err) {
ru.resError(res, err)
} else {
if (result.del == 1) {
ru.resError(res, '作品已删除')
} else {
ru.resSuccess(res, result);
}
}
});
}
});
项目整体功能还在开发中,待基础功能完成后,我会放在Github上,方便大家交流讨论。
评论