كيف قمنا ببناء تقارير ديناميكية في SSRS 2014


لقد تحدثنا بالفعل عن الكيفية التي ساعدنا بها إحدى شركات التصنيع على تحويل عمليات التدريب المؤسسي وتطوير الموظفين. حصل موظفو العميل ، الذين كانوا يغرقون في المستندات الورقية وجداول بيانات Excel ، على تطبيق iPad مناسب وبوابة ويب. واحدة من أهم وظائف هذا المنتج هي إنشاء تقارير ديناميكية يحكم من خلالها المديرين على عمل الموظفين "في الميدان". هذه وثائق ضخمة بعشرات الحقول ومتوسط ​​الأحجام 3000 * 1600 بكسل.

في هذه المقالة ، سنتحدث عن كيفية نشر هذا الجمال استنادًا إلى Microsoft SQL Server Reporting Services ، ولماذا يمكن أن تكون هذه الواجهة الخلفية أصدقاء سيئين مع بوابة الويب وما هي الحيل التي ستساعد في إقامة علاقاتهم. لقد تم بالفعل وصف الجزء التجاري بالكامل من الحل في المقالة السابقة ، لذلك نركز هنا على المشكلات الفنية. هيا بنا نبدأ!


صياغة المشكلة


لدينا بوابة يعمل بها عدة مئات من المستخدمين. يتم ترتيبها في تسلسل هرمي متدرج ، حيث يكون لكل مستخدم مشرف من رتبة أعلى. هذا التفريق في الحقوق ضروري بحيث يمكن للمستخدمين إنشاء الأحداث مع أي موظفين تابعين. يمكنك القفز فوق الخطوات ، أي يمكن للمستخدم بدء النشاط مع موظف من أي رتبة أدنى منه.

ما الأحداث المقصود هنا؟ يمكن أن يكون هذا تدريبًا أو دعمًا أو شهادة لموظف في شركة تجارية ، يقوم بها المشرف في نقطة البيع. نتيجة هذا الحدث هو استبيان معبأ على جهاز iPad مع تقييمات الموظفين للصفات والمهارات المهنية.

وفقًا للاستبيانات ، يمكنك إعداد إحصاءات ، على سبيل المثال:

  • كم عدد الأحداث مع مرؤوسيه من هذا النوع التي أنشأتها Vasya Ivanov في شهر؟ كم منهم اكتمل؟
  • ما هي النسبة المئوية للتقييمات المرضية؟ ما الأسئلة التي يجيب التجار على الأسوأ؟ أي مدير أسوأ في الخضوع للاختبارات؟

يتم تضمين هذه الإحصائيات في التقارير التي يمكن إنشاؤها عبر واجهة الويب بتنسيق XLS و PDF و DOCX وطباعتها. تم تصميم جميع هذه الوظائف للمديرين على مستويات مختلفة.

يتم تحديد محتوى وتصميم التقارير في النماذج ، مما يسمح لك بتعيين المعلمات الضرورية. إذا كان المستخدمون في المستقبل سيحتاجون إلى أنواع جديدة من التقارير ، فإن النظام لديه القدرة على إنشاء قوالب وتحديد معلمات قابلة للتعديل وإضافة قالب إلى البوابة الإلكترونية. كل هذا - دون التدخل في شفرة المصدر وعمليات عمل المنتج.

المواصفات والقيود


تعمل البوابة على بنية الخدمات الصغيرة ، والجبهة مكتوبة باللغة Angular 5. يستخدم المورد إذن JWT ، ويدعم متصفحات Google Chrome و Firefox و Microsoft Edge و IE 11 .

يتم تخزين كافة البيانات على MS SQL Server 2014. يتم تثبيت SQL Server Reporting Services (SSRS) على الخادم ، ويستخدمها العميل ولن يرفض. ومن هنا أهم القيود: الوصول إلى SSRS مغلق من الخارج ، حتى تتمكن من الوصول إلى واجهة الويب و SOAP فقط من الشبكة المحلية من خلال إذن NTLM.

بضع كلمات حول SSRS
SSRS – , , . docs.microsoft.com, SSRS (API) ( Report Server, - HTTP).

انتباه ، السؤال: كيف تكمل المهمة بدون طرق يدوية ، بأقل موارد وأقصى قدر من الفوائد للعميل؟

