425 lines
15 KiB
Dart
425 lines
15 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:odf/bean/search_list_bean.dart';
|
||
import 'package:odf/tools/machine/machine_details_page.dart';
|
||
import 'package:odf/tools/search/search_model.dart';
|
||
|
||
import '../../bean/new_search_bean.dart';
|
||
import '../../bean/new_search_room_bean.dart';
|
||
import '../machine/machine_page.dart';
|
||
|
||
class SearchPage extends StatefulWidget {
|
||
const SearchPage({super.key});
|
||
|
||
@override
|
||
State<SearchPage> createState() => _SearchPageState();
|
||
}
|
||
|
||
class _SearchPageState extends State<SearchPage> {
|
||
late StreamSubscription subscription;
|
||
final SearchModel _viewmodel = SearchModel();
|
||
|
||
List<SearchListBean> dataList = [];
|
||
List<NewSearchRoomBean> roomList = [];
|
||
|
||
// 控制列表滚动
|
||
final ScrollController _scrollController = ScrollController();
|
||
|
||
// 是否正在加载更多
|
||
bool _isLoadingMore = false;
|
||
|
||
// 是否还有更多数据
|
||
final bool _hasMoreData = true;
|
||
int pageNum = 1;
|
||
|
||
@override
|
||
void initState() {
|
||
// TODO: implement initState
|
||
super.initState();
|
||
|
||
// 监听滚动事件,实现上拉加载
|
||
_scrollController.addListener(_scrollListener);
|
||
|
||
subscription = _viewmodel.streamController.stream.listen((event) {
|
||
String code = event['code'];
|
||
if (code.isNotEmpty) {
|
||
switch (code) {
|
||
case "newSearch":
|
||
_isLoadingMore = false;
|
||
NewSearchBean newSearchBean = event['data'];
|
||
roomList.addAll(newSearchBean.rooms);
|
||
dataList.addAll(newSearchBean.ports!.result!);
|
||
|
||
// print("dataList==${dataList.length}");
|
||
break;
|
||
}
|
||
}
|
||
setState(() {});
|
||
});
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
// TODO: implement dispose
|
||
_scrollController.dispose();
|
||
subscription.cancel();
|
||
super.dispose();
|
||
}
|
||
|
||
String text = "";
|
||
|
||
void _textFieldChanged(String str) {
|
||
text = str;
|
||
setState(() {});
|
||
}
|
||
|
||
void search(data) {
|
||
text = data;
|
||
roomList.clear();
|
||
dataList.clear();
|
||
_viewmodel.newSearch(data, 1, 20);
|
||
}
|
||
|
||
// 滚动监听
|
||
void _scrollListener() {
|
||
// 判断是否滑到了列表底部
|
||
if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 100 && !_isLoadingMore && _hasMoreData) {
|
||
_loadMoreData();
|
||
}
|
||
}
|
||
|
||
// 加载更多数据
|
||
Future<void> _loadMoreData() async {
|
||
if (_isLoadingMore) return;
|
||
setState(() {
|
||
_isLoadingMore = true;
|
||
pageNum++;
|
||
});
|
||
_viewmodel.searchDevice(text, pageNum, 20);
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final double statusBarHeight = MediaQuery.of(context).padding.top;
|
||
final size = MediaQuery.of(context).size;
|
||
final t10 = size.width / 36;
|
||
final w25 = size.width / 14.4;
|
||
final p5 = size.width / 72;
|
||
final w9 = size.width / 40;
|
||
final s21 = size.width / 17.142857142857;
|
||
final t20 = size.width / 18;
|
||
final l15 = size.width / 24;
|
||
final h32 = size.width / 11.25;
|
||
final c16 = size.width / 22.5;
|
||
final t14 = size.width / 25.714285714285;
|
||
final s12 = size.width / 30;
|
||
final w60 = size.width / 6;
|
||
|
||
return Scaffold(
|
||
backgroundColor: const Color(0xFFD8D8D8),
|
||
body: Container(
|
||
decoration: const BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage('assets/images/home_bg.png'),
|
||
fit: BoxFit.cover,
|
||
)),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Container(
|
||
margin: EdgeInsets.only(top: statusBarHeight + t10, left: t10, right: t10),
|
||
child: Row(
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
GestureDetector(
|
||
onTap: () {
|
||
Navigator.pop(context);
|
||
},
|
||
child: Container(
|
||
width: w25,
|
||
height: w25,
|
||
padding: EdgeInsets.all(p5),
|
||
child: Image(
|
||
width: w9,
|
||
image: const AssetImage('assets/images/ic_back.png'),
|
||
),
|
||
),
|
||
),
|
||
Container(
|
||
alignment: Alignment.center,
|
||
child: Text(
|
||
'搜索',
|
||
style: TextStyle(fontSize: s21, fontWeight: FontWeight.w600),
|
||
),
|
||
),
|
||
Container(
|
||
width: w25,
|
||
height: w25,
|
||
padding: EdgeInsets.all(p5),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Container(
|
||
margin: EdgeInsets.only(top: t10, left: l15, right: l15, bottom: t10),
|
||
child: Row(
|
||
children: [
|
||
Expanded(
|
||
child: Container(
|
||
height: h32,
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
border: Border.all(width: 0.5, color: Colors.black12),
|
||
borderRadius: BorderRadius.all(Radius.circular(c16)),
|
||
),
|
||
child: Container(
|
||
margin: EdgeInsets.only(left: t20),
|
||
padding: EdgeInsets.only(top: t14),
|
||
child: TextField(
|
||
onChanged: _textFieldChanged,
|
||
cursorColor: const Color(0xFF1A73EC),
|
||
decoration: InputDecoration(
|
||
hintText: '请输入要搜索的备注内容',
|
||
border: InputBorder.none,
|
||
enabledBorder: InputBorder.none,
|
||
focusedBorder: InputBorder.none,
|
||
hintStyle: TextStyle(color: const Color(0xFF999999), fontSize: s12),
|
||
),
|
||
textInputAction: TextInputAction.search,
|
||
style: TextStyle(fontSize: s12),
|
||
onSubmitted: (value) {
|
||
// 当用户点击键盘的 "搜索" 按钮时触发
|
||
// print("搜索内容: $value");
|
||
search(value);
|
||
},
|
||
),
|
||
),
|
||
),
|
||
),
|
||
GestureDetector(
|
||
onTap: () {
|
||
search(text);
|
||
},
|
||
child: Container(
|
||
width: w60,
|
||
height: h32,
|
||
alignment: Alignment.center,
|
||
margin: EdgeInsets.only(left: t20),
|
||
decoration: BoxDecoration(
|
||
color: const Color(0xFF1A73EC),
|
||
borderRadius: BorderRadius.all(Radius.circular(c16)),
|
||
),
|
||
child: Text(
|
||
"搜索",
|
||
style: TextStyle(color: Colors.white, fontSize: t14),
|
||
),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
Expanded(
|
||
child: SingleChildScrollView(
|
||
// 添加内边距,让内容与边缘有间距
|
||
padding: EdgeInsets.symmetric(horizontal: t10, vertical: t10),
|
||
// 滚动物理效果(iOS风格的弹性滚动)
|
||
physics: const BouncingScrollPhysics(),
|
||
controller: _scrollController,
|
||
child: Column(
|
||
children: [
|
||
roomList.isNotEmpty
|
||
? Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 5),
|
||
child: Text(
|
||
'机房',
|
||
style: TextStyle(fontSize: 16, color: Color(0xFF1A73EC)),
|
||
),
|
||
)
|
||
: Container(),
|
||
roomList.isNotEmpty
|
||
? ListView.builder(
|
||
itemCount: roomList.length,
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
padding: const EdgeInsets.all(0),
|
||
itemBuilder: (BuildContext context, int index) {
|
||
return _roomItem(roomList[index], t10);
|
||
})
|
||
: Container(),
|
||
dataList.isNotEmpty
|
||
? Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 5),
|
||
child: Text(
|
||
'备注信息',
|
||
style: TextStyle(fontSize: 16, color: Color(0xFF1A73EC)),
|
||
),
|
||
)
|
||
: Container(),
|
||
ListView.builder(
|
||
itemCount: dataList.length,
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
padding: const EdgeInsets.all(0),
|
||
itemBuilder: (BuildContext context, int index) {
|
||
return _item(dataList[index], t10);
|
||
}),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
_roomItem(NewSearchRoomBean data, t10) {
|
||
return GestureDetector(
|
||
onTap: () {
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (context) => MachinePage(
|
||
roomId: "${data.roomId}",
|
||
roomName: "${data.roomName}",
|
||
),
|
||
),
|
||
);
|
||
},
|
||
child: Card(
|
||
color: Colors.white,
|
||
child: Container(
|
||
margin: EdgeInsets.only(bottom: t10),
|
||
child: Column(
|
||
children: [
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10),
|
||
child: Text(
|
||
"机房名: ${data.roomName}",
|
||
style: const TextStyle(color: Color(0xFF666666)),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
_item(SearchListBean data, t10) {
|
||
return GestureDetector(
|
||
onTap: () {
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (context) => MachineDetailsPage(
|
||
rackId: '${data.rackId}',
|
||
dofName: '${data.rackName}',
|
||
isOpenPop: true,
|
||
dropId: '${data.id}',
|
||
roomName: '${data.roomName}',
|
||
),
|
||
),
|
||
);
|
||
},
|
||
child: Card(
|
||
color: Colors.white,
|
||
child: Container(
|
||
margin: EdgeInsets.only(bottom: t10),
|
||
child: Column(
|
||
children: [
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10),
|
||
child: Text(
|
||
"机房名: ${data.roomName}",
|
||
style: const TextStyle(color: Color(0xFF666666)),
|
||
),
|
||
),
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Text(
|
||
"地址: ${data.address}",
|
||
style: const TextStyle(color: Color(0xFF666666)),
|
||
),
|
||
),
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Text("ODF名称: ${data.rackName}"),
|
||
),
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Text("点位置: ${data.frameName}${data.name}"),
|
||
),
|
||
data.remarks != ""
|
||
? Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Text("备注: ${data.remarks}"),
|
||
)
|
||
: Container(),
|
||
data.opticalAttenuation != ""
|
||
? Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Text("光衰信息: ${data.opticalAttenuation}"),
|
||
)
|
||
: Container(),
|
||
data.historyRemarks != ""
|
||
? Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Text("历史故障原因及时间: ${data.historyRemarks}"),
|
||
)
|
||
: Container(),
|
||
data.opticalCableOffRemarks != ""
|
||
? Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Text("光缆段信息: ${data.opticalCableOffRemarks}"),
|
||
)
|
||
: Container(),
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: t10, top: t10, right: t10),
|
||
child: Row(
|
||
children: [
|
||
Text(
|
||
"当前状态:",
|
||
style: TextStyle(fontSize: 12),
|
||
),
|
||
Container(
|
||
width: 12,
|
||
height: 12,
|
||
margin: EdgeInsets.only(left: t10, right: 5),
|
||
decoration: BoxDecoration(
|
||
color: data.status == 0 ? Colors.red : Colors.green,
|
||
shape: BoxShape.circle,
|
||
),
|
||
),
|
||
Container(
|
||
child: Text(
|
||
data.status == 0 ? "已断开" : "已连接",
|
||
style: TextStyle(fontSize: 12),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|