چگونه یک پلتفرم مدیریت فرم با Angular 17 و SurveyJS ساختم
پلتفرمهای نظرسنجی SaaS مانند SurveyMonkey، Typeform و Google Forms ایجاد نظرسنجی را برای بسیاری از کاربران در دسترس قرار دادهاند. با این حال، این ابزارها محدودیتهای متعددی را نیز ایجاد میکنند که بر انعطافپذیری و کنترل دادهها تأثیر میگذارد.
مشکلات رایج شامل محدودیت در تعداد پاسخها، گزینههای محدود برای سفارشیسازی رابط کاربری، گزینههای محدود برای طراحی فرم، اتکا به سرویسهای شخص ثالث برای ذخیره اطلاعات حساس و افزایش هزینههای اشتراک است که میتواند برای سازمانهای در حال رشد دشوار شود.
برای سازمانهایی که میخواهند فرآیندهای جمعآوری دادههای خود را خودکار کنند، اما همچنان به کنترل کامل بر گردشهای کاری دادههای خود نیاز دارند، یک راهکار مدیریت فرم سفارشی مزایای آشکاری را ارائه میدهد.
یک سیستم خود-میزبان، مالکیت کامل دادهها و زیرساختها، سفارشیسازی بدون محدودیت برای موارد استفاده مختلف، هزینههای عملیاتی قابل پیشبینی بدون محدودیتهای مبتنی بر استفاده و ادغام مستقیم با سیستمهای داخلی را تضمین میکند. هنگامی که Angular 17 و SurveyJS با هم استفاده میشوند، یک پشته فناوری قابل اعتماد برای ساخت یک پلتفرم مدیریت فرم سفارشی ارائه میدهند که از قابلیتهای هر راهحل SaaS تجاری فراتر میرود.
معماری شرح داده شده در اینجا بر اساس سه جزء کلیدی است:
یک رابط کاربری مدرن Angular که از کامپوننتهای مستقل استفاده میکند.
یک ابزار ساخت فرمهای بصری از SurveyJS (در گیتهاب) برای ایجاد فرمها و نظرسنجیها.
یک بکاند ساده PHP که مسئول عملیات داده است. آیا منظورتان تغییر چیزی در مقاله است؟
این ترکیب به شما امکان میدهد یک پلتفرم مقیاسپذیر و قابل نگهداری بسازید که تمام جنبههای مدیریت فرم را کاملاً تحت کنترل شما نگه میدارد.
راهاندازی محیط: معماری فنی و وابستگیها
ساختار پروژه و وابستگیها
هدف این مقاله ارائه حجم زیادی از کد نیست، بلکه توضیح چگونگی سازماندهی سیستمی از این نوع است. کد منبع به صورت جداگانه در دسترس است تا بتوانید ضمن دنبال کردن توضیحات ساختاری، آن را به طور مفصل بررسی کنید.
برای شروع، یک پروژه Angular 17 را پیکربندی میکنیم و وابستگیهای لازم SurveyJS را نصب میکنیم. معماری برنامه از یک ساختار ماژولار پیروی میکند که مراحل اصلی گردش کار مدیریت فرم را از هم جدا میکند:
ساخت فرم و نظرسنجی
رندر و تجسم فرم
پردازش و تحلیل نتایج نظرسنجی
ایجاد پروژه انگولار
ng new survey1 --standalone --routing --style=scss cd survey1انگولار ۱۷ پیشرفتهای قابل توجهی در مدیریت مستقل کامپوننتها ارائه میدهد، نیاز به NgModuleها را از بین میبرد و معماری کلی برنامه را ساده میکند. این امر منجر به ساختاری تمیزتر و قابل نگهداریتر میشود.
نصب بستههای SurveyJS
بستههای اصلی SurveyJS را نصب کنید:
npm install survey-creator-angular survey-angular-ui npm install @types/survey-creator --save-dev پیکربندی بکاند PHP
یک دایرکتوری api ایجاد کنید و API PHP را تنظیم کنید:
mkdir api cd apiبرای توسعه محلی، از سرور PHP داخلی استفاده کنید:
php -S localhost:8080فایلهای PHP لازم را برای نقاط پایانی API خود ایجاد کنید. این فایلها، ایجاد، ذخیرهسازی و جمعآوری نتایج نظرسنجی را مدیریت خواهند کرد.
ساختار کامل پروژه
برای روشنتر شدن کاربرد، بخش زیر نحوه سازماندهی پروژه را نشان میدهد.

