修正上架時 Google Play 檢查出的 issue
This commit is contained in:
@@ -24,17 +24,17 @@ class PlaceholderScreen extends StatelessWidget {
|
||||
|
||||
// 各功能頁面 (繼承自 PlaceholderScreen,方便未來替換成真實頁面)
|
||||
class AttendanceScreen extends PlaceholderScreen {
|
||||
AttendanceScreen({super.key}) : super(title: '員工打卡');
|
||||
const AttendanceScreen({super.key}) : super(title: '員工打卡');
|
||||
}
|
||||
|
||||
class ApprovalScreen extends PlaceholderScreen {
|
||||
ApprovalScreen({super.key}) : super(title: '待簽核事項');
|
||||
const ApprovalScreen({super.key}) : super(title: '待簽核事項');
|
||||
}
|
||||
|
||||
class TodoScreen extends PlaceholderScreen {
|
||||
TodoScreen({super.key}) : super(title: '待辦事項');
|
||||
const TodoScreen({super.key}) : super(title: '待辦事項');
|
||||
}
|
||||
|
||||
class CalendarScreen extends PlaceholderScreen {
|
||||
CalendarScreen({super.key}) : super(title: '行事曆');
|
||||
const CalendarScreen({super.key}) : super(title: '行事曆');
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
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";
|
||||
|
||||
class LoginPage extends StatefulWidget {
|
||||
const LoginPage({super.key});
|
||||
|
||||
@override
|
||||
State<LoginPage> createState() => _LoginPageState();
|
||||
}
|
||||
|
||||
class _LoginPageState extends State<LoginPage> {
|
||||
// 用於獲取輸入框內容
|
||||
final TextEditingController _userController = TextEditingController(text: '120102'); // 預設帳號
|
||||
final TextEditingController _pwdController = TextEditingController(text: 'gex123'); // 預設密碼
|
||||
final TextEditingController _compController = TextEditingController(text: 'demo'); // [新增] 預設值
|
||||
|
||||
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 = '請輸入帳號和密碼';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_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 回應
|
||||
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?
|
||||
: null;
|
||||
|
||||
if (token != null && token.isNotEmpty) {
|
||||
await AuthManager.saveLoginInfo(token, userId, comp); // 呼叫 AuthManager 儲存 Token
|
||||
} else {
|
||||
print("警告: 登入成功但未收到 Token,將不儲存。");
|
||||
}
|
||||
|
||||
// 登入成功:導航至 MainMenu 並替換登入頁面(防止按返回鍵回到登入)
|
||||
if (mounted) {
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const MainMenu()),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 登入失敗:顯示錯誤訊息
|
||||
setState(() {
|
||||
_errorMessage = '登入失敗,請重新輸入正確的帳號及密碼!';
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// 網路或伺服器錯誤
|
||||
setState(() {
|
||||
_errorMessage = '網路錯誤或伺服器無法連線。';
|
||||
});
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('用戶登入')),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
const Icon(Icons.lock_open, size: 80, color: Colors.blue),
|
||||
const SizedBox(height: 48.0),
|
||||
|
||||
// 公司別輸入框
|
||||
TextField(
|
||||
controller: _compController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: '公司代號',
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.person),
|
||||
),
|
||||
keyboardType: TextInputType.text,
|
||||
),
|
||||
const SizedBox(height: 16.0),
|
||||
|
||||
// 帳號輸入框
|
||||
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),
|
||||
|
||||
// 錯誤訊息顯示
|
||||
if (_errorMessage != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12.0),
|
||||
child: Text(
|
||||
_errorMessage!,
|
||||
style: const TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
|
||||
// 登入按鈕
|
||||
ElevatedButton(
|
||||
onPressed: _isLoading ? null : _logon,
|
||||
style: ElevatedButton.styleFrom(
|
||||
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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user