提交 8872e6ad authored 作者: maodou's avatar maodou

Merge remote-tracking branch 'origin/test' into test

# Conflicts: # lib/apis/mine.dart # lib/models/index.dart # lib/utils/styles.dart
......@@ -4,5 +4,5 @@ keyPassword=123456
keyAlias=zijing
#storeFile=/Users/apple/zijiing_key.jks
storeFile=zijiing_key.jks
\ No newline at end of file
storeFile=/Users/apple/zijiing_key.jks
#storeFile=zijiing_key.jks
\ No newline at end of file
......@@ -477,6 +477,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = MYN43C5WGE;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "紫荆数智学堂";
......@@ -644,6 +645,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = MYN43C5WGE;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "紫荆数智学堂";
......@@ -664,6 +666,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = MYN43C5WGE;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "紫荆数智学堂";
......
......@@ -163,4 +163,29 @@ abstract class CommonAPI {
return result.data['filesUrl'];
}
/// 11、创建订单
///
static Future <PayOrderModel> createOrder({
required String bookIdsList,
required String totalPrice,
required String couponRecId,
required String integral,
required String type
}) async {
final result = await HttpService.to.post(
'/v1/orders/Orders/createOrders',
params: {
'book_ids_list':bookIdsList,
'total_price':totalPrice,
'coupon_rec_id':couponRecId,
'integral':integral,
'type':type,
},
);
if (result.data is! Map) return PayOrderModel();
return PayOrderModel.fromJson(result.data);
}
}
\ No newline at end of file
......@@ -64,7 +64,8 @@ abstract class LibraryAPI {
final result = await HttpService.to.post(
'/v1/book/category/getBookList',
params: params
params: params,
showLoading: true
);
if (result.data is! Map && result.data['list'] is! List) return [];
return List.generate(result.data['list'].length, (index){
......@@ -125,5 +126,20 @@ abstract class LibraryAPI {
return BookDetailModel.fromJson(result.data);
}
/// 6、学习报告
///
static Future <ReportModel> report({
required String bookId
}) async {
final result = await HttpService.to.post(
'/v1/members/Information/myStudyReport',
params: {
'book_id':bookId
},
);
if (result.data is! Map) return ReportModel();
return ReportModel.fromJson(result.data);
}
}
\ No newline at end of file
......@@ -330,4 +330,22 @@ abstract class MineAPI {
return OrderListModel.fromJson(result.data['list'][index]);
});
}
/// 19、紫荆币充值列表
///
static Future<List<CoinModel>> coinsRechargeList(
{
required String type,
}) async {
final result = await HttpService.to.post(
'/v1/orders/Orders/getRechargeConfig',
params: {
'config_type': type,
},
);
if (result.data is! Map && result.data['list'] is! List) return [];
return List.generate(result.data['list'].length, (index) {
return CoinModel.fromJson(result.data['list'][index]);
});
}
}
......@@ -54,6 +54,60 @@ abstract class ShopAPI {
});
}
/// 4、获取使用积分
///
static Future <CreditPointModel> creditPoints({
required String price,
}) async {
final result = await HttpService.to.post(
'/v1/coupon/Coupon/getIntegral',
params: {
'price': price,
},
);
if (result.data is! Map ) return CreditPointModel();
return CreditPointModel.fromJson(result.data);
}
/// 5、优惠券和积分是否展示
///
static Future <ShowModel> show() async {
final result = await HttpService.to.post(
'/v1/orders/Orders/getSetting',
params: {},
);
if (result.data is! Map ) return ShowModel();
return ShowModel.fromJson(result.data);
}
/// 6、 支付时选的优惠券列表
static Future<CouponListModel> coupon({
int page = 1,
int limit = 10,
required String type,
required String price
}) async {
final result = await HttpService.to.post(
'/v1/coupon/Coupon/getCouponAll',
params: {'page': page, 'page_size': limit, 'type': type,'price':price},
);
if (result.data is! Map ) return CouponListModel();
return CouponListModel.fromJson(result.data);
}
/// 7、获取优惠券可使用和不可使用数量
static Future<CouponNumModel> couponNum({
required String price
}) async {
final result = await HttpService.to.post(
'/v1/coupon/Coupon/getCouponNum',
params: {
'price':price
},
);
if (result.data is! Map ) return CouponNumModel();
return CouponNumModel.fromJson(result.data);
}
}
\ No newline at end of file
......@@ -52,9 +52,10 @@ class MyApp extends StatelessWidget {
behavior: _NoShadowScrollBehavior(),
child: OKToast(
radius: 8.0,
backgroundColor: AppTheme.primary,
backgroundColor: const Color(0xFF000000).withOpacity(0.2),
textPadding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0),
position: ToastPosition.bottom,
// textStyle: ,
child: child ?? const Material(),
),
);
......
......@@ -12,4 +12,5 @@ part 'msg.dart';
part 'study_history.dart';
part 'library.dart';
part 'mine.dart';
part 'order.dart';
\ No newline at end of file
part 'order.dart';
part 'shop.dart';
\ No newline at end of file
......@@ -5,14 +5,17 @@ class CategoryModel {
CategoryModel({
this.categoryId,
this.name,
this.selected = false,
});
CategoryModel.fromJson(dynamic json) {
categoryId = json['category_id'];
name = json['name'];
selected = false;
}
num? categoryId;
String? name;
late bool selected;
CategoryModel copyWith({ num? categoryId,
String? name,
}) => CategoryModel( categoryId: categoryId ?? this.categoryId,
......@@ -346,17 +349,116 @@ class BookDetailModel {
}
/// 删选模型
class FilterModel {
FilterModel({
required this.id,
required this.name,
this.id,
this.name,
this.selected = false
});
String id;
String name;
String? id;
String? name;
late bool selected = false;
}
/// 学习报告模型
class ReportModel {
ReportModel({
this.bookName,
this.authors,
this.img,
this.progress,
this.readSecond,
this.maxSecond,
this.lastChapter,
this.commentPostNums,
this.commentReplyNums,
this.lineNums,
this.colorNums,
this.noteNums,
this.questionAllNums,
this.questionAccuracy,});
ReportModel.fromJson(dynamic json) {
bookName = json['book_name'];
authors = json['authors'];
img = json['img'];
progress = json['progress'];
readSecond = json['read_second'];
maxSecond = json['max_second'];
lastChapter = json['last_chapter'];
commentPostNums = json['comment_post_nums'];
commentReplyNums = json['comment_reply_nums'];
lineNums = json['line_nums'];
colorNums = json['color_nums'];
noteNums = json['note_nums'];
questionAllNums = json['question_all_nums'];
questionAccuracy = json['question_accuracy'];
}
String? bookName;
String? authors;
String? img;
String? progress;
String? readSecond;
num? maxSecond;
String? lastChapter;
num? commentPostNums;
num? commentReplyNums;
num? lineNums;
num? colorNums;
num? noteNums;
num? questionAllNums;
String? questionAccuracy;
ReportModel copyWith({ String? bookName,
String? authors,
String? img,
String? progress,
String? readSecond,
num? maxSecond,
String? lastChapter,
num? commentPostNums,
num? commentReplyNums,
num? lineNums,
num? colorNums,
num? noteNums,
num? questionAllNums,
String? questionAccuracy,
}) => ReportModel( bookName: bookName ?? this.bookName,
authors: authors ?? this.authors,
img: img ?? this.img,
progress: progress ?? this.progress,
readSecond: readSecond ?? this.readSecond,
maxSecond: maxSecond ?? this.maxSecond,
lastChapter: lastChapter ?? this.lastChapter,
commentPostNums: commentPostNums ?? this.commentPostNums,
commentReplyNums: commentReplyNums ?? this.commentReplyNums,
lineNums: lineNums ?? this.lineNums,
colorNums: colorNums ?? this.colorNums,
noteNums: noteNums ?? this.noteNums,
questionAllNums: questionAllNums ?? this.questionAllNums,
questionAccuracy: questionAccuracy ?? this.questionAccuracy,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['book_name'] = bookName;
map['authors'] = authors;
map['img'] = img;
map['progress'] = progress;
map['read_second'] = readSecond;
map['max_second'] = maxSecond;
map['last_chapter'] = lastChapter;
map['comment_post_nums'] = commentPostNums;
map['comment_reply_nums'] = commentReplyNums;
map['line_nums'] = lineNums;
map['color_nums'] = colorNums;
map['note_nums'] = noteNums;
map['question_all_nums'] = questionAllNums;
map['question_accuracy'] = questionAccuracy;
return map;
}
}
......@@ -77,6 +77,7 @@ class CouponModel {
this.couponName,
this.normPrice,
this.reducedPrice,
this.type
});
CouponModel.fromJson(dynamic json) {
......@@ -96,6 +97,7 @@ class CouponModel {
String? couponName;
num? normPrice;
String? reducedPrice;
num? type;
CouponModel copyWith({
num? couponRecId,
......@@ -119,7 +121,7 @@ class CouponModel {
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['coupon_rec_id'] = couponRecId;
map['end_time'] = endTime;
// map['end_time'] = endTime;
map['coupon_id'] = couponId;
map['use_status'] = useStatus;
map['coupon_name'] = couponName;
......@@ -612,3 +614,51 @@ class HelpCenterContentModel {
return map;
}
}
/// 紫荆币模型
class CoinModel {
CoinModel({
this.beanName,
this.beanValue,
this.priceName,
this.priceValue,
this.identifying,
this.selected = false,
});
CoinModel.fromJson(dynamic json) {
beanName = json['bean_name'];
beanValue = json['bean_value'];
priceName = json['price_name'];
priceValue = json['price_value'];
identifying = json['identifying'];
selected = false;
}
String? beanName;
String? beanValue;
String? priceName;
String? priceValue;
String? identifying;
late bool selected;
CoinModel copyWith({ String? beanName,
String? beanValue,
String? priceName,
String? priceValue,
String? identifying,
}) => CoinModel( beanName: beanName ?? this.beanName,
beanValue: beanValue ?? this.beanValue,
priceName: priceName ?? this.priceName,
priceValue: priceValue ?? this.priceValue,
identifying: identifying ?? this.identifying,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['bean_name'] = beanName;
map['bean_value'] = beanValue;
map['price_name'] = priceName;
map['price_value'] = priceValue;
map['identifying'] = identifying;
return map;
}
}
......@@ -23,7 +23,7 @@ class MsgModel {
title = json['title'];
content = json['content'];
status = json['status'];
urlId = json['url_id'];
urlId = json['url_id'] != null ? UrlIdModel.fromJson(json['url_id']) : null;
createTime = json['create_time'];
}
num? id;
......@@ -31,7 +31,7 @@ class MsgModel {
String? title;
String? content;
num? status;
num? urlId;
UrlIdModel? urlId;
String? createTime;
MsgModel copyWith({
num? id,
......@@ -39,7 +39,7 @@ class MsgModel {
String? title,
String? content,
num? status,
num? urlId,
UrlIdModel? urlId,
String? createTime,
}) => MsgModel(
id: id ?? this.id,
......@@ -57,9 +57,36 @@ class MsgModel {
map['title'] = title;
map['content'] = content;
map['status'] = status;
map['url_id'] = urlId;
if (urlId != null) {
map['url_id'] = urlId?.toJson();
}
map['create_time'] = createTime;
return map;
}
}
class UrlIdModel {
UrlIdModel({
this.bookId,
this.chapterId,});
UrlIdModel.fromJson(dynamic json) {
bookId = json['book_id'];
chapterId = json['chapter_id'];
}
num? bookId;
num? chapterId;
UrlIdModel copyWith({ num? bookId,
num? chapterId,
}) => UrlIdModel( bookId: bookId ?? this.bookId,
chapterId: chapterId ?? this.chapterId,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['book_id'] = bookId;
map['chapter_id'] = chapterId;
return map;
}
}
\ No newline at end of file
part of models;
class PayModel {
PayModel({
required this.type,
......@@ -12,4 +14,226 @@ class PayModel {
String icon;
bool selected;
}
/// 可使用积分模型
class CreditPointModel {
CreditPointModel({
this.integral,
this.onePointDeductionAmount,
this.integralUseLimit,
this.integralSwitch,
this.deductibleAmount,
this.deductibleIntegral,});
CreditPointModel.fromJson(dynamic json) {
integral = json['integral'];
onePointDeductionAmount = json['one_point_deduction_amount'];
integralUseLimit = json['integral_use_limit'];
integralSwitch = json['integral_switch'];
deductibleAmount = json['deductible_amount'];
deductibleIntegral = json['deductible_integral'];
}
num? integral;
String? onePointDeductionAmount;
String? integralUseLimit;
String? integralSwitch;
String? deductibleAmount;
num? deductibleIntegral;
CreditPointModel copyWith({ num? integral,
String? onePointDeductionAmount,
String? integralUseLimit,
String? integralSwitch,
String? deductibleAmount,
num? deductibleIntegral,
}) => CreditPointModel( integral: integral ?? this.integral,
onePointDeductionAmount: onePointDeductionAmount ?? this.onePointDeductionAmount,
integralUseLimit: integralUseLimit ?? this.integralUseLimit,
integralSwitch: integralSwitch ?? this.integralSwitch,
deductibleAmount: deductibleAmount ?? this.deductibleAmount,
deductibleIntegral: deductibleIntegral ?? this.deductibleIntegral,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['integral'] = integral;
map['one_point_deduction_amount'] = onePointDeductionAmount;
map['integral_use_limit'] = integralUseLimit;
map['integral_switch'] = integralSwitch;
map['deductible_amount'] = deductibleAmount;
map['deductible_integral'] = deductibleIntegral;
return map;
}
}
/// 优惠券和 积分是否展示模型
class ShowModel {
ShowModel({
this.couponSwitch,
this.integralSwitch,
this.membersBean,
});
ShowModel.fromJson(dynamic json) {
couponSwitch = json['coupon_switch'];
integralSwitch = json['integral_switch'];
membersBean = json['members_bean'];
}
String? couponSwitch;
String? integralSwitch;
String? membersBean;
ShowModel copyWith({ String? couponSwitch,
String? integralSwitch,
String? membersBean,
}) => ShowModel( couponSwitch: couponSwitch ?? this.couponSwitch,
integralSwitch: integralSwitch ?? this.integralSwitch,
membersBean: membersBean ?? this.integralSwitch
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['coupon_switch'] = couponSwitch;
map['integral_switch'] = integralSwitch;
map['members_bean'] = membersBean;
return map;
}
}
class CouponListModel {
CouponListModel({
this.list,
this.total,});
CouponListModel.fromJson(dynamic json) {
if (json['list'] != null) {
list = [];
json['list'].forEach((v) {
list?.add(CouponModel.fromJson(v));
});
}
total = json['total'];
}
List<CouponModel>? list;
num? total;
CouponListModel copyWith({ List<CouponModel>? list,
num? total,
}) => CouponListModel( list: list ?? this.list,
total: total ?? this.total,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
if (list != null) {
map['list'] = list?.map((v) => v.toJson()).toList();
}
map['total'] = total;
return map;
}
}
/// 优惠券可使用和不可使用数量
class CouponNumModel {
CouponNumModel({
this.availableNum,
this.unavailableNum,});
CouponNumModel.fromJson(dynamic json) {
availableNum = json['available_num'];
unavailableNum = json['unavailable_num'];
}
num? availableNum;
num? unavailableNum;
CouponNumModel copyWith({ num? availableNum,
num? unavailableNum,
}) => CouponNumModel( availableNum: availableNum ?? this.availableNum,
unavailableNum: unavailableNum ?? this.unavailableNum,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['available_num'] = availableNum;
map['unavailable_num'] = unavailableNum;
return map;
}
}
/// 创建订单模型
class PayOrderModel {
PayOrderModel({
this.appid,
this.partnerid,
this.prepayid,
this.package,
this.noncestr,
this.timestamp,
this.sign,
this.ordersnum,
this.encryptionOrder,
this.code,
String? msg,
});
PayOrderModel.fromJson(dynamic json) {
appid = json['appid'];
partnerid = json['partnerid'];
prepayid = json['prepayid'];
package = json['package'];
noncestr = json['noncestr'];
timestamp = json['timestamp'];
sign = json['sign'];
ordersnum = json['ordersnum'];
encryptionOrder = json['encryption_order'];
code = json['code'];
msg = json['msg'];
}
String? appid;
String? partnerid;
String? prepayid;
String? package;
String? noncestr;
num? timestamp;
String? sign;
String? ordersnum;
String? encryptionOrder;
num? code;
String? msg;
PayOrderModel copyWith({ String? appid,
String? partnerid,
String? prepayid,
String? package,
String? noncestr,
num? timestamp,
String? sign,
String? ordersnum,
String? encryptionOrder,
num? code,
String? msg,
}) => PayOrderModel( appid: appid ?? this.appid,
partnerid: partnerid ?? this.partnerid,
prepayid: prepayid ?? this.prepayid,
package: package ?? this.package,
noncestr: noncestr ?? this.noncestr,
timestamp: timestamp ?? this.timestamp,
sign: sign ?? this.sign,
ordersnum: ordersnum ?? this.ordersnum,
encryptionOrder: encryptionOrder ?? this.encryptionOrder,
code: code ?? this.code,
msg: msg?? this.msg,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['appid'] = appid;
map['partnerid'] = partnerid;
map['prepayid'] = prepayid;
map['package'] = package;
map['noncestr'] = noncestr;
map['timestamp'] = timestamp;
map['sign'] = sign;
map['ordersnum'] = ordersnum;
map['encryption_order'] = encryptionOrder;
map['code'] = code;
map['msg'] = msg;
return map;
}
}
\ No newline at end of file
......@@ -13,25 +13,34 @@ class _AdPageState extends State<AdPage> {
return GetBuilder<AdController>(
init: AdController(context),
builder:(controller) => Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 200.w,
width: 200.w,
color: Colors.lime,
),
SizedBox(height: 20.w),
Text(
'倒计时:${controller._countdown}',
style: TextStyle(
fontSize: 20.w
body: Stack(
fit: StackFit.expand,
children: [
Container(
color: Colors.green,
),
Positioned(
top: 40.w,
right: 20.w,
child: GestureDetector(
onTap: (){
context.goNamed(Routes.main);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12.0.w, vertical: 8.0.w),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.6),
borderRadius: BorderRadius.circular(8.0.w),
),
child: Text(
'跳过 ${controller._countdown} s',
style: const TextStyle(color: Colors.white),
),
),
),
],
),
),
)
)
],
)
)
);
......
......@@ -33,7 +33,7 @@ class _BuildItemState extends State<BuildItem> {
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(widget.model.name??'',style: TextStyle(fontSize: 14.w,color: widget.model.seen ==0? Colours.c3:Colours.c9,fontWeight: Fonts.medium,height: 1.4),),
Text(widget.model.name??'',style: TextStyle(fontSize: 14.w,color: widget.model.seen ==0? Colours.c3:Colours.c9,fontWeight: Fonts.medium,height: 2),),
Gaps.hGaps5,
widget.model.isReading == 1? Container(
height: 17,
......@@ -76,7 +76,7 @@ class _BuildItemState extends State<BuildItem> {
return Container(
color: Colors.white,
padding: const EdgeInsets.only(left: 60),
child: Text(model.name??'',style:TextStyle(fontSize: 12,color: model.seen ==0? Colours.c3:Colours.c9,height: 1.6),),
child: Text(model.name??'',style:TextStyle(fontSize: 12,color: model.seen ==0? Colours.c3:Colours.c9,height: 2),),
);
}
}
......@@ -39,6 +39,14 @@ class BookDetailController extends GetxController with GetSingleTickerProviderSt
super.onClose();
}
/// 加入书架
void addCart(String bookId) async {
final result = await ShopAPI.addCart(bookId: bookId);
if(result){
Toast.show('添加购物车成功');
}
}
/// 获取目录信息
void _getChapters() async {
chapters = await LibraryAPI.chapters(bookId: bookId);
......
......@@ -98,7 +98,12 @@ class _BookDetailPageState extends State<BookDetailPage> with SingleTickerProvid
Expanded(
child: GestureDetector(
onTap: (){
context.pushNamed(Routes.studyReport);
if(controller.bookDetails.isHave ==1){
context.pushNamed(Routes.studyReport,queryParameters: {'book_id':widget.bookId});
}
else{
controller.addCart(widget.bookId);
}
},
child: Container(
alignment: Alignment.center,
......@@ -126,7 +131,22 @@ class _BookDetailPageState extends State<BookDetailPage> with SingleTickerProvid
/// 没有购买并且没有试读直接跳转 购买页
bool noTryRead = true;
if(controller.bookDetails.isHave == 0 && noTryRead){
context.pushNamed(Routes.bookPay);
List<CourseModel> buy = [];
CourseModel model= CourseModel(
bookId: controller.bookDetails.bookId,
price: controller.bookDetails.price,
vipPrice: controller.bookDetails.vipPrice,
img: controller.bookDetails.img,
bookName: controller.bookDetails.bookName,
cartId: 0,
status: 1,
selected: true
);
buy.add(model);
context.pushNamed(Routes.bookPay,extra: buy);
}
else {
context.pushNamed(Routes.web);
}
},
child: Container(
......
part of book_pay;
class BookPayController extends GetxController {
// 购物车选中的书籍列表
final List<CourseModel> buy;
BookPayController(this.buy);
BookPayController({required this.buy});
// 积分模型
CreditPointModel creditPointModel = CreditPointModel(deductibleIntegral: 0);
// 是否展示优惠券和积分模型
ShowModel showModel = ShowModel();
// 是否使用积分
bool useCreditPoint = false;
// 优惠券可用不可用数量模型
CouponNumModel couponNumModel = CouponNumModel();
// 选择的优惠券模型
late CouponModel useCouponModel = CouponModel(couponId: 0,reducedPrice: '0.00',couponRecId: 0);
// 创建订单模型
late PayOrderModel payOrderModel;
// 支付方式
List<PayModel> pays = Platform.isIOS ?[
......@@ -13,11 +27,42 @@ class BookPayController extends GetxController {
PayModel(type: 3, name: '紫荆币', icon: 'assets/images/pay_coin.png', selected: false),
];
// 时候展示底部视图
bool showDetail = false;
// 支付方式
// 优惠前的原始价钱
late double originalPrice = getOriginalPrice();
// late double finalPrice = 0.00;
Decimal finalPrice = Decimal.zero;
@override
void onReady() {
_getCreditPoints(price: originalPrice.toString());
_getShow();
computeFinalPrice();
_getCouponNumber();
super.onReady();
}
/// 使用优惠券
void setUseCoupon(CouponModel model){
useCouponModel = model;
print('使用优惠券。。。。。。。。。。。。。。。。');
computeFinalPrice();
}
/// 支付方式 默认第一个
late PayModel _payModel = pays.first;
PayModel get payModel => _payModel;
/// 选择积分状态
void show(){
showDetail = !showDetail;
update();
}
/// 设置支付渠道
void setPayModel(PayModel payModel){
for (PayModel model in pays) {
if (model.type == payModel.type){
......@@ -31,19 +76,114 @@ class BookPayController extends GetxController {
update();
}
/// 是否使用积分
void setUse(){
useCreditPoint = !useCreditPoint;
// 计算
computeFinalPrice();
update();
}
/// 获取积分
void _getCreditPoints({
required String price
}) async {
creditPointModel = await ShopAPI.creditPoints(price: price);
update();
}
/// 是否展示优惠券 和积分使用 模型
void _getShow () async {
showModel = await ShopAPI.show();
update();
}
/// 获取优惠券可用数量与不可用数量模型
void _getCouponNumber() async{
couponNumModel = await ShopAPI.couponNum(price: originalPrice.toString());
update();
}
/// 获取优惠前的价钱
/// 总价钱
double getOriginalPrice(){
Decimal price = Decimal.zero;
for (CourseModel model in buy!) {
if (model.status == 1){
if (model.selected == true){
price = price + Decimal.parse(model.vipPrice??'0.00');
print('==============11111111111==================$price');
}
}
}
print('================================$price');
return price.toDouble();
}
/// 获取优惠后的价格
void computeFinalPrice(){
finalPrice = Decimal.parse(originalPrice.toString());
if (useCreditPoint){
finalPrice = finalPrice - Decimal.parse(creditPointModel.deductibleAmount??'0.00');
}
// 不等0的时候证明使用了 优惠券
if (useCouponModel.couponId !=0){
finalPrice = finalPrice - Decimal.parse(useCouponModel.reducedPrice??'0.00');
}
update();
}
/// 创建订单
void createOrder() async {
List<Map<String, dynamic>> bookIdsList = [];
for (CourseModel model in buy){
Map<String, dynamic> tempMap = {
'book_id': model.bookId,
'price': model.price,
'cart_id': model.cartId,
};
bookIdsList.add(tempMap);
}
// 书豆支付的话先判断书豆数量
if (finalPrice.toDouble() > double.parse(showModel.membersBean.toString())){
Toast.show('紫金币不足,请先充值紫荆币');
return;
}
final result = await CommonAPI.createOrder(
bookIdsList:jsonEncode(bookIdsList) ,
totalPrice: finalPrice.toString(),
couponRecId: useCouponModel.couponRecId.toString(),
integral: creditPointModel.deductibleIntegral.toString(),
type: payModel.type.toString()
);
payOrderModel = result;
// 微信
if(payModel.type == 1){
String orderNumber = payOrderModel.ordersnum.toString();
//TODO: 拿到订单编号进行微信支付操作
}
// 支付宝
else if(payModel.type == 2){
String orderNumber = payOrderModel.ordersnum.toString();
//TODO: 拿到订单编号进行支付宝支付操作
}
// 书豆
else if (payModel.type == 3){
if(payOrderModel.code == -1){
Toast.show('紫金币不足,请先充值紫荆币');
}
String orderNumber = payOrderModel.ordersnum.toString();
//TODO: 拿到订单编号进行后续操作
}
}
// /// 获取总价
// ///总价格
// double get allPrice{
// Decimal price = Decimal.zero;
// for (CourseModel model in buy) {
// if (model.status == 1){
// if (model.selected == true){
// price = price + Decimal.parse(model.vipPrice??'0.00');
// }
// }
// }
// return price.toDouble();
// }
}
\ No newline at end of file
library book_pay;
import 'dart:convert';
import 'dart:core';
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_book/apis/index.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
......@@ -10,7 +14,6 @@ import 'package:get/get.dart';
import 'package:go_router/go_router.dart';
import '../../models/index.dart';
import '../../models/shop.dart';
import '../../routes/index.dart';
import '../../utils/index.dart';
import '../../widgets/index.dart';
......
part of book_pay;
class BuildPayCount extends StatelessWidget {
const BuildPayCount({Key? key}) : super(key: key);
final void Function()? payTap;
final void Function()? showTap;
final BookPayController controller;
const BuildPayCount({
Key? key,
required this.payTap,
required this.showTap,
required this.controller
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 15.w),
height: 55.w,
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
Text('应付:',style: TextStyle(fontSize:14.w,color: Colours.c3 ,height: 1.1),),
Text('¥98.9',style: TextStyle(fontSize:15.w,color:AppTheme.primary,fontWeight: Fonts.medium ,height: 1.1),)
],
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.w),
color: AppTheme.primary
return GetBuilder<BookPayController>(
init: BookPayController(buy: []),
builder:(controller)=> Container(
padding: EdgeInsets.symmetric(horizontal: 15.w),
height: 55.w,
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IgnorePointer(
ignoring: controller.showModel.integralSwitch =='0'&& controller.showModel.couponSwitch ==''?true:false,
child: GestureDetector(
onTap: showTap,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('应付:',style: TextStyle(fontSize:14.w,color: Colours.c3 ,height: 1.1),),
Text('¥${controller.finalPrice}',style: TextStyle(fontSize:15.w,color:AppTheme.primary,fontWeight: Fonts.medium ,height: 1.1),),
controller.showModel.integralSwitch =='1'&& controller.showModel.couponSwitch =='1'?SizedBox(
// color: Colors.cyan,
width: 20.w,
height: 20.w,
child: Image.asset('assets/images/pay_up.png')
):const SizedBox()
],
),
),
),
padding: EdgeInsets.symmetric(horizontal:13.5.w,vertical: 8.w),
child: Text('确认支付',style: TextStyle(fontSize: 14.w,fontWeight: Fonts.medium,color: Colors.white),),
)
],
GestureDetector(
onTap: payTap,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.w),
color: AppTheme.primary
),
padding: EdgeInsets.symmetric(horizontal:13.5.w,vertical: 8.w),
child: Text('确认支付',style: TextStyle(fontSize: 14.w,fontWeight: Fonts.medium,color: Colors.white),),
),
)
],
),
),
);
}
......
......@@ -15,15 +15,15 @@ class BuildItem extends StatelessWidget {
padding: EdgeInsets.only(left: 15.w, top: 15.w,right: 10.w,bottom: 15.w),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
boxShadow: [
BoxShadow(
color: Colours.cC7,
offset: Offset(0, 3),
blurRadius: 4,
color: Colours.cC7.withOpacity(0.5),
offset: Offset(3.w, 0.w),
blurRadius: 4.w,
spreadRadius: 0,
),
],
borderRadius: BorderRadius.circular(8)
borderRadius: BorderRadius.circular(8.w)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
......@@ -31,13 +31,13 @@ class BuildItem extends StatelessWidget {
Row(
children: [
Container(
width: 35,
height: 35,
width: 35.w,
height: 35.w,
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(17.5)
borderRadius: BorderRadius.circular(17.5.w)
),
child: CustomImage.network(url: model.usersImg??''),
child: CustomImage.network(url: model.usersImg??'',radius: 17.5.w,),
),
Gaps.hGaps10,
Expanded(
......@@ -47,9 +47,9 @@ class BuildItem extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(model.users??'',style: const TextStyle(fontSize: 12,height: 1.3,color: Colours.c9),),
Text(model.users??'',style: TextStyle(fontSize: 12.w,height: 1.3,color: Colours.c9),),
// Spacer(),
Text(model.createTime??'',style: const TextStyle(fontSize: 12,height: 1.3,color: Colours.c9),)
Text(model.createTime??'',style: TextStyle(fontSize: 12.w,height: 1.3,color: Colours.c9),)
],
),
AbsorbPointer(
......@@ -57,10 +57,10 @@ class BuildItem extends StatelessWidget {
child: CustomRating(
max: 5,
score:model.rating!.toDouble() ,
star: const Star(
star: Star(
progress: 7,
fillColor: AppTheme.primary,
size: 12,
size: 12.w,
emptyColor: Colours.cE2,
), onRating: (double ) {},
),
......@@ -71,7 +71,7 @@ class BuildItem extends StatelessWidget {
],
),
Gaps.vGaps15,
Text(model.comments??'',style: const TextStyle(fontSize: 14,height: 1.5,color: Colours.c3),)
Text(model.comments??'',style: TextStyle(fontSize: 14.w,height: 1.5,color: Colours.c3),)
],
),
),
......
......@@ -152,7 +152,7 @@ class BookshopController extends GetxController {
);
// 如果是刷新 清理数据
if (isRefresh) carts.clear();
carts.addAll(_test());
// carts.addAll(_test());
carts.addAll(result);
_page ++;
_noMore = result.length < _limit;
......@@ -186,9 +186,11 @@ class BookshopController extends GetxController {
List<CourseModel> _test(){
return [
CourseModel(bookName: '哈1',bookId: 111,vipPrice: '12.33',authors: 'John',status: 1),
CourseModel(bookName: '哈1',bookId: 111,vipPrice: '100.33',authors: 'John',status: 1),
CourseModel(bookName: '哈2',bookId: 123,vipPrice: '12.00',authors: 'json',status: 1),
CourseModel(bookName: '哈3',bookId: 11,vipPrice: '12.43',authors: 'hash',status: 1),
CourseModel(bookName: '哈3',bookId: 11,vipPrice: '12.43',authors: 'hash',status: 1),
CourseModel(bookName: '哈3',bookId: 11,vipPrice: '12.43',authors: 'hash',status: 1),
];
}
......
part of change_pwd;
class ChangePwdController extends GetxController {
final UserInfoModel userInfo;
ChangePwdController(this.userInfo);
// 新密码
final TextEditingController pwdInput = TextEditingController();
// 确认密码
......@@ -40,7 +41,14 @@ class ChangePwdController extends GetxController {
}
Future <bool> changePwd() async {
final result = await MineAPI.changePwd(password: EncryptUtil.encodeMd5(EncryptUtil.encodeMd5(pwdInput.text)), rePassword: EncryptUtil.encodeMd5(EncryptUtil.encodeMd5(pwd2Input.text)));
final result = await MineAPI.changePwd(
password: EncryptUtil.encodeMd5(EncryptUtil.encodeMd5(pwdInput.text)),
rePassword: EncryptUtil.encodeMd5(EncryptUtil.encodeMd5(pwd2Input.text))
);
if(result){
userInfo.password = EncryptUtil.encodeMd5(EncryptUtil.encodeMd5(pwdInput.text));
update();
}
return result;
}
......
......@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../../apis/index.dart';
import '../../models/index.dart';
import '../../routes/index.dart';
import '../../widgets/index.dart';
......
part of change_pwd;
class ChangePwdPage extends StatefulWidget {
final String type;
final UserInfoModel userInfo;
const ChangePwdPage({
Key? key ,
required this.type,
required this.userInfo,
}) : super(key: key);
// const ResetPwdPage({Key? key}) : super(key: key);
......@@ -17,11 +17,11 @@ class _ChangePwdPageState extends State<ChangePwdPage> {
Widget build(BuildContext context) {
final currentContext = context;
return GetBuilder<ChangePwdController>(
init: ChangePwdController(),
init: ChangePwdController(widget.userInfo),
builder: (controller) =>Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(widget.type =='1'?'设置密码':'修改密码'),
title: Text(widget.userInfo.password.toString().isEmpty?'设置密码':'修改密码'),
),
body: Container(
margin: EdgeInsets.only(left: 10.w,top: 15.w,right: 10.w),
......@@ -117,7 +117,7 @@ class _ChangePwdPageState extends State<ChangePwdPage> {
),
Gaps.vGaps40,
CustomGradientButton(
text: widget.type == '1'?'确认':'确认修改',
text: widget.userInfo.password.toString().isEmpty ?'确认':'确认修改',
isEnabled: controller.enable,
onPressed: () async {
Tools.unfocus();
......
part of credit_points;
class CreditPointController extends GetxController {
final String price;
CreditPointController(this.price);
CreditPointModel creditPointModel = CreditPointModel();
bool use = false;
@override
void onReady() {
_getCreditPoints(price: price);
super.onReady();
}
void setUse(){
use = !use;
update();
}
void _getCreditPoints({
required String price
}) async {
creditPointModel = await ShopAPI.creditPoints(price: price);
update();
}
}
......@@ -6,6 +6,12 @@ import 'package:flutter/material.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
import 'package:go_router/go_router.dart';
part 'view.dart';
\ No newline at end of file
import '../../apis/index.dart';
import '../../models/index.dart';
import '../book_pay/index.dart';
part 'view.dart';
part 'controller.dart';
\ No newline at end of file
part of library;
class LibraryContentController extends GetxController {
final EasyRefreshController refreshController = EasyRefreshController(
controlFinishLoad: true,
controlFinishRefresh: true,
);
// 图书列表数据
List<CourseModel> books = [];
final int _limit = 20;
int _page = 1;
bool _noMore = false;
@override
void onClose() {
refreshController.dispose();
super.onClose();
}
/// 收藏 与 取消收藏
void love({
required String bookId,
required num isCollection
}) async {
if (isCollection == 0){
isCollection = 1;
}
else{
isCollection = 0;
}
bool result = await CommonAPI.love(bookId: bookId, love: isCollection.toString());
if (result) {
onRefresh();
}
}
/// 获取图书列表数据
Future<void> _getBooks([bool isRefresh = false]) async {
if (isRefresh) _page = 1;
// 网路请求
final result = await LibraryAPI.books(
page: _page,
limit: _limit, categoryId: '',
);
// 如果是刷新 清理数据
if (isRefresh) books.clear();
books.addAll(result);
_page ++;
_noMore = result.length < _limit;
update();
}
void onRefresh() async {
try {
await _getBooks(true);
refreshController.finishRefresh(IndicatorResult.success);
refreshController.resetFooter();
} catch (error) {
refreshController.finishRefresh(IndicatorResult.fail);
}
}
void onLoading() async {
if (_noMore) {
refreshController.finishLoad(IndicatorResult.noMore);
return;
}
try {
await _getBooks();
refreshController.finishLoad();
} catch (error) {
refreshController.finishLoad(IndicatorResult.fail);
}
}
}
\ No newline at end of file
......@@ -9,11 +9,39 @@ class LibraryController extends GetxController with GetTickerProviderStateMixin{
// 广告数组
List<AdModel> ads = [];
late LabelModel selectedLabel = LabelModel();
// 选中标签
late FilterModel selectedLabel = FilterModel();
// 选中分类
late FilterModel selectedCategory = FilterModel();
// 选中是否收费
late FilterModel selectedFree = FilterModel();
late FilterModel selectedDown = FilterModel();
late TabController tabController = TabController(length:categories.length, vsync: this);
final EasyRefreshController refreshController = EasyRefreshController(
controlFinishLoad: true,
controlFinishRefresh: true,
);
// 图书列表数据
List<CourseModel> books = [];
List<FilterModel> filterCategories = [];
List<FilterModel> filterLabels = [];
List<FilterModel> filterFree = [
FilterModel(id: '0', name: '收费',selected: false),
FilterModel(id: '1', name: '免费',selected: false)
];
List<FilterModel> filterDown = [
FilterModel(id: 'read_num', name: '读过'),
FilterModel(id: 'rating', name: '评分')
];
final int _limit = 20;
int _page = 1;
bool _noMore = false;
late AnimationController _controller;
......@@ -54,23 +82,89 @@ class LibraryController extends GetxController with GetTickerProviderStateMixin{
// 获取标签数据
_getLabels();
_getAds();
onRefresh();
super.onReady();
}
@override
void onClose() {
tabController.dispose();
refreshController.dispose();
super.onClose();
}
/// 重置
void resetFilter() {
for(FilterModel model in filterCategories){
model.selected = false;
}
filterCategories.first.selected = true;
for(FilterModel model in filterLabels){
model.selected = false;
}
filterLabels.first.selected = true;
for(FilterModel model in filterFree){
model.selected = false;
}
for(FilterModel model in filterDown){
model.selected = false;
}
update();
}
/// 确定
void sureFilter(){
WidgetsBinding.instance!.addPostFrameCallback((_) {
tabController.animateTo(3); // 你想要的标签索引
});
update();
for(FilterModel model in filterCategories){
if (model.selected){
selectedCategory = model;
}
}
for(FilterModel model in filterLabels){
if(model.selected){
selectedLabel= model;
}
}
for(FilterModel model in filterFree){
if(model.selected){
selectedFree= model;
}
}
void selectLabel(LabelModel model){
for (LabelModel m in labels){
for(FilterModel model in filterDown){
if(model.selected){
selectedDown= model;
}
}
onRefresh();
}
void selectLabel(FilterModel model){
for (FilterModel m in filterLabels){
m.selected = false;
}
model.selected = true;
selectedLabel = model;
update();
onRefresh();
}
void selectCategory(FilterModel model){
for (FilterModel m in filterCategories){
m.selected = false;
}
model.selected = true;
selectedCategory = model;
onRefresh();
}
/// 获取广告数据
......@@ -84,15 +178,88 @@ class LibraryController extends GetxController with GetTickerProviderStateMixin{
categories = await LibraryAPI.categories();
tabController.dispose();
tabController = TabController(length:categories.length, vsync: this);
categories.first.selected = true;
filterCategories = categories.map((model) {
return FilterModel(id: model.categoryId.toString(), name: model.name??'',selected: model.selected);
}).toList();
print('===========$filterCategories');
update();
}
/// 获取标签数据
void _getLabels() async {
labels = await LibraryAPI.labels();
selectedLabel = labels.first;
filterLabels = labels.map((model) {
return FilterModel(id: model.labelId.toString(), name: model.name??'',selected: model.selected);
}).toList();
selectedLabel = filterLabels.first;
selectedLabel.selected = true;
update(['label']);
}
/// 收藏 与 取消收藏
void love({
required String bookId,
required num isCollection
}) async {
if (isCollection == 0){
isCollection = 1;
}
else{
isCollection = 0;
}
bool result = await CommonAPI.love(bookId: bookId, love: isCollection.toString());
if (result) {
onRefresh();
}
}
/// 获取图书列表数据
Future<void> _getBooks([bool isRefresh = false]) async {
if (isRefresh) _page = 1;
// 网路请求
final result = await LibraryAPI.books(
page: _page,
limit: _limit,
categoryId: selectedCategory.id??'',
labelId: selectedLabel.id??'',
isFree: selectedFree.id??'',
sortField: selectedDown.id??''
);
// 如果是刷新 清理数据
if (isRefresh) books.clear();
books.addAll(result);
_page ++;
_noMore = result.length < _limit;
update();
}
void onRefresh() async {
try {
await _getBooks(true);
refreshController.finishRefresh(IndicatorResult.success);
refreshController.resetFooter();
} catch (error) {
refreshController.finishRefresh(IndicatorResult.fail);
}
}
void onLoading() async {
if (_noMore) {
refreshController.finishLoad(IndicatorResult.noMore);
return;
}
try {
await _getBooks();
refreshController.finishLoad();
} catch (error) {
refreshController.finishLoad(IndicatorResult.fail);
}
}
......
library library;
import 'package:azlistview/azlistview.dart';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter_book/apis/index.dart';
......@@ -14,7 +15,6 @@ import '../../models/index.dart';
import '../../routes/index.dart';
import '../../widgets/index.dart';
import '../course/index.dart';
import '../library_content/index.dart';
import '../study/index.dart';
......@@ -26,4 +26,3 @@ part 'widgets/content.dart';
part 'widgets/subject.dart';
part 'widgets/filter.dart';
part 'test.dart';
part 'content_controller.dart';
\ No newline at end of file
......@@ -35,40 +35,65 @@ class _LibraryPageState extends State<LibraryPage> {
return Stack(
children: [
Column(
mainAxisSize: MainAxisSize.max,
children: [
_buildTab(controller),
// _buildTab(controller),
Row(
children: [
Expanded(child: _buildCategory()),
GestureDetector(
onTap: (){
controller.setShow(controller.show);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10.w),
alignment: Alignment.center,
height: 38.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 12.w,
height: 12.w,
// color: Colors.red,
alignment: Alignment.center,
child: Image.asset(
'assets/images/filter.png',
),
),
Gaps.hGaps5,
Text('筛选',style: TextStyle(color: Colours.c9,fontSize: 14.w,height: 1.5),)
],
),
// width: 75,
),
)
],
),
_buildLabel(),
GetBuilder<LibraryContentController>(
init: LibraryContentController(),
builder:(contentController)=> Expanded(
Container(
// color: Colors.red,
child: Expanded(
child: CustomPullScrollView(
controller: contentController.refreshController,
onRefresh: contentController.onRefresh,
onLoading: contentController.onLoading,
child: CustomScrollView(
slivers: [
// 广告位
SliverToBoxAdapter(
child: Container(
color: Colors.red,
padding: EdgeInsets.symmetric(horizontal: 10.w),
child: BuildBanner(items: controller.ads,),
),
),
SliverFillRemaining(
child: TabBarView(
controller: controller.tabController,
children: List.generate(controller.categories.length, (index){
print('=======================================$index');
return LibraryContentPage(controller: contentController,);
})
),
),
],
controller: controller.refreshController,
// onRefresh: controller.onRefresh,
onLoading: controller.onLoading,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
controller.ads.isNotEmpty?Container(
color: Colors.cyan,
child: BuildBanner(items:controller.ads)
):const SizedBox(),
LibraryContentPage(controller: controller,)
],
),
),
),
),
),
)
],
),
Visibility(
......@@ -97,18 +122,46 @@ class _LibraryPageState extends State<LibraryPage> {
scrollDirection:Axis.horizontal ,
itemBuilder: (BuildContext context, int index){
return GestureDetector(
child: BuildLabelWidget(model: controller.labels[index],),
child: BuildLabelWidget(model: controller.filterLabels[index],),
onTap: (){
controller.selectLabel( controller.labels[index]);
controller.selectLabel( controller.filterLabels[index]);
},
);
},
itemCount: controller.labels.length,
itemCount: controller.filterLabels.length,
),
),
);
}
Widget _buildCategory(){
return Container(
height: 38,
child: GetBuilder<LibraryController>(
init: LibraryController(),
builder: (controller) =>ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index){
FilterModel model = controller.filterCategories[index];
return GestureDetector(
onTap: (){
controller.selectCategory(model);
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 10.w,horizontal: 10.w),
color: model.selected?const Color(0xFFC02D55).withOpacity(0.08):Colors.white,
alignment: Alignment.center,
child: Text(model.name??'',style: model.selected?TextStyle(fontSize: 14.w,color: AppTheme.primary,fontWeight: Fonts.medium,):TextStyle(fontSize: 14.w,color: Colours.c9,),),
),
);
},
itemCount: controller.filterCategories.length
)
),
);
}
PreferredSizeWidget _buildTab(LibraryController controller){
return PreferredSize(
preferredSize: Size.fromHeight(48.w),
......@@ -128,7 +181,7 @@ class _LibraryPageState extends State<LibraryPage> {
unselectedLabelStyle: TextStyle(color: Colours.c9,fontSize: 14.w,height: 1.5),
controller: controller.tabController,
isScrollable: true,
tabs: controller.categories.map((model){
tabs: controller.filterCategories.map((model){
return Tab(text: model.name);
}).toList(),
),
......
part of library;
class LibraryContentPage extends StatefulWidget {
final LibraryContentController controller;
final LibraryController controller;
// final CategoryModel categoryModel;
const LibraryContentPage({
Key? key,
......@@ -17,7 +17,7 @@ class _LibraryContentPageState extends State<LibraryContentPage> with AutomaticK
@override
Widget build(BuildContext context) {
return ListView.builder(
// shrinkWrap: true,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: widget.controller.books.length,
itemBuilder: (BuildContext context, int index) {
......
......@@ -18,13 +18,13 @@ class FilterPage extends StatefulWidget {
class _FilterPageState extends State<FilterPage> {
@override
Widget build(BuildContext context) {
List<FilterModel> categories = widget.controller.categories.map((model) {
return FilterModel(id: model.categoryId.toString(), name: model.name??'');
}).toList();
List<FilterModel> labels = widget.controller.labels.map((model) {
return FilterModel(id: model.labelId.toString(), name: model.name??'');
}).toList();
// List<FilterModel> categories = widget.controller.categories.map((model) {
// return FilterModel(id: model.categoryId.toString(), name: model.name??'');
// }).toList();
//
// List<FilterModel> labels = widget.controller.labels.map((model) {
// return FilterModel(id: model.labelId.toString(), name: model.name??'');
// }).toList();
return Container(
color: const Color(0xFF000000).withOpacity(0.5),
......@@ -39,10 +39,10 @@ class _FilterPageState extends State<FilterPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildWrapWidget('分类', categories),
_buildWrapWidget('标签', labels),
_buildWrapWidget('是否收费', [FilterModel(id: '0', name: '收费'),FilterModel(id: '1', name: '免费')]),
_buildWrapWidget('排序', [FilterModel(id: '0', name: '读过'),FilterModel(id: '1', name: '评分')]),
_buildWrapWidget('分类', widget.controller.filterCategories),
_buildWrapWidget('标签', widget.controller.filterLabels),
_buildWrapWidget('是否收费', widget.controller.filterFree),
_buildWrapWidget('排序', widget.controller.filterDown),
],
)
],
......@@ -58,7 +58,9 @@ class _FilterPageState extends State<FilterPage> {
children: [
Expanded(
child: GestureDetector(
onTap: widget.resetTap,
onTap: (){
widget.controller.resetFilter();
},
child: Container(
alignment: Alignment.center,
height: 35.w,
......@@ -105,8 +107,8 @@ class _FilterPageState extends State<FilterPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(left: 10,bottom: 10,top: 10),
child: Text(title,style: TextStyle(fontSize: 15,height:1.6,color: Colours.c3,fontWeight: Fonts.medium),)
margin: EdgeInsets.only(left: 10.w,bottom: 10.w,top: 10.w),
child: Text(title,style: TextStyle(fontSize: 15.w,height:1.6,color: Colours.c3,fontWeight: Fonts.medium),)
),
Wrap(
spacing: 10,
......@@ -116,9 +118,10 @@ class _FilterPageState extends State<FilterPage> {
children: data.map((model){
return GestureDetector(
onTap: (){
print('================================');
setState(() {
print('--------------------------------${model.selected}');
for (FilterModel model in data){
model.selected = false;
}
model.selected = !model.selected;
});
},
......@@ -126,17 +129,19 @@ class _FilterPageState extends State<FilterPage> {
height: 27,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(13.5),
color: model.selected?AppTheme.primary: Colours.cF4
color: model.selected?const Color(0xFFC02D55).withOpacity(0.08): Colours.cF4,
border: model.selected?Border.all(width: 0.5.w,color: AppTheme.primary):null
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal:15,vertical: 5),
child: model.name == '读过' || model.name == '评分'?Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(model.name,style: TextStyle(fontSize: 13,height: 1.4,color: model.selected?AppTheme.primary: Colours.c3),textAlign: TextAlign.center,),
Image.asset('assets/images/down.png'),
Text(model.name??'',style: TextStyle(fontSize: 13,height: 1.4,color: model.selected?AppTheme.primary: Colours.c3),textAlign: TextAlign.center,),
Image.asset(model.selected?'assets/images/filter_select.png':'assets/images/filter_unselect.png'),
],
):Text(model.name,style: TextStyle(fontSize: 13,height: 1.4,color: model.selected?AppTheme.primary: Colours.c3),textAlign: TextAlign.center,),
):Text(model.name??'',style: TextStyle(fontSize: 13,height: 1.4,color: model.selected?AppTheme.primary: Colours.c3),textAlign: TextAlign.center,),
),
),
);
......
......@@ -2,7 +2,7 @@ part of library;
class BuildLabelWidget extends StatelessWidget {
final LabelModel model;
final FilterModel model;
const BuildLabelWidget({
Key? key,
required this.model
......
// part of library_content;
//
// class LibraryContentController extends GetxController {
//
// final CategoryModel categoryModel;
// late LabelModel labelModel;
// LibraryContentController(this.categoryModel, this.labelModel);
//
// final EasyRefreshController refreshController = EasyRefreshController(
// controlFinishLoad: true,
// controlFinishRefresh: true,
// );
//
// // 广告数组
// List<AdModel> ads = [];
//
// final int _limit = 10;
// int _page = 1;
// bool _noMore = false;
//
//
// // 图书列表数据
// List<CourseModel> books = [];
//
//
// @override
// void onReady() {
//
// super.onReady();
// }
//
//
// @override
// void onClose() {
// refreshController.dispose();
// super.onClose();
// }
//
//
// /// 收藏 与 取消收藏
// void love({
// required String bookId,
// required num isCollection
// }) async {
// if (isCollection == 0){
// isCollection = 1;
// }
// else{
// isCollection = 0;
// }
// bool result = await CommonAPI.love(bookId: bookId, love: isCollection.toString());
// if (result) {
// onRefresh();
// }
// }
//
// /// 获取图书列表数据
// Future<void> _getBooks([bool isRefresh = false]) async {
// if (isRefresh) _page = 1;
// // 网路请求
// final result = await LibraryAPI.books(
// page: _page,
// limit: _limit,
// categoryId: categoryModel.categoryId.toString(),
// labelId: labelModel.labelId.toString()
// );
// // 如果是刷新 清理数据
// if (isRefresh) books.clear();
// books.addAll(result);
// _page ++;
// _noMore = result.length < _limit;
// update();
//
// }
//
// void onRefresh() async {
// try {
// await _getBooks(true);
// refreshController.finishRefresh(IndicatorResult.success);
// refreshController.resetFooter();
// } catch (error) {
// refreshController.finishRefresh(IndicatorResult.fail);
// }
// }
//
// void onLoading() async {
// if (_noMore) {
// refreshController.finishLoad(IndicatorResult.noMore);
// return;
// }
// try {
// await _getBooks();
// refreshController.finishLoad();
// } catch (error) {
// refreshController.finishLoad(IndicatorResult.fail);
// }
// }
//
// }
\ No newline at end of file
// library library_content;
//
// import 'package:easy_refresh/easy_refresh.dart';
// import 'package:flutter/material.dart';
// import 'package:get/get.dart';
// import 'package:get/get_state_manager/src/simple/get_controllers.dart';
// import 'package:go_router/go_router.dart';
//
// import '../../apis/index.dart';
// import '../../models/index.dart';
// import '../../routes/index.dart';
// import '../../widgets/index.dart';
// import '../course/index.dart';
// import '../library/index.dart';
//
// part 'view.dart';
// part 'controller.dart';
\ No newline at end of file
// part of library_content;
//
// class LibraryContentPage extends StatefulWidget {
// final CategoryModel categoryModel;
// final LabelModel labelModel;
// final String tag;
// const LibraryContentPage({
// Key? key,
// required this.categoryModel,
// required this.labelModel,
// required this.tag
// }) : super(key: key);
//
// @override
// State<LibraryContentPage> createState() => _LibraryContentPageState();
// }
//
// class _LibraryContentPageState extends State<LibraryContentPage> {
// @override
// Widget build(BuildContext context) {
// return GetBuilder<LibraryContentController>(
// // tag: widget.tag,
// init: LibraryContentController(widget.categoryModel,widget.labelModel),
// builder: (controller) => CustomPullScrollView(
// controller: controller.refreshController,
// onRefresh: controller.onRefresh,
// onLoading: controller.onLoading,
// child: ListView.builder(
// itemCount: controller.books.length+1,
// itemBuilder: (BuildContext context, int index) {
// if (index == 0){
// return Container(
// color: Colors.red,
// padding: const EdgeInsets.symmetric(horizontal: 10),
// child: BuildBanner(items: controller.ads,),
// );
// }
// else {
// CourseModel model = controller.books[index-1];
// return GestureDetector(
// onTap: (){
// context.pushNamed(Routes.bookDetail,queryParameters: {'book_id':model.bookId.toString()});
// },
// child: LibraryCell(model: model,onTap: (){
// controller.love(bookId: model.bookId.toString(), isCollection: model.isCollection!);
// },),
// );
// }
// },
// ),
// ),
// );
// }
// // @override
// // bool get wantKeepAlive => true;
// }
......@@ -60,12 +60,23 @@ class LoginController extends GetxController {
}
void setCanClick(){
if (ValidatorTool.isValidPhoneNumber(phoneInput.text) && ValidatorTool.isValidPassword(passwordInput.text)){
_enable = true;
if (loginType == 0){
if (ValidatorTool.isValidPhoneNumber(phoneInput.text) && ValidatorTool.isValidPassword(passwordInput.text)){
_enable = true;
}
else{
_enable = false;
}
}
else{
_enable = false;
else {
if (ValidatorTool.isValidPhoneNumber(phoneInput.text) && ValidatorTool.isValidCode(codeInput.text)){
_enable = true;
}
else{
_enable = false;
}
}
update();
}
......@@ -144,6 +155,10 @@ class LoginController extends GetxController {
}
void sendCode() async {
if (!agree) {
Toast.show('请先阅读并同意《用户协议》和《隐私政策》');
return;
}
final result = await AccountAPI.sendCode(phone: phoneInput.text, type: 'login');
if (result){
Toast.show('发送成功');
......
......@@ -113,6 +113,9 @@ class _LoginPageState extends State<LoginPage> {
hintText: '请输入验证码',
keyboardType: TextInputType.number,
controller: controller.codeInput,
onChanged: (text){
controller.setCanClick();
},
),
Positioned(
right: 10.w,
......
......@@ -11,6 +11,7 @@ import '../../routes/index.dart';
import '../../store/index.dart';
import '../book_shop/index.dart';
import '../course/index.dart';
import '../web/index.dart';
......
......@@ -19,7 +19,7 @@ class MineController extends GetxController {
@override
void onReady() {
_getAds();
_getNums();
getNums();
getInfo();
super.onReady();
}
......@@ -31,7 +31,7 @@ class MineController extends GetxController {
}
/// 消息未读数
void _getNums() async {
void getNums() async {
num = await CommonAPI.num();
update();
}
......
......@@ -42,9 +42,13 @@ class _MinePageState extends State<MinePage> {
onPressed: () => context.pushNamed(Routes.set),
),
GestureDetector(
onTap: (){
context.pushNamed(Routes.msgs);
// controller.logout(context);
onTap: () async{
final result = await context.pushNamed(Routes.msgs);
print('---------------------------------1111$result');
if (result == true){
controller.getNums();
}
},
child: badges.Badge(
position: badges.BadgePosition.topEnd(top: -5, end: 0),
......
part of pay_coupon;
class PayCouponController extends GetxController {
class PayCouponController extends GetxController with GetSingleTickerProviderStateMixin{
late TabController tabController;
List <Widget>tabs = [
const Tab(text: '可用',),
const Tab(text: '不可用',),
];
final String tag;
final BookPayController payController;
PayCouponController(this.tag,this.payController){
// tabs = [
// Tab(text: '可用(${payController.couponNumModel.availableNum})',),
// Tab(text: '不可用(${payController.couponNumModel.unavailableNum})',),
// ];
}
// List <Widget>tabs = [];
// late TabController tabController = TabController(length:tabs.length, vsync: this);
final EasyRefreshController refreshController = EasyRefreshController(
controlFinishLoad: true,
controlFinishRefresh: true,
);
CouponListModel couponListModel = CouponListModel();
// 优惠券
List <CouponModel> coupons = [];
final int _limit = 10;
int _page = 1;
bool _noMore = false;
Future<void> _getCoupon([bool isRefresh = false]) async {
if (isRefresh) _page = 1;
// 网路请求
final result = await ShopAPI.coupon(
page: _page,
limit: _limit,
type: tag,
price: payController.finalPrice.toString()
);
for(CouponModel model in result.list!) {
print('================================${tag}');
model.type = num.parse(tag);
}
// 如果是刷新 清理数据
if (isRefresh) coupons.clear();
coupons.addAll(result.list!);
_page ++;
_noMore = result.list!.length < _limit;
update();
}
void onRefresh() async {
try {
await _getCoupon(true);
refreshController.finishRefresh(IndicatorResult.success);
refreshController.resetFooter();
} catch (error) {
print('--------------------------------$error');
refreshController.finishRefresh(IndicatorResult.fail);
}
}
void onLoading() async {
if (_noMore) {
refreshController.finishLoad(IndicatorResult.noMore);
return;
}
try {
await _getCoupon();
refreshController.finishLoad();
} catch (error) {
refreshController.finishLoad(IndicatorResult.fail);
}
}
}
\ No newline at end of file
library pay_coupon;
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter_book/pages/user_coupon/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:go_router/go_router.dart';
import '../../apis/index.dart';
import '../../models/index.dart';
import '../../theme.dart';
import '../../utils/index.dart';
import '../book_pay/index.dart';
part 'view.dart';
part 'controller.dart';
\ No newline at end of file
part 'controller.dart';
part 'widgets/item.dart';
......@@ -3,18 +3,34 @@ part of pay_coupon;
class PayCouponPage extends StatefulWidget {
const PayCouponPage({Key? key}) : super(key: key);
final BookPayController payController;
const PayCouponPage({
Key? key,
required this.payController
}) : super(key: key);
@override
State<PayCouponPage> createState() => _PayCouponPageState();
}
class _PayCouponPageState extends State<PayCouponPage> {
class _PayCouponPageState extends State<PayCouponPage> with SingleTickerProviderStateMixin{
List <Widget> tabs= [];
late TabController tabController;
@override
void initState() {
tabs = [
Tab(text: '可用(${widget.payController.couponNumModel.availableNum})',),
Tab(text: '不可用(${widget.payController.couponNumModel.unavailableNum})',),
];
tabController = TabController(length:tabs.length, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
return GetBuilder<PayCouponController>(
init: PayCouponController(),
builder: (controller) =>Scaffold(
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('选择优惠券'),
......@@ -22,49 +38,73 @@ class _PayCouponPageState extends State<PayCouponPage> {
body: Column(
children: [
TabBar(
labelColor: AppTheme.primary,
// isScrollable: true,
labelColor: Colours.c3,
labelStyle: TextStyle(fontSize: 15.w,height: 1.4,fontWeight: Fonts.medium),
unselectedLabelColor: Colours.c9,
unselectedLabelStyle: TextStyle(fontSize: 15.w,height: 1.4),
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: AppTheme.primary,
tabs:controller.tabs,
tabs:tabs,
physics: const NeverScrollableScrollPhysics(),
controller: controller.tabController,
controller: tabController,
),
Expanded(
child: TabBarView(
controller: controller.tabController,
children: [
],
controller: tabController,
children: List.generate(tabs.length, (index){
return CouponPage(tag:'${1-index}',payController: widget.payController,);
})
),
),
],
),
),
);
);
}
}
class CouponPage extends StatefulWidget {
const CouponPage({Key? key}) : super(key: key);
final String tag;
final BookPayController payController;
const CouponPage({
Key? key,
required this.tag,
required this.payController
}) : super(key: key);
@override
State<CouponPage> createState() => _CouponPageState();
}
class _CouponPageState extends State<CouponPage> {
class _CouponPageState extends State<CouponPage> with AutomaticKeepAliveClientMixin{
@override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (BuildContext context, int index){
// return BuildItem(model: ,);
},
itemCount: 2,
return GetBuilder<PayCouponController>(
tag: widget.tag,
init: PayCouponController(widget.tag,widget.payController),
builder: (controller) =>CustomPullScrollView(
controller: controller.refreshController,
onRefresh: controller.onRefresh,
onLoading: controller.onLoading,
child: ListView.builder(
itemBuilder: (BuildContext context, int index){
CouponModel model = controller.coupons[index];
return BuildItem(model:model,useTap: (){
widget.payController.setUseCoupon(model);
context.pop();
},);
},
itemCount: controller.coupons.length,
),
),
);
}
@override
bool get wantKeepAlive => true;
}
part of pay_coupon;
class BuildItem extends StatelessWidget {
final CouponModel model;
final void Function()? useTap;
const BuildItem({
Key? key,
required this.model,
required this.useTap
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(left: 10.w,top: 10.w,right: 10.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.w),
color: Colors.white,
boxShadow: [
BoxShadow(
color: const Color(0xFFC7C7C7).withOpacity(0.5),
offset: Offset(3.w, 0),
blurRadius: 10.w,
spreadRadius: 0.w,
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(
children: [
Image.asset(model.type ==1?'assets/images/coupon_yes.png':'assets/images/coupon_no.png'),
Positioned(
left: 0.w,
right: 0.w,
bottom: 0.w,
top: 0.w,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: '¥',
style: TextStyle(fontSize: 15.w,fontWeight: Fonts.boldSemi,height: 1.5,color: model.type ==1?Colors.white:Colours.cC8)
),
TextSpan(
text: model.reducedPrice??'',
style: TextStyle(fontSize: 40.w,fontWeight: Fonts.boldSemi,height: 1.5,color: model.type ==1?Colors.white:Colours.cC8)
),
]
),
),
Text('满${model.normPrice}可用',style: TextStyle(fontSize: 11.w,height: 1.5,color: model.type ==1?Colors.white:Colours.cC8),)
],
),
)
],
),
Expanded(
child: Container(
margin: EdgeInsets.only(left:15.w,right: 15.w ),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(model.couponName??'',style: TextStyle(fontSize: 16.w,fontWeight: Fonts.medium,height: 1.5,color: model.type ==1?Colours.c3:Colours.c9),),
Gaps.vGaps5,
Text('满${model.normPrice}${model.reducedPrice}元',style: TextStyle(fontSize: 12.w,height: 1.5,color: Colours.c9),),
Gaps.vGaps5,
Text('有效至:${model.endTime}',style: TextStyle(fontSize: 12.w,height: 1.5,color: Colours.c9),),
],
),
if (model.type == 1) GestureDetector(
onTap: useTap,
child: Container(
width: 65.w,
height: 24.w,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.w),
color: Colors.white,
border: Border.all(width: 1.w,color: AppTheme.primary)
),
child: Text('立即使用',style: TextStyle(fontSize: 12.w,fontWeight: Fonts.medium,color: AppTheme.primary),),
),
) else const SizedBox()
],
),
),
)
],
)
);
}
}
......@@ -52,7 +52,9 @@ class ResetPwdController extends GetxController {
);
if (result){
if (context.mounted){
context.goNamed(Routes.login);
// context.goNamed(Routes.login);
context.pop();
context.pop();
}
}
else{
......
......@@ -76,7 +76,6 @@ class _ResetPwdPageState extends State<ResetPwdPage> {
isEnabled: controller.enable,
onPressed: () {
controller.resetPassword(context);
// context.goNamed(Routes.login);
},
)
],
......
......@@ -2,6 +2,7 @@ library splash_page;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_book/apis/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:go_router/go_router.dart';
......
......@@ -15,11 +15,13 @@ class _SplashPageState extends State<SplashPage> {
Future.wait([
Future.delayed(const Duration(seconds: 2))
]).whenComplete(() async {
// final userModel = await AccountAPI.login(phone: '18337678567', password: '013790d7eb52197bead4c757ebfae7cf', type: '1');
// Console.log('++++++++++++++++');
// Console.log(userModel.name);
// context.goNamed(Routes.main);
context.pushReplacementNamed(Routes.ad);
final ads = await CommonAPI.list(type: '1');
if (ads.isNotEmpty){
context.pushReplacementNamed(Routes.ad,extra: ads);
}
else {
context.pushReplacementNamed(Routes.main);
}
});
......@@ -47,10 +49,10 @@ class _SplashPageState extends State<SplashPage> {
),
)
),
Expanded(
flex: 2,
child: Center(child: CupertinoActivityIndicator(),),
)
// Expanded(
// flex: 2,
// child: Center(child: CupertinoActivityIndicator(),),
// )
],
),
);
......
part of study_report;
class StudyReportController extends GetxController {
final String bookId;
StudyReportController(this.bookId);
ReportModel model = ReportModel();
@override
void onReady() {
_getReport();
super.onReady();
}
void _getReport() async {
model = await LibraryAPI.report(bookId: bookId);
update();
}
}
\ No newline at end of file
library study_report;
import 'package:flutter/material.dart';
import 'package:flutter_book/apis/index.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get_state_manager/src/simple/get_controllers.dart';
import 'package:get/get_state_manager/src/simple/get_state.dart';
import '../../models/index.dart';
part 'view.dart';
part 'widgets/card.dart';
\ No newline at end of file
part 'widgets/card.dart';
part 'controller.dart';
\ No newline at end of file
part of study_report;
class BuildCard extends StatelessWidget {
const BuildCard({Key? key}) : super(key: key);
final ReportModel model;
const BuildCard({
Key? key,
required this.model
}) : super(key: key);
@override
Widget build(BuildContext context) {
......@@ -10,6 +14,8 @@ class BuildCard extends StatelessWidget {
Container(
child: Image.asset(
'assets/images/report_bg.png',
width: double.infinity,
fit: BoxFit.contain,
),
),
Positioned(
......@@ -27,13 +33,13 @@ class BuildCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('恰如其分的孤独',style: TextStyle(fontSize: 20.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),),
Text(model.bookName??'',style: TextStyle(fontSize: 20.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),),
Gaps.vGaps15,
Row(
children: [
Text('学习总进度',style: TextStyle(fontSize: 13.w,height: 1.4,color: Colors.white),),
Gaps.hGaps15,
Text('4.98%',style: TextStyle(fontSize: 16.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),),
Text(model.progress??'',style: TextStyle(fontSize: 16.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),),
]
),
Gaps.vGaps10,
......@@ -41,20 +47,20 @@ class BuildCard extends StatelessWidget {
children: [
Text('学习总时长',style: TextStyle(fontSize: 13.w,height: 1.4,color: Colors.white),),
Gaps.hGaps15,
Text('30分钟',style: TextStyle(fontSize: 16.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),),
Text('${model.readSecond??''}分钟',style: TextStyle(fontSize: 16.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),),
]
),
Gaps.vGaps10,
Text('上次读到',style: TextStyle(fontSize: 13.w,height: 1.4,color: Colors.white),),
Gaps.vGaps5,
Text('第3章 情节…情节…情节情节情节情节',style: TextStyle(fontSize: 16.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),maxLines: 1,overflow: TextOverflow.ellipsis,),
Text(model.lastChapter??'',style: TextStyle(fontSize: 16.w,height: 1.4,color: Colors.white,fontWeight: Fonts.medium),maxLines: 1,overflow: TextOverflow.ellipsis,),
]
),
),
Container(
height: 120.w,
width: 100.w,
color: Colors.lime,
child: CustomImage.asset(url: model.img??''),
)
],
),
......
......@@ -7,12 +7,22 @@ class CoinRechargeController extends GetxController {
PayModel(type: 1, name: '微信', icon: 'assets/images/pay_wechat.png', selected: true),
PayModel(type: 2, name: '支付宝', icon: 'assets/images/pay_ali.png', selected: false),
];
List<CoinModel> data = [];
late CoinModel rechargeModel = CoinModel();
// 支付方式
late PayModel _payModel = pays.first;
PayModel get payModel => _payModel;
@override
void onReady() {
_getlist();
super.onReady();
}
void setPayModel(PayModel payModel){
for (PayModel model in pays) {
if (model.type == payModel.type){
......@@ -25,4 +35,29 @@ class CoinRechargeController extends GetxController {
}
update();
}
void choose(CoinModel coinModel){
for (CoinModel model in data) {
model.selected = (model == coinModel);
}
rechargeModel = coinModel;
update();
}
void _getlist()async{
String type = '';
if(Platform.isIOS){
type = 'ios';
}
if(Platform.isAndroid){
type = 'android';
}
final result = await MineAPI.coinsRechargeList(type: type);
data = result;
update();
}
}
\ No newline at end of file
......@@ -2,11 +2,14 @@ library recharge;
import 'package:flutter/material.dart';
import 'package:flutter_book/apis/index.dart';
import 'package:flutter_book/models/index.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:get/get_state_manager/src/simple/get_controllers.dart';
import 'package:go_router/go_router.dart';
import '../../models/shop.dart';
import '../../utils/index.dart';
import '../../widgets/index.dart';
import '../book_pay/index.dart';
......
......@@ -14,74 +14,76 @@ class _CoinRechargePageState extends State<CoinRechargePage> {
Widget build(BuildContext context) {
return GetBuilder<CoinRechargeController>(
init: CoinRechargeController(),
builder:(controller) => Container(
// height: 100,
// color: Colors.amberAccent,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.symmetric(vertical: 17),
width: double.infinity,
margin: EdgeInsets.fromLTRB(10, 10, 10, 0),
child: Container(
color: Colors.red,
child:Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('紫荆币充值',textAlign:TextAlign.center),
],
),
Positioned(
right: 0,
top: 0,
child: Container(
width: 20,
height: 20,
color: Colors.green,
builder:(controller) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
color: Colors.white,
padding: EdgeInsets.symmetric(vertical: 17.w),
width: double.infinity,
margin: EdgeInsets.fromLTRB(10.w, 0.w, 10.w, 0.w),
child: Container(
// color: Colors.red,
child:Stack(
children: [
const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('紫荆币充值',textAlign:TextAlign.center),
],
),
Positioned(
right: 0.w,
top: 0.w,
child: GestureDetector(
onTap: (){
context.pop();
},
child: SizedBox(
width: 20.w,
height: 20.w,
child: Image.asset('assets/images/close.png'),
),
)
],
)
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child: _buildAudioGridView()
),
)
],
)
),
Gaps.vGaps15,
_buildListView(controller),
Gaps.vGaps15,
Container(
margin: EdgeInsets.symmetric(horizontal:15),
child: CustomGradientButton(
text: '立即充值',
isEnabled: true,
onPressed: () {
// context.goNamed(Routes.login);
},
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 20.w),
child: _buildAudioGridView(controller)
),
Gaps.vGaps15,
_buildListView(controller),
Gaps.vGaps15,
Container(
margin: EdgeInsets.symmetric(horizontal:15.w),
child: CustomGradientButton(
text: '立即充值${controller.rechargeModel.priceName??''}',
isEnabled: true,
onPressed: () {
// context.goNamed(Routes.login);
},
),
Gaps.vGaps15,
RichText(text: TextSpan(
children: [
TextSpan(text: '充值即代表同意',style: TextStyle(fontSize: 13.w,height: 1.5,color: Colours.c9)),
TextSpan(text: '《用户充值协议》',style: TextStyle(fontSize: 13.w,height: 1.5,color: Color(0xFF2A82D9))),
]
)),
Gaps.vGaps15
],
),
),
Gaps.vGaps15,
RichText(text: TextSpan(
children: [
TextSpan(text: '充值即代表同意',style: TextStyle(fontSize: 13.w,height: 1.5,color: Colours.c9)),
TextSpan(text: '《用户充值协议》',style: TextStyle(fontSize: 13.w,height: 1.5,color: Color(0xFF2A82D9))),
]
)),
Gaps.vGaps15
],
),
);
}
Widget _buildAudioGridView(){
Widget _buildAudioGridView(CoinRechargeController controller){
return GridView.builder(
// padding: const EdgeInsets.only(left: 13,top: 10),
physics: NeverScrollableScrollPhysics(),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
......@@ -90,23 +92,29 @@ class _CoinRechargePageState extends State<CoinRechargePage> {
childAspectRatio: 2
),
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(8.w),
border: Border.all(width: 0.5.w,color: Color(0xFFDADADA))
),
CoinModel model = controller.data[index];
return GestureDetector(
onTap: (){
controller.choose(model);
},
child: Container(
decoration: BoxDecoration(
color: model.selected?AppTheme.primary.withOpacity(0.1):Colors.white,
borderRadius: BorderRadius.circular(8.w),
border: Border.all(width: 0.5.w,color: model.selected?AppTheme.primary:const Color(0xFFDADADA))
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('42紫荆币',style: TextStyle(color: Colours.c3,fontSize: 14,height: 1.5),),
Text('6元',style: TextStyle(color: Colours.c9,fontSize: 11,height: 1.5),),
],
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(model.beanName??'',style: TextStyle(color: model.selected?AppTheme.primary:Colours.c3,fontSize: 14.w,height: 1.5),),
Text(model.priceName??'',style: TextStyle(color: model.selected?AppTheme.primary:Colours.c9,fontSize: 11.w,height: 1.5),),
],
),
),
);
},
itemCount: 6,
itemCount: controller.data.length,
);
}
Widget _buildListView(CoinRechargeController controller){
......
......@@ -31,7 +31,7 @@ class UserCouponController extends GetxController {
_getCoupon();
}
/// 获取课程内图书列表
/// 获取我的优惠券
Future<void> _getCoupon([bool isRefresh = false]) async {
if (isRefresh) _page = 1;
// 网路请求
......
......@@ -8,6 +8,7 @@ import 'package:flutter_book/utils/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:go_router/go_router.dart';
import '../../models/index.dart';
......
......@@ -11,36 +11,42 @@ class UserCouponPage extends StatefulWidget {
class _UserCouponPageState extends State<UserCouponPage> {
@override
Widget build(BuildContext context) {
return GetBuilder<UserCouponController>(
init: UserCouponController(),
builder:(controller) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('优惠券'),
),
body: CustomPullScrollView(
controller: controller.refreshController,
onRefresh: controller.onRefresh,
onLoading: controller.onLoading,
child: ListView.builder(
itemBuilder: (BuildContext context, int index){
if (index == controller.coupons.length){
return GestureDetector(
onTap: (){
controller.getOverCoupons();
},
child: Container(
height: 40.w,
color: Colors.cyan,
child: Text('过期优惠券'),
),
);
}
else {
return BuildItem(model: controller.coupons[index],);
}
},
itemCount: controller.coupons.length +1,
return WillPopScope(
onWillPop: () async {
context.pop(true);
return false;
},
child: GetBuilder<UserCouponController>(
init: UserCouponController(),
builder:(controller) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('优惠券'),
),
body: CustomPullScrollView(
controller: controller.refreshController,
onRefresh: controller.onRefresh,
onLoading: controller.onLoading,
child: ListView.builder(
itemBuilder: (BuildContext context, int index){
if (index == controller.coupons.length){
return GestureDetector(
onTap: (){
controller.getOverCoupons();
},
child: Container(
height: 40.w,
color: Colors.cyan,
child: Text('过期优惠券'),
),
);
}
else {
return BuildItem(model: controller.coupons[index],);
}
},
itemCount: controller.coupons.length +1,
),
),
),
),
......
......@@ -65,7 +65,7 @@ class BuildItem extends StatelessWidget {
Gaps.vGaps5,
Text('满${model.normPrice}${model.reducedPrice}元',style: TextStyle(fontSize: 12.w,height: 1.5,color: Colours.c9),),
Gaps.vGaps5,
Text(model.endTime??'',style: TextStyle(fontSize: 12.w,height: 1.5,color: Colours.c9),),
// Text(model.endTime??'',style: TextStyle(fontSize: 12.w,height: 1.5,color: Colours.c9),),
],
),
Container(
......
......@@ -17,30 +17,19 @@ class _UserDiscussPageState extends State<UserDiscussPage> {
centerTitle: true,
title: const Text('讨论'),
),
body: Container(
color: Colors.transparent,
child: CustomPullScrollView(
controller: controller.refreshController,
// onRefresh: controller.onRefresh,
onLoading: controller.onLoading,
child:SingleChildScrollView(
child: Container(
margin: EdgeInsets.all(10.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.w),
color: Colors.white,
boxShadow: [
BoxShadow(
color: const Color(0xFFC7C7C7).withOpacity(0.5),
offset: Offset(3.w, 0),
blurRadius: 10.w,
spreadRadius: 0.w,
),
],
),
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(left: 22.5.w,top: 16.w),
child: Text('共${controller.discuss.length}本书',style: TextStyle(fontSize: 13.w,height: 1.5,color: Colours.c6,fontWeight: Fonts.medium),)
),
Expanded(
child: CustomPullScrollView(
controller: controller.refreshController,
onRefresh: controller.onRefresh,
onLoading: controller.onLoading,
child:ListView.builder(
itemBuilder: (BuildContext context, int index){
return GestureDetector(
onTap: (){
......@@ -50,10 +39,10 @@ class _UserDiscussPageState extends State<UserDiscussPage> {
);
},
itemCount: controller.discuss.length,
),
)
),
)
),
),
],
),
),
);
......
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论