برای درک دقیقتر هر بخش، میتوانید کد منبع را بررسی کنید. ایده اصلی ما میتواند به این شکل باشد:

رابط بصری و تعاملی بودن کامپوننت سازنده نظرسنجی
پیادهسازی SurveyCreator
ابزار Survey Creator بخش مرکزی این پلتفرم است. این ابزار به کاربران امکان میدهد تا از طریق یک رابط کاربری بصری، نظرسنجی طراحی کنند. انگولار ۱۷ پایه ساختاری لازم برای ادغام این بخش را به شیوهای پایدار و قابل پیشبینی ارائه میدهد.
رابط کاربری فرمساز از طریق اقدامات کشیدن و رها کردن، پیکربندی منطق شرطی، تعریف قوانین اعتبارسنجی و تنظیم تنظیمات بصری، ساخت نظرسنجیها را پشتیبانی میکند. SurveyJS Creator به طور خودکار طرحواره JSON را تولید میکند که نشان دهنده ساختار هر فرم است.
این طرحواره JSON بخشی از گردش کار مدیریت فرم سیستم میشود، زیرا در backend ذخیره میشود و بعداً برای وظایف اتوماسیون فرم مانند رندر فرم، بهروزرسانی و تجسم و تحلیل دادههای نظرسنجی استفاده میشود.

پیکربندی کامپوننتهای انگولار
با Angular 17 و اجزای مستقل آن، پیکربندی به طور قابل توجهی ساده شده است:
// src/app/survey-creator/survey-creator.component.ts import { Component, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SurveyCreatorModel } from 'survey-creator-core'; import { SurveyCreatorModule } from 'survey-creator-angular'; import { SurveyService } from '../survey.service'; @Component({ selector: 'app-survey-creator', standalone: true, imports: [CommonModule, SurveyCreatorModule], template: ` <div class="creator-container"> <h2>Survey Creator </h2> <p class="instructions"> Use the visual editor below to design your survey. Drag questions from the left panel, configure them, and click "Save Survey" when done. </p> <div class="creator-wrapper"> <survey-creator [model]="creator"></survey-creator> </div> <div class="actions"> <button (click)="saveSurvey()" [disabled]="saving" class="save-btn"> {{ saving ? 'Saving... ' : 'Save Survey ' }} </button> <button (click)="loadSurvey()" [disabled]="loading" class="load-btn"> {{ loading ? 'Loading...' : 'Load Survey ' }} </button> </div> <div *ngIf="message" [class]="'message ' + messageType"> {{ message }} </div> </div> `, styles: [` .creator-container { padding: 20px; } h2 { color: #1976d2; margin-bottom: 10px; } .instructions { color: #666; margin-bottom: 15px; line-height: 1.6; } .creator-wrapper { margin: 20px 0; border: 1px solid #ddd; border-radius: 4px; overflow: hidden; } .actions { display: flex; gap: 10px; margin-top: 20px; } button { padding: 12px 24px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background-color 0.3s; } button:disabled { opacity: 0.6; cursor: not-allowed; } .save-btn { background-color: #4caf50; color: white; } .save-btn:hover:not(:disabled) { background-color: #45a049; } .load-btn { background-color: #2196f3; color: white; } .load-btn:hover:not(:disabled) { background-color: #1976d2; } .message { margin-top: 15px; padding: 12px; border-radius: 4px; } .message.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .message.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } `] }) export class SurveyCreatorComponent implements OnInit { creator!: SurveyCreatorModel; saving = false; loading = false; message = ''; messageType: 'success' | 'error' = 'success'; constructor(private surveyService: SurveyService) {} ngOnInit() { // Initialize Survey Creator // Inicializar el Creador de Encuestas this.creator = new SurveyCreatorModel({ showLogicTab: true, showJSONEditorTab: true, showTestSurveyTab: true, showDesignerTab: true }); // Optional: Set default JSON // Opcional: Establecer JSON por defecto this.creator.JSON = { pages: [ { name: "page1", elements: [ { type: "text", name: "question1", title: "What is your name?" } ] } ] }; } /** * Save survey to backend * Guardar encuesta en el backend */ saveSurvey() { this.saving = true; this.message = ''; const surveyJson = this.creator.JSON; this.surveyService.saveSurvey(surveyJson).subscribe({ next: (response) => { this.saving = false; if (response.success) { this.showMessage('Survey saved successfully!', 'success'); } else { this.showMessage('Error saving survey', 'error'); } }, error: (error) => { this.saving = false; console.error('Error saving survey:', error); this.showMessage('Error: ' + (error.message || 'Failed to save'), 'error'); } }); } /** * Load survey from backend * Cargar encuesta desde el backend */ loadSurvey() { this.loading = true; this.message = ''; this.surveyService.loadSurvey().subscribe({ next: (survey) => { this.loading = false; if (survey && Object.keys(survey).length > 0) { this.creator.JSON = survey; this.showMessage('Survey loaded successfully! ', 'success'); } else { this.showMessage('No survey found ', 'error'); } }, error: (error) => { this.loading = false; console.error('Error loading survey:', error); this.showMessage('Error: ' + (error.message || 'Failed to load '), 'error'); } }); } private showMessage(text: string, type: 'success' | 'error') { this.message = text; this.messageType = type; if (type === 'success') { setTimeout(() => { this.message = ''; }, 3000); } } }طرحوارههای JSON: ساختار و منطق شرطی// src/app/survey-creator/survey-creator.component.ts import { Component, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SurveyCreatorModel } from 'survey-creator-core'; import { SurveyCreatorModule } from 'survey-creator-angular'; import { SurveyService } from '../survey.service'; @Component({ selector: 'app-survey-creator', standalone: true, imports: [CommonModule, SurveyCreatorModule], template: ` <div class="creator-container"> <h2>Survey Creator </h2> <p class="instructions"> Use the visual editor below to design your survey. Drag questions from the left panel, configure them, and click "Save Survey" when done. </p> <div class="creator-wrapper"> <survey-creator [model]="creator"></survey-creator> </div> <div class="actions"> <button (click)="saveSurvey()" [disabled]="saving" class="save-btn"> {{ saving ? 'Saving... ' : 'Save Survey ' }} </button> <button (click)="loadSurvey()" [disabled]="loading" class="load-btn"> {{ loading ? 'Loading...' : 'Load Survey ' }} </button> </div> <div *ngIf="message" [class]="'message ' + messageType"> {{ message }} </div> </div> `, styles: [` .creator-container { padding: 20px; } h2 { color: #1976d2; margin-bottom: 10px; } .instructions { color: #666; margin-bottom: 15px; line-height: 1.6; } .creator-wrapper { margin: 20px 0; border: 1px solid #ddd; border-radius: 4px; overflow: hidden; } .actions { display: flex; gap: 10px; margin-top: 20px; } button { padding: 12px 24px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background-color 0.3s; } button:disabled { opacity: 0.6; cursor: not-allowed; } .save-btn { background-color: #4caf50; color: white; } .save-btn:hover:not(:disabled) { background-color: #45a049; } .load-btn { background-color: #2196f3; color: white; } .load-btn:hover:not(:disabled) { background-color: #1976d2; } .message { margin-top: 15px; padding: 12px; border-radius: 4px; } .message.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .message.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } `] }) export class SurveyCreatorComponent implements OnInit { creator!: SurveyCreatorModel; saving = false; loading = false; message = ''; messageType: 'success' | 'error' = 'success'; constructor(private surveyService: SurveyService) {} ngOnInit() { // Initialize Survey Creator // Inicializar el Creador de Encuestas this.creator = new SurveyCreatorModel({ showLogicTab: true, showJSONEditorTab: true, showTestSurveyTab: true, showDesignerTab: true }); // Optional: Set default JSON // Opcional: Establecer JSON por defecto this.creator.JSON = { pages: [ { name: "page1", elements: [ { type: "text", name: "question1", title: "What is your name?" } ] } ] }; } /** * Save survey to backend * Guardar encuesta en el backend */ saveSurvey() { this.saving = true; this.message = ''; const surveyJson = this.creator.JSON; this.surveyService.saveSurvey(surveyJson).subscribe({ next: (response) => { this.saving = false; if (response.success) { this.showMessage('Survey saved successfully!', 'success'); } else { this.showMessage('Error saving survey', 'error'); } }, error: (error) => { this.saving = false; console.error('Error saving survey:', error); this.showMessage('Error: ' + (error.message || 'Failed to save'), 'error'); } }); } /** * Load survey from backend * Cargar encuesta desde el backend */ loadSurvey() { this.loading = true; this.message = ''; this.surveyService.loadSurvey().subscribe({ next: (survey) => { this.loading = false; if (survey && Object.keys(survey).length > 0) { this.creator.JSON = survey; this.showMessage('Survey loaded successfully! ', 'success'); } else { this.showMessage('No survey found ', 'error'); } }, error: (error) => { this.loading = false; console.error('Error loading survey:', error); this.showMessage('Error: ' + (error.message || 'Failed to load '), 'error'); } }); } private showMessage(text: string, type: 'success' | 'error') { this.message = text; this.messageType = type; if (type === 'success') { setTimeout(() => { this.message = ''; }, 3000); } } }
مبانی اسکیمای SurveyJS
طرح JSON تولید شده توسط SurveyJS Creator نشان دهنده ساختار، محتوا و رفتار کامل یک نظرسنجی است. این طرح شامل تمام اطلاعات مربوط به سوالات، صفحات و عناصر نظرسنجی و همچنین هرگونه منطق شرطی است که نحوه نمایش یا پنهان کردن سوالات را بر اساس پاسخهای کاربر تعیین میکند. با استفاده از این طرح، میتوان بدون نوشتن کد اضافی، نظرسنجیهای ساده و پیچیده ایجاد کرد.
بخش زیر مثالی از یک طرحواره JSON تولید شده توسط SurveyJS Creator را ارائه میدهد:
{ "title": "Customer Satisfaction Survey", "description": "Help us improve our services", "pages": [ { "name": "page1", "elements": [ { "type": "rating", "name": "question1", "title": "How satisfied are you with our service?", "autoGenerate": false, "rateCount": 2, "rateValues": [ { "value": 1, "text": "Not at all satisfied" }, { "value": 2, "text": "Very satisfied" } ], "rateMax": 2 } ] } ] }همچنین میتوانیم این را به صورت بصری به این شکل ببینیم:

