Weller 4 роки тому
джерело
коміт
503ca3ab31
25 змінених файлів з 1071 додано та 154 видалено
  1. +19
    -0
      lib/pages/feedback_page/bloc/feedback_bloc.dart
  2. +5
    -1
      lib/pages/feedback_page/bloc/feedback_event.dart
  3. +73
    -0
      lib/pages/feedback_page/bloc/feedback_record_bloc.dart
  4. +13
    -0
      lib/pages/feedback_page/bloc/feedback_record_event.dart
  5. +117
    -0
      lib/pages/feedback_page/bloc/feedback_record_repository.dart
  6. +26
    -0
      lib/pages/feedback_page/bloc/feedback_record_state.dart
  7. +90
    -4
      lib/pages/feedback_page/bloc/feedback_repository.dart
  8. +6
    -0
      lib/pages/feedback_page/bloc/feedback_state.dart
  9. +67
    -27
      lib/pages/feedback_page/feedback_page.dart
  10. +146
    -15
      lib/pages/feedback_page/feedback_record_page.dart
  11. +5
    -2
      lib/pages/feedback_page/model/feedback_model.dart
  12. +60
    -0
      lib/pages/feedback_page/model/feedback_record_data_model.dart
  13. +140
    -0
      lib/pages/feedback_page/model/feedback_record_style_model.dart
  14. +9
    -0
      lib/pages/feedback_page/model/feedback_save_model.dart
  15. +56
    -23
      lib/pages/feedback_page/widgets/feedback_record_item.dart
  16. +10
    -2
      lib/pages/hot_ranking_page/hot_ranking_page.dart
  17. +18
    -1
      lib/pages/webview/base_webview.dart
  18. +38
    -14
      lib/pages/withdraw_page/withdraw_page.dart
  19. +4
    -1
      lib/register.dart
  20. +3
    -3
      lib/widgets/goods_details/coupon/counpon_widget.dart
  21. +13
    -12
      lib/widgets/goods_details/detail_img/goods_details_img.dart
  22. +7
    -3
      lib/widgets/goods_details/slide_banner/goods_details_slide_banner_widget.dart
  23. +119
    -35
      lib/widgets/hot_ranking/hot_ranking_goods/hot_ranking_goods.dart
  24. +11
    -4
      lib/widgets/hot_ranking/hot_ranking_list/hot_ranking_bloc.dart
  25. +16
    -7
      lib/widgets/hot_ranking/hot_ranking_list/hot_ranking_list.dart

+ 19
- 0
lib/pages/feedback_page/bloc/feedback_bloc.dart Переглянути файл

@@ -22,10 +22,29 @@ class FeedbackBloc extends Bloc<FeedbackEvent, FeedbackState> {
if (event is FeedbackInitEvent) {
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* {
var cache = await repository.fetchCachedData(event.model);
if (!EmptyUtil.isEmpty(cache)) {
yield FeedbackLoadedState(model: cache);
}
var result = await repository.fetchData(event.model);
if (!EmptyUtil.isEmpty(result)) {
yield FeedbackLoadedState(model: result);


+ 5
- 1
lib/pages/feedback_page/bloc/feedback_event.dart Переглянути файл

@@ -10,4 +10,8 @@ class FeedbackInitEvent extends FeedbackEvent{
}

/// 提交反馈
class FeedbackSubmitEvent extends FeedbackEvent{}
class FeedbackSubmitEvent extends FeedbackEvent{
final Map<String, dynamic> model;

FeedbackSubmitEvent({this.model});
}

+ 73
- 0
lib/pages/feedback_page/bloc/feedback_record_bloc.dart Переглянути файл

@@ -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();
}
}
}

+ 13
- 0
lib/pages/feedback_page/bloc/feedback_record_event.dart Переглянути файл

@@ -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 {}

+ 117
- 0
lib/pages/feedback_page/bloc/feedback_record_repository.dart Переглянути файл

@@ -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;
}
}

+ 26
- 0
lib/pages/feedback_page/bloc/feedback_record_state.dart Переглянути файл

@@ -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{}

+ 90
- 4
lib/pages/feedback_page/bloc/feedback_repository.dart Переглянути файл