نظرًا لأن العميل لديه SSRS على خادم مخصص ، دع SSRS يقوم بكل الأعمال القذرة لإنشاء التقارير وتصديرها. بعد ذلك ، لا يتعين علينا كتابة خدمة إعداد التقارير الخاصة بنا ، وتصدير الوحدات النمطية إلى XLS و PDF و DOCX و HTML وواجهة برمجة التطبيقات المقابلة.

وبالتالي ، كانت المهمة هي تكوين صداقات SSRS مع البوابة الإلكترونية وضمان تشغيل الوظائف المحددة في المهمة. لذلك دعونا نراجع قائمة هذه السيناريوهات - تم العثور على التفاصيل الدقيقة المثيرة للاهتمام في كل نقطة تقريبًا.

هيكل الحل


نظرًا لأن لدينا SSRS بالفعل ، فهناك جميع الأدوات لإدارة قوالب التقارير:

  • Report Server - المسؤول عن منطق العمل الكامل مع التقارير وتخزينها وإنشائها وإدارتها وأكثر من ذلك بكثير.
  • Report Manager - خدمة بواجهة ويب لإدارة التقارير. هنا يمكنك تحميل القوالب التي تم إنشاؤها في أدوات بيانات SQL Server إلى الخادم ، وتكوين حقوق الوصول ومصادر البيانات والمعلمات (بما في ذلك تلك التي يمكن تغييرها عند إعداد تقارير الطلبات). إنه قادر على إنشاء تقارير عن النماذج التي تم تنزيلها وتحميلها إلى تنسيقات مختلفة ، بما في ذلك XLS و PDF و DOCX و HTML.

الإجمالي: نقوم بإنشاء قوالب في SQL Server Data Tools ، بمساعدة Report Manager ، نملأها على Report Server ، ونقوم بتكوينها - وهي جاهزة. يمكننا إنشاء تقارير وتغيير معلماتها.

السؤال التالي: كيفية طلب إنشاء تقارير عن قوالب محددة من خلال البوابة الإلكترونية والحصول على النتيجة في المقدمة لإخراجها إلى واجهة المستخدم أو تنزيلها بالتنسيق المطلوب؟

التقارير من SSRS إلى البوابة


كما قلنا أعلاه ، فإن SSRS لديه واجهة برمجة تطبيقات خاصة به للوصول إلى التقارير. لكننا لا نريد إعطاء وظائفها لأسباب تتعلق بالأمان والنظافة الرقمية - نحتاج فقط إلى طلب البيانات من SSRS بالشكل الصحيح وإرسال النتيجة إلى المستخدم. سيتم التعامل مع إدارة التقارير من قبل موظفي العملاء المدربين تدريبا خاصا.

نظرًا لأن الوصول إلى SSRS يتم فقط من الشبكة المحلية ، فإن تبادل البيانات بين الخادم والبوابة يتم من خلال خدمة الوكيل.


تبادل البيانات بين البوابة والخادم

لنرى كيف يعمل ولماذا ReportProxy موجود هنا.

لذلك ، على جانب البوابة ، لدينا ReportService ، الذي تصله البوابة للتقارير. تتحقق الخدمة من تفويض المستخدم ، ومستوى حقوقه ، وتحول البيانات من SSRS إلى النموذج المطلوب بموجب العقد.

يحتوي ReportService API على طريقتين فقط ، وهي كافية بالنسبة لنا:

  1. GetReports - يوفر معرفات وأسماء جميع القوالب التي يمكن للمستخدم الحالي استلامها ؛
  2. GetReportData (التنسيق ، المعلمات) - يوفر بيانات تقرير جاهزة ومصدرة بالتنسيق المحدد ، مع مجموعة معينة من المعلمات.

تحتاج الآن إلى هاتين الطريقتين لتتمكن من التواصل مع SSRS وأخذ البيانات اللازمة منه بالشكل الصحيح. من الوثائق المعروفة أنه يمكننا الوصول إلى خادم التقارير عبر HTTP باستخدام واجهة برمجة تطبيقات SOAP. يبدو أن اللغز آخذ في التطور ... ولكن في الحقيقة ، تنتظرنا مفاجأة هنا.

