App开发之帖子系统(实战篇)

漂泊80

共 52316字,需浏览 105分钟

 · 2020-11-23

帖子系统数据库设计

帖子表

评论表

收藏表

点赞表

点赞评论表(点赞帖子和点赞评论我用了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 { @override 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();
@override 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(); }
@override void dispose() { _controller.dispose(); super.dispose(); }
@override 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 photos = 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 { @override 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);
@override void initState() { super.initState(); pull_type = 0; _requestNDiscuss(); }
@override 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);
@override 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);
@override void initState() { super.initState(); _requestDiscuss(); _requestNewestComment(); _requestLoves(); }
@override 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上,方便大家交流讨论。

浏览 9
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报