Compare commits
2 Commits
baee5dba83
...
20ef495571
| Author | SHA1 | Date | |
|---|---|---|---|
| 20ef495571 | |||
| 285a20f070 |
@@ -7,9 +7,12 @@ class AppTheme {
|
|||||||
|
|
||||||
static const Color themeColor = Color(0xFF0c83c3);
|
static const Color themeColor = Color(0xFF0c83c3);
|
||||||
|
|
||||||
|
//是否开放域名切换
|
||||||
|
static const bool is_show_host = true;
|
||||||
|
|
||||||
//http://192.168.110.222:8080/
|
//http://192.168.110.222:8080/
|
||||||
//http://192.168.110.44:8080/
|
//http://192.168.110.44:8080/
|
||||||
static const String test_service_url = "https://beta-esg.api.lnh2e.com/";
|
static String test_service_url = "https://beta-esg.api.lnh2e.com/";
|
||||||
static const String release_service_url = "";
|
static const String release_service_url = "";
|
||||||
|
|
||||||
//加氢站相关查询
|
//加氢站相关查询
|
||||||
@@ -23,10 +26,10 @@ class AppTheme {
|
|||||||
|
|
||||||
static const Color darkThemeColor = Color(0xFF032896);
|
static const Color darkThemeColor = Color(0xFF032896);
|
||||||
|
|
||||||
static const String android_key ="335642645";
|
static const String android_key = "335642645";
|
||||||
static const String android_appsecret="39628204345a4240b5b645b68a5896c7";
|
static const String android_appsecret = "39628204345a4240b5b645b68a5896c7";
|
||||||
static const String ios_key="335642649";
|
static const String ios_key = "335642649";
|
||||||
static const String ios_appsecret="173bc08bd5df422da20c8e3ffbf0521b";
|
static const String ios_appsecret = "173bc08bd5df422da20c8e3ffbf0521b";
|
||||||
|
|
||||||
/// 亮色主题样式
|
/// 亮色主题样式
|
||||||
static ThemeData light = ThemeData(
|
static ThemeData light = ThemeData(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
import 'package:ln_jq_app/storage_service.dart';
|
import 'package:ln_jq_app/storage_service.dart';
|
||||||
|
|
||||||
/// 专门用于处理和添加 Token 的拦截器
|
/// 专门用于处理和添加 Token 的拦截器
|
||||||
@@ -13,7 +14,7 @@ class TokenInterceptor extends Interceptor {
|
|||||||
TokenInterceptor({this.tokenKey = 'Authorization', this.sourceKey = 'source'});
|
TokenInterceptor({this.tokenKey = 'Authorization', this.sourceKey = 'source'});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async{
|
||||||
// 从 StorageService 中获取已保存的 token
|
// 从 StorageService 中获取已保存的 token
|
||||||
final String? token = StorageService.to.token;
|
final String? token = StorageService.to.token;
|
||||||
|
|
||||||
@@ -38,6 +39,9 @@ class TokenInterceptor extends Interceptor {
|
|||||||
options.headers[sourceKey] = platformSource;
|
options.headers[sourceKey] = platformSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options.headers['appVersion'] = await getVersion();
|
||||||
|
options.headers['brand'] = await getDeviceModel();
|
||||||
|
|
||||||
// 调用 handler.next(options) 以继续执行请求
|
// 调用 handler.next(options) 以继续执行请求
|
||||||
// 这一步至关重要,否则请求会被中断
|
// 这一步至关重要,否则请求会被中断
|
||||||
super.onRequest(options, handler);
|
super.onRequest(options, handler);
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ void main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initHttpSet() {
|
void initHttpSet() {
|
||||||
|
AppTheme.test_service_url = StorageService.to.hostUrl ?? AppTheme.test_service_url;
|
||||||
|
|
||||||
// 设置基础 URL
|
// 设置基础 URL
|
||||||
HttpService.to.setBaseUrl(AppTheme.test_service_url);
|
HttpService.to.setBaseUrl(AppTheme.test_service_url);
|
||||||
//指定请求头
|
//指定请求头
|
||||||
|
|||||||
@@ -1,32 +1,47 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:getx_scaffold/getx_scaffold.dart';
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
import 'package:ln_jq_app/common/model/base_model.dart';
|
import 'package:ln_jq_app/common/model/base_model.dart';
|
||||||
import 'package:ln_jq_app/pages/login/view.dart';
|
import 'package:ln_jq_app/pages/login/view.dart';
|
||||||
|
|
||||||
|
import '../../../common/styles/theme.dart';
|
||||||
import '../../../storage_service.dart';
|
import '../../../storage_service.dart';
|
||||||
|
|
||||||
class ReservationController extends GetxController with BaseControllerMixin {
|
class ReservationController extends GetxController with BaseControllerMixin {
|
||||||
@override
|
@override
|
||||||
String get builderId => 'b_reservation'; // 确保ID与View中一致
|
String get builderId => 'b_reservation';
|
||||||
|
|
||||||
// --- 运营状态下拉菜单所需的状态 ---
|
|
||||||
// 下拉菜单的选项列表
|
|
||||||
final List<String> operationStatusOptions = ["营运中", "维修中", "暂停营业", "站点关闭"];
|
final List<String> operationStatusOptions = ["营运中", "维修中", "暂停营业", "站点关闭"];
|
||||||
|
|
||||||
// 当前选中的值,默认为'运营中'
|
|
||||||
String selectedOperationStatus = "营运中";
|
String selectedOperationStatus = "营运中";
|
||||||
|
|
||||||
|
// --- 其它状态下的时间选择 ---
|
||||||
|
DateTime? customStartTime;
|
||||||
|
DateTime? customEndTime;
|
||||||
|
|
||||||
|
String get customStartTimeStr => customStartTime != null
|
||||||
|
? DateFormat('yyyy-MM-dd HH:mm').format(customStartTime!)
|
||||||
|
: '点击选择开始时间';
|
||||||
|
|
||||||
|
String get customEndTimeStr => customEndTime != null
|
||||||
|
? DateFormat('yyyy-MM-dd HH:mm').format(customEndTime!)
|
||||||
|
: '点击选择结束时间';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
// 1. 初始化默认时间
|
||||||
|
customStartTime = DateTime.now();
|
||||||
|
customEndTime = customStartTime!.add(const Duration(days: 1));
|
||||||
renderData();
|
renderData();
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = "";
|
String name = "";
|
||||||
String address = "";
|
String address = "";
|
||||||
String phone = "";
|
String phone = "";
|
||||||
String costPrice = ""; //氢气价格
|
String costPrice = "";
|
||||||
String customerPrice = ""; //官方价格
|
String customerPrice = "";
|
||||||
String startBusiness = "";
|
String startBusiness = "";
|
||||||
String endBusiness = "";
|
String endBusiness = "";
|
||||||
String timeStr = "";
|
String timeStr = "";
|
||||||
@@ -35,7 +50,6 @@ class ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
|
|
||||||
Future<void> renderData() async {
|
Future<void> renderData() async {
|
||||||
showLoading("加载中");
|
showLoading("加载中");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var responseData = await HttpService.to.get(
|
var responseData = await HttpService.to.get(
|
||||||
'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}',
|
'appointment/station/getStationInfoById?hydrogenId=${StorageService.to.userId}',
|
||||||
@@ -49,32 +63,30 @@ class ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
var result = BaseModel.fromJson(responseData.data);
|
var result = BaseModel.fromJson(responseData.data);
|
||||||
|
name = result.data["name"] ?? "";
|
||||||
name = result.data["name"];
|
|
||||||
hydrogenId = result.data["hydrogenId"].toString();
|
hydrogenId = result.data["hydrogenId"].toString();
|
||||||
address = result.data["address"];
|
address = result.data["address"] ?? "";
|
||||||
var rawCostPrice = result.data["costPrice"];
|
|
||||||
if (rawCostPrice != null && rawCostPrice.toString().isNotEmpty) {
|
|
||||||
costPrice = "¥$rawCostPrice";
|
|
||||||
} else {
|
|
||||||
costPrice = "暂无价格";
|
|
||||||
}
|
|
||||||
var customerPriceTemp = result.data["customerPrice"];
|
|
||||||
if (customerPriceTemp != null && customerPriceTemp.toString().isNotEmpty) {
|
|
||||||
customerPrice = "$customerPriceTemp";
|
|
||||||
} else {
|
|
||||||
customerPrice = "暂无价格";
|
|
||||||
}
|
|
||||||
|
|
||||||
phone = result.data["phone"];
|
var rawCostPrice = result.data["costPrice"];
|
||||||
startBusiness = result.data["startBusiness"];
|
costPrice = (rawCostPrice != null && rawCostPrice.toString().isNotEmpty)
|
||||||
endBusiness = result.data["endBusiness"];
|
? "¥$rawCostPrice"
|
||||||
|
: "暂无价格";
|
||||||
|
|
||||||
|
var customerPriceTemp = result.data["customerPrice"];
|
||||||
|
customerPrice =
|
||||||
|
(customerPriceTemp != null && customerPriceTemp.toString().isNotEmpty)
|
||||||
|
? "$customerPriceTemp"
|
||||||
|
: "暂无价格";
|
||||||
|
|
||||||
|
phone = result.data["phone"] ?? "";
|
||||||
|
startBusiness = result.data["startBusiness"] ?? "";
|
||||||
|
endBusiness = result.data["endBusiness"] ?? "";
|
||||||
operatingEnterprise = result.data["operatingEnterprise"].toString();
|
operatingEnterprise = result.data["operatingEnterprise"].toString();
|
||||||
|
|
||||||
String temp = result.data["siteStatusName"].toString();
|
String temp = result.data["siteStatusName"].toString();
|
||||||
selectedOperationStatus = (temp.isEmpty || temp == "null") ? "营运中" : temp;
|
selectedOperationStatus = (temp.isEmpty || temp == "null") ? "营运中" : temp;
|
||||||
|
|
||||||
if (startBusiness.isNotEmpty && endBusiness.isNotEmpty) {
|
if (startBusiness.isNotEmpty && endBusiness.isNotEmpty) {
|
||||||
// 营业时间为24小时的特殊处理
|
|
||||||
if (startBusiness == "00:00:00" && endBusiness == "23:59:59") {
|
if (startBusiness == "00:00:00" && endBusiness == "23:59:59") {
|
||||||
timeStr = "24小时营业";
|
timeStr = "24小时营业";
|
||||||
} else {
|
} else {
|
||||||
@@ -85,11 +97,9 @@ class ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
operatingEnterprise = operatingEnterprise.isEmpty ? "暂未设置" : operatingEnterprise;
|
operatingEnterprise = operatingEnterprise.isEmpty ? "暂未设置" : operatingEnterprise;
|
||||||
|
|
||||||
updateUi();
|
updateUi();
|
||||||
dismissLoading();
|
dismissLoading();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 如果解析 JSON 失败
|
|
||||||
dismissLoading();
|
dismissLoading();
|
||||||
showToast('数据异常');
|
showToast('数据异常');
|
||||||
}
|
}
|
||||||
@@ -98,7 +108,6 @@ class ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 更新运营状态的方法
|
|
||||||
void onOperationStatusChanged(String? newValue) {
|
void onOperationStatusChanged(String? newValue) {
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
selectedOperationStatus = newValue;
|
selectedOperationStatus = newValue;
|
||||||
@@ -106,9 +115,102 @@ class ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveInfo() async {
|
/// 使用底部滚轮形式选择时间(下拉框效果)
|
||||||
showLoading("保存中");
|
void pickDateTime(BuildContext context, bool isStart) {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
DateTime initialDate = isStart ? (customStartTime ?? now) : (customEndTime ?? now);
|
||||||
|
|
||||||
|
// 确保初始时间不早于最小允许时间
|
||||||
|
// 将 minimumDate 稍微提前一点点(比如1分钟)
|
||||||
|
DateTime minLimit = isStart
|
||||||
|
? now.subtract(const Duration(minutes: 1))
|
||||||
|
: (customStartTime ?? now).subtract(const Duration(minutes: 1));
|
||||||
|
|
||||||
|
if (initialDate.isBefore(minLimit)) {
|
||||||
|
initialDate = isStart ? now : (customStartTime ?? now);
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime tempDate = initialDate;
|
||||||
|
|
||||||
|
Get.bottomSheet(
|
||||||
|
Container(
|
||||||
|
height: 300,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(16),
|
||||||
|
topRight: Radius.circular(16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
CupertinoButton(
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
child: const Text('取消', style: TextStyle(color: Colors.grey)),
|
||||||
|
),
|
||||||
|
CupertinoButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (isStart) {
|
||||||
|
customStartTime = tempDate;
|
||||||
|
// 如果开始时间变动后,结束时间早于开始时间,自动顺延一天
|
||||||
|
if (customEndTime != null &&
|
||||||
|
customEndTime!.isBefore(customStartTime!)) {
|
||||||
|
customEndTime = customStartTime!.add(const Duration(days: 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tempDate.isBefore(customStartTime ?? DateTime.now())) {
|
||||||
|
showToast('结束时间不能早于开始时间');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
customEndTime = tempDate;
|
||||||
|
}
|
||||||
|
updateUi();
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: const Text(
|
||||||
|
'确定',
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppTheme.themeColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(height: 1),
|
||||||
|
Expanded(
|
||||||
|
child: CupertinoDatePicker(
|
||||||
|
mode: CupertinoDatePickerMode.dateAndTime,
|
||||||
|
initialDateTime: initialDate,
|
||||||
|
minimumDate: minLimit,
|
||||||
|
use24hFormat: true,
|
||||||
|
onDateTimeChanged: (DateTime newDate) {
|
||||||
|
tempDate = newDate;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveInfo() async {
|
||||||
|
if (selectedOperationStatus != "营运中") {
|
||||||
|
if (customStartTime == null || customEndTime == null) {
|
||||||
|
showToast("请选择开始和结束时间");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoading("保存中");
|
||||||
try {
|
try {
|
||||||
var responseData = await HttpService.to.post(
|
var responseData = await HttpService.to.post(
|
||||||
'appointment/station/updateStationStatus',
|
'appointment/station/updateStationStatus',
|
||||||
@@ -123,11 +225,17 @@ class ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
: selectedOperationStatus == "暂停营业"
|
: selectedOperationStatus == "暂停营业"
|
||||||
? "3"
|
? "3"
|
||||||
: 0,
|
: 0,
|
||||||
|
'beginTime': selectedOperationStatus == "营运中"
|
||||||
|
? null
|
||||||
|
: DateFormat('yyyy-MM-dd HH:mm:ss').format(customStartTime!),
|
||||||
|
'endTime': selectedOperationStatus == "营运中"
|
||||||
|
? null
|
||||||
|
: DateFormat('yyyy-MM-dd HH:mm:ss').format(customEndTime!),
|
||||||
'updateTime': getNowDateTimeString(),
|
'updateTime': getNowDateTimeString(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (responseData == null && responseData!.data == null) {
|
if (responseData == null || responseData!.data == null) {
|
||||||
dismissLoading();
|
dismissLoading();
|
||||||
showToast('服务暂不可用,请稍后');
|
showToast('服务暂不可用,请稍后');
|
||||||
return;
|
return;
|
||||||
@@ -143,10 +251,7 @@ class ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void logout() async {
|
void logout() async {
|
||||||
// TODO: 在这里执行退出登录的逻辑
|
|
||||||
//清理本地缓存的用户信息 导航到登录页面
|
|
||||||
await StorageService.to.clearLoginInfo();
|
await StorageService.to.clearLoginInfo();
|
||||||
|
|
||||||
Get.offAll(() => LoginPage());
|
Get.offAll(() => LoginPage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,14 +127,12 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
_buildSectionTitle('运营信息'),
|
_buildSectionTitle('运营信息'),
|
||||||
Text('运营状态', style: TextStyle(color: Colors.grey[600], fontSize: 14)),
|
Text('运营状态', style: TextStyle(color: Colors.grey[600], fontSize: 14)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
//下拉选择框
|
|
||||||
|
// 下拉选择框
|
||||||
DropdownButtonFormField<String>(
|
DropdownButtonFormField<String>(
|
||||||
value: controller.selectedOperationStatus,
|
value: controller.selectedOperationStatus,
|
||||||
items: controller.operationStatusOptions.map((String value) {
|
items: controller.operationStatusOptions.map((String value) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(value: value, child: Text(value));
|
||||||
value: value,
|
|
||||||
child: Text(value),
|
|
||||||
);
|
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: controller.onOperationStatusChanged,
|
onChanged: controller.onOperationStatusChanged,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -142,8 +140,27 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 16),
|
||||||
_buildDisplayField(label: '营业时间', value: controller.timeStr),
|
|
||||||
|
// 根据状态动态显示 UI
|
||||||
|
if (controller.selectedOperationStatus == "营运中")
|
||||||
|
_buildDisplayField(label: '营业时间', value: controller.timeStr)
|
||||||
|
else
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
_buildClickField(
|
||||||
|
label: '开始时间',
|
||||||
|
value: controller.customStartTimeStr,
|
||||||
|
onTap: () => controller.pickDateTime(context, true),
|
||||||
|
),
|
||||||
|
_buildClickField(
|
||||||
|
label: '结束时间',
|
||||||
|
value: controller.customEndTimeStr,
|
||||||
|
onTap: () => controller.pickDateTime(context, false),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
_buildDisplayField(label: '联系电话', value: controller.phone),
|
_buildDisplayField(label: '联系电话', value: controller.phone),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
@@ -162,70 +179,6 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 构建静态提示信息卡片
|
|
||||||
Widget _buildTipsCard() {
|
|
||||||
return Card(
|
|
||||||
elevation: 2,
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
_buildInfoItem(Icons.info_outline, '请确保信息准确无误'),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
_buildInfoItem(Icons.help_outline, '价格信息将实时更新到用户端'),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
_buildInfoItem(Icons.headset_mic_outlined, '如有疑问请联系技术支持: 400-021-1773'),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.verified_outlined, color: Colors.blue, size: 20),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: FutureBuilder<String>(
|
|
||||||
future: getVersion(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
// 判断是否还在加载
|
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
||||||
return const Text("");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果加载完成且有数据
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return TextX.labelSmall("当前版本: ${snapshot.data}",color: Colors.black54,);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 错误处理
|
|
||||||
return const Text("");
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 构建退出登录按钮
|
|
||||||
Widget _buildLogoutButton() {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: controller.logout,
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.red,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
minimumSize: const Size(double.infinity, 48),
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
|
|
||||||
elevation: 2,
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
'退出登录',
|
|
||||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 构建带标题的表单区域
|
/// 构建带标题的表单区域
|
||||||
Widget _buildSectionTitle(String title) {
|
Widget _buildSectionTitle(String title) {
|
||||||
return Padding(
|
return Padding(
|
||||||
@@ -253,7 +206,7 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
|
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey[200], // 使用灰色背景以区分
|
color: Colors.grey[200],
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
border: Border.all(color: Colors.grey[300]!),
|
border: Border.all(color: Colors.grey[300]!),
|
||||||
),
|
),
|
||||||
@@ -267,6 +220,104 @@ class ReservationPage extends GetView<ReservationController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 构建一个“可点击”的选择行
|
||||||
|
Widget _buildClickField({required String label, required String value, required VoidCallback onTap}) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 12.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 14)),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
|
border: Border.all(color: Colors.blue.withOpacity(0.5)),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: const TextStyle(fontSize: 14, color: Colors.black87),
|
||||||
|
),
|
||||||
|
const Icon(Icons.calendar_month, size: 18, color: Colors.blue),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 构建静态提示信息卡片
|
||||||
|
Widget _buildTipsCard() {
|
||||||
|
return Card(
|
||||||
|
elevation: 2,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildInfoItem(Icons.info_outline, '请确保信息准确无误'),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
_buildInfoItem(Icons.help_outline, '价格信息将实时更新到用户端'),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
_buildInfoItem(Icons.headset_mic_outlined, '如有疑问请联系技术支持: 400-021-1773'),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.verified_outlined, color: Colors.blue, size: 20),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: FutureBuilder<String>(
|
||||||
|
future: getVersion(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return const Text("");
|
||||||
|
}
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
return TextX.labelSmall(
|
||||||
|
"当前版本: ${snapshot.data}",
|
||||||
|
color: Colors.black54,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const Text("");
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 构建退出登录按钮
|
||||||
|
Widget _buildLogoutButton() {
|
||||||
|
return ElevatedButton(
|
||||||
|
onPressed: controller.logout,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
minimumSize: const Size(double.infinity, 48),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
|
||||||
|
elevation: 2,
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'退出登录',
|
||||||
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// 构建带图标的提示信息行
|
/// 构建带图标的提示信息行
|
||||||
Widget _buildInfoItem(IconData icon, String text) {
|
Widget _buildInfoItem(IconData icon, String text) {
|
||||||
return Row(
|
return Row(
|
||||||
|
|||||||
@@ -394,14 +394,16 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var result = BaseModel.fromJson(responseData?.data);
|
||||||
|
|
||||||
if (responseData == null) {
|
if (responseData == null) {
|
||||||
dismissLoading();
|
dismissLoading();
|
||||||
showToast('服务暂不可用,请稍后');
|
showToast(result.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dismissLoading();
|
dismissLoading();
|
||||||
|
|
||||||
var result = BaseModel.fromJson(responseData.data);
|
|
||||||
if (result.code == 0) {
|
if (result.code == 0) {
|
||||||
showSuccessToast("预约成功");
|
showSuccessToast("预约成功");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'package:aliyun_push_flutter/aliyun_push_flutter.dart';
|
import 'package:aliyun_push_flutter/aliyun_push_flutter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:getx_scaffold/getx_scaffold.dart';
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
import 'package:ln_jq_app/common/login_util.dart';
|
import 'package:ln_jq_app/common/login_util.dart';
|
||||||
import 'package:ln_jq_app/common/model/base_model.dart';
|
import 'package:ln_jq_app/common/model/base_model.dart';
|
||||||
@@ -8,6 +10,7 @@ import 'package:ln_jq_app/common/styles/theme.dart';
|
|||||||
import 'package:ln_jq_app/pages/b_page/base_widgets/view.dart';
|
import 'package:ln_jq_app/pages/b_page/base_widgets/view.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/base_widgets/view.dart';
|
import 'package:ln_jq_app/pages/c_page/base_widgets/view.dart';
|
||||||
import 'package:ln_jq_app/pages/login/controller.dart';
|
import 'package:ln_jq_app/pages/login/controller.dart';
|
||||||
|
import 'package:ln_jq_app/pages/url_host/view.dart';
|
||||||
import 'package:ln_jq_app/storage_service.dart';
|
import 'package:ln_jq_app/storage_service.dart';
|
||||||
|
|
||||||
class LoginPage extends StatefulWidget {
|
class LoginPage extends StatefulWidget {
|
||||||
@@ -414,7 +417,31 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
|
|||||||
init: LoginController(),
|
init: LoginController(),
|
||||||
id: 'login',
|
id: 'login',
|
||||||
builder: (controller) {
|
builder: (controller) {
|
||||||
return Scaffold(body: _buildView(controller));
|
return Scaffold(
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(child: _buildView(controller)),
|
||||||
|
if (AppTheme.is_show_host)
|
||||||
|
Positioned(
|
||||||
|
top: 40.h,
|
||||||
|
right: 20.w,
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Get.to(() => const UrlHostPage());
|
||||||
|
},
|
||||||
|
child: const Text(
|
||||||
|
"域名配置",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
65
ln_jq_app/lib/pages/url_host/controller.dart
Normal file
65
ln_jq_app/lib/pages/url_host/controller.dart
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
|
import 'package:ln_jq_app/common/styles/theme.dart';
|
||||||
|
import 'package:ln_jq_app/storage_service.dart';
|
||||||
|
|
||||||
|
class UrlHostController extends GetxController {
|
||||||
|
final TextEditingController urlController = TextEditingController();
|
||||||
|
|
||||||
|
// 预设的域名列表
|
||||||
|
final List<String> presetUrls = [
|
||||||
|
'https://beta-esg.api.lnh2e.com/', // 测试环境
|
||||||
|
'http://192.168.110.44:8080/', // 沈辰本地
|
||||||
|
'http://192.168.110.222:8080/', // 何斐本地
|
||||||
|
];
|
||||||
|
|
||||||
|
final List<String> urlNames = [
|
||||||
|
'测试环境',
|
||||||
|
'沈辰本地环境',
|
||||||
|
'何斐本地环境',
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
// 初始化时,尝试从 StorageService 获取已保存的域名
|
||||||
|
// 如果没有保存过,则使用当前的全局配置
|
||||||
|
String? savedUrl = StorageService.to.hostUrl;
|
||||||
|
if (savedUrl != null && savedUrl.isNotEmpty) {
|
||||||
|
urlController.text = savedUrl;
|
||||||
|
} else {
|
||||||
|
urlController.text = AppTheme.test_service_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 当用户点击列表中的某一项时,将其填入编辑框
|
||||||
|
void selectUrl(String url) {
|
||||||
|
urlController.text = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 保存配置并关闭页面
|
||||||
|
void saveAndExit() async {
|
||||||
|
String newUrl = urlController.text.trim();
|
||||||
|
if (newUrl.isEmpty) {
|
||||||
|
showToast('请输入有效的域名');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到本地存储,以便下次启动时加载
|
||||||
|
await StorageService.to.saveHostUrl(newUrl);
|
||||||
|
AppTheme.test_service_url = newUrl;
|
||||||
|
|
||||||
|
//设置框架
|
||||||
|
HttpService.to.setBaseUrl(AppTheme.test_service_url);
|
||||||
|
|
||||||
|
showSuccessToast('域名已更新:${AppTheme.test_service_url}');
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
urlController.dispose();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
82
ln_jq_app/lib/pages/url_host/view.dart
Normal file
82
ln_jq_app/lib/pages/url_host/view.dart
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
|
|
||||||
|
import 'controller.dart';
|
||||||
|
|
||||||
|
class UrlHostPage extends GetView<UrlHostController> {
|
||||||
|
const UrlHostPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Get.put(UrlHostController());
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('域名配置'),
|
||||||
|
centerTitle: true,
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'当前环境配置',
|
||||||
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
TextField(
|
||||||
|
controller: controller.urlController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: '请输入或选择API域名',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
const Text(
|
||||||
|
'预设环境',
|
||||||
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: controller.presetUrls.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final url = controller.presetUrls[index];
|
||||||
|
return Card(
|
||||||
|
elevation: 1,
|
||||||
|
margin: const EdgeInsets.only(bottom: 8),
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(controller.urlNames[index], style: const TextStyle(fontSize: 14)),
|
||||||
|
subtitle: Text(url, style: const TextStyle(fontSize: 14)),
|
||||||
|
trailing: const Icon(Icons.touch_app, size: 18, color: Colors.grey),
|
||||||
|
onTap: () {
|
||||||
|
// 点击列表项:先填入编辑框,然后直接保存退出
|
||||||
|
controller.selectUrl(url);
|
||||||
|
controller.saveAndExit();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: controller.saveAndExit,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
minimumSize: const Size(double.infinity, 48),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text('保存配置', style: TextStyle(fontSize: 16)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,8 @@ class StorageService extends GetxService {
|
|||||||
// 新增:用于标记“绑定车辆”弹窗是否已在本会话中显示过
|
// 新增:用于标记“绑定车辆”弹窗是否已在本会话中显示过
|
||||||
static const String _bindDialogShownKey = 'bind_vehicle_dialog_shown';
|
static const String _bindDialogShownKey = 'bind_vehicle_dialog_shown';
|
||||||
|
|
||||||
|
static const String _hostUrlKey = 'host_url';
|
||||||
|
|
||||||
static StorageService get to => Get.find();
|
static StorageService get to => Get.find();
|
||||||
|
|
||||||
Future<StorageService> init() async {
|
Future<StorageService> init() async {
|
||||||
@@ -36,6 +38,13 @@ class StorageService extends GetxService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Getters ---
|
// --- Getters ---
|
||||||
|
String? get hostUrl => _box.read<String?>(_hostUrlKey);
|
||||||
|
|
||||||
|
///:保存自定义域名
|
||||||
|
Future<void> saveHostUrl(String url) async {
|
||||||
|
await _box.write(_hostUrlKey, url);
|
||||||
|
}
|
||||||
|
|
||||||
bool get isLoggedIn => _box.read<String?>(_tokenKey)?.isNotEmpty ?? false;
|
bool get isLoggedIn => _box.read<String?>(_tokenKey)?.isNotEmpty ?? false;
|
||||||
|
|
||||||
String? get token => _box.read<String?>(_tokenKey);
|
String? get token => _box.read<String?>(_tokenKey);
|
||||||
|
|||||||
Reference in New Issue
Block a user