نظرًا لأن SSRS مغلق على العالم الخارجي ولا يمكنك الوصول إليه إلا من خلال مصادقة NTLM ، فإنه لا يتوفر مباشرة من بوابة SOAP. هناك أيضًا رغباتنا الخاصة:

  • امنح حق الوصول فقط إلى مجموعة الوظائف المطلوبة ، بل وحظر التغيير ؛
  • إذا كان عليك التبديل إلى نظام إعداد تقارير آخر ، فيجب أن تكون التعديلات في ReportService ضئيلة ، ومن الأفضل ألا تكون مطلوبة على الإطلاق.

هذا هو المكان الذي يساعدنا فيه ReportProxy ، والذي يقع على نفس الجهاز مثل SSRS وهو مسؤول عن طلبات الوكلاء من ReportService إلى SSRS. معالجة الطلب على النحو التالي:

  1. تتلقى الخدمة طلبًا من ReportService ، وتتحقق من تفويض JWT ؛
  2. وفقًا لطريقة واجهة برمجة التطبيقات (API) ، يمر الوكيل عبر بروتوكول SOAP في SSRS للحصول على البيانات اللازمة ، ويسجل الدخول عبر NTLM على طول الطريق ؛
  3. يتم إرسال البيانات المستلمة من SSRS إلى ReportService استجابة للطلب.

في الواقع ، ReportProxy هو محول بين SSRS و ReportService.
وحدة التحكم كما يلي:
[BasicAuthentication]
public class ReportProxyController : ApiController
{
    [HttpGet()]
    public List<ReportItem> Get(string rootPath)
    {
        //  ...
    }

    public HttpResponseMessage Post([FromBody]ReportRequest request)
    {
        //  ...
    }
}

BasicAuthentication :

public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        var authHeader = actionContext.Request.Headers.Authorization;

        if (authHeader != null)
        {
            var authenticationToken = actionContext.Request.Headers.Authorization.Parameter;
            var tokenFromBase64 = Convert.FromBase64String(authenticationToken);
            var decodedAuthenticationToken = Encoding.UTF8.GetString(tokenFromBase64);
            var usernamePasswordArray = decodedAuthenticationToken.Split(':');
            var userName = usernamePasswordArray[0];
            var password = usernamePasswordArray[1];

            var isValid = userName == BasiAuthConf.Login && password == BasiAuthConf.Password;

            if (isValid)
            {
                var principal = new GenericPrincipal(new GenericIdentity(userName), null);
                Thread.CurrentPrincipal = principal;

                return;
            }
        }

        HandleUnathorized(actionContext);
    }

    private static void HandleUnathorized(HttpActionContext actionContext)
    {
        actionContext.Response = actionContext.Request.CreateResponse(
            HttpStatusCode.Unauthorized
        );

        actionContext.Response.Headers.Add(
            "WWW-Authenticate", "Basic Scheme='Data' location = 'http://localhost:"
        );
    }
}


ونتيجة لذلك ، تبدو العملية كما يلي:

  1. ترسل الجبهة طلب http إلى ReportService ؛
  2. ترسل ReportService طلب http إلى ReportProxy ؛
  3. ReportProxy من خلال واجهة SOAP يتلقى البيانات من SSRS ويرسل النتيجة إلى ReportService ؛
  4. تقوم ReportService بإحضار النتيجة وفقًا للعقد وإعطائها للعميل.

لقد حصلنا على نظام عمل يطلب قائمة بالقوالب المتاحة ، ويذهب إلى SSRS لإعداد التقارير ، ويقدمها إلى الأمام بأي تنسيقات مدعومة. تحتاج الآن إلى عرض التقارير التي تم إنشاؤها في المقدمة وفقًا للمعايير المحددة ، وإعطاء الفرصة لتحميلها إلى ملفات XLS و PDF و DOCX والطباعة. لنبدأ بالشاشة.

العمل مع تقارير SSRS في البوابة


للوهلة الأولى ، إنه أمر يومي - يأتي التقرير بتنسيق HTML ، حتى نتمكن من القيام بكل ما نريد به! سنقوم بتضمينها في الصفحة ، وصبغها بأنماط التصميم ، والشيء في القبعة. في الواقع ، اتضح أن هناك ما يكفي من المزالق.

وفقًا لمفهوم التصميم ، يجب أن يتكون قسم التقارير على البوابة من صفحتين:

1) قائمة بالقوالب حيث يمكننا:

  • عرض إحصائيات عن أنشطة البوابة بأكملها ؛
  • رؤية جميع القوالب المتاحة لنا ؛
  • انقر على النموذج المطلوب وانتقل إلى منشئ التقارير المقابل.