رندرینگ و تجربه کاربری
پیادهسازی SurveyViewer
نمایشگر نظرسنجی، مؤلفهای است که نظرسنجیها را به کاربران نمایش میدهد. این نمایشگر تضمین میکند که نظرسنجیها به صورت واکنشگرا ارائه میشوند و با دستگاهها و اندازههای مختلف صفحه نمایش سازگار میشوند. ترکیب Angular 17 و SurveyJS نمایشگر نظرسنجی را قادر میسازد تا به طور کارآمد عمل کند و به شما امکان میدهد یک تجربه سازگار و کاربرپسند را در دسکتاپ، تبلت و دستگاههای تلفن همراه ارائه دهید.
بخش زیر نمونهای از ابزار نمایش نظرسنجی را نشان میدهد که یک نظرسنجی بارگذاری شده را نمایش میدهد:

و این کد کامپوننت نمایشگر ماست:
import { Component, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SurveyModel } from 'survey-core'; import { SurveyModule } from 'survey-angular-ui'; import { SurveyService, SurveySchema } from '../survey.service';
@Component({ selector: 'app-survey-viewer', standalone: true, imports: [CommonModule, SurveyModule], template: ` <div class="viewer-container"> <h2>Survey Viewer / Visor de Encuestas</h2> <p class="instructions"> Complete the survey below. All fields are required unless otherwise noted. </p> <p class="instructions"> Completa la encuesta a continuación. Todos los campos son obligatorios a menos que se indique lo contrario. </p>
<div *ngIf="loading" class="loading"> Loading survey... / Cargando encuesta... </div>
<div *ngIf="error" class="error-message"> {{ error }} </div>
<div *ngIf="survey && !loading" class="survey-wrapper"> <survey [model]="survey"></survey> </div>
<div *ngIf="message" [class]="'message ' + messageType"> {{ message }} </div> </div> `, styles: [` .viewer-container { padding: 20px; }
h2 { color: #1976d2; margin-bottom: 10px; }
.instructions { color: #666; margin-bottom: 15px; line-height: 1.6; }
.loading { text-align: center; padding: 40px; color: #666; font-size: 18px; }
.error-message { padding: 15px; background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; border-radius: 4px; margin: 20px 0; }
.survey-wrapper { margin: 20px 0; }
.message { margin-top: 15px; padding: 12px; border-radius: 4px; }
.message.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.message.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } `] }) export class SurveyViewerComponent implements OnInit { survey: SurveyModel | null = null; loading = false; error = ''; message = ''; messageType: 'success' | 'error' = 'success';
constructor(private surveyService: SurveyService) {}
ngOnInit() { this.loadSurvey(); }
/** * Load survey from backend * Cargar encuesta desde el backend */ loadSurvey() { this.loading = true; this.error = ''; this.message = '';
this.surveyService.loadSurvey().subscribe({ next: (response: any) => { this.loading = false; const surveyJson = response.survey || response; if (surveyJson && Object.keys(surveyJson).length > 0) { this.survey = new SurveyModel(surveyJson); this.setupSurveyCompleteHandler(); console.log('Survey loaded:', surveyJson); } else { this.error = 'No survey found. Please create one first. / No se encontró encuesta. Por favor crea una primero.'; } }, error: (error) => { this.loading = false; console.error('Error loading survey:', error); this.error = 'Error loading survey. / Error al cargar encuesta.'; } }); }
/** * Setup survey complete handler after survey is loaded * Configurar el manejador de finalización según la forma oficial de SurveyJS * Official docs: https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onComplete */ private setupSurveyCompleteHandler() { if (this.survey) { // Forma oficial de SurveyJS según la documentación this.survey.onComplete.add((sender) => { const results = sender.data; console.log('Survey completed:', results);
this.surveyService.saveResults(results).subscribe({ next: (response) => { if (response.success) { this.showMessage('Thank you! Your responses have been saved. / ¡Gracias! Tus respuestas han sido guardadas.', 'success'); } else { this.showMessage('Error saving results / Error al guardar resultados', 'error'); } }, error: (error) => { console.error('Error saving results:', error); this.showMessage('Error: ' + (error.message || 'Failed to save / Error al guardar'), 'error'); } }); }); } }
private showMessage(text: string, type: 'success' | 'error') { this.message = text; this.messageType = type; if (type === 'success') { setTimeout(() => { this.message = ''; }, 5000); } } } تمها و سفارشیسازی بصری
SurveyJS یک سیستم قالب ارائه میدهد که امکان سفارشیسازی کامل ظاهر نظرسنجی را فراهم میکند. از قالبهای سفارشی میتوان برای حفظ هویت بصری منسجم که با برندسازی سازمان همسو است، استفاده کرد.
یکپارچهسازی کامل: گردش کار و سرویسها
سرویسهای انگولار برای ارتباطات بکاند
در برنامههای وب مدرن که با دادههای خارجی تعامل دارند، حفظ جدایی واضح بین رابط کاربری و منطق backend بسیار مهم است. در این پلتفرم مدیریت فرم، لایه سرویس Angular به عنوان واسطهای بین رابط کاربری SurveyJS و API backend PHP عمل میکند. این جدایی، برنامه را ماژولار، قابل آزمایش و نگهداری آن را آسانتر میکند.
سرویسهای Angular تمام ارتباطات با بکاند PHP را مدیریت میکنند. آنها یک لایه انتزاعی ارائه میدهند که عملیات ایجاد، خواندن، بهروزرسانی و حذف (CRUD) را ساده میکند، در عین حال در صورت نیاز احراز هویت را نیز مدیریت میکند.
سرویس اصلی در این پروژه SurveyService است که در src/app/survey.service.ts قرار دارد. این سرویس مسئول تمام تعاملات کلاینت-سرور مربوط به نظرسنجیها است. در داخل، از HttpClient انگولار برای ارتباط با نقاط انتهایی REST تعریف شده در بکاند PHP استفاده میکند، مانند:
/api/load_survey.php
/api/save_survey.php
/api/save_results.php
مسئولیتهای اصلی SurveyService عبارتند از:
loadSurvey() – طرحواره نظرسنجی را از backend بارگذاری میکند.
saveSurvey() – طرح نظرسنجی را با ارسال دادههای JSON به save_survey.php ذخیره میکند.
saveResults() – پاسخهای کاربر را در survey_results.json ذخیره میکند.
loadResults() – تمام پاسخهای جمعآوریشده در نظرسنجی را برای تجزیه و تحلیل بازیابی میکند.
این سرویس یک رابط کاربری ساده و مؤثر برای مدیریت تمام عملیات نظرسنجی بدون نیاز به احراز هویت پیچیده یا منطق اعتبارسنجی ارائه میدهد. این سرویس به رابط کاربری اجازه میدهد تا به طور مؤثر با رابط کاربری بکاند تعامل داشته باشد و در عین حال کد را ماژولار و قابل نگهداری نگه دارد.
فایل: src/app/survey.service.ts
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs';
export interface SurveySchema { pages?: any[]; questions?: any[]; [key: string]: any; }
export interface SurveyResult { timestamp: string; results: any; }
@Injectable({ providedIn: 'root' }) export class SurveyService { // API URL - Adjust if your Laragon setup uses a different path private apiUrl = '/api';
constructor(private http: HttpClient) {}
/** * Save survey schema to backend */ saveSurvey(survey: SurveySchema): Observable<any> { return this.http.post(`${this.apiUrl}/save_survey.php`, { survey }); }
/** * Load survey schema from backend */ loadSurvey(): Observable<SurveySchema> { return this.http.get<SurveySchema>(`${this.apiUrl}/load_survey.php`); }
/** * Save survey results */ saveResults(results: any): Observable<any> { const data: SurveyResult = { timestamp: new Date().toISOString(), results }; return this.http.post(`${this.apiUrl}/save_results.php`, data); }
/** * Load survey results */ loadResults(): Observable<SurveyResult[]> { return this.http.get<SurveyResult[]>(`${this.apiUrl}/load_results.php`); } } بکاند PHP: معماری مستقیم و جریان ارتباطی
بکاند به عنوان یک سیستم پردازش
بکاند PHP تمام پردازش دادهها را برای پلتفرم مدیریت فرم انجام میدهد. این بکاند درخواستها را از فرانتاند Angular دریافت میکند، آنها را پردازش میکند و پاسخهای ساختاریافته را برمیگرداند. بکاند از یک الگوی نقاط پایانی مستقیم استفاده میکند و به جای یک معماری چندلایه پیچیده، بر سادگی و عملکرد فوری تمرکز دارد.
لایه ۱: رابط ارتباطی و پیکربندی CORS
پیادهسازی فنی
لایه اول، ارتباط HTTP را برقرار میکند و سیاستهای اشتراکگذاری منابع بین مبدا (CORS) را پیکربندی میکند. این لایه در چهار فایل اصلی PHP پیادهسازی شده است که به عنوان نقاط ورود به سیستم عمل میکنند:
api/load_survey.php – بارگذاری طرحواره نظرسنجی
هدرهای CORS را برای توسعه محلی تنظیم میکند.
Content-Type را روی application/json پیکربندی میکند.
اعتبارسنجی متد HTTP GET
survey_schema.json از دایرکتوری data/ میخواند.
قبل از بازگرداندن JSON، صحت آن را بررسی میکند.
api/save_survey.php – ذخیره طرحواره
هدرهای امنیتی و CORS را تنظیم میکند.
اعتبارسنجی متد HTTP POST
ورودی JSON را با اعتبارسنجی پردازش میکند
اگر دایرکتوری data/ وجود نداشته باشد، به طور خودکار آن را ایجاد میکند.
فایل را با قالببندی قابل خواندن و پشتیبانی از یونیکد مینویسد
لایه ۲: مدیریت خطا و اعتبارسنجی اولیه
نقاط پایانی ذخیرهسازی
api/save_results.php – ذخیرهسازی پاسخها
ساختار دادههای ورودی را اعتبارسنجی میکند
نتایج موجود را میخواند تا پاسخهای انباشتهشده را حفظ کند.
پاسخهای جدید را با یک مهر زمانی خودکار اضافه میکند
حفظ یکپارچگی دادههای موجود
تعداد کل ارسالها را برمیگرداند
api/load_results.php – بازیابی نتایج
با برگرداندن یک آرایه خالی، فایلهای ناموجود را مدیریت میکند.
اعتبارسنجی یکپارچگی JSON
دادهها را به یک قالب آرایهای ثابت نرمالسازی میکند.
اعتبارسنجی ساختار را برای دادههای برگشتی انجام میدهد.
جریان پردازش مستقیم
ذخیره طرح نظرسنجی
درخواست ورودی: POST /api/save_survey.php با طرح JSON نظرسنجی
جریان گام به گام:
رابط ( api/save_survey.php )
تجزیه هدرهای HTTP و پیکربندی CORS
تأیید کنید که روش درخواست POST است
خواندن دادههای JSON از php://input
اعتبارسنجی (همان فایل)
بررسی سینتکس JSON
ساختار مورد نیاز ( data['survey'] ) را تأیید کنید
اطمینان از خالی نبودن فیلدها
پایداری (همان فایل)
اگر دایرکتوری data/ وجود ندارد، آن را ایجاد کنید.
نوشتن survey_schema.json با استفاده از JSON_PRETTY_PRINT
تأیید بازگشت شامل اطلاعات فایل و بایتهای نوشته شده
پاسخ:
{ "success": true, "message": "...", "file": "...", "bytes_written": ... } ذخیره پاسخهای کاربر
درخواست ورودی: POST /api/save_results.php با پاسخهای نظرسنجی
جریان گام به گام:
رابط ( api/save_results.php )
پیکربندی هدرهای HTTP
اعتبارسنجی روش درخواست
پردازش ورودی JSON
اعتبارسنجی (همان فایل)
ساختار نتایج مورد نیاز را تأیید کنید
اعتبارسنجی مهر زمانی، در صورت مفقود بودن، یکی ایجاد کنید
انباشت (همان فایل)
خواندن survey_results.json موجود
پاسخ جدید را اضافه کنید
پاسخهای قبلی را حفظ کنید
پایداری (همان فایل)
نوشتن آرایه بهروزرسانیشده در فایل
پاسخ بازگشتی شامل تعداد کل ارسالها
پاسخ:
{ "success": true, "message": "...", "total_submissions": ..., "bytes_written": ... } گردش کار و معماری کامل
پلتفرم نظرسنجی به عنوان یک سیستم یکپارچه با ساختار زیر عمل میکند:
Frontend Angular ←→ PHP API Endpoints ←→ JSON Files (data/) ↑ ↑ SurveyJS Direct Endpoints Components + survey_schema.json SurveyService + survey_results.json CORS Configured مراحل گردش کار:
۱. آفرینش:
طراحی نظرسنجی توسط کاربر → SurveyCreator → save_survey.php → data/survey_schema.json
۲. تجسم:
بارگذاری برنامه → load_survey.php → SurveyViewer نظرسنجی را رندر میکند
۳. جمعآوری پاسخها:
کاربر نظرسنجی را تکمیل میکند → SurveyService.saveResults() → save_results.php → data/survey_results.json
۴. تحلیل:
کوئریهای برنامه → load_results.php → پردازش آرایه پاسخ
نتیجهگیری
ترکیب Angular 17 و SurveyJS پایه و اساس پایداری برای ساخت یک پلتفرم مدیریت فرم قوی فراهم میکند. معماری نقطه پایانی مستقیم نشان میدهد که سادگی در طراحی، عملکرد را کاهش نمیدهد.
این سیستم، ایجاد، رندر، پاسخهای کاربر و ذخیرهسازی نتایج نظرسنجی را به طور کارآمد مدیریت میکند و در عین حال نگهداری آن آسان است. همچنین بر محدودیتهای ابزارهای نظرسنجی SaaS غلبه میکند و به سازمانها کنترل کامل بر دادههای خود و انعطافپذیری لازم برای پیادهسازی هرگونه سفارشیسازی را هم در رابط کاربری سازنده فرم و هم در فرمها میدهد.
با استفاده از یک معماری ساده با نقاط پایانی کاملاً تعریفشده، این پلتفرم بدون پیچیدگی غیرضروری به قابلیتهای کاربردی دست مییابد.





ارسال نظر