@@ -1,21 +1,42 @@
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_comm/zhiying_comm.dart';

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 {
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])) {
var modListData = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list'][0]['data'];
if (!EmptyUtil.isEmpty(modListData)) {
FeedbackModel model = FeedbackModel.fromJson(jsonDecode(modListData));
model.feedbackTypes.last.isSelect = true;
return model;
}
}
@@ -25,6 +46,71 @@ class FeedBackRepository {
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;
}
}

+ 6
- 0
lib/pages/feedback_page/bloc/feedback_state.dart Переглянути файл

@@ -13,3 +13,9 @@ class FeedbackLoadedState extends FeedbackState{
}

class FeedbackErrorState extends FeedbackState{}

/// 保存反馈成功
class FeedbackSaveSuccessState extends FeedbackState{}

/// 保存反馈失败
class FeedbackSaveErrorState extends FeedbackState{}

+ 67
- 27
lib/pages/feedback_page/feedback_page.dart Переглянути файл

@@ -1,4 +1,5 @@
import 'dart:io';
import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -55,6 +56,9 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {

TextEditingController _title;

// 是否上传中
bool isUpLoading = false;

@override
void initState() {
_feedback = TextEditingController();
@@ -69,7 +73,6 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
super.dispose();
}


/// 选择图片
void _onAddImage() async {
if (_images.length >= 4) {
@@ -107,9 +110,13 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {

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);
}
@@ -120,6 +127,19 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
return BlocConsumer<FeedbackBloc, FeedbackState>(
listener: (context, state) {},
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;
},
builder: (context, state) {
@@ -169,14 +189,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
Center(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (_) => FeedbackRecordPage(),
),
);
},
onTap: () => RouterUtil.route(model, model.toJson(), context),
child: Container(
width: 120,
height: 30,
@@ -273,6 +286,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
),
),
const SizedBox(height: 2),

/// 异常选项
Padding(
padding: EdgeInsets.only(top: 4, bottom: 4),
@@ -281,16 +295,15 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
child: Row(
children: model.feedbackTypes
.map((e) => Expanded(
child: GestureDetector(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: (){
onTap: () {
setState(() {
model.feedbackTypes.forEach((element) {
element.isSelect = false;
});
e.isSelect = true;
});

},
child: Container(
margin: EdgeInsets.only(left: 2, right: 2),
@@ -311,9 +324,8 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
e.name ?? '',
style: TextStyle(
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(
file: file,
onDelete: () {
_images.remove(file);
setState(() {});
setState(() {
_images.remove(file);
});
},
),
));
@@ -425,6 +438,8 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
}

return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
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,
)
),
],
);
}
@@ -461,9 +485,27 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
if (!_submitable) {
return;
}

if(isUpLoading){
// Fluttertoast.showToast(msg: '提交中...');
return;
}

setState(() {
isUpLoading = true;
});

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(
margin: EdgeInsets.only(top: 24, bottom: 4),
@@ -474,7 +516,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
),
child: Center(
child: Text(
model?.feedbackPostBtnText ?? '提交意见',
isUpLoading ? '提交意见...' : model?.feedbackPostBtnText ?? '提交意见',
style: TextStyle(
fontSize: 14,
color: HexColor.fromHex(model?.feedbackPostBtnTextColor ?? '#FFFFFF'),
@@ -484,6 +526,4 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> {
),
);
}


}

+ 146
- 15
lib/pages/feedback_page/feedback_record_page.dart Переглянути файл