2) منشئ تقارير يتيح لنا:

  • تعيين معلمات القالب وإنشاء تقرير عنها ؛
  • عرض ما حدث نتيجة لذلك ؛
  • حدد تنسيق ملف الإخراج ، قم بتنزيله ؛
  • طباعة التقرير بشكل مرئي ومريح.



لم تكن هناك مشاكل خاصة في الصفحة الأولى ، لذلك لن نأخذها في الاعتبار. وأجبرنا منشئ التقرير على تشغيل المهندس ، بحيث يكون من الملائم لأشخاص حقيقيين استخدام جميع الوظائف في المعارف التقليدية.

المشكلة رقم 1. طاولات عملاقة


وفقًا لمفهوم التصميم ، يجب أن تحتوي هذه الصفحة على منطقة عرض حتى يتمكن المستخدم من رؤية تقريره قبل التصدير. إذا كان التقرير لا يتناسب مع النافذة ، يمكنك التمرير أفقيًا وعموديًا. في الوقت نفسه ، يمكن أن يصل التقرير النموذجي إلى أحجام عدة شاشات ، مما يعني أننا بحاجة إلى كتل لاصقة بأسماء الصفوف والأعمدة. بدون ذلك ، سيتعين على المستخدمين العودة باستمرار إلى أعلى الجدول لتذكر ماذا تعني خلية معينة. أو بشكل عام ، سيكون من الأسهل طباعة تقرير والاحتفاظ بالأوراق اللازمة باستمرار أمام عينيك ، ولكن بعد ذلك يفقد الجدول الموجود على الشاشة معناه.

بشكل عام ، لا يمكن تجنب الكتل اللاصقة. ولا يعرف SSRS 2014 كيفية إصلاح الصفوف والأعمدة في مستند MHTML - فقط في واجهة الويب الخاصة به.

نذكر هنا أن المتصفحات الحديثة تدعم خاصية CSS اللاصقة ، التي توفر الوظيفة التي نحتاجها فقط. نضع الموضع: لزجة على الكتلة المحددة ، حدد المسافة البادئة على اليسار أو في الأعلى (خصائص اليسار ، أعلى) ، وستظل الكتلة في مكانها أثناء التمرير الأفقي والرأسي.

تحتاج إلى العثور على معلمة يمكن لـ CSS اللحاق بها. تُفقد قيم الخلايا المخصصة التي تسمح لـ SSRS 2014 بالتقاطها في واجهة الويب عند التصدير إلى HTML. حسنًا ، سنضع علامة عليها بأنفسنا - لن نفهم إلا الطريقة.

بعد عدة ساعات من قراءة الوثائق والمناقشات مع الزملاء ، بدا أنه لا توجد خيارات. وهنا ، بموجب جميع قوانين المؤامرة ، ظهر حقل تلميح الأدوات لنا ، مما يسمح لنا بتحديد تلميحات الأدوات للخلايا. اتضح أنه تم طرحه في رمز HTML الذي تم تصديره في سمة تلميح الأدوات - بالضبط على العلامة التي تنتمي إلى الخلية المخصصة في أدوات بيانات SQL Server. لم يكن هناك خيار - لم نجد طريقة أخرى لوضع علامة على الخلايا للتثبيت.

لذلك ، تحتاج إلى بناء قواعد وضع العلامات وإعادة توجيه العلامات في HTML عبر ToolTip. بعد ذلك ، باستخدام JS ، نقوم بتغيير سمة تلميح الأداة إلى فئة CSS في العلامة المحددة.

هناك طريقتان فقط لإصلاح الخلايا: عموديا (عمود ثابت) وأفقيا (صف ثابت). من المنطقي وضع علامة أخرى على خلايا الزوايا ، والتي تظل في مكانها عند التمرير في كلا الاتجاهين - ثابتة - كلاهما.

الخطوة التالية هي القيام بواجهة المستخدم. عندما تتلقى مستند HTML ، تحتاج إلى العثور على جميع عناصر HTML التي تحتوي على علامات ، والتعرف على القيم ، وتعيين فئة CSS المناسبة وإزالة سمة تلميح الأدوات بحيث لا تظهر عند المرور فوقها. وتجدر الإشارة إلى أن الترميز الناتج يتكون من جداول متداخلة (علامات جدول).

عرض الكود
type FixationType = 'row' | 'column' | 'both';

