برنامه نویسی

نحوه ساخت کنترل مجموعه داده PCF با استفاده از REACT

Summarize this content to 400 words in Persian Lang
در این آموزش، شما یک کنترل داده تعاملی PCF را با استفاده از React ایجاد می‌کنید که می‌تواند در شبکه موجودیت Dynamics CRM ادغام شود.

تکنیک هایی که در این آموزش خواهید آموخت به شما درک عمیق تری از کنترل های PCF در Dynamics CRM می دهد. در سراسر این راهنما، ما همه چیز را از راه‌اندازی محیط توسعه تا استقرار و آزمایش کنترل سفارشی شما پوشش خواهیم داد.

چی میسازی؟

در این آموزش، کنترلی خواهید ساخت که فایل اکسل پیوست شده به یادداشت‌های درون CRM را نمایش می‌دهد و به کاربران روشی بصری‌تر و سازمان‌دهی‌شده‌تر برای دسترسی به پیوست‌های اکسل مرتبط با رکوردهای یادداشت ارائه می‌دهد.

در اینجا می‌توانید ببینید که وقتی کارتان تمام شد چگونه به نظر می‌رسد:

در برگه Timeline، سه یادداشت مرتبط با حساب وجود دارد که هر کدام یک فایل اکسل پیوست شده است.

در تب Notes، کنترل سفارشی ما اضافه شده است که این فایل‌های اکسل را استخراج کرده و در منوی انتخاب فایل فهرست می‌کند و با انتخاب فایل، برگه‌های آن فایل اکسل در منوی انتخاب برگه نمایش داده می‌شود.

وقتی کاربر برگه‌ای را انتخاب می‌کند، داده‌های آن مطابق شکل بالا در شبکه نمایش داده می‌شود، و همانطور که متوجه شدید ما یک قابلیت دانلود سفارشی نیز ایجاد می‌کنیم که فایل انتخابی را در سیستم ما دانلود می‌کند.

راه اندازی برای آموزش

قبل از شروع ساختن کنترل‌های PCF با React، مطمئن شوید که ابزارهای لازم را روی دستگاه خود نصب کرده‌اید:

Node.js: نسخه LTS توصیه می شود
کد ویژوال استودیو (VS Code): برای تجربه بهتر کدنویسی توصیه می شود از ویرایشگری مانند Visual Studio Code استفاده کنید.
Microsoft Power Platform CLI: برای نصب Power Platform CLI از ابزارهای Power Platform برای VS Code یا Power Platform CLI برای ویندوز استفاده کنید.

ایجاد یک پروژه جدید

هنگامی که محیط شما آماده شد، یک پروژه کنترل مجموعه داده PCF جدید ایجاد کنید.

کد ویژوال استودیو را باز کنید و از ترمینال به پوشه ای که می خواهید پروژه کنترل PCF را در آن ایجاد کنید بروید.
دستور زیر را از ترمینال خود برای ایجاد یک پروژه کنترل PCF جدید اجرا کنید:

pac pcf init –namespace SampleNamespace –name ReactDatasetControl –template dataset –framework react –run-npm-install

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

–namespace فضای نام را برای کنترل شما مشخص می کند.
–name نام کنترل شما را مشخص می کند.
–template نوع کنترل را مشخص می کند (مثلاً فیلد یا مجموعه داده)
–framework (اختیاری) چارچوب کنترل را مشخص می کند.
–run-npm-install ماژول های گره مورد نیاز را برای کنترل نصب می کند.

اجرای موارد بالا pac pcf init فرمان یک کنترل PCF اولیه را با تمام فایل‌ها و وابستگی‌های مورد نیاز تنظیم می‌کند و آن را برای سفارشی‌سازی و استقرار در PowerApps آماده می‌کند.

در این آموزش ما از کتابخانه XLSX برای کار با فایل های اکسل استفاده می کنیم. آنها را در پروژه خود با استفاده از

npm install xlsx
npm install –save-dev ajv

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نمای کلی

اکنون که راه اندازی شده اید، بیایید مروری بر PCF Dataset Control داشته باشیم!

بررسی کد شروع

در کاوشگر سه بخش اصلی را مشاهده خواهید کرد:

node_modules شامل تمام بسته های گره مورد نیاز برای پروژه است.
ReactDatasetControl پوشه پروژه حاوی فایل های اصلی است.
eslintrc.json ،package.json فایل های پیکربندی پروژه هستند.

بیایید نگاهی به برخی از فایل های کلیدی بیندازیم.

ControlManifest.Input.xml

اینجا جایی است که پیکربندی و ویژگی های کنترل PCF خود را تعریف می کنید. این شامل اطلاعاتی مانند نام کنترل، نسخه، توضیحات و انواع داده هایی است که می پذیرد.

index.ts

این به عنوان نقطه ورود برای منطق تجاری کنترل PCF شما عمل می کند. جایی است که شما رفتار و تعاملات کنترل خود را تعریف می کنید.

روش های چرخه زندگی:

init: این متد زمانی فراخوانی می شود که کنترل مقداردهی اولیه شود. برای راه‌اندازی کنترل، از جمله کنترل‌کننده‌های رویداد، و رندر کردن رابط کاربری اولیه استفاده می‌شود.
updateView: هر زمان که کنترل نیاز به به روز رسانی داشته باشد، این روش فراخوانی می شود، برای مثال زمانی که داده ها یا ویژگی های کنترل تغییر می کند. برای رندر مجدد رابط کاربری با آخرین داده ها استفاده می شود.
getOutputs: این متد مقدار فعلی خروجی های کنترل را برمی گرداند که می تواند توسط اجزای دیگر استفاده شود یا در پایگاه داده ذخیره شود.
destroy: این متد زمانی فراخوانی می شود که کنترل از DOM حذف شود. برای پاکسازی منابع، مانند کنترل کننده رویدادها، برای جلوگیری از نشت حافظه استفاده می شود.

در کنترل ما، updateView متد زمانی فراخوانی می شود که صفحه بارگیری می شود. این روش رندر می کند HelloWorld جزء از HelloWorld.tsx فایل

ساخت جزء

بیایید با ایجاد یک فایل App.tsx در داخل پوشه پروژه ReactDatasetControl شروع کنیم. این منطق کنترل PCF ما را تشکیل می دهد.

/* App.tsx */

import * as React from ‘react’;
import { IInputs } from “./generated/ManifestTypes”;
import { DetailsList } from ‘@fluentui/react’;