@@ -1,36 +1,167 @@
import 'package:flutter/cupertino.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/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
_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
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(
appBar: _createNav(),
appBar: _createNav(null),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
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(
border: Border(
bottom: BorderSide(
@@ -38,7 +169,7 @@ class _FeedbackRecordPageState extends State<FeedbackRecordPage> {
style: BorderStyle.none,
),
),
backgroundColor: Colors.white,
backgroundColor: HexColor.fromHex(styleModel?.appBarBgColor ?? '#FFFFFF'),
leading: Navigator.canPop(context)
? GestureDetector(
child: Container(
@@ -56,10 +187,10 @@ class _FeedbackRecordPageState extends State<FeedbackRecordPage> {
)
: Container(),
middle: Text(
'反馈列表',
styleModel?.appBarName ?? '反馈列表',
style: TextStyle(
fontSize: 15,
color: Color(0xff333333),
color: HexColor.fromHex(styleModel?.appBarNameColor ?? '#FF333333'),
),
),
);


+ 5
- 2
lib/pages/feedback_page/model/feedback_model.dart Переглянути файл

@@ -1,4 +1,6 @@
class FeedbackModel {
import 'package:zhiying_comm/zhiying_comm.dart';

class FeedbackModel extends SkipModel{
String appBarName;
String appBarNameColor;
String appBarBgColor;
@@ -73,6 +75,7 @@ class FeedbackModel {
this.skipIdentifier});

FeedbackModel.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'];
@@ -121,7 +124,7 @@ class FeedbackModel {
}

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_color'] = this.appBarNameColor;
data['app_bar_bg_color'] = this.appBarBgColor;


+ 60
- 0
lib/pages/feedback_page/model/feedback_record_data_model.dart Переглянути файл

@@ -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;
}
}

+ 140
- 0
lib/pages/feedback_page/model/feedback_record_style_model.dart Переглянути файл

@@ -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;
}
}

+ 9
- 0
lib/pages/feedback_page/model/feedback_save_model.dart Переглянути файл

@@ -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});
}

+ 56
- 23
lib/pages/feedback_page/widgets/feedback_record_item.dart Переглянути файл