init(reportHTML: HTMLElement) {
    //    

    // -  
    const rowsFixed: NodeList = reportHTML.querySelectorAll('[title^="RowFixed"]');
    // -  
    const columnFixed: NodeList = reportHTML.querySelectorAll('[title^="ColumnFixed"]');
    // -    
    const bothFixed: NodeList = reportHTML.querySelectorAll('[title^="BothFixed"]');

    this.prepare(rowsFixed, 'row');
    this.prepare(columnFixed, 'column');
    this.prepare(bothFixed, 'both');
}

//    
prepare(nodeList: NodeList, fixingType: FixationType) {
    for (let i = 0; i < nodeList.length; i++) {
        const element: HTMLElement = nodeList[i];
        //   -
        element.classList.add(fixingType + '-fixed');

        element.removeAttribute('title');
        element.removeAttribute('alt'); //   SSRS

        element.parentElement.classList.add(fixingType  + '-fixed-parent');

        //     ,     
        element.style.width = element.getBoundingClientRect().width  + 'px';
        //     ,     
        element.style.height = element.getBoundingClientRect().height  + 'px';

        //  
        this.calculateCellCascadeParams(element, fixingType);
    }
}


وهنا مشكلة جديدة: مع السلوك المتتالي ، عندما يتم إصلاح عدة كتل تتحرك في اتجاه واحد في الجدول مرة واحدة ، فإن الخلايا التي تتحرك واحدة تلو الأخرى سيتم وضعها في طبقات. في الوقت نفسه ، ليس من الواضح كم يجب أن تتراجع كل كتلة تالية - يجب حساب المسافات البادئة عبر JavaScript بناءً على ارتفاع الكتلة أمامها. كل هذا ينطبق على كل من المراسي الرأسية والأفقية.

حل البرنامج النصي التصحيح المشكلة.
//      
calculateCellCascadeParams(cell: HTMLElement, fixationType: FixationType) {
    const currentTD: HTMLTableCellElement = cell.parentElement;
    const currentCellIndex = currentTD.cellIndex;

    //   
    currentTD.style.left = '';
    currentTD.style.top = '';

    const currentTDStyles = getComputedStyle(currentTD);

    //  
    if (fixationType === 'row' || fixationType === 'both') {
        const parentRow: HTMLTableRowElement = currentTD.parentElement;

        //        
        //    .
        //   ,    .
        let previousRow: HTMLTableRowElement = parentRow;
        let topOffset = 0;

        while (previousRow = previousRow.previousElementSibling) {
            let previousCellIndex = 0;
            let cellIndexBulk = 0;

            for (let i = 0; i < previousRow.cells.length; i++) {
                if (previousRow.cells[i].colSpan > 1) {
                    cellIndexBulk += previousRow.cells[i].colSpan;
                } else {
                    cellIndexBulk += 1;
                }

                if ((cellIndexBulk - 1) >= currentCellIndex) {
                    previousCellIndex = i;
                    break;
                }
            }

            const previousCell = previousRow.cells[previousCellIndex];

            if (previousCell.classList.contains(fixationType + '_fixed_parent')) {
                topOffset += previousCell.getBoundingClientRect().height;
            }
        }

        if (topOffset > 0) {
            if (currentTDStyles.top) {
                topOffset += <any>currentTDStyles.top.replace('px', '') - 0;
            }

            currentTD.style.top = topOffset + 'px';
        }
    }

    //  
    if (fixationType === 'column' || fixationType === 'both') {
        //       
        //     .
        //   ,    .
        let previousCell: HTMLTableCellElement = currentTD;
        let leftOffset = 0;

        while (previousCell = previousCell.previousElementSibling) {
            if (previousCell.classList.contains(fixationType + '_fixed_parent')) {
                leftOffset += previousCell.getBoundingClientRect().width;
            }
        }

        if (leftOffset > 0) {
            if (currentTDStyles.left) {
                leftOffset += <any>currentTDStyles.left.replace('px', '') - 0;
            }

            currentTD.style.left = leftOffset + 'px';
        }
    }
}


يتحقق الرمز من علامات العناصر المميزة ويضيف معلمات الخلايا الثابتة إلى قيمة المسافة البادئة. في حالة الصفوف الملتصقة ، يتم إضافة ارتفاعها للأعمدة وعرضها.


مثال على تقرير بخط علوي ثابت ،

