Upload 4 files
Browse files
Code.gs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
/*
|
| 2 |
سجل المهام - Google Apps Script
|
|
|
|
|
|
|
| 3 |
الأعمدة:
|
| 4 |
A = اليوم
|
| 5 |
B = المهمة
|
|
@@ -8,10 +10,26 @@
|
|
| 8 |
*/
|
| 9 |
const SHEET_NAME = "المهام";
|
| 10 |
|
| 11 |
-
function doGet() {
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
}
|
| 14 |
|
|
|
|
| 15 |
function doPost(e) {
|
| 16 |
try {
|
| 17 |
const body = JSON.parse((e && e.postData && e.postData.contents) || "{}");
|
|
@@ -51,7 +69,7 @@ function listTasks_() {
|
|
| 51 |
})).filter(x => x.date || x.task || x.department || x.status)
|
| 52 |
.sort((a,b) => a.date === b.date ? b.row-a.row : (a.date < b.date ? 1 : -1));
|
| 53 |
|
| 54 |
-
return json_({ok:true, tasks});
|
| 55 |
}
|
| 56 |
|
| 57 |
function addTask_(body) {
|
|
@@ -59,15 +77,13 @@ function addTask_(body) {
|
|
| 59 |
const task = String(body.task || "").trim();
|
| 60 |
const department = String(body.department || "").trim();
|
| 61 |
const status = validStatus_(body.status);
|
| 62 |
-
|
| 63 |
validateTask_(date, task, department);
|
| 64 |
|
| 65 |
const sh = sheet_();
|
| 66 |
const lock = LockService.getDocumentLock();
|
| 67 |
lock.waitLock(10000);
|
| 68 |
try {
|
| 69 |
-
|
| 70 |
-
sh.appendRow([dateObj, task, department, status]);
|
| 71 |
sh.getRange(sh.getLastRow(),1).setNumberFormat("yyyy-mm-dd");
|
| 72 |
SpreadsheetApp.flush();
|
| 73 |
} finally {
|
|
@@ -129,7 +145,7 @@ function validateTask_(date, task, department) {
|
|
| 129 |
function validStatus_(value) {
|
| 130 |
const status = String(value || "").trim();
|
| 131 |
const allowed = ["", "مخطط لها", "جاري العمل", "تم الإنجاز"];
|
| 132 |
-
if (
|
| 133 |
return status;
|
| 134 |
}
|
| 135 |
|
|
|
|
| 1 |
/*
|
| 2 |
سجل المهام - Google Apps Script
|
| 3 |
+
النسخة 18: جميع العمليات تدعم GET لتفادي مشكلة الاتصال من الاستضافة.
|
| 4 |
+
|
| 5 |
الأعمدة:
|
| 6 |
A = اليوم
|
| 7 |
B = المهمة
|
|
|
|
| 10 |
*/
|
| 11 |
const SHEET_NAME = "المهام";
|
| 12 |
|
| 13 |
+
function doGet(e) {
|
| 14 |
+
try {
|
| 15 |
+
const p = (e && e.parameter) || {};
|
| 16 |
+
const action = String(p.action || "").trim();
|
| 17 |
+
|
| 18 |
+
// فتح رابط /exec مباشرة للاختبار
|
| 19 |
+
if (!action) return json_({ok:true, message:"Tasks API is running"});
|
| 20 |
+
|
| 21 |
+
if (action === "list") return listTasks_();
|
| 22 |
+
if (action === "add") return addTask_(p);
|
| 23 |
+
if (action === "update") return updateTask_(p);
|
| 24 |
+
if (action === "delete") return deleteTask_(p);
|
| 25 |
+
|
| 26 |
+
return json_({ok:false, message:"طلب غير معروف"});
|
| 27 |
+
} catch (err) {
|
| 28 |
+
return json_({ok:false, message:err.message || "حدث خطأ غير متوقع"});
|
| 29 |
+
}
|
| 30 |
}
|
| 31 |
|
| 32 |
+
// إبقاء POST للتوافق مع أي نسخة قديمة من الصفحة.
|
| 33 |
function doPost(e) {
|
| 34 |
try {
|
| 35 |
const body = JSON.parse((e && e.postData && e.postData.contents) || "{}");
|
|
|
|
| 69 |
})).filter(x => x.date || x.task || x.department || x.status)
|
| 70 |
.sort((a,b) => a.date === b.date ? b.row-a.row : (a.date < b.date ? 1 : -1));
|
| 71 |
|
| 72 |
+
return json_({ok:true, tasks:tasks});
|
| 73 |
}
|
| 74 |
|
| 75 |
function addTask_(body) {
|
|
|
|
| 77 |
const task = String(body.task || "").trim();
|
| 78 |
const department = String(body.department || "").trim();
|
| 79 |
const status = validStatus_(body.status);
|
|
|
|
| 80 |
validateTask_(date, task, department);
|
| 81 |
|
| 82 |
const sh = sheet_();
|
| 83 |
const lock = LockService.getDocumentLock();
|
| 84 |
lock.waitLock(10000);
|
| 85 |
try {
|
| 86 |
+
sh.appendRow([dateObject_(date), task, department, status]);
|
|
|
|
| 87 |
sh.getRange(sh.getLastRow(),1).setNumberFormat("yyyy-mm-dd");
|
| 88 |
SpreadsheetApp.flush();
|
| 89 |
} finally {
|
|
|
|
| 145 |
function validStatus_(value) {
|
| 146 |
const status = String(value || "").trim();
|
| 147 |
const allowed = ["", "مخطط لها", "جاري العمل", "تم الإنجاز"];
|
| 148 |
+
if (allowed.indexOf(status) === -1) throw new Error("حالة المهمة غير صحيحة");
|
| 149 |
return status;
|
| 150 |
}
|
| 151 |
|
script.js
CHANGED
|
@@ -21,17 +21,12 @@ function toast(message,error=false){
|
|
| 21 |
}
|
| 22 |
async function apiRequest(payload){
|
| 23 |
try {
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
{type:"text/plain"}
|
| 28 |
-
);
|
| 29 |
-
const res = await fetch(API_URL, {
|
| 30 |
-
method: "POST",
|
| 31 |
-
body,
|
| 32 |
-
redirect: "follow",
|
| 33 |
-
cache: "no-store"
|
| 34 |
});
|
|
|
|
|
|
|
| 35 |
if (!res.ok) throw new Error(`تعذر الاتصال بالخادم (${res.status})`);
|
| 36 |
const text = await res.text();
|
| 37 |
let data;
|
|
@@ -40,9 +35,7 @@ async function apiRequest(payload){
|
|
| 40 |
if (!data.ok) throw new Error(data.message || "حدث خطأ");
|
| 41 |
return data;
|
| 42 |
} catch (err) {
|
| 43 |
-
if (err instanceof TypeError)
|
| 44 |
-
throw new Error("تعذر الاتصال بقاعدة البيانات");
|
| 45 |
-
}
|
| 46 |
throw err;
|
| 47 |
}
|
| 48 |
}
|
|
|
|
| 21 |
}
|
| 22 |
async function apiRequest(payload){
|
| 23 |
try {
|
| 24 |
+
const params = new URLSearchParams();
|
| 25 |
+
Object.entries({...payload, _ts: Date.now()}).forEach(([k,v]) => {
|
| 26 |
+
params.set(k, v == null ? "" : String(v));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
});
|
| 28 |
+
const url = `${API_URL}?${params.toString()}`;
|
| 29 |
+
const res = await fetch(url, {method:"GET", cache:"no-store", redirect:"follow"});
|
| 30 |
if (!res.ok) throw new Error(`تعذر الاتصال بالخادم (${res.status})`);
|
| 31 |
const text = await res.text();
|
| 32 |
let data;
|
|
|
|
| 35 |
if (!data.ok) throw new Error(data.message || "حدث خطأ");
|
| 36 |
return data;
|
| 37 |
} catch (err) {
|
| 38 |
+
if (err instanceof TypeError) throw new Error("تعذر الاتصال بقاعدة البيانات");
|
|
|
|
|
|
|
| 39 |
throw err;
|
| 40 |
}
|
| 41 |
}
|