@@ -1,6 +1,14 @@
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 {
FeedbackRecordStyleModel styleModel;
FeedbackRecordDataItemModel dataModel;

FeedbackRecordItem(this.styleModel, this.dataModel);

@override
Widget build(BuildContext context) {
return Container(
@@ -8,7 +16,7 @@ class FeedbackRecordItem extends StatelessWidget {
padding: EdgeInsets.all(15),
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
color: HexColor.fromHex(styleModel?.itemStyle?.bgColor ?? '#FFFFFF'),
borderRadius: BorderRadius.circular(7.5),
),
child: Row(
@@ -31,40 +39,53 @@ class FeedbackRecordItem extends StatelessWidget {
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.green,
// color: Colors.green,
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() {
List<InlineSpan> list = List();

list.add(WidgetSpan(
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),
child: Text(
'功能异常',
dataModel?.typeText ?? '其它',
style: TextStyle(
fontSize: 9,
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(
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(
maxLines: 2,
@@ -76,32 +97,44 @@ class FeedbackRecordItem extends StatelessWidget {
Widget _createDesc() {
return Container(
child: Text(
'我今天想使用我的提现功能的时候,发现官方已经把这个功能给暂时关闭了,所以我很伤心,不开心不开心不开心,所以我很伤心,不开心不开心不开心',
style: TextStyle(fontSize: 11, color: Color(0xff999999)),
dataModel?.content ?? '',
style: TextStyle(fontSize: 11, color: HexColor.fromHex(styleModel?.itemStyle?.contentTextColor ?? '#999999')),
),
);
}

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(
width: 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() {
return Container(
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')),
),
);
}


+ 10
- 2
lib/pages/hot_ranking_page/hot_ranking_page.dart Переглянути файл

@@ -22,7 +22,7 @@ class HotRankingPage extends StatefulWidget {
_HotRankingPageState createState() => _HotRankingPageState();
}

class _HotRankingPageState extends State<HotRankingPage> {
class _HotRankingPageState extends State<HotRankingPage> with AutomaticKeepAliveClientMixin{
@override
Widget build(BuildContext context) {
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 {
@@ -60,7 +64,7 @@ class _HotRankingPageContainer extends StatefulWidget {
__HotRankingPageContainerState();
}

class __HotRankingPageContainerState extends State<_HotRankingPageContainer> {
class __HotRankingPageContainerState extends State<_HotRankingPageContainer> with AutomaticKeepAliveClientMixin{
HotRankingPageBloc _bloc;
RefreshController _refreshController;
String backgroundImage;
@@ -136,6 +140,10 @@ class __HotRankingPageContainerState extends State<_HotRankingPageContainer> {
}
return list;
}

@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

class _SilverAppBarDelegate extends SliverPersistentHeaderDelegate {


+ 18
- 1
lib/pages/webview/base_webview.dart Переглянути файл

@@ -1,5 +1,11 @@
import 'dart:io';

import 'package:flutter/cupertino.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';

class BaseWebview extends StatefulWidget {
@@ -33,7 +39,18 @@ class _BaseWebviewState extends State<BaseWebview> {
onWebViewCreated: (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;
},
onPageStarted: (String url) {


+ 38
- 14
lib/pages/withdraw_page/withdraw_page.dart Переглянути файл

@@ -363,10 +363,28 @@ class _WithdrawContainerState extends State<_WithdrawContainer> {
}

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 {
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;
} else {
_submitable = false;
@@ -434,18 +452,24 @@ class _WithdrawContainerState extends State<_WithdrawContainer> {
);
}

///检查提现按钮是否可用
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(() {});
}
}

+ 4
- 1
lib/register.dart Переглянути файл

@@ -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/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_record_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/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/zhiying_comm.dart';

import 'pages/custom_page/custom_page.dart';
import 'pages/favorites_page/favorites_page.dart';
import 'pages/message_notice_page/message_notice_page.dart';
import 'pages/privacy_settings_page/privacy_settings_page.dart';
@@ -139,6 +141,7 @@ class BaseWidgetRegister {
PageFactory.regist(
'search_result_item', (model) => SearchResultItemPage(model));
PageFactory.regist('pub.flutter.feedback', (model) => FeedbackPage(model));
PageFactory.regist('pub.flutter.feedback_list', (model) => FeedbackRecordPage(model));
PageFactory.regist(
'pub.flutter.wechat_teacher', (model) => WechatTeacherPage());
PageFactory.regist('pub.flutter.cash_out', (model) => WithdrawPage(model));
@@ -199,7 +202,7 @@ class BaseWidgetRegister {
'pub.flutter.my_wallet_detail', (model) => BilDetailPage(model));

/// 通用模块
PageFactory.regist('pub.flutter.custom', (model) => EmptyPage());
PageFactory.regist('pub.flutter.custom', (model) => CustomPage(model));
}

// 注册控件


+ 3
- 3
lib/widgets/goods_details/coupon/counpon_widget.dart Переглянути файл

@@ -58,7 +58,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> {

/// 点击领取
void _onJump(CounponModel model) async{
TurnChainUtil.openReceiveCoupon(context, _user, model.provider, model.toJson());
TurnChainUtil.openReceiveCoupon(context, _user, model.provider, model?.convertArgs?.toJson());
}

@override
@@ -73,7 +73,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> {
},
builder: (context, state) {
if (state is CounponLoadedState) {
return _getMainWdiget(state.model);
return _getMainWidget(state.model);
}
return CounponSkeleton();
},
@@ -81,7 +81,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> {
}

/// 主视图
Widget _getMainWdiget(CounponModel model) {
Widget _getMainWidget(CounponModel model) {
return Visibility(
visible: !EmptyUtil.isEmpty(model?.coupon_price),
child: GestureDetector(


+ 13
- 12
lib/widgets/goods_details/detail_img/goods_details_img.dart Переглянути файл

@@ -97,18 +97,19 @@ class _GoodsDetailsImgWidgetContainerState
return Column(
children: model.image_detail_list.map((item) {
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(),
);
} else {


+ 7
- 3
lib/widgets/goods_details/slide_banner/goods_details_slide_banner_widget.dart Переглянути файл

@@ -46,8 +46,9 @@ class _GoodsDetailsSlideBannerContainerState
/// 子元素点击事件
void _itemOnClick(String model, List<String> images, int index) {
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];
return Container(
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,


+ 119
- 35
lib/widgets/hot_ranking/hot_ranking_goods/hot_ranking_goods.dart Переглянути файл

@@ -12,25 +12,31 @@ class HotRankingGoods extends StatelessWidget {
HotRankingListModel styleModel;
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
Widget build(BuildContext context) {
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];
}
Providers providers = getProvider(good.provider);
return GestureDetector(
onTap: () {
RouterUtil.route(SkipModel(skipIdentifier: "goods_details"), good?.toJson(), context);
RouterUtil.route(SkipModel(skipIdentifier: "goods_details"),
good?.toJson(), context);
},
child: Stack(
children: <Widget>[
Container(
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(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
@@ -40,11 +46,15 @@ class HotRankingGoods extends StatelessWidget {
height: 254.w,
child: ClipRRect(
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(
alignment: ui.PlaceholderAlignment.middle,
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(
good.providerName ?? "",
style: TextStyle(
@@ -79,7 +93,12 @@ class HotRankingGoods extends StatelessWidget {
child: SizedBox(
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 == ""
? Container()
: Container(
margin: EdgeInsets.only(top: 4, bottom: 4, right: 15.w),
margin: EdgeInsets.only(
top: 4, bottom: 4, right: 15.w),
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(
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(
(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(
margin: EdgeInsets.only(top: 4, bottom: 4),
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(
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(
(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),
child: Text(
"¥",
style: TextStyle(color: HexColor.fromHex(styleModel.currentPriceColor ?? ""), fontSize: 20.sp),
style: TextStyle(
color: HexColor.fromHex(
styleModel.currentPriceColor ?? ""),
fontSize: 20.sp),
),
),
Text(
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(
width: 6,
@@ -144,7 +207,13 @@ class HotRankingGoods extends StatelessWidget {
padding: EdgeInsets.only(bottom: 4.sp),
child: Text(
"¥" + 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(
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(
"热销" + 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,
height: 48.w,
child: CachedNetworkImage(
imageUrl: styleModel?.hotRank?.hotSaleImg ?? "",
imageUrl:
styleModel?.hotRank?.hotSaleImg ?? "",
width: 48.w,
height: 48.w,
placeholder: (context, _) => Container(color: Colors.yellow),
placeholder: (context, _) =>
Container(color: Colors.yellow),
fit: BoxFit.fill,
),
),
@@ -193,8 +270,13 @@ class HotRankingGoods extends StatelessWidget {
height: 48.h,
width: 127.w,
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),
))
],
@@ -210,7 +292,9 @@ class HotRankingGoods extends StatelessWidget {
Align(
alignment: Alignment.topLeft,
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),
height: 60.w,
width: 60.w,


+ 11
- 4
lib/widgets/hot_ranking/hot_ranking_list/hot_ranking_bloc.dart Переглянути файл

@@ -1,6 +1,11 @@
import 'dart:async';
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_comm/util/base_bloc.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
@@ -25,7 +30,7 @@ class HotRankingListBloc extends BlocBase {
_dataController = null;
}

void loadData(String typeId, int page,Function complete) {
void loadData(String typeId, int page, Function complete) {
if (isLoading) {
complete();
return;
@@ -35,16 +40,18 @@ class HotRankingListBloc extends BlocBase {
NetUtil.request(
'/api/v1/rec/taobao?type_id=' + typeId + '&page=' + page.toString(),
method: NetMethod.GET, onSuccess: (data) {
complete();
complete();
isLoading = false;
_loadData(data);
Loading.dismiss();
}, onError: (e) {
complete();
Loading.dismiss();
complete();
isLoading = false;
});
}

void loadMoreData(String typeId,Function complete) {
void loadMoreData(String typeId, Function complete) {
if (isLoading) {
complete();
return;


+ 16
- 7
lib/widgets/hot_ranking/hot_ranking_list/hot_ranking_list.dart Переглянути файл

@@ -2,6 +2,8 @@ import 'dart:convert';

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/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_list/model/hot_ranking_list_data_model.dart';
@@ -23,7 +25,7 @@ class HotRankingList extends StatefulWidget {
}

class _HotRankingState extends State<HotRankingList>
with TickerProviderStateMixin {
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
HotRankingListBloc _bloc;
TabController _tabController;
RefreshController _refreshController;
@@ -33,6 +35,8 @@ class _HotRankingState extends State<HotRankingList>

ScrollController _scrollcontroller;

bool isFirstTime=true;

@override
void initState() {
_bloc = HotRankingListBloc();
@@ -43,8 +47,14 @@ class _HotRankingState extends State<HotRankingList>
if (_pageBloc != null) {
_pageBloc.event.listen((event) {
if (event.containsKey('type') && event['type'] == "loadData") {
if(!isFirstTime){
Loading.show(context);
}
isFirstTime=false;
_bloc.currentPage = 1;
_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();
} else {
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(
controller: _refreshController,
enablePullDown: true,
@@ -121,4 +126,8 @@ class _HotRankingState extends State<HotRankingList>
index: index,
);
}

@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

Завантаження…
Відмінити
Зберегти