ونتيجة لذلك ، تبدو العملية كما يلي:

  1. نحصل على الترميز من SSRS ولصقه في المكان الصحيح في DOM ؛
  2. التعرف على العلامات ؛
  3. اضبط معلمات السلوك المتتالي.

نظرًا لأن السلوك اللاصق يتم تنفيذه بالكامل من خلال CSS ، ويشارك JS فقط في إعداد المستند الوارد ، فإن الحل يعمل بسرعة كافية وبدون تأخيرات.

لسوء الحظ ، بالنسبة لـ IE ، كان يجب تعطيل الكتل اللاصقة بسبب لا يدعم الموقف: خاصية لزجة. والباقي - سفاري وموزيلا فايرفوكس و Chrome - يقومون بعمل ممتاز.

استمر.

المشكلة رقم 2. تقرير التصدير


لسحب تقرير خارج النظام ، يجب عليك (1) الوصول إلى SSRS عبر ReportService لكائن Blob ، (2) الحصول على رابط للكائن عبر الواجهة باستخدام طريقة window.URL.createObjectURL ، (3) وضع الرابط في العلامة ومحاكاة النقر على تحميل الملف.

يعمل هذا في Firefox و Safari وفي جميع إصدارات Chrome باستثناء Apple. حتى يدعم IE و Edge و Chrome لنظام iOS الوظيفة أيضًا ، كان علي أن أرمي أدمغتي مرة أخرى.

في IE و Edge ، لن يقوم الحدث ببساطة بتشغيل طلب متصفح لتنزيل الملف. تحتوي هذه المتصفحات على مثل هذه الميزة التي من أجل محاكاة النقر ، يلزم تأكيد المستخدم للتنزيل ، بالإضافة إلى إشارة واضحة لمزيد من الإجراءات. تم العثور على الحل في أسلوب window.navigator.msSaveOrOpenBlob () ، المتوفر في كل من IE و Edge. إنه يعرف فقط كيف يطلب إذن المستخدم للعملية ويوضح ما يجب القيام به بعد ذلك. لذا ، نحدد ما إذا كانت طريقة window.navigator.msSaveOrOpenBlob موجودة ، ونتصرف بناءً على الموقف.

لم يكن متصفح Chrome على iOS مثل هذا الاختراق ، وبدلاً من تقرير ، حصلنا على صفحة فارغة فقط. أثناء التجول في الويب ، وجدنا قصة مشابهة ، استنادًا إلى أنه في iOS 13 كان يجب إصلاح هذا الخطأ. للأسف ، كتبنا التطبيق مرة أخرى في أيام iOS 12 ، لذلك قررنا في النهاية عدم إضاعة المزيد من الوقت وإيقاف تشغيل الزر ببساطة في Chrome لنظام iOS.
الآن حول ما تبدو عليه عملية التصدير النهائية لواجهة المستخدم. يوجد زر في مكون التقرير الزاوي يطلق سلسلة من الخطوات:

  • من خلال معلمات الحدث ، يتلقى المعالج معرف تنسيق التصدير (على سبيل المثال ، "PDF") ؛
  • إرسال طلب إلى ReportService لتلقي كائن Blob للتنسيق المحدد ؛
  • للتحقق مما إذا كان المتصفح هو IE أو Edge ؛
  • عندما تأتي الإجابة من ReportService:
    • إذا كان IE أو Edge ، فإنه يطلق على window.navigator.msSaveOrOpenBlob (fileStream ، fileName) ؛
    • وإلا ، فإنه يستدعي طريقة this.exportDownload (fileStream ، fileName) ، حيث يكون fileStream هو النقطة التي تم الحصول عليها من الطلب إلى ReportService ، و fileName هو اسم الملف الذي سيتم حفظه. تنشئ الطريقة علامة مخفية مع ارتباط إلى window.URL.createObjectURL (fileStream) ، تحاكي نقرة وتزيل العلامة.

مع هذا الترتيب ، بقيت المغامرة الأخيرة.

المشكلة رقم 3. اطبع


يمكننا الآن رؤية التقرير على البوابة الإلكترونية وتصديره إلى تنسيقات XLS و PDF و DOCX. يبقى تنفيذ طباعة المستند من أجل الحصول على تقرير دقيق متعدد الصفحات. إذا تبين أن الجدول مقسم إلى صفحات ، فيجب أن يحتوي كل منها على عناوين - نفس الكتل اللاصقة التي تحدثنا عنها في القسم قبل الأخير.

