修正上架時 Google Play 檢查出的 issue

This commit is contained in:
2026-04-09 23:15:19 +08:00
parent af27b77ad7
commit bdc0ee7dd4
108 changed files with 3446 additions and 276 deletions
+61 -135
View File
@@ -1,15 +1,7 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:crypto/crypto.dart';
// 引入九宮格主選單,登入成功後跳轉
import 'main.dart';
import './auth_manager.dart'; // 確保路徑正確
// API 相關常數
const String BASE_IP = "https://api.gex.com.tw:8033";
//const String API_ENDPOINT = "xapi/v1/eis_demo/checklogin/2/";
//const String API_URL = "$BASE_IP/$API_ENDPOINT";
import 'auth_manager.dart';
import 'auth_api.dart'; // 引入新抽離的 API Service
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@@ -19,25 +11,21 @@ class LoginPage extends StatefulWidget {
}
class _LoginPageState extends State<LoginPage> {
// 用於獲取輸入框內容
final TextEditingController _userController = TextEditingController(text: '120102'); // 預設帳號
final TextEditingController _pwdController = TextEditingController(text: 'gex123'); // 預設密碼
final TextEditingController _compController = TextEditingController(text: 'demo'); // [新增] 預設值
final TextEditingController _userController = TextEditingController(text: '120102');
final TextEditingController _pwdController = TextEditingController(text: 'gex123');
final TextEditingController _compController = TextEditingController(text: 'demo');
final AuthApiService _authApi = AuthApiService(); // 實例化 API 工具
bool _isLoading = false;
String? _errorMessage;
// 輔助函數:將字串轉換為 MD5 雜湊值
String _generateMd5(String input) {
return md5.convert(utf8.encode(input)).toString();
}
// 登入邏輯,模擬您的 JS logon() 函數
Future<void> _logon() async {
if (_userController.text.isEmpty || _pwdController.text.isEmpty || _compController.text.isEmpty) {
setState(() {
_errorMessage = '請輸入帳號和密碼';
});
final String comp = _compController.text.trim();
final String userId = _userController.text.trim();
final String password = _pwdController.text;
if (userId.isEmpty || password.isEmpty || comp.isEmpty) {
setState(() => _errorMessage = '請完整填寫公司、帳號與密碼');
return;
}
@@ -46,81 +34,48 @@ class _LoginPageState extends State<LoginPage> {
_errorMessage = null;
});
final String userId = _userController.text;
final String password = _pwdController.text;
// 對密碼進行 MD5 加密
final String md5Password = _generateMd5(password);
// 建立 API 參數,使用您的邏輯
final Map<String, String> params = {
'token': 'xxx',
'para01': userId,
'para02': md5Password,
'para03': 'web',
};
try {
// 執行 POST 請求。使用 application/x-www-form-urlencoded 格式
// [關鍵] 動態組合登入 API 網址,取代固定的 eis_demo
final String comp = _compController.text.trim().toLowerCase();
final String loginUrl = "$BASE_IP/xapi/v1/eis_$comp/checklogin/2/";
final response = await http.post(
Uri.parse(loginUrl),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
// 呼叫封裝好的 API Service
final responseData = await _authApi.login(
comp: comp,
userId: userId,
password: password,
);
// 解析 API 回應
final Map<String, dynamic> responseData = json.decode(response.body);
// 根據您的 API 邏輯:res.data.code === 0 為成功
if (responseData['code'] == 0) {
// 1. 預期 responseData['data'] 是一個 List
final List<dynamic>? dataList = responseData['data'] as List<dynamic>?;
// 2. 檢查 List 不為空,並從第一個元素中提取 'token'
final String? token = (dataList != null && dataList.isNotEmpty)
? (dataList[0] as Map<String, dynamic>)['token'] as String?
? dataList[0]['token'] as String?
: null;
if (token != null && token.isNotEmpty) {
await AuthManager.saveLoginInfo(token, userId, comp); // 呼叫 AuthManager 儲存 Token
} else {
print("警告: 登入成功但未收到 Token,將不儲存。");
}
if (token != null) {
// 儲存資訊至 AuthManager (包含公司別與 UserID)
await AuthManager.saveLoginInfo(token, userId, comp);
// 登入成功:導航至 MainMenu 並替換登入頁面(防止按返回鍵回到登入)
if (mounted) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MainMenu()),
);
if (mounted) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MainMenu()),
);
}
} else {
setState(() => _errorMessage = '登入成功但未取得授權碼(Token)');
}
} else {
// 登入失敗:顯示錯誤訊息
setState(() {
_errorMessage = '登入失敗,請重新輸入正確的帳號及密碼!';
});
setState(() => _errorMessage = responseData['msg'] ?? '帳號或密碼錯誤');
}
} catch (e) {
// 網路或伺服器錯誤
setState(() {
_errorMessage = '網路錯誤或伺服器無法連線。';
});
setState(() => _errorMessage = '系統發生異常,請聯繫管理員');
} finally {
setState(() {
_isLoading = false;
});
if (mounted) setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
// UI 部分保持不變,但按鈕觸發的是重構後的 _logon
return Scaffold(
appBar: AppBar(title: const Text('用戶登入')),
appBar: AppBar(title: const Text('企業行動化系統')),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(32.0),
@@ -128,73 +83,32 @@ class _LoginPageState extends State<LoginPage> {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const Icon(Icons.lock_open, size: 80, color: Colors.blue),
const SizedBox(height: 48.0),
const Icon(Icons.business_center, size: 80, color: Colors.blueAccent),
const SizedBox(height: 40),
// 公司別輸入框
TextField(
controller: _compController,
decoration: const InputDecoration(
labelText: '公司代號',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.person),
),
keyboardType: TextInputType.text,
),
const SizedBox(height: 16.0),
_buildTextField(_compController, '公司代號', Icons.domain),
const SizedBox(height: 16),
_buildTextField(_userController, '用戶帳號', Icons.person),
const SizedBox(height: 16),
_buildTextField(_pwdController, '密碼', Icons.lock, obscure: true),
// 帳號輸入框
TextField(
controller: _userController,
decoration: const InputDecoration(
labelText: '用戶帳號',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.person),
),
keyboardType: TextInputType.text,
),
const SizedBox(height: 16.0),
// 密碼輸入框
TextField(
controller: _pwdController,
obscureText: true,
decoration: const InputDecoration(
labelText: '密碼',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.lock),
),
onSubmitted: (_) => _logon(), // 允許按 Enter 鍵登入
),
const SizedBox(height: 16.0),
// 錯誤訊息顯示
const SizedBox(height: 20),
if (_errorMessage != null)
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Text(
_errorMessage!,
Text(_errorMessage!,
style: const TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
textAlign: TextAlign.center),
// 登入按鈕
const SizedBox(height: 20),
ElevatedButton(
onPressed: _isLoading ? null : _logon,
style: ElevatedButton.styleFrom(
// 修正點:使用 minimumSize 設定寬度與高度
// Size(double.infinity, 50) 代表寬度撐滿,高度為 50
minimumSize: const Size(double.infinity, 50),
),
child: _isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(strokeWidth: 3.0),
)
: const Text(
'登入',
style: TextStyle(fontSize: 18),
),
? const CircularProgressIndicator()
: const Text('登入系統', style: TextStyle(fontSize: 18)),
),
],
),
@@ -202,4 +116,16 @@ class _LoginPageState extends State<LoginPage> {
),
);
}
Widget _buildTextField(TextEditingController controller, String label, IconData icon, {bool obscure = false}) {
return TextField(
controller: controller,
obscureText: obscure,
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(icon),
border: const OutlineInputBorder(),
),
);
}
}