قبل ما تبدين
الفكرة في سطر
الداشبورد ما يقرأ الملفات اللي توصلك أبدًا. يقرأ جدول واحد اسمه tblHEMAYA_Log شكله ثابت. كل ملف جديد يمر بخطوة ترجمة تحوله لهذا الشكل. لو تغير المصدر بكرة، تعدلين الترجمة بس، والداشبورد ما يحس.
05_Daily_Meeting\3_Output\HEMAYA_Merge_Template.xlsx: فيه مثال لمصدرين مختلفين، وجدول الترجمة، والدمج بمعادلات الإكسل، وكود Power Query جاهز للنسخ. افتحيه جنب هذا الدليل.الخطوة 1
الشكل القياسي: 19 عمود ما تتغير
هذي أعمدة tblHEMAYA_Log اللي يقرأها الداشبورد. لا تغيرين اسم ولا ترتيب. إذا مصدر ما عنده عمود، يبقى فاضي.
| العمود | النوع | وش يعني | يظهر في الداشبورد اليومي؟ |
|---|---|---|---|
ID | نص | رقم الملاحظة، لازم يكون فريد | مفتاح العد |
Reported | تاريخ | تاريخ الرصد | هذا الشهر |
Area · Location | نص | المنطقة (Train A/B/C، Common Area، Cooling Tower) والمكان بالضبط | نعم: وين |
Type · Category · Severity | نص | نوع الملاحظة وتصنيفها وشدتها | نعم: وش نوعها |
What happened | نص | الوصف | نعم |
Corrective action (how closed) | نص | خطوات الإصلاح | نعم: كيف تنقفل |
Raised by | نص | مين رفعها | نعم: كل موظف كم رفع |
Owner | نص | مين مسند له الإغلاق | نعم: المسند للميكانيكال |
Target date · Closed date · Status | تاريخ / نص | الهدف، الإغلاق الفعلي، الحالة (Open، In progress، Closed) | مفتوح أو متأخر |
Source | نص | من أي ملف جات (System، Contractor) | للتدقيق |
الجدول الثاني: People
الداشبورد ما يعرف إن "Foreman B" ميكانيكي. يعرفه من جدول tblHEMAYA_People: الاسم، والقسم. كل اسم يظهر في Raised by أو Owner لازم يكون فيه، وإلا قسمه يطلع Other وما ينحسب للفريق.
| Name | Department | Role |
|---|---|---|
| Foreman A | Mechanical | Foreman |
| Mechanical supervisor | Mechanical | Supervisor |
| Rawabi | Mechanical | Data analyst |
| HSE officer | HSE | Officer |
| Supervisor Common | Operations | Supervisor |
ليش ما نكتب القسم في كل سطر ملاحظة؟ لأن الاسم يتكرر مئات المرات والقسم يتغير مرة بالسنة. مكان واحد للمعلومة، مثل ماستر الموظفين.
الخطوة 2
بالإكسل أولًا: XLOOKUP و VSTACK
هذي الطريقة عشان تفهمين وتتحققين. الطريقة اليومية هي Power Query في الخطوة 3. افتحي شيت Merged_Excel في القالب وشوفي المعادلات وهي شغالة.
أ. ترجمة القيم بـ XLOOKUP
المقاول يكتب Train-B وإحنا نكتب Train B. جدول tblValueFix فيه From و To، والمعادلة:
=XLOOKUP([@Section], tblValueFix[From], tblValueFix[To], [@Section])
آخر وسيطة هي "إذا ما لقيت": ترجّع القيمة نفسها. كذا القيم الصحيحة أصلًا تمر بدون تغيير.
ب. القسم من People بـ XLOOKUP
=XLOOKUP([@Owner], tblPeople[Name], tblPeople[Department], "Other")
نفس الفكرة: الاسم ← القسم، والافتراضي Other عشان تلاحظين الأسماء الناقصة بسرعة (فلتري على Other).
ج. لزق الملفين تحت بعض بـ VSTACK (Excel 365)
كل مصدر تختارين أعمدته بالترتيب القياسي بـ HSTACK، وبعدين VSTACK يحطهم تحت بعض:
=VSTACK(
HSTACK(tblSrcSystem[ID], tblSrcSystem[Reported], tblSrcSystem[Area], ...),
HSTACK(tblSrcContractor[Ref No], DATEVALUE(tblSrcContractor[Date]),
XLOOKUP(tblSrcContractor[Section], tblValueFix[From], tblValueFix[To], tblSrcContractor[Section]), ...)
)
- DATEVALUE لأن المقاول يكتب التاريخ نص "10/09/2026"، والداشبورد يبغاه تاريخ.
- المعادلة تنسكب (spill) لحالها بعدد الصفوف. لا تكتبين شي تحتها.
- الأعمدة الناقصة عند المقاول (Equipment، Root cause) تحط مكانها
"".
الخطوة 3
الطريقة المعتمدة: Power Query
الهدف: ملف اسمه HEMAYA_Merged.xlsx فيه شيت People وشيت HEMAYA_Log (جدول tblHEMAYA_Log) يتعبى لحاله من الملفين.
- جهزي مجلد ثابت وأسماء ثابتةمثلًا
OneDrive\HEMAYA\وفيهHEMAYA_System_Export.xlsxوHEMAYA_Contractor.xlsx. كل مرة يوصلك ملف، احفظيه فوق القديم بنفس الاسم. ليش: Power Query يبحث بالاسم، ولو تغير الاسم ينكسر. - سوي ملف HEMAYA_Merged.xlsx وفيه شيت Peopleانسخي جدول People من القالب (Ctrl+T واسمه tblPeople).
- Data ← Get Data ← From Other Sources ← Blank Query ← Advanced Editorالصقي الكود اللي تحت (موجود كامل في شيت PowerQuery_M بالقالب)، وغيري FolderPath بس.
- سمّي الاستعلام HEMAYA_Log ← Close & Load To ← Table ← شيت جديدالجدول اللي يطلع اسمه تلقائيًا
HEMAYA_Log. غيريه إلىtblHEMAYA_Logمن Table Design. ليش: الداشبورد يدور على هذا الاسم بالضبط. - تحققيفلتري عمود Owner dept على Other: كل اسم يطلع هنا ناقص في People. أضيفيه وRefresh.
الكود، خطوة خطوة
// المصدر 1: تصدير النظام (أعمدته أصلاً قياسية) Sys1 = Excel.Workbook(File.Contents(FolderPath & "HEMAYA_System_Export.xlsx"), null, true){[Item="tblSrcSystem", Kind="Table"]}[Data], Sys2 = Table.AddColumn(Sys1, "Source", each "System", type text), // المصدر 2: المقاول. الترجمة = إعادة تسمية الأعمدة (نفس Column_Map في القالب) Con2 = Table.RenameColumns(Con1, {{"Ref No","ID"}, {"Date","Reported"}, {"Section","Area"}, {"Place","Location"}, {"Observation","What happened"}, {"Obs Type","Type"}, {"Hazard","Category"}, {"Risk","Severity"}, {"Reported By","Raised by"}, {"Assigned To","Owner"}, {"Action Taken","Corrective action (how closed)"}, {"Due","Target date"}, {"Closed On","Closed date"}, {"Stage","Status"}}), Con4 = Table.ReplaceValue(Con3, "Train-", "Train ", Replacer.ReplaceText, {"Area"}), // تصحيح القيم // الشكل القياسي: دالة صغيرة تضيف الأعمدة الناقصة فاضية وترتب الأعمدة Std = {"ID","Reported","Area","Location","Equipment","Type","Category","Severity","What happened", "Root cause (why)","Immediate action","Corrective action (how closed)","Raised by","Owner", "Target date","Closed date","Status","Verified by","Source"}, Fill = (t as table) as table => let missing = List.Difference(Std, Table.ColumnNames(t)), added = List.Accumulate(missing, t, (acc, c) => Table.AddColumn(acc, c, each null, type text)) in Table.SelectColumns(added, Std), // الدمج تحت بعض = Append All = Table.Combine({Fill(Sys2), Fill(Con8)}), Typed = Table.TransformColumnTypes(All, {{"Reported", type date}, {"Target date", type date}, {"Closed date", type date}}, "en-GB"), // القسم من People = Merge (نفس XLOOKUP) J1 = Table.NestedJoin(Typed, {"Owner"}, People0, {"Name"}, "OP", JoinKind.LeftOuter), J2 = Table.ExpandTableColumn(J1, "OP", {"Department"}, {"Owner dept"}), J3 = Table.NestedJoin(J2, {"Raised by"}, People0, {"Name"}, "RP", JoinKind.LeftOuter), J4 = Table.ExpandTableColumn(J3, "RP", {"Department"}, {"Raised dept"}), Final = Table.ReplaceValue(J4, null, "Other", Replacer.ReplaceValue, {"Owner dept", "Raised dept"})
| في الإكسل | في Power Query | الفرق |
|---|---|---|
| XLOOKUP | Merge Queries (NestedJoin) ثم Expand | Merge يجيب أكثر من عمود مرة وحدة، ويفرق بين الكبيرة والصغيرة |
| VSTACK | Append Queries (Table.Combine) | Combine يطابق بالاسم مو بالترتيب، فلازم الأسماء متطابقة |
| إعادة تسمية العمود يدويًا | Table.RenameColumns | تنكتب مرة وتتكرر كل Refresh |
| DATEVALUE | Table.TransformColumnTypes مع "en-GB" | en-GB تقول له اليوم قبل الشهر |
ليش كل هذا بدل ما تنسخين وتلصقين؟ لأن النسخ يصير كل يوم ويغلط مرة بالأسبوع. هنا الغلط يصير مرة وحدة وقت الإعداد، وبعدين Refresh.
الخطوة 4
ربط الداشبورد
في Power BI الجدول HEMAYA_Log حاليًا يقرأ من Daily_Inputs.xlsx. لما يجهز HEMAYA_Merged.xlsx غيري المصدر بس:
- Transform data ← الاستعلام HEMAYA_Log ← خطوة Source ← غيري المسار إلى HEMAYA_Merged.xlsx (أو رابط OneDrive في الدوام).
- نفس الشي للاستعلام HEMAYA_People ← tblPeople.
- Close & Apply. الأعمدة نفسها، فكل المقاييس والصفحات تشتغل مثل ما هي.
وإذا كان الدمج داخل Power BI مباشرة أسهل عندك (بدون ملف وسيط)، نفس كود M ينلصق في Power BI Desktop حرفيًا. الفرق إن الملف الوسيط يخلي أي أحد يفتح الإكسل ويشوف النتيجة بدون Power BI.
الخطوة 5
الداشبورد اليومي: بطاقة بطاقة
صفحة "Daily meeting" في اللوحة الموحدة اتغيرت: حماية أول شي. هذا شكلها الجديد، وتحته تفصيل كل عنصر.