export function PCFControl({sampleDataSet} : IInputs) {

const records = [
{
“First Name”: “Saturo”,
“Last Name”: “Gojo”,
“Domain”: “Infinity Void”
},
{
“First Name”: “Sukuna”,
“Last Name”: “Ryomen”,
“Domain”: “Malevolent Shrine”
}
];

return DetailsList items={records}/>
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خطوط 1-3 تمام واردات لازم برای کنترل را به ارمغان می آورد.
خط بعدی تابعی به نام تعریف می کند PCFControl . را export کلیدواژه جاوا اسکریپت این تابع را خارج از این فایل قابل دسترسی می کند.
در PCFControl تابع a sampleDataSet ویژگی ارسال می شود که شامل داده ها/سوابق شبکه ای است که کنترل ما به آنها متصل می شود.
تابع a را برمی گرداند DetailsList کنترل با سوابق داده های ارسال شده به آن items دارایی
DetailsList یک کنترل واکنش Fluent UI ایجاد شده توسط مایکروسافت است که برای مشاهده داده ها در قالب لیست استفاده می شود.

index.ts

فایل با عنوان را باز کنید index.ts ، ما را وارد کنید PCFControl در بالای فایل و اجازه دهید تغییر دهید updateView تابعی برای برگرداندن کنترل سفارشی ما.

import { PCFControl } from “./App”

// …

public updateView(context: ComponentFramework.ContextIInputs>): React.ReactElement
{
const props: IInputs = { sampleDataSet: context.parameters.sampleDataSet };
return React.createElement(PCFControl, props);
}

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

context.parameters.sampleDataSet به ویژگی مجموعه داده از context پارامتر این شامل داده ها/سوابق شبکه ای است که کنترل ما در بخش های بعدی به آن ملزم خواهد شد. سپس یک عنصر React متشکل از PCFControl مؤلفه و مجموعه داده ارسالی props به عنوان خواص به آن.

اکنون که یک ساختار اساسی برای کنترل خود ایجاد کرده ایم، بیایید کنترل خود را بسازیم و اجرا کنیم تا ببینیم ظاهر آن چگونه است. برای مشاهده کنترل در مرورگر محلی خود دستورات زیر را در ترمینال اجرا کنید.

npm run build
npm start watch

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می توانید رکوردهای خود را در قالب لیست جدولی مشاهده کنید،

استفاده از داده ها از طریق props

در مرحله بعدی، می‌خواهیم داده‌های شبکه CRM را که از آن دریافت می‌کنیم، نمایش دهیم sampleDataSet ویژگی در کنترل به جای استفاده از رکوردهای داده استاتیک.

باز کنید App.tsx و اجازه دهید ابتدا یک تابع به نام ایجاد کنیم parseDatasetToJSON در داخل تابع PCFControl، که آن را تجزیه می کند sampleDataSet ویژگی (شامل داده های شبکه) و آن داده ها را در آرایه ای از اشیاء json برمی گرداند.

// …

function parseDatasetToJSON()
{
const jsonData = [];
for(const recordID of sampleDataSet.sortedRecordIds)
{
// Dataset record
const record = sampleDataSet.records[recordID];
const temp: Recordstring, any> = {};

// Loop through each dataset columns
for(const column of sampleDataSet.columns)
{
temp[column.name] = record.getFormattedValue(column.name)
}

jsonData.push(temp);
}
return jsonData;
}

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون که تابعی برای تبدیل مجموعه داده به JSON دریافت کرده‌ایم، می‌خواهیم این تابع را به‌سرعت فراخوانی کنیم sampleDataSet دارایی بارگیری یا تغییر کرده است.

React یک توابع ویژه به نام ارائه می کند قلاب، مانند useState که به شما این امکان را می دهد که داده های خود را در یک متغیر ویژگی نوع حالت و useEffect به شما امکان می دهد توابع مربوط به هر یک از تغییر ویژگی نوع حالت را فراخوانی کنید.

بیشتر بدانید useState و useEffect از،

واردات useState و useEffect در بالای فایل، سپس یک متغیر حالت به نام را مقداردهی اولیه کنید notes که رکوردهای مجموعه داده با فرمت JSON ما را ذخیره می کند.

زمانی که sampleDataSet دارایی بارگیری/تغییر شده است، useEffect تابع فراخوانی می شود و notes متغیر با رکوردهای مجموعه داده جدید به روز می شود.

سپس DetailsList را به روز می کنیم items دارایی برای استفاده notes داده ها به جای سوابق داده های ایستا.

import { useState, useEffect } from ‘react’;

// …

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON Objects

useEffect(() => {

const notesRecords = parseDatasetToJSON();
setNotes(notesRecords);

}, [sampleDataSet]); // On dataset property load or change

return DetailsList items={notes}/>

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مرحله شما App.tsx کد باید چیزی شبیه به این باشد:

import * as React from ‘react’;
import { useState, useEffect } from ‘react’;
import { IInputs } from “./generated/ManifestTypes”;
import { DetailsList } from ‘@fluentui/react’;

export function PCFControl({sampleDataSet} : IInputs) {

function parseDatasetToJSON()
{
const jsonData = [];
for(const recordID of sampleDataSet.sortedRecordIds)
{
// Dataset record
const record = sampleDataSet.records[recordID];
const temp: Recordstring, any> = {};

// Loop through each dataset columns
for(const column of sampleDataSet.columns)
{
temp[column.name] = record.getFormattedValue(column.name)
}
jsonData.push(temp);
}
return jsonData;
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON Objects

useEffect(() => {

const notesRecords = parseDatasetToJSON();
setNotes(notesRecords);

}, [sampleDataSet]); // On dataset property load or change

return DetailsList items={notes}/>

}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون پروژه خود را بسازید، و باید چیزی شبیه به این را ببینید،

در بارگذاری، کنترل مجموعه داده PCF این مجموعه داده ساختگی را فراهم می کند. برای ارائه مجموعه داده های سفارشی خود، از قسمت هایلایت شده پایین سمت راست، هر فایل اکسلی را که حاوی لیستی از ستون ها و ردیف ها باشد، انتخاب کنید. در انتخاب PCF Dataset Control این فایل اکسل را به sampleDataSet دارایی

درک موجودیت CRM: یادداشت ها

در این آموزش ما در حال ایجاد یک کنترل مجموعه داده PCF برای استفاده در موجودیت OOB Notes Dynamics CRM هستیم. بیایید یک لحظه کوتاه به مرور برخی از ستون‌های کلیدی موجودیت Notes که بعداً در کنترل ما استفاده خواهند شد، اختصاص دهیم.

را یادداشت ها موجودیت در Dynamics CRM برای ذخیره و مدیریت پیوست‌ها یا نظرات مرتبط با سایر نهادها، مانند حساب‌ها، مخاطبین یا فرصت‌ها استفاده می‌شود. اغلب برای پیگیری پرونده ها یا یادداشت های مهم مربوط به سوابق استفاده می شود.

در اینجا یک نمای کلی از ستون‌های کلیدی موجودیت Notes آورده شده است:

نام فایل (filename): این ستون نام فایل پیوست شده به یادداشت را ذخیره می کند. این یک فیلد رشته ای است و برای پر کردن فایل کشویی در کنترل ما استفاده می شود.
بدنه سند (documentbody): این ستون حاوی محتوای واقعی فایل پیوست شده است که در رشته فرمت Base64 کدگذاری شده است. این جایی است که داده های فایل ذخیره می شود و آن را به بخش مهمی از مدیریت پیوست تبدیل می کند.

اکنون که درک بهتری از زمینه های مختلف در موجودیت یادداشت داریم، اجازه دهید به ایجاد کنترل خود ادامه دهیم.

افزودن کشویی فایل

اکنون یک منوی کشویی File ایجاد می کنیم که لیست فایل های پیوست شده با رکوردهای یادداشت را نمایش می دهد.

توجه: در CRM، یک رکورد موجودیت می‌تواند چندین رکورد یادداشت مرتبط به آن داشته باشد، جایی که هر رکورد یادداشت می‌تواند دارای فقط یک فایل در آن متصل شده است.

بیایید یک تابع به نام ایجاد کنیم createFileOptions که خواهد گرفت notes به عنوان یک پارامتر ثبت می کند و آرایه ای از گزینه ها را برای کشویی برمی گرداند.

// …

function createFileOptions(notes: ArrayRecordstring, any>>)
{
const options: IDropdownOption[] = [];

for(const [index, note] of notes.entries())
{
const option = { key: index, text: note[“filename”] ?? “No File” };
options.push(option);
}
return options;
}

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این تابع یک آرایه از IDropdownOption اشیاء، با هر شیء حاوی یک ویژگی متنی است که مقدار the را در خود دارد filename فیلد از سوابق یادداشت.

به یاد داشته باشید: notes یک متغیر حالت است که با استفاده از آن ایجاد کردیم parseDatasetToJSON تابع و هر رکورد یادداشت حاوی دو ویژگی اصلی است filename و documentbody

در مرحله بعد، با استفاده از این تابع، داده های این گزینه را در یک ذخیره می کنیم fileOptions متغیر state، و این گزینه را به یک کنترل کشویی Fluent UI منتقل می کند تا در بالای آن اضافه شود DetailsList کنترل در بیانیه بازگشت.

import { DetailsList, Dropdown, IDropdownOption, Stack } from ‘@fluentui/react’;

// …

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects

useEffect(() => {

const notesRecords = parseDatasetToJSON();
const fileOptionsRecords = createFileOptions(notesRecords);

setNotes(notesRecords);
setFileOptions(fileOptionsRecords);

}, [sampleDataSet]); // On dataset change

return (
Stack>
Dropdown placeholder=”Select File” options={fileOptions}/>
DetailsList items={notes}/>
/Stack>
);

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مرحله کد App.tsx شما باید چیزی شبیه به این باشد:

import * as React from ‘react’;
import { useState, useEffect } from ‘react’;
import { IInputs } from “./generated/ManifestTypes”;
import { DetailsList, Dropdown, IDropdownOption, Stack } from ‘@fluentui/react’;

export function PCFControl({sampleDataSet} : IInputs) {

function parseDatasetToJSON()
{
const jsonData = [];
for(const recordID of sampleDataSet.sortedRecordIds)
{
// Dataset record
const record = sampleDataSet.records[recordID];
const temp: Recordstring, any> = {};

for(const column of sampleDataSet.columns)
{
temp[column.name] = record.getFormattedValue(column.name)
}
jsonData.push(temp);
}
return jsonData;
}

function createFileOptions(notes: ArrayRecordstring, any>>)
{
const options: IDropdownOption[] = [];

for(const [index, note] of notes.entries())
{
const option = { key: index, text: note[“filename”] ?? “No File” }
options.push(option);
}
return options;
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects

useEffect(() => {

const notesRecords = parseDatasetToJSON();
const fileOptionsRecords = createFileOptions(notesRecords);

setNotes(notesRecords);
setFileOptions(fileOptionsRecords);

}, [sampleDataSet]); // On dataset change

return (
Stack>
Dropdown placeholder=”Select File” options={fileOptions}/>
DetailsList items={notes}/>
/Stack>
);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پروژه خود را بسازید و اکنون یک کشویی در بالای لیست خود اضافه می شود که شامل filename مقادیر از فایل مجموعه داده شما

هنگام ساخت با گفتن خطا مواجه شد غیر منتظره هر. نوع دیگری @typescript-eslint/no-explicit-any را مشخص کنید ?

خوب، زیرا تایپ اسکریپت یک زبان با تایپ قوی است و از ما انتظار دارد که انواع متغیرها را در طول زمان کامپایل تعریف کنیم تا از هرگونه خطای زمان اجرا جلوگیری کنیم.

برای رفع این مشکل، به آدرس خود بروید .eslintrc.json فایل کنید و این تنظیمات را به ویژگی قوانین اضافه کنید، این به ما امکان می دهد از متغیرهای نوع استفاده کنیم any. سپس دوباره پروژه خود را بسازید.

“@typescript-eslint/no-explicit-any”: “off”

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در حال حاضر از آنجایی که ما در حال استفاده از filename فیلد از سوابق یادداشت، مطمئن شوید که آن را اضافه کرده اید filename ستون در مجموعه داده شما به یاد داشته باشید که فایل مجموعه داده شما نشان دهنده رکوردهای موجودیت یادداشت در CRM است.

برای مرجع در اینجا فایل dataset.csv است که ما برای این آموزش استفاده می کنیم،

در حال حاضر سبک کنترل ها را نادیده بگیرید، ما آنها را در بخش های بعدی اضافه خواهیم کرد.

حال وقتی کاربر یک فایل را از منوی بازشو انتخاب می کند، می خواهیم داده های آن فایل را دریافت کنیم که همانطور که گفته شد در documentbody فیلد رکورد یادداشت

برای پیاده سازی آن، اجازه دهید یک تابع به نام ایجاد کنیم handleSelectFile زمانی که کاربر یک فایل را در منوی کشویی انتخاب می کند، فراخوانی می شود.

با انتخاب یک فایل، این تابع داده های آن فایل را از فایل بازیابی می کند documentbody فیلد، و سپس این داده ها را که در قالب رشته Base64 هستند به یک تبدیل می کند excelWorkbook شی با استفاده از کتابخانه XLSX.

توجه: excelWorkbook شی داده های فایل انتخابی فعلی را ذخیره می کند.

import * as XLSX from ‘xlsx’;

// …

function handleSelectFile(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
if(option === undefined) return; // Return if no option is selected

const note = notes[option.key as number]; // Get note record using index
const base64Data = note[“documentbody”] ?? “”; // Get file data of that note record
const workbook = XLSX.read(base64Data, { type: ‘base64’, cellDates: true }); // Converts base64 data to excel workbook object
setExcelWorkbook(workbook);

console.log(workbook);
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس این تابع را در قسمت اضافه کنید onChange ویژگی کشویی، که هر زمان که فایلی در منوی کشویی انتخاب شود، این تابع را فراخوانی می کند.

return (
Stack>
Dropdown placeholder=”Select File” options={fileOptions} onChange={handleSelectFile}/>
DetailsList items={notes}/>
/Stack>
);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قبل از اعتبارسنجی به‌روزرسانی‌ها، ابتدا ستونی به نام اضافه می‌کنیم documentbody در فایل مجموعه داده نمونه ما که حاوی مقادیر رشته base64 یک فایل اکسل است. برای تبدیل یک فایل اکسل به رشته base64 می توانید از این ابزار آنلاین استفاده کنید.

توجه: documentbody مقدار نشان دهنده فایل اکسل است که به رکوردهای یادداشت ما در CRM پیوست می شود

در اینجا نمونه فایلی است که استفاده کردیم، که در آن سلول F2 حاوی یک رشته کدگذاری شده base64 از یک فایل اکسل است.

حالا وقتی پروژه خود را می سازیم و فایل را انتخاب می کنیم Sales.xlsx، آن فایل documentbody مقدار بازیابی می شود و به شیء اکسل کتاب کار تبدیل می شود و به کنسول وارد می شود.

اضافه کردن برگه کشویی

تا این مرحله که موفق به دریافت excelWorkbook هنگامی که کاربر یک فایل را در منوی کشویی انتخاب می کند، در کد ما شیء قرار می گیرد. در مراحل بعدی، اکنون می‌خواهیم تمام برگه‌های موجود در این کتاب کار را دریافت کرده و در یک برگه کشویی جداگانه نمایش دهیم.

بنابراین اکنون کنترل کشویی برگه را ایجاد می کنیم که لیست برگه های موجود در داخل ما را نمایش می دهد excelWorkbook شی هنگامی که کاربر یک برگه را انتخاب می کند، ما ردیف ها/سوابق این برگه را به فرمت آرایه json تبدیل می کنیم و آن را با استفاده از ما نمایش می دهیم. DetailsList کنترل کنید.

برای آن، ابتدا یک تابع به نام ایجاد می کنیم createSheetOptions که از طریق آن تجزیه خواهد شد workbook شی و لیستی از گزینه های حاوی نام برگه را ایجاد می کند، مشابه کاری که برای گزینه های کشویی فایل انجام دادیم.

// …

function createSheetOptions(workbook: XLSX.WorkBook)
{
const options: IDropdownOption[] = [];
for(const [index, sheetName] of workbook.SheetNames.entries())
{
const option = { key: index, text: sheetName };
options.push(option);
}
return options;
}

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در مرحله بعد، با استفاده از این تابع، گزینه های این برگه را در یک ذخیره می کنیم sheetOptions متغیر، و این گزینه ها را با استفاده از a نمایش می دهد Dropdown کنترل کنید.

یادش بخیر داشتیم زنگ میزدیم createFileOptions هنگامی که مجموعه داده در کنترل ما از روی بارگیری یا تغییر می کند useEffect تابع حالا چه زمانی باید با آن تماس بگیریم createSheetOptions ?

درسته! باید به محض اینکه کاربر یک فایل را انتخاب کرد، یعنی داخل، فراخوانی شود handleSelectFile تابع با این کار هر زمان که کاربر یک فایل را انتخاب کند، ما sheetOptions بر اساس فایل انتخابی به روز می شود.

بیایید به روز رسانی کنیم handleSelectFile عملکرد برای رسیدن به همان،

// …

function handleSelectFile(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
if(option === undefined) return; // Return if no option is selected

const note = notes[option.key as number]; // Get note record using index
const base64Data = note[“documentbody”] ?? “”; // Get file data
const workbook = XLSX.read(base64Data, { type: ‘base64’, cellDates: true }); // Converts base64 data to excel workbook object
setExcelWorkbook(workbook);

const sheetOptionsRecords = createSheetOptions(workbook);
setSheetOptions(sheetOptionsRecords);
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object
const [sheetOptions, setSheetOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا بیایید یک کنترل کشویی جدید در عبارت بازگشت خود اضافه کنیم که اینها را نمایش می دهد sheetOptions به کاربر.

return (
Stack>
Stack horizontal>
Dropdown placeholder=”Select File” options={fileOptions} onChange={handleSelectFile}/>
Dropdown placeholder=”Select Sheet” options={sheetOptions} />
/Stack>
DetailsList items={notes}/>
/Stack>
);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما برگه‌ها را در فهرست کشویی خود دریافت کردیم، برای مرحله بعدی، می‌خواهیم هر زمان که کاربر برگه‌ای را در فهرست کشویی انتخاب کرد، ردیف‌ها/سوابق برگه باید در صفحه نمایش داده شوند. DetailsList کنترل کنید.

برای رسیدن به آن، اجازه دهید یک تابع به نام ایجاد کنیم handleSelectSheet هر زمان که کاربر برگه را در منوی کشویی انتخاب کند، فراخوانی می شود.

این تابع برگه انتخاب شده فعلی را از excelWorkbook شی در کد ما ذخیره می شود و آن رکورد/ردیف برگه را به یک آرایه json تبدیل می کند. سپس این داده های json را در یک متغیر حالت به نام ذخیره می کنیم rows که می تواند به ما منتقل شود DetailsList کنترل کنید.

function handleSelectSheet(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
if(option === undefined) return; // Return if no option is selected

const sheet = excelWorkbook.Sheets[option.text as string]; // Get sheet record using SheetName
const rowRecords: Recordstring, any>[] = XLSX.utils.sheet_to_json(sheet, {raw: false}); // Sheet Records in JSON Array
setRows(rowRecords);
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object
const [sheetOptions, setSheetOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [rows, setRows] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا این تابع را در قسمت اضافه کنید onChange ویژگی برگه کشویی که این تابع را هنگام انتخاب یک برگه فراخوانی می کند و به روز رسانی می کند items دارایی از DetailsList کنترل برای استفاده از rows داده هایی که شامل سوابق برگه انتخابی ما هستند.

return (
Stack>
Stack horizontal>
Dropdown placeholder=”Select File” options={fileOptions} onChange={handleSelectFile}/>
Dropdown placeholder=”Select Sheet” options={sheetOptions} onChange={handleSelectSheet} />
/Stack>
DetailsList items={rows}/>
/Stack>
);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

افزودن دکمه دانلود

قبل از اینکه به جلو برویم و کنترل خود را آزمایش کنیم، اجازه دهید ابتدا قسمت نهایی عملکرد کنترل PCF خود را اضافه کنیم، یعنی قابلیت دانلود فایل.

هر زمان که کاربر بر روی دکمه دانلود کلیک کند، فایل انتخابی فعلی را دانلود می کند (ذخیره شده در excelWorkbook شی) در سیستم کاربر.

ما می توانیم این را با اجرای ساده اجرا کنیم XLSX.writeFile() روش بر روی onClick کنترل دکمه این متد شیء کتاب کار را به عنوان پارامتر اول و نام فایلی که باید دانلود شود را به عنوان پارامتر دوم در نظر می گیرد.

بیایید یک را ایجاد کنیم PrimaryButton به همراه سایر کنترل های کشویی کنترل کنید و تابعی به نام اجرا کنید handleDownload با استفاده از onClick ویژگی کنترل دکمه

// …

function handleDownload()
{
XLSX.writeFile(excelWorkbook, ‘download.xlsx’);
}

// …

return (
Stack>
Stack horizontal>
Dropdown placeholder=”Select File” options={fileOptions} onChange={handleSelectFile}/>
Dropdown placeholder=”Select Sheet” options={sheetOptions} onChange={handleSelectSheet} />
PrimaryButton text=”Download” allowDisabledFocus onClick={handleDownload}/>
/Stack>
DetailsList items={rows}/>
/Stack>
);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حال با کلیک بر روی دکمه دانلود فایل انتخابی در سیستم شما دانلود می شود.

در این مرحله شما App.tsx کد باید چیزی شبیه به این باشد:

import * as React from ‘react’;
import { useState, useEffect } from ‘react’;
import { IInputs } from “./generated/ManifestTypes”;
import { DetailsList, DetailsListLayoutMode, Dropdown, IDropdownOption, PrimaryButton, Stack } from ‘@fluentui/react’;
import * as XLSX from ‘xlsx’;
import { text } from ‘stream/consumers’;

export function PCFControl({sampleDataSet} : IInputs) {

function parseDatasetToJSON()
{
const jsonData = [];
for(const recordID of sampleDataSet.sortedRecordIds)
{
// Dataset record
const record = sampleDataSet.records[recordID];
const temp: Recordstring, any> = {};

for(const column of sampleDataSet.columns)
{
temp[column.name] = record.getFormattedValue(column.name)
}
jsonData.push(temp);
}
return jsonData;
}

function createFileOptions(notes: ArrayRecordstring, any>>)
{
const options: IDropdownOption[] = [];

for(const [index, note] of notes.entries())
{
const option = { key: index, text: note[“filename”] ?? “No File” };
options.push(option);
}
return options;
}

function createSheetOptions(workbook: XLSX.WorkBook)
{
const options: IDropdownOption[] = [];
for(const [index, sheetName] of workbook.SheetNames.entries())
{
const option = { key: index, text: sheetName };
options.push(option);
}
return options;
}

function handleSelectFile(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
if(option === undefined) return; // Return if no option is selected

const note = notes[option.key as number]; // Get note record using index
const base64Data = note[“documentbody”] ?? “”; // Get file data
const workbook = XLSX.read(base64Data, { type: ‘base64’, cellDates: true }); // Converts base64 data to excel workbook object
setExcelWorkbook(workbook);

const sheetOptionsRecords = createSheetOptions(workbook);
setSheetOptions(sheetOptionsRecords);
}

function handleSelectSheet(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
if(option === undefined) return; // Return if no option is selected

const sheet = excelWorkbook.Sheets[option.text as string]; // Get sheet record using SheetName
const rowRecords: Recordstring, any>[] = XLSX.utils.sheet_to_json(sheet, {raw: false}); // Sheet Records in JSON Array
setRows(rowRecords);
}

function handleDownload()
{
XLSX.writeFile(excelWorkbook, ‘download.xlsx’);
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object
const [sheetOptions, setSheetOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [rows, setRows] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects

useEffect(() => {
const notesRecords = parseDatasetToJSON();
const fileOptionsRecords = createFileOptions(notesRecords);

setNotes(notesRecords);
setFileOptions(fileOptionsRecords);

}, [sampleDataSet]); // On dataset change

return (
Stack>
Stack horizontal>
Dropdown placeholder=”Select File” options={fileOptions} onChange={handleSelectFile}/>
Dropdown placeholder=”Select Sheet” options={sheetOptions} onChange={handleSelectSheet} />
PrimaryButton text=”Download” allowDisabledFocus onClick={handleDownload}/>
/Stack>
DetailsList items={rows}/>
/Stack>
);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون وقتی کنترل را می‌سازید، در منوی کشویی فایل‌ها، همه فایل‌های فهرست شده توسط را مشاهده خواهید کرد filename ستون (این نشان دهنده نام فایلی است که به رکوردهای یادداشت در CRM پیوست شده است).

هنگامی که یک فایل را انتخاب می کنید، در کد documentbody ارزش (این نشان دهنده فایل واقعی است که به رکورد یادداشت در CRM پیوست شده است) از آن فایل به یک کتاب کار اکسل تبدیل می‌شود و برگه‌های آن در برگه‌های کشویی نمایش داده می‌شود.

پس از انتخاب یک شیت، رکوردهای آن شیت به آرایه json تبدیل شده و در لیست نمایش داده می شود.

توجه: برای تبدیل یک فایل اکسل به رشته base64 می توانید از این ابزار آنلاین استفاده کنید.

برای مرجع، این فایل مجموعه داده اکسل است که ما برای این آموزش استفاده کردیم،

یک ظاهر طراحی را به کنترل ها اضافه کنید

کار عالی تا اینجا در آموزش…

اکنون که عملکرد اصلی این کنترل PCF را پیاده‌سازی کرده‌ایم، بیایید برای تجربه کاربری بهتر، سبکی به کنترل خود اضافه کنیم.

یک فایل جدید ایجاد کنید ControlStyles.tsx در پوشه پروژه خود و ویژگی های سبک زیر را در آن فایل اضافه کنید.

/* ControlStyles.tsx */

import { IStackTokens, IStackStyles, IDetailsListStyles, IDropdownStyles } from “@fluentui/react”;

export const stackTokens: IStackTokens = {
childrenGap: 10
};

export const stackStyles: IStackStyles = {
root: {
padding: 10,
width: ‘100%’,
marginBottom: 20,
},
};

export const detailsListStyles: IDetailsListStyles = {
root: {
overflowX: ‘auto’
},
contentWrapper: {
overflowY: ‘auto’,
width: ‘max-content’,
height: 450
},
focusZone : {},
headerWrapper: {}
}

export const dropDownStyles : PartialIDropdownStyles> = {
root : {
width: ‘auto’,
minWidth: 200
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس این ویژگی های سبک را در اصلی ما وارد کنید App.tsx فایل و این ویژگی ها را در کنترل های Fluent UI ما اضافه کنید.

// …

import {stackTokens, stackStyles, detailsListStyles, dropDownStyles} from ‘./ControlStyles’

// …

return (
Stack tokens={stackTokens} styles={stackStyles}>
Stack horizontal tokens={stackTokens} styles={stackStyles}>
Dropdown
placeholder=”Select File”
options={fileOptions}
onChange={handleSelectFile}
styles={dropDownStyles}
/>
Dropdown
placeholder=”Select Sheet”
options={sheetOptions}
onChange={handleSelectSheet}
styles={dropDownStyles}
defaultSelectedKey=’0′
/>
PrimaryButton text=”Download” allowDisabledFocus onClick={handleDownload}/>
/Stack>
DetailsList
items={rows}
styles={detailsListStyles}
data-is-scrollable={false}
layoutMode={DetailsListLayoutMode.fixedColumns}
/>
/Stack>
);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پروژه خود را بسازید و می توانید کنترل PCF استایل خود را در عمل ببینید،

جمع بندی نهایی

هنگامی که کنترل PCF خود را به یک شبکه متصل می کنید، کنترل به مجموعه داده های ارائه شده توسط آن شبکه مشترک می شود. فیلدها و رکوردهایی که برای نمایش در شبکه پیکربندی شده‌اند به ویژگی مجموعه داده کنترل PCF شما منتقل می‌شوند و به آن اجازه می‌دهند این داده‌ها را به شیوه‌ای سفارشی‌شده ارائه یا پردازش کند.

با این حال، برخی از ستون های خاص مانند documentbody در note موجودیت برای افزودن مستقیم به شبکه در دسترس نیست زیرا یک فیلد باینری است و Dynamics CRM به دلیل نگرانی‌های مربوط به عملکرد و قابلیت استفاده، اجازه نمی‌دهد فیلدهای باینری در نماهای شبکه نمایش داده شوند.

بنابراین برای دسترسی به documentbody و filename داده‌های ستون‌ها، می‌توانیم این کار را با افزودن برنامه‌نویسی آن ستون‌ها در مجموعه داده خود انجام دهیم. بیایید این ستون ها را به ما اضافه کنیم sampleDataSet اموال از updateView روش در index.ts فایل

// …

public updateView(context: ComponentFramework.ContextIInputs>): React.ReactElement
{

if (context.parameters.sampleDataSet.addColumn)
{
context.parameters.sampleDataSet.addColumn(“documentbody”);
context.parameters.sampleDataSet.addColumn(“filename”);
context.parameters.sampleDataSet.refresh();
}

const props: IInputs = { sampleDataSet: context.parameters.sampleDataSet };
return React.createElement(PCFControl, props);
}

// …

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

استقرار کنترل PCF

زمان آن رسیده است که کنترل PCF خود را از طریق Power Apps در عمل مشاهده کنیم.

برای استقرار کنترل PCF خود در محیط Power Apps، دستورات زیر را در ترمینال اجرا کنید.

npm run build

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با محیط برنامه های قدرت خود ارتباط برقرار کنید،

pac auth create –environment “{Your Environment Name}”

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کنترل را در محیط خود مستقر کنید،

pac pcf push

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از استقرار موفقیت آمیز، به make.powerapps.com بروید:

محیط خود را انتخاب کنید: محیطی را که کنترل را در آن مستقر کرده اید انتخاب کنید.
به راه حل ها بروید: به Solutions > Default Solution > Custom Controls بروید.
کنترل خود را بررسی کنید: کنترل PCF شما باید در لیست ظاهر شود.

اضافه کردن کنترل در Grid

برای این آموزش، کنترل خود را بر روی شبکه یادداشت‌ها در فرم جدول حساب ضمیمه می‌کنیم.

توجه: می‌توانید این کنترل را در هر فرم موجودی که فعال باشد تا پیوست‌هایی با آن پیوند داده شود، اضافه کنید.

جدول مربوطه را به عنوان یادداشت در زیرشبکه انتخاب کنید.

فیلترهای کلیدی را که باید در نمای یادداشت‌های خود اضافه کنید، افزودن این فیلترها در نمای، تضمین می‌کند که فقط آن رکوردهای یادداشت را به مجموعه داده ما بازگردانید که یک فایل اکسل به آنها پیوست شده است.

سپس به Get More Components و جستجو کنید ReactDatasetControl که به تازگی ایجاد کرده و به لیست اضافه کرده ایم.
آن کنترل را به شبکه اضافه کنید و فرم را ذخیره و منتشر کنید.

هر رکورد حسابی را که دارای یادداشت هایی با پیوست های اکسل است باز کنید و باید بتوانید فایل های خود را در کنترل مشاهده کنید.

بسته شدن

تبریک می گویم! شما یک کنترل مجموعه داده PCF سفارشی ایجاد کرده اید که:

نمایش یادداشت‌های پیوست اکسل در برنامه‌های مبتنی بر مدل،
هر برگه را در فایل اکسل فهرست می کند،
فایل را درون سیستم دانلود می کند.
از کنترل‌های Fluent UI React استفاده می‌کند که توسط مایکروسافت برای توسعه برنامه‌های Dynamics مدرن ساخته شده‌اند.

کار خوب! امیدوارم اکنون احساس کنید که درک مناسبی از کنترل‌های React و PCF در دینامیک دارید.

اگر می‌خواهید مهارت‌های کنترلی React و PCF خود را بیشتر تقویت کنید، در اینجا ایده‌هایی برای بهبودهایی وجود دارد که می‌توانید در این کنترل انجام دهید:

منطق رسیدگی به خطا را اضافه کنید تا نیازی به فیلترهای مشاهده نباشد.
قابلیت مرتب سازی، فیلتر و جستجو را در کنترل گرید DetailsList اضافه کنید.
برای خواندن انواع دیگر فایل‌ها مانند txt، pdf، docx و غیره، پشتیبانی اضافه کنید.
ویژگی های CRUD را در شبکه اضافه کنید.

می‌توانید سایر ویژگی‌های جالبی را که می‌توان اضافه کرد یا تردیدهای خود را در مورد این آموزش در بخش نظرات به اشتراک بگذارید.

در اینجا مخزن GitHub برای این پروژه است.

کدنویسی مبارک…

در این آموزش، شما یک کنترل داده تعاملی PCF را با استفاده از React ایجاد می‌کنید که می‌تواند در شبکه موجودیت Dynamics CRM ادغام شود.

تکنیک هایی که در این آموزش خواهید آموخت به شما درک عمیق تری از کنترل های PCF در Dynamics CRM می دهد. در سراسر این راهنما، ما همه چیز را از راه‌اندازی محیط توسعه تا استقرار و آزمایش کنترل سفارشی شما پوشش خواهیم داد.

چی میسازی؟

در این آموزش، کنترلی خواهید ساخت که فایل اکسل پیوست شده به یادداشت‌های درون CRM را نمایش می‌دهد و به کاربران روشی بصری‌تر و سازمان‌دهی‌شده‌تر برای دسترسی به پیوست‌های اکسل مرتبط با رکوردهای یادداشت ارائه می‌دهد.

در اینجا می‌توانید ببینید که وقتی کارتان تمام شد چگونه به نظر می‌رسد:

توضیحات تصویر

در برگه Timeline، سه یادداشت مرتبط با حساب وجود دارد که هر کدام یک فایل اکسل پیوست شده است.

در تب Notes، کنترل سفارشی ما اضافه شده است که این فایل‌های اکسل را استخراج کرده و در منوی انتخاب فایل فهرست می‌کند و با انتخاب فایل، برگه‌های آن فایل اکسل در منوی انتخاب برگه نمایش داده می‌شود.

وقتی کاربر برگه‌ای را انتخاب می‌کند، داده‌های آن مطابق شکل بالا در شبکه نمایش داده می‌شود، و همانطور که متوجه شدید ما یک قابلیت دانلود سفارشی نیز ایجاد می‌کنیم که فایل انتخابی را در سیستم ما دانلود می‌کند.

راه اندازی برای آموزش

قبل از شروع ساختن کنترل‌های PCF با React، مطمئن شوید که ابزارهای لازم را روی دستگاه خود نصب کرده‌اید:

  1. Node.js: نسخه LTS توصیه می شود

  2. کد ویژوال استودیو (VS Code): برای تجربه بهتر کدنویسی توصیه می شود از ویرایشگری مانند Visual Studio Code استفاده کنید.

  3. Microsoft Power Platform CLI: برای نصب Power Platform CLI از ابزارهای Power Platform برای VS Code یا Power Platform CLI برای ویندوز استفاده کنید.

ایجاد یک پروژه جدید

هنگامی که محیط شما آماده شد، یک پروژه کنترل مجموعه داده PCF جدید ایجاد کنید.

  1. کد ویژوال استودیو را باز کنید و از ترمینال به پوشه ای که می خواهید پروژه کنترل PCF را در آن ایجاد کنید بروید.

  2. دستور زیر را از ترمینال خود برای ایجاد یک پروژه کنترل PCF جدید اجرا کنید:

pac pcf init --namespace SampleNamespace --name ReactDatasetControl --template dataset --framework react --run-npm-install
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • --namespace فضای نام را برای کنترل شما مشخص می کند.

  • --name نام کنترل شما را مشخص می کند.

  • --template نوع کنترل را مشخص می کند (مثلاً فیلد یا مجموعه داده)

  • --framework (اختیاری) چارچوب کنترل را مشخص می کند.

  • --run-npm-install ماژول های گره مورد نیاز را برای کنترل نصب می کند.

اجرای موارد بالا pac pcf init فرمان یک کنترل PCF اولیه را با تمام فایل‌ها و وابستگی‌های مورد نیاز تنظیم می‌کند و آن را برای سفارشی‌سازی و استقرار در PowerApps آماده می‌کند.

در این آموزش ما از کتابخانه XLSX برای کار با فایل های اکسل استفاده می کنیم. آنها را در پروژه خود با استفاده از

npm install xlsx
npm install --save-dev ajv
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نمای کلی

اکنون که راه اندازی شده اید، بیایید مروری بر PCF Dataset Control داشته باشیم!

بررسی کد شروع

در کاوشگر سه بخش اصلی را مشاهده خواهید کرد:

توضیحات تصویر

  1. node_modules شامل تمام بسته های گره مورد نیاز برای پروژه است.

  2. ReactDatasetControl پوشه پروژه حاوی فایل های اصلی است.

  3. eslintrc.json ،package.json فایل های پیکربندی پروژه هستند.

بیایید نگاهی به برخی از فایل های کلیدی بیندازیم.

ControlManifest.Input.xml

اینجا جایی است که پیکربندی و ویژگی های کنترل PCF خود را تعریف می کنید. این شامل اطلاعاتی مانند نام کنترل، نسخه، توضیحات و انواع داده هایی است که می پذیرد.

index.ts

این به عنوان نقطه ورود برای منطق تجاری کنترل PCF شما عمل می کند. جایی است که شما رفتار و تعاملات کنترل خود را تعریف می کنید.

توضیحات تصویر

روش های چرخه زندگی:

  • init: این متد زمانی فراخوانی می شود که کنترل مقداردهی اولیه شود. برای راه‌اندازی کنترل، از جمله کنترل‌کننده‌های رویداد، و رندر کردن رابط کاربری اولیه استفاده می‌شود.

  • updateView: هر زمان که کنترل نیاز به به روز رسانی داشته باشد، این روش فراخوانی می شود، برای مثال زمانی که داده ها یا ویژگی های کنترل تغییر می کند. برای رندر مجدد رابط کاربری با آخرین داده ها استفاده می شود.

  • getOutputs: این متد مقدار فعلی خروجی های کنترل را برمی گرداند که می تواند توسط اجزای دیگر استفاده شود یا در پایگاه داده ذخیره شود.

  • destroy: این متد زمانی فراخوانی می شود که کنترل از DOM حذف شود. برای پاکسازی منابع، مانند کنترل کننده رویدادها، برای جلوگیری از نشت حافظه استفاده می شود.

در کنترل ما، updateView متد زمانی فراخوانی می شود که صفحه بارگیری می شود. این روش رندر می کند HelloWorld جزء از HelloWorld.tsx فایل

ساخت جزء

بیایید با ایجاد یک فایل App.tsx در داخل پوشه پروژه ReactDatasetControl شروع کنیم. این منطق کنترل PCF ما را تشکیل می دهد.

/* App.tsx */

import * as React from 'react';
import { IInputs } from "./generated/ManifestTypes";
import { DetailsList } from '@fluentui/react';

export function PCFControl({sampleDataSet} : IInputs) {

    const records = [
        {
            "First Name": "Saturo",
            "Last Name": "Gojo",
            "Domain": "Infinity Void"
        },
        {
            "First Name": "Sukuna",
            "Last Name": "Ryomen",
            "Domain": "Malevolent Shrine"
        }
    ];

    return DetailsList items={records}/>
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • خطوط 1-3 تمام واردات لازم برای کنترل را به ارمغان می آورد.

  • خط بعدی تابعی به نام تعریف می کند PCFControl . را export کلیدواژه جاوا اسکریپت این تابع را خارج از این فایل قابل دسترسی می کند.

  • در PCFControl تابع a sampleDataSet ویژگی ارسال می شود که شامل داده ها/سوابق شبکه ای است که کنترل ما به آنها متصل می شود.

  • تابع a را برمی گرداند DetailsList کنترل با سوابق داده های ارسال شده به آن items دارایی

  • DetailsList یک کنترل واکنش Fluent UI ایجاد شده توسط مایکروسافت است که برای مشاهده داده ها در قالب لیست استفاده می شود.

index.ts

فایل با عنوان را باز کنید index.ts ، ما را وارد کنید PCFControl در بالای فایل و اجازه دهید تغییر دهید updateView تابعی برای برگرداندن کنترل سفارشی ما.

import { PCFControl } from "./App"

// ...

public updateView(context: ComponentFramework.ContextIInputs>): React.ReactElement 
{
    const props: IInputs = { sampleDataSet: context.parameters.sampleDataSet };
    return React.createElement(PCFControl, props);
}

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

context.parameters.sampleDataSet به ویژگی مجموعه داده از context پارامتر این شامل داده ها/سوابق شبکه ای است که کنترل ما در بخش های بعدی به آن ملزم خواهد شد. سپس یک عنصر React متشکل از PCFControl مؤلفه و مجموعه داده ارسالی props به عنوان خواص به آن.

اکنون که یک ساختار اساسی برای کنترل خود ایجاد کرده ایم، بیایید کنترل خود را بسازیم و اجرا کنیم تا ببینیم ظاهر آن چگونه است. برای مشاهده کنترل در مرورگر محلی خود دستورات زیر را در ترمینال اجرا کنید.

npm run build
npm start watch
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می توانید رکوردهای خود را در قالب لیست جدولی مشاهده کنید،

توضیحات تصویر

استفاده از داده ها از طریق props

در مرحله بعدی، می‌خواهیم داده‌های شبکه CRM را که از آن دریافت می‌کنیم، نمایش دهیم sampleDataSet ویژگی در کنترل به جای استفاده از رکوردهای داده استاتیک.

باز کنید App.tsx و اجازه دهید ابتدا یک تابع به نام ایجاد کنیم parseDatasetToJSON در داخل تابع PCFControl، که آن را تجزیه می کند sampleDataSet ویژگی (شامل داده های شبکه) و آن داده ها را در آرایه ای از اشیاء json برمی گرداند.

// ...

function parseDatasetToJSON() 
{
    const jsonData = [];
    for(const recordID of sampleDataSet.sortedRecordIds) 
    {
        // Dataset record
        const record = sampleDataSet.records[recordID];
        const temp: Recordstring, any> = {};

        // Loop through each dataset columns
        for(const column of sampleDataSet.columns) 
        {
            temp[column.name] = record.getFormattedValue(column.name)
        }

        jsonData.push(temp);
    }
    return jsonData;
}

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون که تابعی برای تبدیل مجموعه داده به JSON دریافت کرده‌ایم، می‌خواهیم این تابع را به‌سرعت فراخوانی کنیم sampleDataSet دارایی بارگیری یا تغییر کرده است.

React یک توابع ویژه به نام ارائه می کند قلاب، مانند useState که به شما این امکان را می دهد که داده های خود را در یک متغیر ویژگی نوع حالت و useEffect به شما امکان می دهد توابع مربوط به هر یک از تغییر ویژگی نوع حالت را فراخوانی کنید.

بیشتر بدانید useState و useEffect از،

واردات useState و useEffect در بالای فایل، سپس یک متغیر حالت به نام را مقداردهی اولیه کنید notes که رکوردهای مجموعه داده با فرمت JSON ما را ذخیره می کند.

زمانی که sampleDataSet دارایی بارگیری/تغییر شده است، useEffect تابع فراخوانی می شود و notes متغیر با رکوردهای مجموعه داده جدید به روز می شود.

سپس DetailsList را به روز می کنیم items دارایی برای استفاده notes داده ها به جای سوابق داده های ایستا.

import { useState, useEffect } from 'react';

// ...

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON Objects

useEffect(() => {

    const notesRecords = parseDatasetToJSON();
    setNotes(notesRecords);

}, [sampleDataSet]); // On dataset property load or change

return DetailsList items={notes}/>

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مرحله شما App.tsx کد باید چیزی شبیه به این باشد:

import * as React from 'react';
import { useState, useEffect } from 'react';
import { IInputs } from "./generated/ManifestTypes";
import { DetailsList } from '@fluentui/react';

export function PCFControl({sampleDataSet} : IInputs) {

    function parseDatasetToJSON() 
    {
        const jsonData = [];
        for(const recordID of sampleDataSet.sortedRecordIds) 
        {
            // Dataset record
            const record = sampleDataSet.records[recordID];
            const temp: Recordstring, any> = {};

            // Loop through each dataset columns
            for(const column of sampleDataSet.columns) 
            {
                temp[column.name] = record.getFormattedValue(column.name)
            }
            jsonData.push(temp);
        }
        return jsonData;
    }

    const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON Objects

    useEffect(() => {

        const notesRecords = parseDatasetToJSON();
        setNotes(notesRecords);

    }, [sampleDataSet]); // On dataset property load or change

    return DetailsList items={notes}/>

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون پروژه خود را بسازید، و باید چیزی شبیه به این را ببینید،

توضیحات تصویر

در بارگذاری، کنترل مجموعه داده PCF این مجموعه داده ساختگی را فراهم می کند. برای ارائه مجموعه داده های سفارشی خود، از قسمت هایلایت شده پایین سمت راست، هر فایل اکسلی را که حاوی لیستی از ستون ها و ردیف ها باشد، انتخاب کنید. در انتخاب PCF Dataset Control این فایل اکسل را به sampleDataSet دارایی

توضیحات تصویر

درک موجودیت CRM: یادداشت ها

در این آموزش ما در حال ایجاد یک کنترل مجموعه داده PCF برای استفاده در موجودیت OOB Notes Dynamics CRM هستیم. بیایید یک لحظه کوتاه به مرور برخی از ستون‌های کلیدی موجودیت Notes که بعداً در کنترل ما استفاده خواهند شد، اختصاص دهیم.

را یادداشت ها موجودیت در Dynamics CRM برای ذخیره و مدیریت پیوست‌ها یا نظرات مرتبط با سایر نهادها، مانند حساب‌ها، مخاطبین یا فرصت‌ها استفاده می‌شود. اغلب برای پیگیری پرونده ها یا یادداشت های مهم مربوط به سوابق استفاده می شود.

در اینجا یک نمای کلی از ستون‌های کلیدی موجودیت Notes آورده شده است:

  1. نام فایل (filename): این ستون نام فایل پیوست شده به یادداشت را ذخیره می کند. این یک فیلد رشته ای است و برای پر کردن فایل کشویی در کنترل ما استفاده می شود.

  2. بدنه سند (documentbody): این ستون حاوی محتوای واقعی فایل پیوست شده است که در رشته فرمت Base64 کدگذاری شده است. این جایی است که داده های فایل ذخیره می شود و آن را به بخش مهمی از مدیریت پیوست تبدیل می کند.

اکنون که درک بهتری از زمینه های مختلف در موجودیت یادداشت داریم، اجازه دهید به ایجاد کنترل خود ادامه دهیم.

افزودن کشویی فایل

اکنون یک منوی کشویی File ایجاد می کنیم که لیست فایل های پیوست شده با رکوردهای یادداشت را نمایش می دهد.

توجه: در CRM، یک رکورد موجودیت می‌تواند چندین رکورد یادداشت مرتبط به آن داشته باشد، جایی که هر رکورد یادداشت می‌تواند دارای فقط یک فایل در آن متصل شده است.

بیایید یک تابع به نام ایجاد کنیم createFileOptions که خواهد گرفت notes به عنوان یک پارامتر ثبت می کند و آرایه ای از گزینه ها را برای کشویی برمی گرداند.

// ...

function createFileOptions(notes: ArrayRecordstring, any>>)
{
    const options: IDropdownOption[] = [];

    for(const [index, note] of notes.entries())
    {
        const option = { key: index, text: note["filename"] ?? "No File" };
        options.push(option);
    }
    return options;
}

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این تابع یک آرایه از IDropdownOption اشیاء، با هر شیء حاوی یک ویژگی متنی است که مقدار the را در خود دارد filename فیلد از سوابق یادداشت.

به یاد داشته باشید: notes یک متغیر حالت است که با استفاده از آن ایجاد کردیم parseDatasetToJSON تابع و هر رکورد یادداشت حاوی دو ویژگی اصلی است filename و documentbody

در مرحله بعد، با استفاده از این تابع، داده های این گزینه را در یک ذخیره می کنیم fileOptions متغیر state، و این گزینه را به یک کنترل کشویی Fluent UI منتقل می کند تا در بالای آن اضافه شود DetailsList کنترل در بیانیه بازگشت.

import { DetailsList, Dropdown, IDropdownOption, Stack } from '@fluentui/react';

// ...

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects 

useEffect(() => {

    const notesRecords = parseDatasetToJSON();
    const fileOptionsRecords = createFileOptions(notesRecords);

    setNotes(notesRecords);
    setFileOptions(fileOptionsRecords);

}, [sampleDataSet]); // On dataset change

return (
    Stack>
        Dropdown placeholder="Select File" options={fileOptions}/>
        DetailsList items={notes}/>
    /Stack>
);

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مرحله کد App.tsx شما باید چیزی شبیه به این باشد:

import * as React from 'react';
import { useState, useEffect } from 'react';
import { IInputs } from "./generated/ManifestTypes";
import { DetailsList, Dropdown, IDropdownOption, Stack } from '@fluentui/react';

export function PCFControl({sampleDataSet} : IInputs) {

    function parseDatasetToJSON() 
    {
        const jsonData = [];
        for(const recordID of sampleDataSet.sortedRecordIds) 
        {
            // Dataset record
            const record = sampleDataSet.records[recordID];
            const temp: Recordstring, any> = {};

            for(const column of sampleDataSet.columns) 
            {
                temp[column.name] = record.getFormattedValue(column.name)
            }
            jsonData.push(temp);
        }
        return jsonData;
    }

    function createFileOptions(notes: ArrayRecordstring, any>>)
    {
        const options: IDropdownOption[] = [];

        for(const [index, note] of notes.entries())
        {
            const option = { key: index, text: note["filename"] ?? "No File" }
            options.push(option);
        }
        return options;
    }

    const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
    const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects

    useEffect(() => {

        const notesRecords = parseDatasetToJSON();
        const fileOptionsRecords = createFileOptions(notesRecords);

        setNotes(notesRecords);
        setFileOptions(fileOptionsRecords);

    }, [sampleDataSet]); // On dataset change

    return (
        Stack>
            Dropdown placeholder="Select File" options={fileOptions}/>
            DetailsList items={notes}/>
        /Stack>
    );
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پروژه خود را بسازید و اکنون یک کشویی در بالای لیست خود اضافه می شود که شامل filename مقادیر از فایل مجموعه داده شما

هنگام ساخت با گفتن خطا مواجه شد غیر منتظره هر. نوع دیگری @typescript-eslint/no-explicit-any را مشخص کنید ?

خوب، زیرا تایپ اسکریپت یک زبان با تایپ قوی است و از ما انتظار دارد که انواع متغیرها را در طول زمان کامپایل تعریف کنیم تا از هرگونه خطای زمان اجرا جلوگیری کنیم.

برای رفع این مشکل، به آدرس خود بروید .eslintrc.json فایل کنید و این تنظیمات را به ویژگی قوانین اضافه کنید، این به ما امکان می دهد از متغیرهای نوع استفاده کنیم any. سپس دوباره پروژه خود را بسازید.

"@typescript-eslint/no-explicit-any": "off"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در حال حاضر از آنجایی که ما در حال استفاده از filename فیلد از سوابق یادداشت، مطمئن شوید که آن را اضافه کرده اید filename ستون در مجموعه داده شما به یاد داشته باشید که فایل مجموعه داده شما نشان دهنده رکوردهای موجودیت یادداشت در CRM است.

برای مرجع در اینجا فایل dataset.csv است که ما برای این آموزش استفاده می کنیم،

توضیحات تصویر

توضیحات تصویر

در حال حاضر سبک کنترل ها را نادیده بگیرید، ما آنها را در بخش های بعدی اضافه خواهیم کرد.

حال وقتی کاربر یک فایل را از منوی بازشو انتخاب می کند، می خواهیم داده های آن فایل را دریافت کنیم که همانطور که گفته شد در documentbody فیلد رکورد یادداشت

برای پیاده سازی آن، اجازه دهید یک تابع به نام ایجاد کنیم handleSelectFile زمانی که کاربر یک فایل را در منوی کشویی انتخاب می کند، فراخوانی می شود.

با انتخاب یک فایل، این تابع داده های آن فایل را از فایل بازیابی می کند documentbody فیلد، و سپس این داده ها را که در قالب رشته Base64 هستند به یک تبدیل می کند excelWorkbook شی با استفاده از کتابخانه XLSX.

توجه: excelWorkbook شی داده های فایل انتخابی فعلی را ذخیره می کند.

import * as XLSX from 'xlsx';

// ...

function handleSelectFile(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
    if(option === undefined) return; // Return if no option is selected

    const note = notes[option.key as number]; // Get note record using index
    const base64Data = note["documentbody"] ?? ""; // Get file data of that note record
    const workbook = XLSX.read(base64Data, { type: 'base64', cellDates: true }); // Converts base64 data to excel workbook object
    setExcelWorkbook(workbook);

    console.log(workbook);
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس این تابع را در قسمت اضافه کنید onChange ویژگی کشویی، که هر زمان که فایلی در منوی کشویی انتخاب شود، این تابع را فراخوانی می کند.

return (
    Stack>
        Dropdown placeholder="Select File" options={fileOptions} onChange={handleSelectFile}/>
        DetailsList items={notes}/>
    /Stack>
);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قبل از اعتبارسنجی به‌روزرسانی‌ها، ابتدا ستونی به نام اضافه می‌کنیم documentbody در فایل مجموعه داده نمونه ما که حاوی مقادیر رشته base64 یک فایل اکسل است. برای تبدیل یک فایل اکسل به رشته base64 می توانید از این ابزار آنلاین استفاده کنید.

توجه: documentbody مقدار نشان دهنده فایل اکسل است که به رکوردهای یادداشت ما در CRM پیوست می شود

در اینجا نمونه فایلی است که استفاده کردیم، که در آن سلول F2 حاوی یک رشته کدگذاری شده base64 از یک فایل اکسل است.

توضیحات تصویر

حالا وقتی پروژه خود را می سازیم و فایل را انتخاب می کنیم Sales.xlsx، آن فایل documentbody مقدار بازیابی می شود و به شیء اکسل کتاب کار تبدیل می شود و به کنسول وارد می شود.

توضیحات تصویر

اضافه کردن برگه کشویی

تا این مرحله که موفق به دریافت excelWorkbook هنگامی که کاربر یک فایل را در منوی کشویی انتخاب می کند، در کد ما شیء قرار می گیرد. در مراحل بعدی، اکنون می‌خواهیم تمام برگه‌های موجود در این کتاب کار را دریافت کرده و در یک برگه کشویی جداگانه نمایش دهیم.

بنابراین اکنون کنترل کشویی برگه را ایجاد می کنیم که لیست برگه های موجود در داخل ما را نمایش می دهد excelWorkbook شی هنگامی که کاربر یک برگه را انتخاب می کند، ما ردیف ها/سوابق این برگه را به فرمت آرایه json تبدیل می کنیم و آن را با استفاده از ما نمایش می دهیم. DetailsList کنترل کنید.

برای آن، ابتدا یک تابع به نام ایجاد می کنیم createSheetOptions که از طریق آن تجزیه خواهد شد workbook شی و لیستی از گزینه های حاوی نام برگه را ایجاد می کند، مشابه کاری که برای گزینه های کشویی فایل انجام دادیم.

// ...

function createSheetOptions(workbook: XLSX.WorkBook)
{
    const options: IDropdownOption[] = [];
    for(const [index, sheetName] of workbook.SheetNames.entries())
    {
        const option = { key: index, text: sheetName };
        options.push(option);
    }
    return options;
}

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در مرحله بعد، با استفاده از این تابع، گزینه های این برگه را در یک ذخیره می کنیم sheetOptions متغیر، و این گزینه ها را با استفاده از a نمایش می دهد Dropdown کنترل کنید.

یادش بخیر داشتیم زنگ میزدیم createFileOptions هنگامی که مجموعه داده در کنترل ما از روی بارگیری یا تغییر می کند useEffect تابع حالا چه زمانی باید با آن تماس بگیریم createSheetOptions ?

درسته! باید به محض اینکه کاربر یک فایل را انتخاب کرد، یعنی داخل، فراخوانی شود handleSelectFile تابع با این کار هر زمان که کاربر یک فایل را انتخاب کند، ما sheetOptions بر اساس فایل انتخابی به روز می شود.

بیایید به روز رسانی کنیم handleSelectFile عملکرد برای رسیدن به همان،

// ...

function handleSelectFile(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
    if(option === undefined) return; // Return if no option is selected

    const note = notes[option.key as number]; // Get note record using index
    const base64Data = note["documentbody"] ?? ""; // Get file data
    const workbook = XLSX.read(base64Data, { type: 'base64', cellDates: true }); // Converts base64 data to excel workbook object
    setExcelWorkbook(workbook);

    const sheetOptionsRecords = createSheetOptions(workbook);
    setSheetOptions(sheetOptionsRecords);
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object
const [sheetOptions, setSheetOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا بیایید یک کنترل کشویی جدید در عبارت بازگشت خود اضافه کنیم که اینها را نمایش می دهد sheetOptions به کاربر.

return (
    Stack>
        Stack horizontal>
            Dropdown placeholder="Select File" options={fileOptions} onChange={handleSelectFile}/>
            Dropdown placeholder="Select Sheet" options={sheetOptions} />
        /Stack>
        DetailsList items={notes}/>
    /Stack>
);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما برگه‌ها را در فهرست کشویی خود دریافت کردیم، برای مرحله بعدی، می‌خواهیم هر زمان که کاربر برگه‌ای را در فهرست کشویی انتخاب کرد، ردیف‌ها/سوابق برگه باید در صفحه نمایش داده شوند. DetailsList کنترل کنید.

برای رسیدن به آن، اجازه دهید یک تابع به نام ایجاد کنیم handleSelectSheet هر زمان که کاربر برگه را در منوی کشویی انتخاب کند، فراخوانی می شود.

این تابع برگه انتخاب شده فعلی را از excelWorkbook شی در کد ما ذخیره می شود و آن رکورد/ردیف برگه را به یک آرایه json تبدیل می کند. سپس این داده های json را در یک متغیر حالت به نام ذخیره می کنیم rows که می تواند به ما منتقل شود DetailsList کنترل کنید.

function handleSelectSheet(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
{
    if(option === undefined) return; // Return if no option is selected

    const sheet = excelWorkbook.Sheets[option.text as string]; // Get sheet record using SheetName
    const rowRecords: Recordstring, any>[] = XLSX.utils.sheet_to_json(sheet, {raw: false}); // Sheet Records in JSON Array
    setRows(rowRecords);
}

const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object
const [sheetOptions, setSheetOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
const [rows, setRows] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا این تابع را در قسمت اضافه کنید onChange ویژگی برگه کشویی که این تابع را هنگام انتخاب یک برگه فراخوانی می کند و به روز رسانی می کند items دارایی از DetailsList کنترل برای استفاده از rows داده هایی که شامل سوابق برگه انتخابی ما هستند.

return (
    Stack>
        Stack horizontal>
            Dropdown placeholder="Select File" options={fileOptions} onChange={handleSelectFile}/>
            Dropdown placeholder="Select Sheet" options={sheetOptions} onChange={handleSelectSheet} />
        /Stack>
        DetailsList items={rows}/>
    /Stack>
);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

افزودن دکمه دانلود

قبل از اینکه به جلو برویم و کنترل خود را آزمایش کنیم، اجازه دهید ابتدا قسمت نهایی عملکرد کنترل PCF خود را اضافه کنیم، یعنی قابلیت دانلود فایل.

هر زمان که کاربر بر روی دکمه دانلود کلیک کند، فایل انتخابی فعلی را دانلود می کند (ذخیره شده در excelWorkbook شی) در سیستم کاربر.

ما می توانیم این را با اجرای ساده اجرا کنیم XLSX.writeFile() روش بر روی onClick کنترل دکمه این متد شیء کتاب کار را به عنوان پارامتر اول و نام فایلی که باید دانلود شود را به عنوان پارامتر دوم در نظر می گیرد.

بیایید یک را ایجاد کنیم PrimaryButton به همراه سایر کنترل های کشویی کنترل کنید و تابعی به نام اجرا کنید handleDownload با استفاده از onClick ویژگی کنترل دکمه

// ...

function handleDownload()
{
    XLSX.writeFile(excelWorkbook, 'download.xlsx');
}

// ...

return (
    Stack>
        Stack horizontal>
            Dropdown placeholder="Select File" options={fileOptions} onChange={handleSelectFile}/>
            Dropdown placeholder="Select Sheet" options={sheetOptions} onChange={handleSelectSheet} />
            PrimaryButton text="Download" allowDisabledFocus onClick={handleDownload}/>
        /Stack>
        DetailsList items={rows}/>
    /Stack>
);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حال با کلیک بر روی دکمه دانلود فایل انتخابی در سیستم شما دانلود می شود.

در این مرحله شما App.tsx کد باید چیزی شبیه به این باشد:

import * as React from 'react';
import { useState, useEffect } from 'react';
import { IInputs } from "./generated/ManifestTypes";
import { DetailsList, DetailsListLayoutMode, Dropdown, IDropdownOption, PrimaryButton, Stack } from '@fluentui/react';
import * as XLSX from 'xlsx';
import { text } from 'stream/consumers';

export function PCFControl({sampleDataSet} : IInputs) {

    function parseDatasetToJSON() 
    {
        const jsonData = [];
        for(const recordID of sampleDataSet.sortedRecordIds) 
        {
            // Dataset record
            const record = sampleDataSet.records[recordID];
            const temp: Recordstring, any> = {};

            for(const column of sampleDataSet.columns) 
            {
                temp[column.name] = record.getFormattedValue(column.name)
            }
            jsonData.push(temp);
        }
        return jsonData;
    }

    function createFileOptions(notes: ArrayRecordstring, any>>)
    {
        const options: IDropdownOption[] = [];

        for(const [index, note] of notes.entries())
        {
            const option = { key: index, text: note["filename"] ?? "No File" };
            options.push(option);
        }
        return options;
    }

    function createSheetOptions(workbook: XLSX.WorkBook)
    {
        const options: IDropdownOption[] = [];
        for(const [index, sheetName] of workbook.SheetNames.entries())
        {
            const option = { key: index, text: sheetName };
            options.push(option);
        }
        return options;
    }

    function handleSelectFile(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
    {
        if(option === undefined) return; // Return if no option is selected

        const note = notes[option.key as number]; // Get note record using index
        const base64Data = note["documentbody"] ?? ""; // Get file data
        const workbook = XLSX.read(base64Data, { type: 'base64', cellDates: true }); // Converts base64 data to excel workbook object
        setExcelWorkbook(workbook);

        const sheetOptionsRecords = createSheetOptions(workbook);
        setSheetOptions(sheetOptionsRecords);
    }

    function handleSelectSheet(event: React.FormEventHTMLDivElement>, option?: IDropdownOption)
    {
        if(option === undefined) return; // Return if no option is selected

        const sheet = excelWorkbook.Sheets[option.text as string]; // Get sheet record using SheetName
        const rowRecords: Recordstring, any>[] = XLSX.utils.sheet_to_json(sheet, {raw: false}); // Sheet Records in JSON Array
        setRows(rowRecords);
    }

    function handleDownload()
    {
        XLSX.writeFile(excelWorkbook, 'download.xlsx');
    }

    const [notes, setNotes] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects
    const [fileOptions, setFileOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
    const [excelWorkbook, setExcelWorkbook] = useStateXLSX.WorkBook>(XLSX.utils.book_new()); // Excel workbook object
    const [sheetOptions, setSheetOptions] = useStateIDropdownOption[]>([]); // Array of IDropdownOption objects
    const [rows, setRows] = useStateArrayRecordstring, any>>>([]); // Array of JSON objects

    useEffect(() => {
        const notesRecords = parseDatasetToJSON();
        const fileOptionsRecords = createFileOptions(notesRecords);

        setNotes(notesRecords);
        setFileOptions(fileOptionsRecords);

    }, [sampleDataSet]); // On dataset change

    return (
        Stack>
            Stack horizontal>
                Dropdown placeholder="Select File" options={fileOptions} onChange={handleSelectFile}/>
                Dropdown placeholder="Select Sheet" options={sheetOptions} onChange={handleSelectSheet} />
                PrimaryButton text="Download" allowDisabledFocus onClick={handleDownload}/>
            /Stack>
            DetailsList items={rows}/>
        /Stack>
    );
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون وقتی کنترل را می‌سازید، در منوی کشویی فایل‌ها، همه فایل‌های فهرست شده توسط را مشاهده خواهید کرد filename ستون (این نشان دهنده نام فایلی است که به رکوردهای یادداشت در CRM پیوست شده است).

هنگامی که یک فایل را انتخاب می کنید، در کد documentbody ارزش (این نشان دهنده فایل واقعی است که به رکورد یادداشت در CRM پیوست شده است) از آن فایل به یک کتاب کار اکسل تبدیل می‌شود و برگه‌های آن در برگه‌های کشویی نمایش داده می‌شود.

پس از انتخاب یک شیت، رکوردهای آن شیت به آرایه json تبدیل شده و در لیست نمایش داده می شود.

توجه: برای تبدیل یک فایل اکسل به رشته base64 می توانید از این ابزار آنلاین استفاده کنید.

برای مرجع، این فایل مجموعه داده اکسل است که ما برای این آموزش استفاده کردیم،

توضیحات تصویر

توضیحات تصویر

یک ظاهر طراحی را به کنترل ها اضافه کنید

کار عالی تا اینجا در آموزش…

اکنون که عملکرد اصلی این کنترل PCF را پیاده‌سازی کرده‌ایم، بیایید برای تجربه کاربری بهتر، سبکی به کنترل خود اضافه کنیم.

یک فایل جدید ایجاد کنید ControlStyles.tsx در پوشه پروژه خود و ویژگی های سبک زیر را در آن فایل اضافه کنید.

/* ControlStyles.tsx */

import { IStackTokens, IStackStyles, IDetailsListStyles, IDropdownStyles } from "@fluentui/react";

export const stackTokens: IStackTokens = { 
    childrenGap: 10 
};

export const stackStyles: IStackStyles = {
    root: {
        padding: 10,
        width: '100%',
        marginBottom: 20,
    },
};

export const detailsListStyles: IDetailsListStyles = {
    root: {
        overflowX: 'auto'
    }, 
    contentWrapper: {
        overflowY: 'auto', 
        width: 'max-content', 
        height: 450
    },
    focusZone : {},
    headerWrapper: {} 
}

export const dropDownStyles : PartialIDropdownStyles> = {
    root : {
        width: 'auto', 
        minWidth: 200
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس این ویژگی های سبک را در اصلی ما وارد کنید App.tsx فایل و این ویژگی ها را در کنترل های Fluent UI ما اضافه کنید.

// ...

import {stackTokens, stackStyles, detailsListStyles, dropDownStyles} from './ControlStyles'

// ...

return (
    Stack tokens={stackTokens} styles={stackStyles}>
        Stack horizontal tokens={stackTokens} styles={stackStyles}>
            Dropdown 
                placeholder="Select File" 
                options={fileOptions} 
                onChange={handleSelectFile} 
                styles={dropDownStyles}
            />
            Dropdown 
                placeholder="Select Sheet" 
                options={sheetOptions} 
                onChange={handleSelectSheet} 
                styles={dropDownStyles}
                defaultSelectedKey='0' 
            />
            PrimaryButton text="Download" allowDisabledFocus onClick={handleDownload}/>
        /Stack>
        DetailsList 
            items={rows} 
            styles={detailsListStyles}
            data-is-scrollable={false}
            layoutMode={DetailsListLayoutMode.fixedColumns}
        />
    /Stack>
);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پروژه خود را بسازید و می توانید کنترل PCF استایل خود را در عمل ببینید،

توضیحات تصویر

جمع بندی نهایی

هنگامی که کنترل PCF خود را به یک شبکه متصل می کنید، کنترل به مجموعه داده های ارائه شده توسط آن شبکه مشترک می شود. فیلدها و رکوردهایی که برای نمایش در شبکه پیکربندی شده‌اند به ویژگی مجموعه داده کنترل PCF شما منتقل می‌شوند و به آن اجازه می‌دهند این داده‌ها را به شیوه‌ای سفارشی‌شده ارائه یا پردازش کند.

با این حال، برخی از ستون های خاص مانند documentbody در note موجودیت برای افزودن مستقیم به شبکه در دسترس نیست زیرا یک فیلد باینری است و Dynamics CRM به دلیل نگرانی‌های مربوط به عملکرد و قابلیت استفاده، اجازه نمی‌دهد فیلدهای باینری در نماهای شبکه نمایش داده شوند.

بنابراین برای دسترسی به documentbody و filename داده‌های ستون‌ها، می‌توانیم این کار را با افزودن برنامه‌نویسی آن ستون‌ها در مجموعه داده خود انجام دهیم. بیایید این ستون ها را به ما اضافه کنیم sampleDataSet اموال از updateView روش در index.ts فایل

// ...

public updateView(context: ComponentFramework.ContextIInputs>): React.ReactElement 
{

    if (context.parameters.sampleDataSet.addColumn) 
    {
        context.parameters.sampleDataSet.addColumn("documentbody");
        context.parameters.sampleDataSet.addColumn("filename");
        context.parameters.sampleDataSet.refresh();
    }

    const props: IInputs = { sampleDataSet: context.parameters.sampleDataSet };
    return React.createElement(PCFControl, props);
}

// ...
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

استقرار کنترل PCF

زمان آن رسیده است که کنترل PCF خود را از طریق Power Apps در عمل مشاهده کنیم.

برای استقرار کنترل PCF خود در محیط Power Apps، دستورات زیر را در ترمینال اجرا کنید.

npm run build
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • با محیط برنامه های قدرت خود ارتباط برقرار کنید،
pac auth create --environment "{Your Environment Name}"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • کنترل را در محیط خود مستقر کنید،
pac pcf push
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از استقرار موفقیت آمیز، به make.powerapps.com بروید:

  • محیط خود را انتخاب کنید: محیطی را که کنترل را در آن مستقر کرده اید انتخاب کنید.

  • به راه حل ها بروید: به Solutions > Default Solution > Custom Controls بروید.

  • کنترل خود را بررسی کنید: کنترل PCF شما باید در لیست ظاهر شود.

توضیحات تصویر

اضافه کردن کنترل در Grid

برای این آموزش، کنترل خود را بر روی شبکه یادداشت‌ها در فرم جدول حساب ضمیمه می‌کنیم.

توجه: می‌توانید این کنترل را در هر فرم موجودی که فعال باشد تا پیوست‌هایی با آن پیوند داده شود، اضافه کنید.

  • جدول مربوطه را به عنوان یادداشت در زیرشبکه انتخاب کنید.

توضیحات تصویر

  • فیلترهای کلیدی را که باید در نمای یادداشت‌های خود اضافه کنید، افزودن این فیلترها در نمای، تضمین می‌کند که فقط آن رکوردهای یادداشت را به مجموعه داده ما بازگردانید که یک فایل اکسل به آنها پیوست شده است.

توضیحات تصویر

  • سپس به Get More Components و جستجو کنید ReactDatasetControl که به تازگی ایجاد کرده و به لیست اضافه کرده ایم.
  • آن کنترل را به شبکه اضافه کنید و فرم را ذخیره و منتشر کنید.

توضیحات تصویر

  • هر رکورد حسابی را که دارای یادداشت هایی با پیوست های اکسل است باز کنید و باید بتوانید فایل های خود را در کنترل مشاهده کنید.

توضیحات تصویر

بسته شدن

تبریک می گویم! شما یک کنترل مجموعه داده PCF سفارشی ایجاد کرده اید که:

  • نمایش یادداشت‌های پیوست اکسل در برنامه‌های مبتنی بر مدل،

  • هر برگه را در فایل اکسل فهرست می کند،

  • فایل را درون سیستم دانلود می کند.

  • از کنترل‌های Fluent UI React استفاده می‌کند که توسط مایکروسافت برای توسعه برنامه‌های Dynamics مدرن ساخته شده‌اند.

کار خوب! امیدوارم اکنون احساس کنید که درک مناسبی از کنترل‌های React و PCF در دینامیک دارید.

اگر می‌خواهید مهارت‌های کنترلی React و PCF خود را بیشتر تقویت کنید، در اینجا ایده‌هایی برای بهبودهایی وجود دارد که می‌توانید در این کنترل انجام دهید:

  1. منطق رسیدگی به خطا را اضافه کنید تا نیازی به فیلترهای مشاهده نباشد.
  2. قابلیت مرتب سازی، فیلتر و جستجو را در کنترل گرید DetailsList اضافه کنید.
  3. برای خواندن انواع دیگر فایل‌ها مانند txt، pdf، docx و غیره، پشتیبانی اضافه کنید.
  4. ویژگی های CRUD را در شبکه اضافه کنید.

می‌توانید سایر ویژگی‌های جالبی را که می‌توان اضافه کرد یا تردیدهای خود را در مورد این آموزش در بخش نظرات به اشتراک بگذارید.

در اینجا مخزن GitHub برای این پروژه است.

کدنویسی مبارک…

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا