修改幾個小 issue

This commit is contained in:
2026-03-21 21:23:56 +08:00
parent 9068d85c92
commit af27b77ad7
11 changed files with 674 additions and 120 deletions
+27 -12
View File
@@ -1,4 +1,4 @@
// todo_api.dart (新增 Create 功能)
// todo_api.dart
import './todo_model.dart';
import '../services/generic_api_service.dart';
@@ -10,16 +10,31 @@ class TodoApiService {
TodoApiService({this.currentUserId = 'admin'});
// 原始的查詢功能...
/// 獲取指定日期的任務清單
Future<List<Todo>> fetchTodos({DateTime? selectedDate}) async {
Future<List<Todo>> fetchTodos({DateTime? selectedDate, String? statusFilter}) async {
// 預設查詢今天的資料
DateTime dateToQuery = selectedDate ?? DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd').format(dateToQuery);
// 構建 queryFilter:過濾特定的 end_date 並根據 id 排序
// 格式範例: 1^100^id^*^^end_date^2024-05-01
String queryFilter = "1^100^id^*^^end_date^$formattedDate";
// 1. 組合 wheresql_org (第 5 個參數)
// 使用 LIKE 來比對 DATETIME 欄位,確保抓到該日期的所有時段
String whereSql = "end_date LIKE '$formattedDate%'";
// 2. 如果有傳入狀態過濾條件,動態加上 AND 語法
if (statusFilter != null && statusFilter != 'All') {
String dbStatus = '';
if (statusFilter == 'Done') dbStatus = 'DONE';
else if (statusFilter == 'In Progress') dbStatus = 'WIP';
else if (statusFilter == 'To do') dbStatus = 'TODO'; // 假設你的待辦狀態是 TODO
if (dbStatus.isNotEmpty) {
whereSql += " AND pbi_status = '$dbStatus'";
}
}
// 3. 嚴格依照 API 規範組裝 10 個參數 (共 9 個 ^ 分隔符)
// 格式:pageno^pagerec^orderby^udf_fields^wheresql_org^menuid^where_fields^where_value^where_field^where_idvalue
String queryFilter = "1^100^id^*^$whereSql^^^^^";
return await _apiService.fetchList<Todo>(
tableName: "eip_todolist",
@@ -36,14 +51,14 @@ class TodoApiService {
"task_name": todo.taskName,
"task_desc": todo.description,
"issue_priority": todo.priority,
"pbi_status": todo.status ?? 'WIP', // 預設為進行中
"pbi_status": todo.status ?? 'WIP',
"end_date": todo.endDate != null ? DateFormat('yyyy-MM-dd HH:mm:ss').format(todo.endDate!) : null,
"create_user": currentUserId,
"create_date": DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()),
// 新增時先不寫入 update_user / update_date
};
try {
// 根據 Generic API 規範,使用 action: "C" 進行新增
await _apiService.fetchList<dynamic>(
tableName: "eip_todolist",
pk: "id",
@@ -63,13 +78,13 @@ class TodoApiService {
Future<bool> updateTodoStatus(int id, String status) async {
final Map<String, dynamic> data = {
"id": id, // 必填 PK
"pbi_status": status, // 更新狀態為 'DONE'
"modify_user": currentUserId,
"modify_date": DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()),
"pbi_status": status, // 更新狀態
// 修正為 Schema 正確的欄位名稱 update_user / update_date
"update_user": currentUserId,
"update_date": DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()),
};
try {
// 使用 Action "U" 代表 Update
await _apiService.fetchList<dynamic>(
tableName: "eip_todolist",
pk: "id",
+26 -13
View File
@@ -1,4 +1,4 @@
// todo_form.dart (適配 Todo Model)
// todo_form.dart (適配 Todo Model - 中文化與選項調整)
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
@@ -21,8 +21,10 @@ class _TodoFormState extends State<TodoForm> {
final TextEditingController _nameController = TextEditingController();
final TextEditingController _descController = TextEditingController();
String _selectedClass = 'Work';
String _selectedPriority = 'Medium';
// 根據需求更新預設值與選項
String _selectedClass = '工作';
String _selectedPriority = 'Middle';
String _selectedStatus = 'ToDo'; // 新增狀態變數
DateTime _endDate = DateTime.now().add(const Duration(days: 7));
final Color primaryPurple = const Color(0xFF6542D0);
@@ -53,7 +55,7 @@ class _TodoFormState extends State<TodoForm> {
className: _selectedClass,
description: _descController.text,
priority: _selectedPriority,
status: 'WIP',
status: _selectedStatus, // 這裡改為帶入表單選擇的狀態
endDate: _endDate,
createdBy: widget.userId,
);
@@ -77,7 +79,7 @@ class _TodoFormState extends State<TodoForm> {
appBar: AppBar(
backgroundColor: bgLight, elevation: 0,
leading: IconButton(icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black87), onPressed: () => Navigator.pop(context)),
title: const Text('New Task', style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold)),
title: const Text('新增任務', style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold)),
centerTitle: true,
),
body: SingleChildScrollView(
@@ -87,15 +89,25 @@ class _TodoFormState extends State<TodoForm> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDropdownField('Task Category', _selectedClass, ['Work', 'Personal', 'Urgent'], (val) => setState(() => _selectedClass = val!)),
// 類別:改為 固定三個選項
_buildDropdownField('任務類別', _selectedClass, ['工作', '個人行程', '其他'], (val) => setState(() => _selectedClass = val!)),
const SizedBox(height: 20),
_buildTextField('Task Name', _nameController, 'e.g. Design UI Mockup', Icons.edit_note),
// 名稱與說明:加上中文提示
_buildTextField('任務名稱', _nameController, '例如:撰寫系統分析報告', Icons.edit_note),
const SizedBox(height: 20),
_buildTextField('Description', _descController, 'Enter details here...', Icons.description, isMultiline: true),
_buildTextField('任務說明', _descController, '請輸入任務詳細說明...', Icons.description, isMultiline: true),
const SizedBox(height: 20),
_buildDropdownField('Priority', _selectedPriority, ['High', 'Medium', 'Low'], (val) => setState(() => _selectedPriority = val!)),
// 優先級:改為 High, Middle, Low
_buildDropdownField('優先級', _selectedPriority, ['High', 'Middle', 'Low'], (val) => setState(() => _selectedPriority = val!)),
const SizedBox(height: 20),
_buildDatePicker('Due Date', _endDate),
// 新增狀態下拉選單
_buildDropdownField('目前狀態', _selectedStatus, ['ToDo', 'WIP', 'Hold', 'Done'], (val) => setState(() => _selectedStatus = val!)),
const SizedBox(height: 20),
_buildDatePicker('截止日期', _endDate),
const SizedBox(height: 40),
_buildSubmitButton(),
],
@@ -119,7 +131,7 @@ class _TodoFormState extends State<TodoForm> {
controller: controller,
maxLines: isMultiline ? 3 : 1,
decoration: InputDecoration(hintText: hint, border: InputBorder.none, isDense: true, contentPadding: const EdgeInsets.only(top: 8)),
validator: (v) => v == null || v.isEmpty ? 'Cannot be empty' : null,
validator: (v) => v == null || v.isEmpty ? '此欄位不能為空' : null, // 必填防呆中文化
)
],
),
@@ -155,7 +167,8 @@ class _TodoFormState extends State<TodoForm> {
children: [
Text(label, style: const TextStyle(fontSize: 12, color: Colors.grey)),
const SizedBox(height: 4),
Text(DateFormat('dd MMM, yyyy').format(date), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
// 日期格式也順便調整成台灣習慣的 YYYY/MM/DD
Text(DateFormat('yyyy/MM/dd').format(date), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
],
),
Icon(Icons.calendar_today, color: primaryPurple, size: 20),
@@ -172,7 +185,7 @@ class _TodoFormState extends State<TodoForm> {
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: primaryPurple, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), elevation: 5),
onPressed: _handleSubmit,
child: const Text('Create Task', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white)),
child: const Text('建立任務', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white)),
),
);
}
+7 -1
View File
@@ -1,3 +1,4 @@
// todo_model.dart
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
@@ -11,6 +12,8 @@ class Todo {
final DateTime? endDate; // end_date (預計完成日期)
final String? createdBy; // create_user (建立者)
final DateTime? createDate; // create_date (建立日期)
final String? updatedBy; // update_user (更新者) - 配合新 Schema 新增
final DateTime? updateDate; // update_date (更新日期) - 配合新 Schema 新增
Todo({
required this.id,
@@ -22,6 +25,8 @@ class Todo {
this.endDate,
this.createdBy,
this.createDate,
this.updatedBy,
this.updateDate,
});
// Factory 構造函數:從 API 返回的 JSON (Map) 創建 Todo 物件
@@ -29,7 +34,6 @@ class Todo {
// 輔助函數:安全解析日期字串
DateTime? parseDate(dynamic date) {
if (date is String && date.isNotEmpty) {
// 假設日期格式為 YYYY-MM-DD HH:mm:ss.sss 或 YYYY-MM-DD
return DateTime.tryParse(date);
}
return null;
@@ -45,6 +49,8 @@ class Todo {
endDate: parseDate(json['end_date']),
createdBy: json['create_user'] as String?,
createDate: parseDate(json['create_date']),
updatedBy: json['update_user'] as String?,
updateDate: parseDate(json['update_date']),
);
}