@@ -22,10 +22,29 @@ class FeedbackBloc extends Bloc<FeedbackEvent, FeedbackState> { | |||||
if (event is FeedbackInitEvent) { | if (event is FeedbackInitEvent) { | ||||
yield* _mapInitToState(event); | yield* _mapInitToState(event); | ||||
} | } | ||||
/// 提交反馈 | |||||
if (event is FeedbackSubmitEvent) { | |||||
yield* _mapSaveToState(event); | |||||
} | |||||
} | |||||
/// 提交反馈 | |||||
Stream<FeedbackState> _mapSaveToState(FeedbackSubmitEvent event) async* { | |||||
var result = await repository.saveFeedback(event?.model); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield FeedbackSaveSuccessState(); | |||||
} else { | |||||
yield FeedbackSaveErrorState(); | |||||
} | |||||
} | } | ||||
/// 初始化 | /// 初始化 | ||||
Stream<FeedbackState> _mapInitToState(FeedbackInitEvent event) async* { | Stream<FeedbackState> _mapInitToState(FeedbackInitEvent event) async* { | ||||
var cache = await repository.fetchCachedData(event.model); | |||||
if (!EmptyUtil.isEmpty(cache)) { | |||||
yield FeedbackLoadedState(model: cache); | |||||
} | |||||
var result = await repository.fetchData(event.model); | var result = await repository.fetchData(event.model); | ||||
if (!EmptyUtil.isEmpty(result)) { | if (!EmptyUtil.isEmpty(result)) { | ||||
yield FeedbackLoadedState(model: result); | yield FeedbackLoadedState(model: result); | ||||
@@ -10,4 +10,8 @@ class FeedbackInitEvent extends FeedbackEvent{ | |||||
} | } | ||||
/// 提交反馈 | /// 提交反馈 | ||||
class FeedbackSubmitEvent extends FeedbackEvent{} | |||||
class FeedbackSubmitEvent extends FeedbackEvent{ | |||||
final Map<String, dynamic> model; | |||||
FeedbackSubmitEvent({this.model}); | |||||
} |
@@ -0,0 +1,73 @@ | |||||
import 'dart:async'; | |||||
import 'package:bloc/bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_record_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'feedback_record_event.dart'; | |||||
import 'feedback_record_state.dart'; | |||||
class FeedbackRecordBloc extends Bloc<FeedbackRecordEvent, FeedbackRecordState> { | |||||
// FeedbackRecordBloc() : super(FeedbackRecordInitial()); | |||||
@override | |||||
FeedbackRecordState get initialState => FeedbackRecordInitial(); | |||||
FeedbackRecordRepository repository; | |||||
FeedbackRecordBloc(this.repository); | |||||
@override | |||||
Stream<FeedbackRecordState> mapEventToState( | |||||
FeedbackRecordEvent event, | |||||
) async* { | |||||
/// 初始化 | |||||
if (event is FeedbackRecordInitEvent) { | |||||
yield* _mapInitEventToState(event); | |||||
} | |||||
/// 刷新 | |||||
if (event is FeedbackRecordRefreshEvent) { | |||||
yield* _mapRefreshEventToState(event); | |||||
} | |||||
/// 加载更多 | |||||
if (event is FeedbackRecordLoadEvent) { | |||||
yield* _mapLoadEventToState(event); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<FeedbackRecordState> _mapInitEventToState(FeedbackRecordInitEvent event) async* { | |||||
var styleCache = await repository.fetchCacheStyle(); | |||||
var styleNet = await repository.fetchInitStyle(); | |||||
var data = await repository.fetchInitData(); | |||||
if (!EmptyUtil.isEmpty(data) && (!EmptyUtil.isEmpty(styleCache) || !EmptyUtil.isEmpty(styleNet))) { | |||||
yield FeedbackRecordLoadedState(dataModel: data, styleModel: !EmptyUtil.isEmpty(styleNet) ? styleNet : styleCache); | |||||
} else { | |||||
yield FeedbackRecordInitErrorState(); | |||||
} | |||||
} | |||||
/// 刷新 | |||||
Stream<FeedbackRecordState> _mapRefreshEventToState(FeedbackRecordRefreshEvent event) async* { | |||||
var style = repository.styleModel; | |||||
var result = await repository.fetchRefreshData(); | |||||
if (!EmptyUtil.isEmpty(result) && !EmptyUtil.isEmpty(style)) { | |||||
yield FeedbackRecordRefreshSuccessState(); | |||||
yield FeedbackRecordLoadedState(dataModel: result, styleModel: style); | |||||
} else { | |||||
yield FeedbackRecordRefreshErrorState(); | |||||
} | |||||
} | |||||
/// 加载更多 | |||||
Stream<FeedbackRecordState> _mapLoadEventToState(FeedbackRecordLoadEvent event) async* { | |||||
var style = repository.styleModel; | |||||
var result = await repository.fetchLoadData(); | |||||
if (!EmptyUtil.isEmpty(result) && !EmptyUtil.isEmpty(style)) { | |||||
yield FeedbackRecordLoadSuccessState(); | |||||
yield FeedbackRecordLoadedState(dataModel: result, styleModel: style); | |||||
} else { | |||||
yield FeedbackRecordLoadErrorState(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,13 @@ | |||||
import 'package:meta/meta.dart'; | |||||
@immutable | |||||
abstract class FeedbackRecordEvent {} | |||||
/// 初始化 | |||||
class FeedbackRecordInitEvent extends FeedbackRecordEvent {} | |||||
/// 下拉刷新 | |||||
class FeedbackRecordRefreshEvent extends FeedbackRecordEvent {} | |||||
/// 加载更多 | |||||
class FeedbackRecordLoadEvent extends FeedbackRecordEvent {} |
@@ -0,0 +1,117 @@ | |||||
import 'dart:convert'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class FeedbackRecordRepository { | |||||
// final int max = 5; | |||||
int _currentPage = 1; | |||||
bool _hasMore = true; | |||||
final Map<String, dynamic> data; | |||||
FeedbackRecordRepository(this.data) { | |||||
_dataModel = FeedbackRecordDataModel(); | |||||
_dataModel.data = []; | |||||
} | |||||
/// 样式数据 | |||||
FeedbackRecordStyleModel _styleModel; | |||||
/// 数据 | |||||
FeedbackRecordDataModel _dataModel; | |||||
FeedbackRecordStyleModel get styleModel => _styleModel; | |||||
FeedbackRecordDataModel get dataModel => _dataModel; | |||||
/// 初始化数据 | |||||
Future<dynamic> fetchInitData() async { | |||||
_hasMore = true; | |||||
_currentPage = 1; | |||||
return _fetchBaseRequest(); | |||||
} | |||||
/// 样式初始化 | |||||
Future<dynamic> fetchInitStyle() async { | |||||
try { | |||||
String skipIdentifier = | |||||
!EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback_list'; | |||||
var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||||
return _handleStyle(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取缓存样式 | |||||
Future<dynamic> fetchCacheStyle() async { | |||||
try { | |||||
String skipIdentifier = | |||||
!EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback_list'; | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skipIdentifier'); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
return _handleStyle(result); | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 处理样式 | |||||
dynamic _handleStyle(Map<String, dynamic> data) { | |||||
try { | |||||
var modListData = data['mod_list'][0]['data']; | |||||
if (!EmptyUtil.isEmpty(modListData)) { | |||||
FeedbackRecordStyleModel model = FeedbackRecordStyleModel.fromJson(modListData is String ? jsonDecode(modListData) : modListData); | |||||
if (!EmptyUtil.isEmpty(model)) { | |||||
_styleModel = model; | |||||
return _styleModel; | |||||
} | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 刷新 | |||||
Future<dynamic> fetchRefreshData() async { | |||||
_hasMore = true; | |||||
_currentPage = 1; | |||||
return _fetchBaseRequest(); | |||||
} | |||||
/// 加载更多 | |||||
Future<dynamic> fetchLoadData() async { | |||||
if (_hasMore) { | |||||
return _fetchBaseRequest(); | |||||
} | |||||
return null; | |||||
} | |||||
/// 基础加载方法 | |||||
Future<dynamic> _fetchBaseRequest() async { | |||||
try { | |||||
var result = await NetUtil.post('/api/v1/feedback/list', method: NetMethod.GET, queryParameters: {'page': _currentPage.toString()}); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||||
FeedbackRecordDataModel model = FeedbackRecordDataModel.fromJson(result); | |||||
if (!EmptyUtil.isEmpty(model) && !EmptyUtil.isEmpty(model?.data)) { | |||||
_dataModel.data.addAll(model.data); | |||||
_hasMore = true; | |||||
++_currentPage; | |||||
return _dataModel; | |||||
} | |||||
} | |||||
_hasMore = false; | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
} |
@@ -0,0 +1,26 @@ | |||||
import 'package:meta/meta.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||||
@immutable | |||||
abstract class FeedbackRecordState {} | |||||
class FeedbackRecordInitial extends FeedbackRecordState {} | |||||
/// 数据加载成功 | |||||
class FeedbackRecordLoadedState extends FeedbackRecordState { | |||||
FeedbackRecordDataModel dataModel; | |||||
FeedbackRecordStyleModel styleModel; | |||||
FeedbackRecordLoadedState({this.dataModel, this.styleModel}); | |||||
} | |||||
/// 初始化失败 | |||||
class FeedbackRecordInitErrorState extends FeedbackRecordState{} | |||||
/// 刷新成功与失败 | |||||
class FeedbackRecordRefreshSuccessState extends FeedbackRecordState{} | |||||
class FeedbackRecordRefreshErrorState extends FeedbackRecordState{} | |||||
/// 加载更多成功与失败 | |||||
class FeedbackRecordLoadSuccessState extends FeedbackRecordState{} | |||||
class FeedbackRecordLoadErrorState extends FeedbackRecordState{} |
@@ -1,21 +1,42 @@ | |||||
import 'dart:convert'; | import 'dart:convert'; | ||||
import 'dart:io'; | |||||
import 'package:path/path.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_model.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_model.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
class FeedBackRepository { | class FeedBackRepository { | ||||
/// 获取缓存样式数据 | /// 获取缓存样式数据 | ||||
Future<FeedbackModel> fetchCachedData(final Map<String, dynamic> data) async { | |||||
try { | |||||
String skipIdentifier = | |||||
!EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback'; | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skipIdentifier'); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
var modListData = result['mod_list'][0]['data']; | |||||
if (!EmptyUtil.isEmpty(modListData)) { | |||||
FeedbackModel model = FeedbackModel.fromJson(jsonDecode(modListData)); | |||||
model.feedbackTypes.last.isSelect = true; | |||||
return model; | |||||
} | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取网络样式数据 | /// 获取网络样式数据 | ||||
Future<FeedbackModel> fetchData(final Map<String, dynamic> data) async { | Future<FeedbackModel> fetchData(final Map<String, dynamic> data) async { | ||||
try { | try { | ||||
String skip_identifier = !EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback'; | |||||
String skipIdentifier = | |||||
!EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback'; | |||||
var result = await NetUtil.post('/api/v1/mod/$skip_identifier', method: NetMethod.GET, cache: true); | |||||
var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | ||||
var modListData = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list'][0]['data']; | var modListData = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list'][0]['data']; | ||||
if (!EmptyUtil.isEmpty(modListData)) { | if (!EmptyUtil.isEmpty(modListData)) { | ||||
FeedbackModel model = FeedbackModel.fromJson(jsonDecode(modListData)); | FeedbackModel model = FeedbackModel.fromJson(jsonDecode(modListData)); | ||||
model.feedbackTypes.last.isSelect = true; | |||||
return model; | return model; | ||||
} | } | ||||
} | } | ||||
@@ -25,6 +46,71 @@ class FeedBackRepository { | |||||
return null; | return null; | ||||
} | } | ||||
/// 获取网络数据 | |||||
/// 提交反馈 | |||||
Future<dynamic> saveFeedback(final Map<String, dynamic> data) async { | |||||
try { | |||||
List<File> files = data['files']; | |||||
List<String> imageList = []; | |||||
if(!EmptyUtil.isEmpty(files)) { | |||||
// files.forEach((element) async { | |||||
// String fileName = await updateFile(element); | |||||
// if (!EmptyUtil.isEmpty(fileName)) { | |||||
// imageList.add(fileName); | |||||
// } | |||||
// }); | |||||
for(int i = 0 ; i < files.length; i++){ | |||||
String imgName = await updateFile(files[i]); | |||||
if(!EmptyUtil.isEmpty(imgName)){ | |||||
imageList.add(imgName); | |||||
} | |||||
} | |||||
if (imageList.length != files.length) { | |||||
return null; | |||||
} | |||||
} | |||||
var result = await NetUtil.post('/api/v1/feedback/save', method: NetMethod.POST, params: { | |||||
'type': data['type']?.toString(), | |||||
'title': data['title']?.toString(), | |||||
'content': data['content']?.toString(), | |||||
'image_list': imageList, | |||||
}); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||||
return result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]; | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 上传图片 | |||||
Future<String> updateFile(final File imageFile) async { | |||||
try { | |||||
List<int> originBytes = await imageFile.readAsBytes(); | |||||
var result1 = await NetUtil.post('/api/v1/img/upload', params: {'dir': 'feedback', 'file_size': originBytes.length, 'file_name': basename(imageFile.path)}, method: NetMethod.PUT); | |||||
if (NetUtil.isSuccess(result1) && !EmptyUtil.isEmpty(result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]) && !EmptyUtil.isEmpty(result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['token'])) { | |||||
String token = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['token']; | |||||
String host = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['host']; | |||||
String key = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['key']; | |||||
String method = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['method']; | |||||
var result2 = await NetUtil.uploadFile(host, imageFile, params: {'key': key, 'token': token}, method: method); | |||||
Map<String, dynamic> json = jsonDecode(result2.toString()); | |||||
if (NetUtil.isSuccess(json) && !EmptyUtil.isEmpty(json[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||||
String filename = json['data']['fname'] ?? ''; | |||||
print(filename); | |||||
// filename += '?${DateTime.now().millisecondsSinceEpoch.toString()}'; | |||||
// print(filename); | |||||
// ⚠️ 这里返回key是因为fname是带有域名的,所以直接用key即可 | |||||
return !EmptyUtil.isEmpty(filename) ? key : null; | |||||
} | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
} | } |
@@ -13,3 +13,9 @@ class FeedbackLoadedState extends FeedbackState{ | |||||
} | } | ||||
class FeedbackErrorState extends FeedbackState{} | class FeedbackErrorState extends FeedbackState{} | ||||
/// 保存反馈成功 | |||||
class FeedbackSaveSuccessState extends FeedbackState{} | |||||
/// 保存反馈失败 | |||||
class FeedbackSaveErrorState extends FeedbackState{} |
@@ -1,4 +1,5 @@ | |||||
import 'dart:io'; | import 'dart:io'; | ||||
import 'dart:math'; | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
@@ -55,6 +56,9 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
TextEditingController _title; | TextEditingController _title; | ||||
// 是否上传中 | |||||
bool isUpLoading = false; | |||||
@override | @override | ||||
void initState() { | void initState() { | ||||
_feedback = TextEditingController(); | _feedback = TextEditingController(); | ||||
@@ -69,7 +73,6 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
super.dispose(); | super.dispose(); | ||||
} | } | ||||
/// 选择图片 | /// 选择图片 | ||||
void _onAddImage() async { | void _onAddImage() async { | ||||
if (_images.length >= 4) { | if (_images.length >= 4) { | ||||
@@ -107,9 +110,13 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
if (file == null) return; | if (file == null) return; | ||||
setState(() { | |||||
_images.add(File(file.path)); | |||||
}); | |||||
if (_images.length <= 4) { | |||||
setState(() { | |||||
_images.add(File(file.path)); | |||||
}); | |||||
} else { | |||||
Fluttertoast.showToast(msg: '最多只能选择4张'); | |||||
} | |||||
// File resultFile = await EncodeUtil.compressImage(file, 800); | // File resultFile = await EncodeUtil.compressImage(file, 800); | ||||
} | } | ||||
@@ -120,6 +127,19 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
return BlocConsumer<FeedbackBloc, FeedbackState>( | return BlocConsumer<FeedbackBloc, FeedbackState>( | ||||
listener: (context, state) {}, | listener: (context, state) {}, | ||||
buildWhen: (prev, current) { | buildWhen: (prev, current) { | ||||
/// 保存成功 | |||||
if (current is FeedbackSaveSuccessState) { | |||||
Fluttertoast.showToast(msg: '反馈成功~'); | |||||
Navigator.pop(context); | |||||
return false; | |||||
} | |||||
if (current is FeedbackSaveErrorState) { | |||||
Fluttertoast.showToast(msg: '反馈失败~'); | |||||
setState(() { | |||||
isUpLoading = false; | |||||
}); | |||||
return false; | |||||
} | |||||
return true; | return true; | ||||
}, | }, | ||||
builder: (context, state) { | builder: (context, state) { | ||||
@@ -169,14 +189,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
Center( | Center( | ||||
child: GestureDetector( | child: GestureDetector( | ||||
behavior: HitTestBehavior.opaque, | behavior: HitTestBehavior.opaque, | ||||
onTap: () { | |||||
Navigator.push( | |||||
context, | |||||
CupertinoPageRoute( | |||||
builder: (_) => FeedbackRecordPage(), | |||||
), | |||||
); | |||||
}, | |||||
onTap: () => RouterUtil.route(model, model.toJson(), context), | |||||
child: Container( | child: Container( | ||||
width: 120, | width: 120, | ||||
height: 30, | height: 30, | ||||
@@ -273,6 +286,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
), | ), | ||||
), | ), | ||||
const SizedBox(height: 2), | const SizedBox(height: 2), | ||||
/// 异常选项 | /// 异常选项 | ||||
Padding( | Padding( | ||||
padding: EdgeInsets.only(top: 4, bottom: 4), | padding: EdgeInsets.only(top: 4, bottom: 4), | ||||
@@ -281,16 +295,15 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
child: Row( | child: Row( | ||||
children: model.feedbackTypes | children: model.feedbackTypes | ||||
.map((e) => Expanded( | .map((e) => Expanded( | ||||
child: GestureDetector( | |||||
child: GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | behavior: HitTestBehavior.opaque, | ||||
onTap: (){ | |||||
onTap: () { | |||||
setState(() { | setState(() { | ||||
model.feedbackTypes.forEach((element) { | model.feedbackTypes.forEach((element) { | ||||
element.isSelect = false; | element.isSelect = false; | ||||
}); | }); | ||||
e.isSelect = true; | e.isSelect = true; | ||||
}); | }); | ||||
}, | }, | ||||
child: Container( | child: Container( | ||||
margin: EdgeInsets.only(left: 2, right: 2), | margin: EdgeInsets.only(left: 2, right: 2), | ||||
@@ -311,9 +324,8 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
e.name ?? '', | e.name ?? '', | ||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 12, | fontSize: 12, | ||||
color: HexColor.fromHex(e.isSelect | |||||
? model?.feedbackTypeSelectedTextColor | |||||
: model?.feedbackTypeNoSelectedTextColor) //e.isSelect ? Colors.redAccent : Color(0xff999999), | |||||
color: HexColor.fromHex( | |||||
e.isSelect ? model?.feedbackTypeSelectedTextColor : model?.feedbackTypeNoSelectedTextColor) //e.isSelect ? Colors.redAccent : Color(0xff999999), | |||||
), | ), | ||||
), | ), | ||||
), | ), | ||||
@@ -401,8 +413,9 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
child: FeedbackImageWidget( | child: FeedbackImageWidget( | ||||
file: file, | file: file, | ||||
onDelete: () { | onDelete: () { | ||||
_images.remove(file); | |||||
setState(() {}); | |||||
setState(() { | |||||
_images.remove(file); | |||||
}); | |||||
}, | }, | ||||
), | ), | ||||
)); | )); | ||||
@@ -425,6 +438,8 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
} | } | ||||
return Column( | return Column( | ||||
mainAxisAlignment: MainAxisAlignment.center, | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
children: <Widget>[ | children: <Widget>[ | ||||
Row( | Row( | ||||
children: <Widget>[ | children: <Widget>[ | ||||
@@ -448,9 +463,18 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
), | ), | ||||
], | ], | ||||
), | ), | ||||
Row( | |||||
// Row( | |||||
// children: images, | |||||
// ) | |||||
Wrap( | |||||
crossAxisAlignment: WrapCrossAlignment.center, | |||||
textDirection: TextDirection.ltr, | |||||
spacing: 0, | |||||
runSpacing: 0, | |||||
runAlignment: WrapAlignment.center, | |||||
alignment: WrapAlignment.start, | |||||
children: images, | children: images, | ||||
) | |||||
), | |||||
], | ], | ||||
); | ); | ||||
} | } | ||||
@@ -461,9 +485,27 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
if (!_submitable) { | if (!_submitable) { | ||||
return; | return; | ||||
} | } | ||||
if(isUpLoading){ | |||||
// Fluttertoast.showToast(msg: '提交中...'); | |||||
return; | |||||
} | |||||
setState(() { | |||||
isUpLoading = true; | |||||
}); | |||||
Logger.debug('提交:${_feedback.text.toString()}'); | Logger.debug('提交:${_feedback.text.toString()}'); | ||||
Fluttertoast.showToast(msg: '提交成功~'); | |||||
Navigator.pop(context); | |||||
String selectId; | |||||
model.feedbackTypes.forEach((element) { | |||||
if (element.isSelect) { | |||||
selectId = element.typeId; | |||||
} | |||||
}); | |||||
BlocProvider.of<FeedbackBloc>(context) | |||||
.add(FeedbackSubmitEvent(model: {'title': _title?.text?.toString(), 'content': _feedback?.text?.toString(), 'type': selectId, 'files': _images})); | |||||
// Fluttertoast.showToast(msg: '提交成功~'); | |||||
// Navigator.pop(context); | |||||
}, | }, | ||||
child: Container( | child: Container( | ||||
margin: EdgeInsets.only(top: 24, bottom: 4), | margin: EdgeInsets.only(top: 24, bottom: 4), | ||||
@@ -474,7 +516,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
), | ), | ||||
child: Center( | child: Center( | ||||
child: Text( | child: Text( | ||||
model?.feedbackPostBtnText ?? '提交意见', | |||||
isUpLoading ? '提交意见...' : model?.feedbackPostBtnText ?? '提交意见', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 14, | fontSize: 14, | ||||
color: HexColor.fromHex(model?.feedbackPostBtnTextColor ?? '#FFFFFF'), | color: HexColor.fromHex(model?.feedbackPostBtnTextColor ?? '#FFFFFF'), | ||||
@@ -484,6 +526,4 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
} | } |
@@ -1,36 +1,167 @@ | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_record_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_record_repository.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_record_item.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_record_item.dart'; | ||||
import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart'; | import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart'; | ||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'bloc/feedback_record_event.dart'; | |||||
import 'bloc/feedback_record_state.dart'; | |||||
class FeedbackRecordPage extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
FeedbackRecordPage(this.data); | |||||
class FeedbackRecordPage extends StatefulWidget { | |||||
@override | @override | ||||
_FeedbackRecordPageState createState() => _FeedbackRecordPageState(); | |||||
Widget build(BuildContext context) { | |||||
return BlocProvider<FeedbackRecordBloc>( | |||||
create: (_) => FeedbackRecordBloc(FeedbackRecordRepository(data))..add(FeedbackRecordInitEvent()), | |||||
child: _FeedbackRecordPage(), | |||||
); | |||||
} | |||||
} | } | ||||
class _FeedbackRecordPageState extends State<FeedbackRecordPage> { | |||||
class _FeedbackRecordPage extends StatefulWidget { | |||||
@override | |||||
__FeedbackRecordPageState createState() => __FeedbackRecordPageState(); | |||||
} | |||||
class __FeedbackRecordPageState extends State<_FeedbackRecordPage> { | |||||
RefreshController _controller; | |||||
/// 点击详情 | |||||
/// 刷新 | |||||
void _refresh() { | |||||
BlocProvider.of<FeedbackRecordBloc>(context).add(FeedbackRecordRefreshEvent()); | |||||
} | |||||
/// 加载更多 | |||||
void _load() { | |||||
BlocProvider.of<FeedbackRecordBloc>(context).add(FeedbackRecordLoadEvent()); | |||||
} | |||||
@override | |||||
void initState() { | |||||
_controller = RefreshController(); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_controller?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return BlocConsumer<FeedbackRecordBloc, FeedbackRecordState>( | |||||
listener: (context, state) {}, | |||||
buildWhen: (prev, current) { | |||||
if (current is FeedbackRecordRefreshSuccessState) { | |||||
_controller?.refreshCompleted(resetFooterState: true); | |||||
return false; | |||||
} | |||||
if (current is FeedbackRecordRefreshErrorState) { | |||||
_controller?.refreshFailed(); | |||||
return false; | |||||
} | |||||
if (current is FeedbackRecordLoadSuccessState) { | |||||
_controller?.loadComplete(); | |||||
return false; | |||||
} | |||||
if (current is FeedbackRecordLoadErrorState) { | |||||
_controller?.loadNoData(); | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
/// 数据视图 | |||||
if (state is FeedbackRecordLoadedState) { | |||||
return _createDataWidget(state?.styleModel, state?.dataModel); | |||||
} | |||||
/// 初始化失败,空视图 | |||||
if (state is FeedbackRecordInitErrorState) { | |||||
return _createEmptyWidget(); | |||||
} | |||||
/// 加载中,骨架图 | |||||
return _createSkeletonWidget(); | |||||
}, | |||||
); | |||||
} | |||||
/// 有数据 | |||||
Widget _createDataWidget(FeedbackRecordStyleModel styleModel, FeedbackRecordDataModel dataModel) { | |||||
int length = dataModel?.data?.length ?? 0; | |||||
if(length == 0 ) return _createEmptyWidget(); | |||||
return Scaffold( | |||||
appBar: _createNav(styleModel), | |||||
body: GestureDetector( | |||||
onTap: () { | |||||
FocusScope.of(context).requestFocus(FocusNode()); | |||||
}, | |||||
child: SafeArea( | |||||
child: SmartRefresher( | |||||
controller: _controller, | |||||
enablePullUp: true, | |||||
enablePullDown: true, | |||||
onRefresh: _refresh, | |||||
onLoading: _load, | |||||
child: ListView.builder( | |||||
itemCount: length, | |||||
itemBuilder: (context, index) { | |||||
return FeedbackRecordItem(styleModel, dataModel.data[index]); | |||||
}), | |||||
), | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 空数据 | |||||
Widget _createEmptyWidget() { | |||||
return Scaffold( | return Scaffold( | ||||
appBar: _createNav(), | |||||
appBar: _createNav(null), | |||||
body: GestureDetector( | body: GestureDetector( | ||||
onTap: () { | onTap: () { | ||||
FocusScope.of(context).requestFocus(FocusNode()); | FocusScope.of(context).requestFocus(FocusNode()); | ||||
}, | }, | ||||
child: SafeArea( | child: SafeArea( | ||||
child: Center(child: EmptyWidget()), | |||||
// child: ListView.builder( | |||||
// itemCount: 10, | |||||
// itemBuilder: (context, index) { | |||||
// return FeedbackRecordItem(); | |||||
// }), | |||||
child: SmartRefresher( | |||||
controller: _controller, | |||||
enablePullDown: true, | |||||
enablePullUp: false, | |||||
onRefresh: _refresh, | |||||
child: Center(child: EmptyWidget()), | |||||
), | |||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
// 导航栏 | |||||
Widget _createNav() { | |||||
/// 骨架图 | |||||
Widget _createSkeletonWidget() { | |||||
return Scaffold( | |||||
appBar: _createNav(null), | |||||
body: Container(), | |||||
); | |||||
} | |||||
/// 导航栏 | |||||
Widget _createNav(FeedbackRecordStyleModel styleModel) { | |||||
return CupertinoNavigationBar( | return CupertinoNavigationBar( | ||||
border: Border( | border: Border( | ||||
bottom: BorderSide( | bottom: BorderSide( | ||||
@@ -38,7 +169,7 @@ class _FeedbackRecordPageState extends State<FeedbackRecordPage> { | |||||
style: BorderStyle.none, | style: BorderStyle.none, | ||||
), | ), | ||||
), | ), | ||||
backgroundColor: Colors.white, | |||||
backgroundColor: HexColor.fromHex(styleModel?.appBarBgColor ?? '#FFFFFF'), | |||||
leading: Navigator.canPop(context) | leading: Navigator.canPop(context) | ||||
? GestureDetector( | ? GestureDetector( | ||||
child: Container( | child: Container( | ||||
@@ -56,10 +187,10 @@ class _FeedbackRecordPageState extends State<FeedbackRecordPage> { | |||||
) | ) | ||||
: Container(), | : Container(), | ||||
middle: Text( | middle: Text( | ||||
'反馈列表', | |||||
styleModel?.appBarName ?? '反馈列表', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 15, | fontSize: 15, | ||||
color: Color(0xff333333), | |||||
color: HexColor.fromHex(styleModel?.appBarNameColor ?? '#FF333333'), | |||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
@@ -1,4 +1,6 @@ | |||||
class FeedbackModel { | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class FeedbackModel extends SkipModel{ | |||||
String appBarName; | String appBarName; | ||||
String appBarNameColor; | String appBarNameColor; | ||||
String appBarBgColor; | String appBarBgColor; | ||||
@@ -73,6 +75,7 @@ class FeedbackModel { | |||||
this.skipIdentifier}); | this.skipIdentifier}); | ||||
FeedbackModel.fromJson(Map<String, dynamic> json) { | FeedbackModel.fromJson(Map<String, dynamic> json) { | ||||
super.fromJson(json); | |||||
appBarName = json['app_bar_name']; | appBarName = json['app_bar_name']; | ||||
appBarNameColor = json['app_bar_name_color']; | appBarNameColor = json['app_bar_name_color']; | ||||
appBarBgColor = json['app_bar_bg_color']; | appBarBgColor = json['app_bar_bg_color']; | ||||
@@ -121,7 +124,7 @@ class FeedbackModel { | |||||
} | } | ||||
Map<String, dynamic> toJson() { | Map<String, dynamic> toJson() { | ||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
final Map<String, dynamic> data = super.toJson(); | |||||
data['app_bar_name'] = this.appBarName; | data['app_bar_name'] = this.appBarName; | ||||
data['app_bar_name_color'] = this.appBarNameColor; | data['app_bar_name_color'] = this.appBarNameColor; | ||||
data['app_bar_bg_color'] = this.appBarBgColor; | data['app_bar_bg_color'] = this.appBarBgColor; | ||||
@@ -0,0 +1,60 @@ | |||||
/// 反馈列表数据 | |||||
class FeedbackRecordDataModel { | |||||
List<FeedbackRecordDataItemModel> data; | |||||
FeedbackRecordDataModel({this.data}); | |||||
FeedbackRecordDataModel.fromJson(Map<String, dynamic> json) { | |||||
if (json['data'] != null) { | |||||
data = new List<FeedbackRecordDataItemModel>(); | |||||
json['data'].forEach((v) { | |||||
data.add(new FeedbackRecordDataItemModel.fromJson(v)); | |||||
}); | |||||
} | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
if (this.data != null) { | |||||
data['data'] = this.data.map((v) => v.toJson()).toList(); | |||||
} | |||||
return data; | |||||
} | |||||
} | |||||
class FeedbackRecordDataItemModel { | |||||
String id; | |||||
String type; | |||||
String typeText; | |||||
String state; | |||||
String title; | |||||
String content; | |||||
List<String> imageList; | |||||
String createTime; | |||||
FeedbackRecordDataItemModel({this.id, this.type, this.typeText, this.state, this.title, this.content, this.imageList, this.createTime}); | |||||
FeedbackRecordDataItemModel.fromJson(Map<String, dynamic> json) { | |||||
id = json['id']; | |||||
type = json['type']; | |||||
typeText = json['type_text']; | |||||
state = json['state']; | |||||
title = json['title']; | |||||
content = json['content']; | |||||
imageList = json['image_list'].cast<String>(); | |||||
createTime = json['create_time']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['id'] = this.id; | |||||
data['type'] = this.type; | |||||
data['type_text'] = this.typeText; | |||||
data['state'] = this.state; | |||||
data['title'] = this.title; | |||||
data['content'] = this.content; | |||||
data['image_list'] = this.imageList; | |||||
data['create_time'] = this.createTime; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,140 @@ | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
/// 反馈列表样式 | |||||
class FeedbackRecordStyleModel extends SkipModel{ | |||||
String appBarName; | |||||
String appBarNameColor; | |||||
String appBarBgColor; | |||||
String bgColor; | |||||
ItemStyle itemStyle; | |||||
List<FeedbackTypes> feedbackTypes; | |||||
List<StateImages> stateImages; | |||||
String requiredLogin; | |||||
String requiredTaobaoAuth; | |||||
String skipIdentifier; | |||||
FeedbackRecordStyleModel( | |||||
{this.appBarName, | |||||
this.appBarNameColor, | |||||
this.appBarBgColor, | |||||
this.bgColor, | |||||
this.itemStyle, | |||||
this.feedbackTypes, | |||||
this.stateImages, | |||||
this.requiredLogin, | |||||
this.requiredTaobaoAuth, | |||||
this.skipIdentifier}); | |||||
FeedbackRecordStyleModel.fromJson(Map<String, dynamic> json) { | |||||
super.fromJson(json); | |||||
appBarName = json['app_bar_name']; | |||||
appBarNameColor = json['app_bar_name_color']; | |||||
appBarBgColor = json['app_bar_bg_color']; | |||||
bgColor = json['bg_color']; | |||||
itemStyle = json['item_style'] != null ? new ItemStyle.fromJson(json['item_style']) : null; | |||||
if (json['feedback_types'] != null) { | |||||
feedbackTypes = new List<FeedbackTypes>(); | |||||
json['feedback_types'].forEach((v) { | |||||
feedbackTypes.add(new FeedbackTypes.fromJson(v)); | |||||
}); | |||||
} | |||||
if (json['state_images'] != null) { | |||||
stateImages = new List<StateImages>(); | |||||
json['state_images'].forEach((v) { | |||||
stateImages.add(new StateImages.fromJson(v)); | |||||
}); | |||||
} | |||||
requiredLogin = json['required_login']; | |||||
requiredTaobaoAuth = json['required_taobao_auth']; | |||||
skipIdentifier = json['skip_identifier']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = super.toJson(); | |||||
data['app_bar_name'] = this.appBarName; | |||||
data['app_bar_name_color'] = this.appBarNameColor; | |||||
data['app_bar_bg_color'] = this.appBarBgColor; | |||||
data['bg_color'] = this.bgColor; | |||||
if (this.itemStyle != null) { | |||||
data['item_style'] = this.itemStyle.toJson(); | |||||
} | |||||
if (this.feedbackTypes != null) { | |||||
data['feedback_types'] = this.feedbackTypes.map((v) => v.toJson()).toList(); | |||||
} | |||||
if (this.stateImages != null) { | |||||
data['state_images'] = this.stateImages.map((v) => v.toJson()).toList(); | |||||
} | |||||
data['required_login'] = this.requiredLogin; | |||||
data['required_taobao_auth'] = this.requiredTaobaoAuth; | |||||
data['skip_identifier'] = this.skipIdentifier; | |||||
return data; | |||||
} | |||||
} | |||||
class ItemStyle { | |||||
String bgColor; | |||||
String typeTextColor; | |||||
String typeBgColor; | |||||
String titleTextColor; | |||||
String contentTextColor; | |||||
String timeTextColor; | |||||
ItemStyle({this.bgColor, this.typeTextColor, this.typeBgColor, this.titleTextColor, this.contentTextColor, this.timeTextColor}); | |||||
ItemStyle.fromJson(Map<String, dynamic> json) { | |||||
bgColor = json['bg_color']; | |||||
typeTextColor = json['type_text_color']; | |||||
typeBgColor = json['type_bg_color']; | |||||
titleTextColor = json['title_text_color']; | |||||
contentTextColor = json['content_text_color']; | |||||
timeTextColor = json['time_text_color']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['bg_color'] = this.bgColor; | |||||
data['type_text_color'] = this.typeTextColor; | |||||
data['type_bg_color'] = this.typeBgColor; | |||||
data['title_text_color'] = this.titleTextColor; | |||||
data['content_text_color'] = this.contentTextColor; | |||||
data['time_text_color'] = this.timeTextColor; | |||||
return data; | |||||
} | |||||
} | |||||
class FeedbackTypes { | |||||
String typeId; | |||||
String name; | |||||
FeedbackTypes({this.typeId, this.name}); | |||||
FeedbackTypes.fromJson(Map<String, dynamic> json) { | |||||
typeId = json['type_id']; | |||||
name = json['name']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['type_id'] = this.typeId; | |||||
data['name'] = this.name; | |||||
return data; | |||||
} | |||||
} | |||||
class StateImages { | |||||
String stateId; | |||||
String img; | |||||
StateImages({this.stateId, this.img}); | |||||
StateImages.fromJson(Map<String, dynamic> json) { | |||||
stateId = json['state_id']; | |||||
img = json['img']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['state_id'] = this.stateId; | |||||
data['img'] = this.img; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
import 'dart:io'; | |||||
class FeedbackSaveModel { | |||||
String type; | |||||
String title; | |||||
String content; | |||||
List<File> files; | |||||
FeedbackSaveModel({this.type, this.title, this.content, this.files}); | |||||
} |
@@ -1,6 +1,14 @@ | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class FeedbackRecordItem extends StatelessWidget { | class FeedbackRecordItem extends StatelessWidget { | ||||
FeedbackRecordStyleModel styleModel; | |||||
FeedbackRecordDataItemModel dataModel; | |||||
FeedbackRecordItem(this.styleModel, this.dataModel); | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return Container( | return Container( | ||||
@@ -8,7 +16,7 @@ class FeedbackRecordItem extends StatelessWidget { | |||||
padding: EdgeInsets.all(15), | padding: EdgeInsets.all(15), | ||||
width: double.infinity, | width: double.infinity, | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
color: Colors.white, | |||||
color: HexColor.fromHex(styleModel?.itemStyle?.bgColor ?? '#FFFFFF'), | |||||
borderRadius: BorderRadius.circular(7.5), | borderRadius: BorderRadius.circular(7.5), | ||||
), | ), | ||||
child: Row( | child: Row( | ||||
@@ -31,40 +39,53 @@ class FeedbackRecordItem extends StatelessWidget { | |||||
width: 60, | width: 60, | ||||
height: 60, | height: 60, | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
color: Colors.green, | |||||
// color: Colors.green, | |||||
borderRadius: BorderRadius.circular(30), | borderRadius: BorderRadius.circular(30), | ||||
), | ), | ||||
child: CachedNetworkImage( | |||||
imageUrl: getStateImageUrl(), | |||||
), | |||||
) | ) | ||||
], | ], | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
String getStateImageUrl(){ | |||||
String result = ''; | |||||
int length = styleModel?.stateImages?.length ?? 0; | |||||
if(length > 0){ | |||||
styleModel.stateImages.forEach((element) { | |||||
if(element.stateId == dataModel.state){ | |||||
result = element.img; | |||||
} | |||||
}); | |||||
} | |||||
return result; | |||||
} | |||||
Widget _createTitle() { | Widget _createTitle() { | ||||
List<InlineSpan> list = List(); | List<InlineSpan> list = List(); | ||||
list.add(WidgetSpan( | list.add(WidgetSpan( | ||||
child: Container( | child: Container( | ||||
padding: EdgeInsets.only(left: 2, right: 2, top: 3, bottom: 3), | |||||
padding: EdgeInsets.only(left: 4.5, right: 4.5, top: 3, bottom: 3), | |||||
margin: EdgeInsets.only(right: 4), | margin: EdgeInsets.only(right: 4), | ||||
child: Text( | child: Text( | ||||
'功能异常', | |||||
dataModel?.typeText ?? '其它', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 9, | fontSize: 9, | ||||
height: 1, | height: 1, | ||||
// color: HexColor.fromHex(style.providerNameColor), | |||||
color: Colors.white, | |||||
color: HexColor.fromHex(styleModel?.itemStyle?.typeTextColor ?? '#FFFFFF'), | |||||
), | ), | ||||
), | ), | ||||
decoration: BoxDecoration( | |||||
color: Colors.redAccent, borderRadius: BorderRadius.circular(2.5)), | |||||
decoration: BoxDecoration(color: HexColor.fromHex(styleModel?.itemStyle?.typeBgColor ?? '#FF4242'), borderRadius: BorderRadius.circular(2.5)), | |||||
), | ), | ||||
)); | )); | ||||
list.add(TextSpan( | list.add(TextSpan( | ||||
text: '关于关闭提现功能的反馈', | |||||
style: TextStyle( | |||||
fontSize: 14, color: Color(0xff333333), fontWeight: FontWeight.bold), | |||||
text: dataModel?.title ?? '', | |||||
style: TextStyle(fontSize: 14, color: HexColor.fromHex(styleModel?.itemStyle?.titleTextColor ?? '#333333'), fontWeight: FontWeight.bold), | |||||
)); | )); | ||||
return RichText( | return RichText( | ||||
maxLines: 2, | maxLines: 2, | ||||
@@ -76,32 +97,44 @@ class FeedbackRecordItem extends StatelessWidget { | |||||
Widget _createDesc() { | Widget _createDesc() { | ||||
return Container( | return Container( | ||||
child: Text( | child: Text( | ||||
'我今天想使用我的提现功能的时候,发现官方已经把这个功能给暂时关闭了,所以我很伤心,不开心不开心不开心,所以我很伤心,不开心不开心不开心', | |||||
style: TextStyle(fontSize: 11, color: Color(0xff999999)), | |||||
dataModel?.content ?? '', | |||||
style: TextStyle(fontSize: 11, color: HexColor.fromHex(styleModel?.itemStyle?.contentTextColor ?? '#999999')), | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
Widget _createImage() { | Widget _createImage() { | ||||
return Container( | |||||
margin: EdgeInsets.only(top: 4, bottom: 4), | |||||
child: Wrap( | |||||
children: <Widget>[ | |||||
List<Widget> images = []; | |||||
int length = dataModel?.imageList?.length ?? 0; | |||||
if (length > 0) { | |||||
for (int i = 0; i < length; i++) { | |||||
images.add( | |||||
Container( | Container( | ||||
width: 60, | width: 60, | ||||
height: 60, | height: 60, | ||||
color: Colors.redAccent, | |||||
child: CachedNetworkImage( | |||||
imageUrl: dataModel?.imageList[i] ?? '', | |||||
), | |||||
), | ), | ||||
], | |||||
), | |||||
); | |||||
); | |||||
} | |||||
return Container( | |||||
margin: EdgeInsets.only(top: 4, bottom: 4), | |||||
child: Wrap( | |||||
children: images, | |||||
), | |||||
); | |||||
} else { | |||||
return Container(); | |||||
} | |||||
} | } | ||||
Widget _createTime() { | Widget _createTime() { | ||||
return Container( | return Container( | ||||
child: Text( | child: Text( | ||||
'2020-06-23 01:00:06', | |||||
style: TextStyle(fontSize: 11, color: Color(0xffd8d8d8)), | |||||
dataModel?.createTime ?? '', | |||||
style: TextStyle(fontSize: 11, color: HexColor.fromHex(styleModel?.itemStyle?.timeTextColor ?? '#D8D8D8')), | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
@@ -22,7 +22,7 @@ class HotRankingPage extends StatefulWidget { | |||||
_HotRankingPageState createState() => _HotRankingPageState(); | _HotRankingPageState createState() => _HotRankingPageState(); | ||||
} | } | ||||
class _HotRankingPageState extends State<HotRankingPage> { | |||||
class _HotRankingPageState extends State<HotRankingPage> with AutomaticKeepAliveClientMixin{ | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
print('hot_ranking_page build'); | print('hot_ranking_page build'); | ||||
@@ -48,6 +48,10 @@ class _HotRankingPageState extends State<HotRankingPage> { | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
@override | |||||
// TODO: implement wantKeepAlive | |||||
bool get wantKeepAlive => true; | |||||
} | } | ||||
class _HotRankingPageContainer extends StatefulWidget { | class _HotRankingPageContainer extends StatefulWidget { | ||||
@@ -60,7 +64,7 @@ class _HotRankingPageContainer extends StatefulWidget { | |||||
__HotRankingPageContainerState(); | __HotRankingPageContainerState(); | ||||
} | } | ||||
class __HotRankingPageContainerState extends State<_HotRankingPageContainer> { | |||||
class __HotRankingPageContainerState extends State<_HotRankingPageContainer> with AutomaticKeepAliveClientMixin{ | |||||
HotRankingPageBloc _bloc; | HotRankingPageBloc _bloc; | ||||
RefreshController _refreshController; | RefreshController _refreshController; | ||||
String backgroundImage; | String backgroundImage; | ||||
@@ -136,6 +140,10 @@ class __HotRankingPageContainerState extends State<_HotRankingPageContainer> { | |||||
} | } | ||||
return list; | return list; | ||||
} | } | ||||
@override | |||||
// TODO: implement wantKeepAlive | |||||
bool get wantKeepAlive => true; | |||||
} | } | ||||
class _SilverAppBarDelegate extends SliverPersistentHeaderDelegate { | class _SilverAppBarDelegate extends SliverPersistentHeaderDelegate { | ||||
@@ -1,5 +1,11 @@ | |||||
import 'dart:io'; | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/pages/launch_page/launch_page.dart'; | |||||
import 'package:zhiying_comm/util/log/let_log.dart'; | |||||
import 'package:zhiying_comm/util/empty_util.dart'; | |||||
import 'package:url_launcher/url_launcher.dart'; | |||||
import 'package:webview_flutter/webview_flutter.dart'; | import 'package:webview_flutter/webview_flutter.dart'; | ||||
class BaseWebview extends StatefulWidget { | class BaseWebview extends StatefulWidget { | ||||
@@ -33,7 +39,18 @@ class _BaseWebviewState extends State<BaseWebview> { | |||||
onWebViewCreated: (WebViewController webViewController) { | onWebViewCreated: (WebViewController webViewController) { | ||||
_webViewController = webViewController; | _webViewController = webViewController; | ||||
}, | }, | ||||
navigationDelegate: (NavigationRequest request) { | |||||
navigationDelegate: (NavigationRequest request) async{ | |||||
// 解决Android的拼多多webview 转发的问题 | |||||
if(Platform.isAndroid){ | |||||
String url = request?.url?.toString(); | |||||
if(!EmptyUtil.isEmpty(url) && !url.startsWith('https://') && !url.startsWith('http://')){ | |||||
Logger.log('navigation url = $url'); | |||||
// if(await canLaunch(url)){ | |||||
// await launch(url); | |||||
// } | |||||
return NavigationDecision.prevent; | |||||
} | |||||
} | |||||
return NavigationDecision.navigate; | return NavigationDecision.navigate; | ||||
}, | }, | ||||
onPageStarted: (String url) { | onPageStarted: (String url) { | ||||
@@ -363,10 +363,28 @@ class _WithdrawContainerState extends State<_WithdrawContainer> { | |||||
} | } | ||||
Widget _createSubmit(WithdrawModel model) { | Widget _createSubmit(WithdrawModel model) { | ||||
String value = model.cashOutDashbordItems[_currentIndex].value; | |||||
// String value = model.cashOutDashbordItems[_currentIndex].value; | |||||
// try { | |||||
// if (num.tryParse(value) != null && | |||||
// null != _bloc.withdrawDataModel && | |||||
// num.tryParse(value) < | |||||
// num.tryParse(_bloc.withdrawDataModel.finValue)) { | |||||
// _submitable = true; | |||||
// } else { | |||||
// _submitable = false; | |||||
// } | |||||
// } catch (e, s) { | |||||
// print(e); | |||||
// print(s); | |||||
// } | |||||
try { | try { | ||||
if (num.tryParse(value) != null && null != _bloc.withdrawDataModel && num.tryParse(value) < num.tryParse(_bloc.withdrawDataModel.finValue)) { | |||||
var currentWithdraw = num.tryParse(_controller.text); | |||||
var finValue = num.tryParse(_bloc.withdrawDataModel.finValue); | |||||
if (currentWithdraw != null && | |||||
currentWithdraw != 0 && | |||||
finValue != null && | |||||
finValue != 0 && | |||||
currentWithdraw <= finValue) { | |||||
_submitable = true; | _submitable = true; | ||||
} else { | } else { | ||||
_submitable = false; | _submitable = false; | ||||
@@ -434,18 +452,24 @@ class _WithdrawContainerState extends State<_WithdrawContainer> { | |||||
); | ); | ||||
} | } | ||||
///检查提现按钮是否可用 | |||||
void _checkSubmit(String value) { | void _checkSubmit(String value) { | ||||
try { | |||||
if (num.tryParse(value) != null && | |||||
num.tryParse(value) < num.tryParse(_bloc.withdrawDataModel.finValue)) { | |||||
_submitable = true; | |||||
} else { | |||||
_submitable = false; | |||||
} | |||||
} catch (e, s) { | |||||
print(e); | |||||
print(s); | |||||
} | |||||
// try { | |||||
// var currentValue = num.tryParse(value); | |||||
// var finValue = num.tryParse(_bloc.withdrawDataModel.finValue); | |||||
// | |||||
// if (currentValue != null && | |||||
// currentValue != 0 && | |||||
// currentValue <= finValue && | |||||
// finValue != 0) { | |||||
// _submitable = true; | |||||
// } else { | |||||
// _submitable = false; | |||||
// } | |||||
// } catch (e, s) { | |||||
// print(e); | |||||
// print(s); | |||||
// } | |||||
setState(() {}); | setState(() {}); | ||||
} | } | ||||
} | } |
@@ -6,6 +6,7 @@ import 'package:sharesdk_plugin/sharesdk_register.dart'; | |||||
import 'package:zhiying_base_widget/pages/about_us_page/about_us_page.dart'; | import 'package:zhiying_base_widget/pages/about_us_page/about_us_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/bil_detail_page/bil_detail_page.dart'; | import 'package:zhiying_base_widget/pages/bil_detail_page/bil_detail_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/feedback_page/feedback_page.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/feedback_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/feedback_page/feedback_record_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/home_page/home_page.dart'; | import 'package:zhiying_base_widget/pages/home_page/home_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/hot_ranking_page/hot_ranking_page.dart'; | import 'package:zhiying_base_widget/pages/hot_ranking_page/hot_ranking_page.dart'; | ||||
@@ -58,6 +59,7 @@ import 'package:zhiying_base_widget/widgets/wallet_bil_detail/wallet_bil_detail. | |||||
import 'package:zhiying_comm/util/defalut_widget_creater.dart'; | import 'package:zhiying_comm/util/defalut_widget_creater.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
import 'pages/custom_page/custom_page.dart'; | |||||
import 'pages/favorites_page/favorites_page.dart'; | import 'pages/favorites_page/favorites_page.dart'; | ||||
import 'pages/message_notice_page/message_notice_page.dart'; | import 'pages/message_notice_page/message_notice_page.dart'; | ||||
import 'pages/privacy_settings_page/privacy_settings_page.dart'; | import 'pages/privacy_settings_page/privacy_settings_page.dart'; | ||||
@@ -139,6 +141,7 @@ class BaseWidgetRegister { | |||||
PageFactory.regist( | PageFactory.regist( | ||||
'search_result_item', (model) => SearchResultItemPage(model)); | 'search_result_item', (model) => SearchResultItemPage(model)); | ||||
PageFactory.regist('pub.flutter.feedback', (model) => FeedbackPage(model)); | PageFactory.regist('pub.flutter.feedback', (model) => FeedbackPage(model)); | ||||
PageFactory.regist('pub.flutter.feedback_list', (model) => FeedbackRecordPage(model)); | |||||
PageFactory.regist( | PageFactory.regist( | ||||
'pub.flutter.wechat_teacher', (model) => WechatTeacherPage()); | 'pub.flutter.wechat_teacher', (model) => WechatTeacherPage()); | ||||
PageFactory.regist('pub.flutter.cash_out', (model) => WithdrawPage(model)); | PageFactory.regist('pub.flutter.cash_out', (model) => WithdrawPage(model)); | ||||
@@ -199,7 +202,7 @@ class BaseWidgetRegister { | |||||
'pub.flutter.my_wallet_detail', (model) => BilDetailPage(model)); | 'pub.flutter.my_wallet_detail', (model) => BilDetailPage(model)); | ||||
/// 通用模块 | /// 通用模块 | ||||
PageFactory.regist('pub.flutter.custom', (model) => EmptyPage()); | |||||
PageFactory.regist('pub.flutter.custom', (model) => CustomPage(model)); | |||||
} | } | ||||
// 注册控件 | // 注册控件 | ||||
@@ -58,7 +58,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> { | |||||
/// 点击领取 | /// 点击领取 | ||||
void _onJump(CounponModel model) async{ | void _onJump(CounponModel model) async{ | ||||
TurnChainUtil.openReceiveCoupon(context, _user, model.provider, model.toJson()); | |||||
TurnChainUtil.openReceiveCoupon(context, _user, model.provider, model?.convertArgs?.toJson()); | |||||
} | } | ||||
@override | @override | ||||
@@ -73,7 +73,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> { | |||||
}, | }, | ||||
builder: (context, state) { | builder: (context, state) { | ||||
if (state is CounponLoadedState) { | if (state is CounponLoadedState) { | ||||
return _getMainWdiget(state.model); | |||||
return _getMainWidget(state.model); | |||||
} | } | ||||
return CounponSkeleton(); | return CounponSkeleton(); | ||||
}, | }, | ||||
@@ -81,7 +81,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> { | |||||
} | } | ||||
/// 主视图 | /// 主视图 | ||||
Widget _getMainWdiget(CounponModel model) { | |||||
Widget _getMainWidget(CounponModel model) { | |||||
return Visibility( | return Visibility( | ||||
visible: !EmptyUtil.isEmpty(model?.coupon_price), | visible: !EmptyUtil.isEmpty(model?.coupon_price), | ||||
child: GestureDetector( | child: GestureDetector( | ||||
@@ -97,18 +97,19 @@ class _GoodsDetailsImgWidgetContainerState | |||||
return Column( | return Column( | ||||
children: model.image_detail_list.map((item) { | children: model.image_detail_list.map((item) { | ||||
return GestureDetector( | return GestureDetector( | ||||
onTap: () { | |||||
if(item!=null){ | |||||
PhotoPreview.showPhotoPreviewByimages( | |||||
context, [item], | |||||
currentIndex: 0); | |||||
} | |||||
}, | |||||
child: CachedNetworkImage( | |||||
imageUrl: item ?? '', | |||||
fit: BoxFit.fitWidth, | |||||
), | |||||
); | |||||
onTap: () { | |||||
if (item != null) { | |||||
PhotoPreview.showPhotoPreviewByimages(context, [item], | |||||
currentIndex: 0, heroTagSuffix: "bottom"); | |||||
} | |||||
}, | |||||
child: Hero( | |||||
tag: item + "bottom", | |||||
child: CachedNetworkImage( | |||||
imageUrl: item ?? '', | |||||
fit: BoxFit.fitWidth, | |||||
), | |||||
)); | |||||
}).toList(), | }).toList(), | ||||
); | ); | ||||
} else { | } else { | ||||
@@ -46,8 +46,9 @@ class _GoodsDetailsSlideBannerContainerState | |||||
/// 子元素点击事件 | /// 子元素点击事件 | ||||
void _itemOnClick(String model, List<String> images, int index) { | void _itemOnClick(String model, List<String> images, int index) { | ||||
print('点击了 $model'); | print('点击了 $model'); | ||||
if(images!=null){ | |||||
PhotoPreview.showPhotoPreviewByimages(context, images, currentIndex: index); | |||||
if (images != null) { | |||||
PhotoPreview.showPhotoPreviewByimages(context, images, | |||||
currentIndex: index, heroTagSuffix: "top"); | |||||
} | } | ||||
} | } | ||||
@@ -108,7 +109,10 @@ class _GoodsDetailsSlideBannerContainerState | |||||
String items = datas.image_list[index]; | String items = datas.image_list[index]; | ||||
return Container( | return Container( | ||||
width: double.infinity, | width: double.infinity, | ||||
child: CachedNetworkImage(imageUrl: items ?? '', fit: BoxFit.cover), | |||||
child: Hero( | |||||
tag: items + "top", | |||||
child: CachedNetworkImage( | |||||
imageUrl: items ?? '', fit: BoxFit.cover)), | |||||
); | ); | ||||
}, | }, | ||||
itemCount: datas?.image_list?.length ?? 0, | itemCount: datas?.image_list?.length ?? 0, | ||||
@@ -12,25 +12,31 @@ class HotRankingGoods extends StatelessWidget { | |||||
HotRankingListModel styleModel; | HotRankingListModel styleModel; | ||||
int index; | int index; | ||||
HotRankingGoods({Key key, this.good, this.styleModel, this.index}) : super(key: key); | |||||
HotRankingGoods({Key key, this.good, this.styleModel, this.index}) | |||||
: super(key: key); | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
var indexImage; | var indexImage; | ||||
if (styleModel.hotRankIconList != null && styleModel.hotRankIconList.length > 0 && styleModel.hotRankIconList.length - 1 >= index) { | |||||
if (styleModel.hotRankIconList != null && | |||||
styleModel.hotRankIconList.length > 0 && | |||||
styleModel.hotRankIconList.length - 1 >= index) { | |||||
indexImage = styleModel.hotRankIconList[index]; | indexImage = styleModel.hotRankIconList[index]; | ||||
} | } | ||||
Providers providers = getProvider(good.provider); | Providers providers = getProvider(good.provider); | ||||
return GestureDetector( | return GestureDetector( | ||||
onTap: () { | onTap: () { | ||||
RouterUtil.route(SkipModel(skipIdentifier: "goods_details"), good?.toJson(), context); | |||||
RouterUtil.route(SkipModel(skipIdentifier: "goods_details"), | |||||
good?.toJson(), context); | |||||
}, | }, | ||||
child: Stack( | child: Stack( | ||||
children: <Widget>[ | children: <Widget>[ | ||||
Container( | Container( | ||||
padding: EdgeInsets.all(15.w), | padding: EdgeInsets.all(15.w), | ||||
margin: EdgeInsets.only(top: 8.w, bottom: 8.w, left: 25.w, right: 25.w), | |||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.w)), | |||||
margin: | |||||
EdgeInsets.only(top: 8.w, bottom: 8.w, left: 25.w, right: 25.w), | |||||
decoration: BoxDecoration( | |||||
color: Colors.white, borderRadius: BorderRadius.circular(15.w)), | |||||
child: Row( | child: Row( | ||||
crossAxisAlignment: CrossAxisAlignment.start, | crossAxisAlignment: CrossAxisAlignment.start, | ||||
children: <Widget>[ | children: <Widget>[ | ||||
@@ -40,11 +46,15 @@ class HotRankingGoods extends StatelessWidget { | |||||
height: 254.w, | height: 254.w, | ||||
child: ClipRRect( | child: ClipRRect( | ||||
borderRadius: BorderRadius.circular(6), | borderRadius: BorderRadius.circular(6), | ||||
child: CachedNetworkImage( | |||||
imageUrl: good?.goodImage ?? '', | |||||
child: Hero( | |||||
tag: (good?.goodImage ?? "") + "top", | |||||
child: CachedNetworkImage( | |||||
imageUrl: good?.goodImage ?? '', | |||||
), | |||||
), | ), | ||||
), | ), | ||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(6)), | |||||
decoration: | |||||
BoxDecoration(borderRadius: BorderRadius.circular(6)), | |||||
), | ), | ||||
/// 商品图片右边视图 | /// 商品图片右边视图 | ||||
@@ -64,8 +74,12 @@ class HotRankingGoods extends StatelessWidget { | |||||
WidgetSpan( | WidgetSpan( | ||||
alignment: ui.PlaceholderAlignment.middle, | alignment: ui.PlaceholderAlignment.middle, | ||||
child: Container( | child: Container( | ||||
padding: EdgeInsets.only(left: 4.w, right: 4.w, top: 1, bottom: 1), | |||||
decoration: BoxDecoration(color: HexColor.fromHex(providers.providerBgColor), borderRadius: BorderRadius.circular(2.5)), | |||||
padding: EdgeInsets.only( | |||||
left: 4.w, right: 4.w, top: 1, bottom: 1), | |||||
decoration: BoxDecoration( | |||||
color: HexColor.fromHex( | |||||
providers.providerBgColor), | |||||
borderRadius: BorderRadius.circular(2.5)), | |||||
child: Text( | child: Text( | ||||
good.providerName ?? "", | good.providerName ?? "", | ||||
style: TextStyle( | style: TextStyle( | ||||
@@ -79,7 +93,12 @@ class HotRankingGoods extends StatelessWidget { | |||||
child: SizedBox( | child: SizedBox( | ||||
width: 4.h, | width: 4.h, | ||||
)), | )), | ||||
TextSpan(text: good.goodTitle, style: TextStyle(color: HexColor.fromHex(styleModel.titleColor ?? ""), fontSize: 30.sp)) | |||||
TextSpan( | |||||
text: good.goodTitle, | |||||
style: TextStyle( | |||||
color: HexColor.fromHex( | |||||
styleModel.titleColor ?? ""), | |||||
fontSize: 30.sp)) | |||||
])), | ])), | ||||
/// 优惠券 | /// 优惠券 | ||||
@@ -88,16 +107,32 @@ class HotRankingGoods extends StatelessWidget { | |||||
good.coupon == "" | good.coupon == "" | ||||
? Container() | ? Container() | ||||
: Container( | : Container( | ||||
margin: EdgeInsets.only(top: 4, bottom: 4, right: 15.w), | |||||
margin: EdgeInsets.only( | |||||
top: 4, bottom: 4, right: 15.w), | |||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
borderRadius: BorderRadius.circular(2.5), | |||||
color: HexColor.fromHex(styleModel.couponCommission.left.couponBgColor), | |||||
image: DecorationImage(image: CachedNetworkImageProvider(styleModel.couponCommission.left.couponBgImg))), | |||||
borderRadius: BorderRadius.circular(2.5), | |||||
color: HexColor.fromHex(styleModel | |||||
.couponCommission.left.couponBgColor), | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider( | |||||
styleModel.couponCommission.left | |||||
.couponBgImg))), | |||||
child: Padding( | child: Padding( | ||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2), | |||||
padding: const EdgeInsets.only( | |||||
left: 8, right: 8, top: 2, bottom: 2), | |||||
child: Text( | child: Text( | ||||
(good.coupon ?? "") + (styleModel.couponCommission.left.couonText ?? ""), | |||||
style: TextStyle(color: HexColor.fromHex(styleModel.couponCommission.left.couponFontColor), fontSize: 22.sp, fontFamily: 'Din', package: 'zhiying_base_widget'), | |||||
(good.coupon ?? "") + | |||||
(styleModel.couponCommission.left | |||||
.couonText ?? | |||||
""), | |||||
style: TextStyle( | |||||
color: HexColor.fromHex(styleModel | |||||
.couponCommission | |||||
.left | |||||
.couponFontColor), | |||||
fontSize: 22.sp, | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget'), | |||||
), | ), | ||||
), | ), | ||||
), | ), | ||||
@@ -106,14 +141,33 @@ class HotRankingGoods extends StatelessWidget { | |||||
: Container( | : Container( | ||||
margin: EdgeInsets.only(top: 4, bottom: 4), | margin: EdgeInsets.only(top: 4, bottom: 4), | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
borderRadius: BorderRadius.circular(2.5), | |||||
color: HexColor.fromHex(styleModel.couponCommission.right.commissionBgColor ?? ""), | |||||
image: DecorationImage(image: CachedNetworkImageProvider(styleModel.couponCommission.right.commissionBgImg ?? ""))), | |||||
borderRadius: BorderRadius.circular(2.5), | |||||
color: HexColor.fromHex(styleModel | |||||
.couponCommission | |||||
.right | |||||
.commissionBgColor ?? | |||||
""), | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider( | |||||
styleModel.couponCommission.right | |||||
.commissionBgImg ?? | |||||
""))), | |||||
child: Padding( | child: Padding( | ||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2), | |||||
padding: const EdgeInsets.only( | |||||
left: 8, right: 8, top: 2, bottom: 2), | |||||
child: Text( | child: Text( | ||||
(styleModel.couponCommission.right.commissionText ?? "") + (good.commission ?? ""), | |||||
style: TextStyle(color: HexColor.fromHex(styleModel.couponCommission.right.commissionFontColor), fontSize: 22.sp,fontFamily: 'Din', package: 'zhiying_base_widget'), | |||||
(styleModel.couponCommission.right | |||||
.commissionText ?? | |||||
"") + | |||||
(good.commission ?? ""), | |||||
style: TextStyle( | |||||
color: HexColor.fromHex(styleModel | |||||
.couponCommission | |||||
.right | |||||
.commissionFontColor), | |||||
fontSize: 22.sp, | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget'), | |||||
), | ), | ||||
), | ), | ||||
), | ), | ||||
@@ -130,12 +184,21 @@ class HotRankingGoods extends StatelessWidget { | |||||
padding: EdgeInsets.only(bottom: 6.sp), | padding: EdgeInsets.only(bottom: 6.sp), | ||||
child: Text( | child: Text( | ||||
"¥", | "¥", | ||||
style: TextStyle(color: HexColor.fromHex(styleModel.currentPriceColor ?? ""), fontSize: 20.sp), | |||||
style: TextStyle( | |||||
color: HexColor.fromHex( | |||||
styleModel.currentPriceColor ?? ""), | |||||
fontSize: 20.sp), | |||||
), | ), | ||||
), | ), | ||||
Text( | Text( | ||||
good.currentPrice ?? "", | good.currentPrice ?? "", | ||||
style: TextStyle(color: HexColor.fromHex(styleModel.currentPriceColor ?? ""), fontSize: 40.sp,fontWeight: FontWeight.bold ,fontFamily: 'Din', package: 'zhiying_base_widget'), | |||||
style: TextStyle( | |||||
color: HexColor.fromHex( | |||||
styleModel.currentPriceColor ?? ""), | |||||
fontSize: 40.sp, | |||||
fontWeight: FontWeight.bold, | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget'), | |||||
), | ), | ||||
SizedBox( | SizedBox( | ||||
width: 6, | width: 6, | ||||
@@ -144,7 +207,13 @@ class HotRankingGoods extends StatelessWidget { | |||||
padding: EdgeInsets.only(bottom: 4.sp), | padding: EdgeInsets.only(bottom: 4.sp), | ||||
child: Text( | child: Text( | ||||
"¥" + good.marketPrice ?? "", | "¥" + good.marketPrice ?? "", | ||||
style: TextStyle(color: HexColor.fromHex(styleModel.marketPriceColor ?? ""), fontSize: 22.sp, decoration: TextDecoration.lineThrough, fontFamily: 'Din', package: 'zhiying_base_widget'), | |||||
style: TextStyle( | |||||
color: HexColor.fromHex( | |||||
styleModel.marketPriceColor ?? ""), | |||||
fontSize: 22.sp, | |||||
decoration: TextDecoration.lineThrough, | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget'), | |||||
), | ), | ||||
), | ), | ||||
], | ], | ||||
@@ -167,11 +236,17 @@ class HotRankingGoods extends StatelessWidget { | |||||
padding: EdgeInsets.only( | padding: EdgeInsets.only( | ||||
left: 40.w, | left: 40.w, | ||||
), | ), | ||||
margin: EdgeInsets.only(right: 20, left: 20.w), | |||||
color: HexColor.fromHex(styleModel.hotRank.bgColor ?? ""), | |||||
margin: | |||||
EdgeInsets.only(right: 20, left: 20.w), | |||||
color: HexColor.fromHex( | |||||
styleModel.hotRank.bgColor ?? ""), | |||||
child: Text( | child: Text( | ||||
"热销" + good.inorderCount + "件", | "热销" + good.inorderCount + "件", | ||||
style: TextStyle(color: Colors.white, fontSize: 22.sp, fontFamily: 'Din', package: 'zhiying_base_widget'), | |||||
style: TextStyle( | |||||
color: Colors.white, | |||||
fontSize: 22.sp, | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget'), | |||||
), | ), | ||||
)) | )) | ||||
], | ], | ||||
@@ -180,10 +255,12 @@ class HotRankingGoods extends StatelessWidget { | |||||
width: 48.w, | width: 48.w, | ||||
height: 48.w, | height: 48.w, | ||||
child: CachedNetworkImage( | child: CachedNetworkImage( | ||||
imageUrl: styleModel?.hotRank?.hotSaleImg ?? "", | |||||
imageUrl: | |||||
styleModel?.hotRank?.hotSaleImg ?? "", | |||||
width: 48.w, | width: 48.w, | ||||
height: 48.w, | height: 48.w, | ||||
placeholder: (context, _) => Container(color: Colors.yellow), | |||||
placeholder: (context, _) => | |||||
Container(color: Colors.yellow), | |||||
fit: BoxFit.fill, | fit: BoxFit.fill, | ||||
), | ), | ||||
), | ), | ||||
@@ -193,8 +270,13 @@ class HotRankingGoods extends StatelessWidget { | |||||
height: 48.h, | height: 48.h, | ||||
width: 127.w, | width: 127.w, | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
image: DecorationImage(image: CachedNetworkImageProvider(styleModel.hotRank.buyNowImg ?? ""), fit: BoxFit.fitWidth), | |||||
borderRadius: BorderRadius.circular(20)), | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider( | |||||
styleModel.hotRank.buyNowImg ?? | |||||
""), | |||||
fit: BoxFit.fitWidth), | |||||
borderRadius: | |||||
BorderRadius.circular(20)), | |||||
margin: EdgeInsets.only(right: 0), | margin: EdgeInsets.only(right: 0), | ||||
)) | )) | ||||
], | ], | ||||
@@ -210,7 +292,9 @@ class HotRankingGoods extends StatelessWidget { | |||||
Align( | Align( | ||||
alignment: Alignment.topLeft, | alignment: Alignment.topLeft, | ||||
child: Container( | child: Container( | ||||
decoration: BoxDecoration(image: DecorationImage(image: CachedNetworkImageProvider(indexImage ?? ""))), | |||||
decoration: BoxDecoration( | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider(indexImage ?? ""))), | |||||
margin: EdgeInsets.only(left: 40.w, top: 8.h), | margin: EdgeInsets.only(left: 40.w, top: 8.h), | ||||
height: 60.w, | height: 60.w, | ||||
width: 60.w, | width: 60.w, | ||||
@@ -1,6 +1,11 @@ | |||||
import 'dart:async'; | import 'dart:async'; | ||||
import 'dart:convert'; | import 'dart:convert'; | ||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||||
import 'package:zhiying_base_widget/dialog/loading/loading.dart'; | |||||
import 'package:zhiying_base_widget/dialog/loading/loading_dialog.dart'; | |||||
import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_list/model/hot_ranking_list_data_model.dart'; | import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_list/model/hot_ranking_list_data_model.dart'; | ||||
import 'package:zhiying_comm/util/base_bloc.dart'; | import 'package:zhiying_comm/util/base_bloc.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
@@ -25,7 +30,7 @@ class HotRankingListBloc extends BlocBase { | |||||
_dataController = null; | _dataController = null; | ||||
} | } | ||||
void loadData(String typeId, int page,Function complete) { | |||||
void loadData(String typeId, int page, Function complete) { | |||||
if (isLoading) { | if (isLoading) { | ||||
complete(); | complete(); | ||||
return; | return; | ||||
@@ -35,16 +40,18 @@ class HotRankingListBloc extends BlocBase { | |||||
NetUtil.request( | NetUtil.request( | ||||
'/api/v1/rec/taobao?type_id=' + typeId + '&page=' + page.toString(), | '/api/v1/rec/taobao?type_id=' + typeId + '&page=' + page.toString(), | ||||
method: NetMethod.GET, onSuccess: (data) { | method: NetMethod.GET, onSuccess: (data) { | ||||
complete(); | |||||
complete(); | |||||
isLoading = false; | isLoading = false; | ||||
_loadData(data); | _loadData(data); | ||||
Loading.dismiss(); | |||||
}, onError: (e) { | }, onError: (e) { | ||||
complete(); | |||||
Loading.dismiss(); | |||||
complete(); | |||||
isLoading = false; | isLoading = false; | ||||
}); | }); | ||||
} | } | ||||
void loadMoreData(String typeId,Function complete) { | |||||
void loadMoreData(String typeId, Function complete) { | |||||
if (isLoading) { | if (isLoading) { | ||||
complete(); | complete(); | ||||
return; | return; | ||||
@@ -2,6 +2,8 @@ import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | import 'package:pull_to_refresh/pull_to_refresh.dart'; | ||||
import 'package:zhiying_base_widget/dialog/loading/loading.dart'; | |||||
import 'package:zhiying_base_widget/dialog/loading/loading_dialog.dart'; | |||||
import 'package:zhiying_base_widget/pages/hot_ranking_page/hot_ranking_page_bloc.dart'; | import 'package:zhiying_base_widget/pages/hot_ranking_page/hot_ranking_page_bloc.dart'; | ||||
import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_goods/hot_ranking_goods.dart'; | import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_goods/hot_ranking_goods.dart'; | ||||
import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_list/model/hot_ranking_list_data_model.dart'; | import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_list/model/hot_ranking_list_data_model.dart'; | ||||
@@ -23,7 +25,7 @@ class HotRankingList extends StatefulWidget { | |||||
} | } | ||||
class _HotRankingState extends State<HotRankingList> | class _HotRankingState extends State<HotRankingList> | ||||
with TickerProviderStateMixin { | |||||
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { | |||||
HotRankingListBloc _bloc; | HotRankingListBloc _bloc; | ||||
TabController _tabController; | TabController _tabController; | ||||
RefreshController _refreshController; | RefreshController _refreshController; | ||||
@@ -33,6 +35,8 @@ class _HotRankingState extends State<HotRankingList> | |||||
ScrollController _scrollcontroller; | ScrollController _scrollcontroller; | ||||
bool isFirstTime=true; | |||||
@override | @override | ||||
void initState() { | void initState() { | ||||
_bloc = HotRankingListBloc(); | _bloc = HotRankingListBloc(); | ||||
@@ -43,8 +47,14 @@ class _HotRankingState extends State<HotRankingList> | |||||
if (_pageBloc != null) { | if (_pageBloc != null) { | ||||
_pageBloc.event.listen((event) { | _pageBloc.event.listen((event) { | ||||
if (event.containsKey('type') && event['type'] == "loadData") { | if (event.containsKey('type') && event['type'] == "loadData") { | ||||
if(!isFirstTime){ | |||||
Loading.show(context); | |||||
} | |||||
isFirstTime=false; | |||||
_bloc.currentPage = 1; | _bloc.currentPage = 1; | ||||
_bloc.loadData(event['type_id'], _bloc.currentPage, () {}); | _bloc.loadData(event['type_id'], _bloc.currentPage, () {}); | ||||
_scrollcontroller.animateTo(0, | |||||
duration: Duration(milliseconds: 500), curve: Curves.bounceInOut); | |||||
} | } | ||||
}); | }); | ||||
} | } | ||||
@@ -72,12 +82,7 @@ class _HotRankingState extends State<HotRankingList> | |||||
return HotRankingSkeleton(); | return HotRankingSkeleton(); | ||||
} else { | } else { | ||||
goods = snapshot.data.good; | goods = snapshot.data.good; | ||||
if (_bloc.currentPage == 1) { | |||||
Future.delayed(Duration(milliseconds: 100), () { | |||||
_scrollcontroller.animateTo(0, | |||||
duration: Duration(milliseconds: 100), curve: Curves.ease); | |||||
}); | |||||
} | |||||
return SmartRefresher( | return SmartRefresher( | ||||
controller: _refreshController, | controller: _refreshController, | ||||
enablePullDown: true, | enablePullDown: true, | ||||
@@ -121,4 +126,8 @@ class _HotRankingState extends State<HotRankingList> | |||||
index: index, | index: index, | ||||
); | ); | ||||
} | } | ||||
@override | |||||
// TODO: implement wantKeepAlive | |||||
bool get wantKeepAlive => true; | |||||
} | } |