App开发之帖子系统(实战篇)
帖子系统数据库设计
帖子表

评论表

收藏表

点赞表

点赞评论表(点赞帖子和点赞评论我用了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 {StatecreateState() { 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 = '';MapqiniuFlies = Map (); Listimages = 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, //横轴三个子widgetchildAspectRatio: 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;}ListupImages = 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) {Listfor (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 {StatecreateState() {return _PageState();}}class _PageState extends State<FoundTab> {Listposts = 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);StatecreateState() { return _PageState(id);}}class _PageState extends State<PostPage> {int id;PostModel post;FollowModel follow;Listcomments = List (); Listloves = 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: (){Listgallery_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},//newonSubmitted: _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;}Listtemp_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;}Listtemp_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上,方便大家交流讨论。
评论