الصف الأول: ست بطاقات
| # | البطاقة | الرقم الكبير (المقياس) | السطر الصغير | ليش هنا |
|---|---|---|---|---|
| 1 | HEMAYA assigned to Mechanical أحمر | H Assigned Mech: عدد الملاحظات اللي Owner dept = Mechanical | H Sub assigned: Open X · overdue Y | هذا شغل القسم المعلق. أحمر لأنه يحتاج فعل |
| 2 | HEMAYA raised by Mechanical أخضر | H Raised Mech: عدد الملاحظات اللي Raised dept = Mechanical | H Sub raised: This month N · count only | مشاركة الفريق في السلامة. عدد فقط مثل ما طلبتي |
| 3 | Production yesterday | D Actual yesterday: مجموع Actual MT ليوم قبل تاريخ الاجتماع | الهدف والنسبة | الرقم اللي يسأل عنه المدير أول |
| 4 | Downtime yesterday, h | D Downtime yesterday | — | يفسر رقم الإنتاج |
| 5 | Concerns open | D Concerns open | كم فات موعده | المتابعات |
| 6 | Condition alerts | D CM open | كم بمستوى Danger | مراقبة الحالة |
المقاييس الجديدة بالكامل (في جدول _Measures، مجلد 01 HEMAYA)
H Assigned Mech = CALCULATE ( COUNTROWS ( HEMAYA_Log ), HEMAYA_Log[Owner dept] = "Mechanical" ) + 0
H Assigned Mech open = CALCULATE ( COUNTROWS ( HEMAYA_Log ), HEMAYA_Log[Owner dept] = "Mechanical", HEMAYA_Log[Status] <> "Closed" ) + 0
H Assigned Mech overdue = CALCULATE ( COUNTROWS ( HEMAYA_Log ), HEMAYA_Log[Owner dept] = "Mechanical", HEMAYA_Log[Overdue] = 1 ) + 0
H Raised Mech = CALCULATE ( COUNTROWS ( HEMAYA_Log ), HEMAYA_Log[Raised dept] = "Mechanical" ) + 0
H Raised Mech month =
VAR ref = CALCULATE ( MAX ( HEMAYA_Log[Reported] ), ALL ( HEMAYA_Log ) )
RETURN CALCULATE ( COUNTROWS ( HEMAYA_Log ), HEMAYA_Log[Raised dept] = "Mechanical",
HEMAYA_Log[Reported] >= DATE ( YEAR ( ref ), MONTH ( ref ), 1 ) ) + 0
H Sub assigned = "Open " & FORMAT ( [H Assigned Mech open], "#,0" ) & " · overdue " & FORMAT ( [H Assigned Mech overdue], "#,0" )
H Sub raised = "This month " & FORMAT ( [H Raised Mech month], "#,0" ) & " · count only"
+ 0في الآخر: عشان تطلع 0 بدل فراغ لما ما فيه شي.Overdue: عمود محسوب في Power Query: مو مقفلة وتاريخ الهدف فات.- "هذا الشهر" يُحسب من آخر تاريخ رصد في البيانات، مو من تاريخ اليوم، عشان الأرقام ما تصير أصفار لو البيانات متأخرة يومين.
الصف الثاني: الجدول والرسم
| العنصر | النوع | الحقول | الفلتر | الترتيب | الموقع والمقاس |
|---|---|---|---|---|---|
| HEMAYA assigned to Mechanical, still open | Table | Location · Type · What happened · Corrective action (يظهر باسم "How to close it") · Owner · Status pill · Age | Owner dept = Mechanical و IsClosed = 0 | Days open تنازلي (الأقدم فوق) | 108, 240 · 746 × 190 |
| Reports raised per employee | Clustered bar | المحور: Raised by · القيمة: H Total (يظهر باسم Reports) | Raised dept = Mechanical | بالعدد تنازلي | 896, 240 · 352 × 190 |
ليش المفتوحة بس في الجدول؟ لأن الاجتماع الصباحي يبغى "وش باقي علينا"، والمقفلة موجودة في صفحة HEMAYA الكاملة. وليش الأقدم فوق؟ لأن الأقدم هو الأخطر، وشارة Age تلونه برتقالي بعد 30 يوم وأحمر بعد 60.
الصف الثالث
| العنصر | النوع | الحقول | الفلتر | الموقع والمقاس |
|---|---|---|---|---|
| Production against target | Line & clustered column | المحور: Meeting date · الأعمدة: D Prod trend actual · الخط: D Prod trend target | — | 108, 504 · 352 × 188 |
| Today's plan | Table | Activities: Area · Activity · Work order · Crew · Status | When = Today | 502, 504 · 352 × 188 |
| Concerns and follow-ups | Table | Concerns: Area · Concern · Owner · Due | Status ≠ Closed | 896, 504 · 352 × 188 |
أرقام تتحققين منها بعد Refresh (البيانات التجريبية)
| البطاقة | المفروض | كيف طلعت |
|---|---|---|
| HEMAYA assigned to Mechanical | 100 | Owner في: Area engineer 24 + Foreman A 24 + Foreman B 20 + Foreman C 18 + Mechanical supervisor 14 |
| HEMAYA raised by Mechanical | 96 | Raised by في: Foreman C 24 + Area engineer 20 + Foreman A 19 + Rawabi 18 + Foreman B 15 |
| الرسم: أعلى موظف | Foreman C = 24 | ترتيب تنازلي |
لو طلع عندك 0 في البطاقتين: يا الاستعلام HEMAYA_People ما انقرأ، يا الأسماء في People مو مطابقة للأسماء في السجل.
لو بتبنينها بنفسك في Power BI (بدون الملف الجاهز)
- Power Query: أضيفي الاستعلام HEMAYA_People، وفي استعلام HEMAYA_Log أضيفي Merge مرتين (Owner ثم Raised by) وExpand عمود Department، وسمّيهم Owner dept و Raised dept، وبدّلي null بـ Other.
- المقاييس السبعة فوق في جدول _Measures.
- الصف الأول: 6 بطاقات Card بالترتيب في الجدول، الرقم DIN 22، والسطر الصغير Segoe UI 7.5 رمادي.
- الجدول: Filters on this visual ← Owner dept is Mechanical، وIsClosed is 0. Sort ← Days open ← Descending.
- الرسم: Clustered bar، Raised by على المحور، H Total في القيم، فلتر Raised dept = Mechanical، Data labels on، لون ذهبي.
التفاصيل الكاملة لكل الصفحات (المواقع بالبكسل والكود) في دليل بناء Maintenance Hub.
انتبهي
الفخاخ
| الفخ | وش يصير | الحل |
|---|---|---|
| اسم بمسافة زايدة أو حرف كبير مختلف | Power Query ما يطابقه، والقسم يطلع Other | Table.TransformColumns مع Text.Trim، أو صححي الاسم في People |
| نفس الملاحظة في الملفين | تنعد مرتين | بعد Combine أضيفي Table.Distinct(All, {"ID"}) |
| ID فاضي في ملف المقاول | الصف ينحذف في NoBlank | اصنعي ID: "CON-" & Date.ToText([Reported],"yyyyMMdd") & "-" & Text.From([Index]) |
| تاريخ يوم/شهر يتفسر شهر/يوم | 10/09 يصير 9 أكتوبر | "en-GB" في TransformColumnTypes |
| حالة مكتوبة "closed" أو "CLOSED" | ما تنحسب مقفلة | Text.Proper على عمود Status |
آخر تحديث 14 سبتمبر 2026. القالب: 05_Daily_Meeting\3_Output\HEMAYA_Merge_Template.xlsx