ODF/lib/tools/search/search_page.dart
2025-09-21 22:07:13 +08:00

425 lines
15 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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),
),
)
],
),
)
],
),
),
),
);
}
}