أسهل خيار هو أخذ الصفحة الحالية مع التقرير المعروض ، وإخفاء كل شيء غير ضروري باستخدام CSS وإرساله للطباعة باستخدام طريقة window.print (). لا تعمل هذه الطريقة على الفور لعدة أسباب:

  1. منطقة عرض غير قياسية - يتم تضمين التقرير نفسه في منطقة قابلة للتمرير بشكل منفصل بحيث لا تمتد الصفحة إلى أبعاد أفقية لا تصدق. يؤدي استخدام window.print () إلى تقليم المحتوى الذي لا يناسب الشاشة ؛
  2. , ;
  3. , .

يمكن إصلاح كل هذا باستخدام JS و CSS ، لكننا قررنا توفير وقت المطورين والبحث عن بديل لـ window.print ().

يمكن لـ SSRS أن يعطينا على الفور ملف PDF جاهزًا مع ترقيم الصفحات الحالي. هذا يخلصنا من كل صعوبات الإصدار السابق ، السؤال الوحيد هو ، هل يمكننا طباعة PDF من خلال متصفح؟

نظرًا لأن PDF هو معيار تابع لجهة خارجية ، فإن المتصفحات تدعمه من خلال المكونات الإضافية المختلفة للمشاهد. لا يوجد مكون إضافي - لا توجد رسوم متحركة ، لذا نحتاج مرة أخرى إلى خيار بديل.

وإذا وضعت ملف PDF على الصفحة كصورة ، وأرسلت هذه الصفحة للطباعة؟ توجد بالفعل مكتبات ومكونات لـ Angular توفر مثل هذا العرض. بحثت ، جربت ، نفذت.

لكي لا نتعامل مع البيانات التي لا نريد طباعتها ، تقرر نقل المحتوى المعروض إلى صفحة جديدة ، وهناك بالفعل تنفيذ window.print (). ونتيجة لذلك ، تكون العملية برمتها على النحو التالي:

  1. طلب ReportService لتصدير التقرير بتنسيق PDF ؛
  2. نحصل على كائن Blob ، ونحوله إلى عنوان URL (URL.createObjectURL (fileStream)) ، ونعطي عنوان URL إلى عارض PDF لعرضه ؛
  3. نأخذ الصور من عارض PDF ؛
  4. افتح صفحة جديدة وأضف القليل من الترميز (العنوان ، والقليل من المسافات البادئة) ؛
  5. أضف الصورة من عارض PDF إلى الترميز ، call window.print ().

بعد عدة عمليات تحقق ، ظهر أيضًا رمز JS على الصفحة ، والذي يتحقق قبل الطباعة من تحميل جميع الصور.

وبالتالي ، يتم تحديد مظهر المستند بالكامل بواسطة معلمات قالب SSRS ، ولا تتداخل واجهة المستخدم مع هذه العملية. هذا يقلل من عدد الأخطاء المحتملة. نظرًا لنقل الصور للطباعة ، فنحن مؤمنون ضد أي تلف أو تشوه في التصميم.

هناك أيضًا عيوب:

  • سيؤثر تقرير كبير كثيرًا ، مما سيؤثر سلبًا على الأنظمة الأساسية للجوّال ؛
  • لا يتم تحديث التصميم تلقائيًا - يلزم تثبيت الألوان والخطوط وعناصر التصميم الأخرى على مستوى القالب.

في حالتنا ، لم يكن من المتوقع إضافة قوالب جديدة بشكل متكرر ، لذلك كان الحل مقبولًا. تم أخذ أداء الجوّال كأمر مسلم به.

الكلمة الأخيرة


هذه هي الطريقة التي يجعلنا فيها المشروع العادي مرة أخرى نبحث عن حلول بسيطة للمهام غير التافهة. المنتج النهائي يلبي تمامًا متطلبات التصميم ويبدو جميلًا. والأهم من ذلك ، على الرغم من أنه لم يكن علينا البحث عن أكثر طرق التنفيذ وضوحًا ، فقد تم الانتهاء من المهمة بشكل أسرع مما لو أخذنا نموذج التقرير الأصلي مع كل العواقب. وفي النهاية ، تمكنا من التركيز على أهداف العمل للمشروع.

Source: https://habr.com/ru/post/undefined/


All Articles