mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 04:23:55 +00:00
Admin Workflow - Admin UI to search and export data
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class AnswerLike implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('answer', 'like', '%' . $value . '%')
|
||||
->orWhereHas('answer', function ($subquery) use($value){
|
||||
$subquery->where('display_text', 'like', '%' . $value . '%');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use App\Classes\ValueObjects\Constants\QuestionGroup;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class WithAnswers implements Filter
|
||||
{
|
||||
@@ -16,12 +15,7 @@ class WithAnswers implements Filter
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where(function ($query) use($value){
|
||||
if($value){
|
||||
$query->where('answer', '=', $value);
|
||||
}
|
||||
else{
|
||||
$query->whereIn('answer', QuestionGroup::QUESTION_GROUPS);
|
||||
}
|
||||
$query->whereIn('answer', $value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Exports\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Exports\Services\ExportsQAWithGroups;
|
||||
use App\Classes\Modules\Exports\Standards\Rules\CanExportQuestionsAnswers;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Classes\General\AWSS3Helper;
|
||||
use App\Classes\General\Helper;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class ExportQAWithGroupsLogic extends AbstractControllerLogic
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => 'Export Questions & Answers',
|
||||
'message' => 'You have successfully exported data'
|
||||
];
|
||||
}
|
||||
|
||||
/** @var ExportsQAWithGroups */
|
||||
private $exportsQAWithGroups;
|
||||
|
||||
/** @var CanExportQuestionsAnswers */
|
||||
private $canExport;
|
||||
|
||||
/**
|
||||
* ExportQAWithGroupsLogic constructor.
|
||||
* @param ExportsQAWithGroups $exportsQAWithGroups
|
||||
* @param CanExportQuestionsAnswers $canExport
|
||||
*/
|
||||
public function __construct(ExportsQAWithGroups $exportsQAWithGroups, CanExportQuestionsAnswers $canExport)
|
||||
{
|
||||
$this->exportsQAWithGroups = $exportsQAWithGroups;
|
||||
$this->canExport = $canExport;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function logic(Request $request) : JsonResponse
|
||||
{
|
||||
$this->canExport->passes();
|
||||
|
||||
$this->exportsQAWithGroups->setFilters(Helper::deserializeFilters($request->input('filters')));
|
||||
|
||||
$exportFileName = 'qas.xls';
|
||||
$filesystemDriver = Storage::getDefaultDriver();
|
||||
if($filesystemDriver === 's3'){
|
||||
return $this->response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $this->exportsQAWithGroups) ]);
|
||||
}
|
||||
|
||||
return $this->response([ 'src' => null ]);
|
||||
}
|
||||
|
||||
}
|
||||
+10
-11
@@ -4,7 +4,7 @@ namespace App\Classes\Modules\Exports\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Exports\Services\ExportsQuestionsAnswers;
|
||||
use App\Classes\Modules\Exports\Services\ExportsQAWithoutGroups;
|
||||
use App\Classes\Modules\Exports\Standards\Rules\CanExportQuestionsAnswers;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Classes\General\AWSS3Helper;
|
||||
@@ -13,7 +13,7 @@ use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
|
||||
class ExportQuestionsAnswersLogic extends AbstractControllerLogic
|
||||
class ExportQAWithoutGroupsLogic extends AbstractControllerLogic
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
@@ -25,20 +25,20 @@ class ExportQuestionsAnswersLogic extends AbstractControllerLogic
|
||||
];
|
||||
}
|
||||
|
||||
/** @var ExportsQuestionsAnswers */
|
||||
private $exportsQuestionsAnswers;
|
||||
/** @var ExportsQAWithoutGroups */
|
||||
private $exportsQAWithoutGroups;
|
||||
|
||||
/** @var CanExportQuestionsAnswers */
|
||||
private $canExport;
|
||||
|
||||
/**
|
||||
* ExportFeedbackDataLogic constructor.
|
||||
* @param ExportsQuestionsAnswers $exportsQuestionsAnswers
|
||||
* ExportQAWithoutGroupsLogic constructor.
|
||||
* @param ExportsQAWithoutGroups $exportsQAWithoutGroups
|
||||
* @param CanExportQuestionsAnswers $canExport
|
||||
*/
|
||||
public function __construct(ExportsQuestionsAnswers $exportsQuestionsAnswers, CanExportQuestionsAnswers $canExport)
|
||||
public function __construct(ExportsQAWithoutGroups $exportsQAWithoutGroups, CanExportQuestionsAnswers $canExport)
|
||||
{
|
||||
$this->exportsQuestionsAnswers = $exportsQuestionsAnswers;
|
||||
$this->exportsQAWithoutGroups = $exportsQAWithoutGroups;
|
||||
$this->canExport = $canExport;
|
||||
}
|
||||
|
||||
@@ -51,15 +51,14 @@ class ExportQuestionsAnswersLogic extends AbstractControllerLogic
|
||||
{
|
||||
$this->canExport->passes();
|
||||
|
||||
$this->exportsQuestionsAnswers->setFilters(Helper::deserializeFilters($request->input('filters')));
|
||||
$this->exportsQAWithoutGroups->setFilters(Helper::deserializeFilters($request->input('filters')));
|
||||
|
||||
$exportFileName = 'qas.xls';
|
||||
$filesystemDriver = Storage::getDefaultDriver();
|
||||
if($filesystemDriver === 's3'){
|
||||
return $this->response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $this->exportsQuestionsAnswers) ]);
|
||||
return $this->response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $this->exportsQAWithoutGroups) ]);
|
||||
}
|
||||
|
||||
return $this->response([ 'src' => null ]);
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -15,7 +15,7 @@ use App\Classes\General\Eloquent\ApplyFiltersToQuery;
|
||||
use App\Classes\ValueObjects\Constants\QuestionGroup;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class ExportsQuestionsAnswers implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
|
||||
class ExportsQAWithGroups implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
|
||||
{
|
||||
|
||||
use Exportable;
|
||||
@@ -63,6 +63,7 @@ class ExportsQuestionsAnswers implements FromQuery, WithHeadings, WithHeadingRow
|
||||
$source = $userAnswer->userSource;
|
||||
$user = $userAnswer->source_id === 0 ? $userAnswer->user : null;
|
||||
$answer = $userAnswer->answer()->first();
|
||||
$questionGroups = explode(',', $userAnswer->question->questionnaire->group);
|
||||
$rows = [[
|
||||
$userAnswer->id,
|
||||
$userAnswer->question->questionnaire->version,
|
||||
@@ -78,7 +79,7 @@ class ExportsQuestionsAnswers implements FromQuery, WithHeadings, WithHeadingRow
|
||||
|
||||
|
||||
$nextId = QAUserAnswerSelected::where('id', '>', $userAnswer->id)
|
||||
->whereIn('answer', QuestionGroup::QUESTION_GROUPS)
|
||||
->whereIn('answer', $questionGroups)
|
||||
->orderBy('id', 'asc')
|
||||
->limit(1)
|
||||
->value('id');
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Exports\Services;
|
||||
|
||||
|
||||
use App\Models\QAUserAnswerSelected;
|
||||
use Maatwebsite\Excel\Concerns\Exportable;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use App\Classes\General\Eloquent\ApplyFiltersToQuery;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class ExportsQAWithoutGroups implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
|
||||
{
|
||||
|
||||
use Exportable;
|
||||
|
||||
private $filters;
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'Id',
|
||||
'Version',
|
||||
'Question Set',
|
||||
'Question Text',
|
||||
'Answer Text',
|
||||
'Answer Value',
|
||||
'Source Email',
|
||||
'Time(Seconds)',
|
||||
'Created Date',
|
||||
'MAIN?'
|
||||
];
|
||||
}
|
||||
|
||||
public function setFilters(array $filters = []): void
|
||||
{
|
||||
$this->filters = $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection|mixed
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
$data = (new ApplyFiltersToQuery())->execute(QAUserAnswerSelected::query(), $this->filters, true);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QAUserAnswerSelected $userAnswer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function map($userAnswer): array
|
||||
{
|
||||
$source = $userAnswer->userSource;
|
||||
$user = $userAnswer->source_id === 0 ? $userAnswer->user : null;
|
||||
$answer = $userAnswer->answer()->first();
|
||||
$questionGroups = explode(',', $userAnswer->question->questionnaire->group);
|
||||
$rows = [[
|
||||
$userAnswer->id,
|
||||
$userAnswer->question->questionnaire->version,
|
||||
$userAnswer->question->questionnaire->description,
|
||||
$userAnswer->question->question_title,
|
||||
$answer ? $answer->display_text : null,
|
||||
$answer ? $answer->value : null,
|
||||
$user ? $user->email : $source->email,
|
||||
$userAnswer->time_used_seconds,
|
||||
Carbon::parse($userAnswer->created_at)->format('d-m-Y'),
|
||||
$answer ? in_array($answer->value, $questionGroups) : false,
|
||||
]];
|
||||
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,19 @@ namespace App\Classes\ValueObjects\Constants;
|
||||
|
||||
final class QuestionGroup {
|
||||
|
||||
public const _1688 = '1688';
|
||||
public const APPROVE_PO = 'approve_po';
|
||||
public const FILL_PO = 'fill_po';
|
||||
// public const _1688 = '1688';
|
||||
// public const APPROVE_PO = 'approve_po';
|
||||
// public const FILL_PO = 'fill_po';
|
||||
|
||||
const OPTIONS_QUESTION_GROUP = [
|
||||
['text' => '1688', 'id' => QuestionGroup::_1688],
|
||||
['text' => 'approve_po', 'id' => QuestionGroup::APPROVE_PO],
|
||||
['text' => 'fill_po', 'id' => QuestionGroup::FILL_PO],
|
||||
];
|
||||
// const OPTIONS_QUESTION_GROUP = [
|
||||
// ['text' => '1688', 'id' => QuestionGroup::_1688],
|
||||
// ['text' => 'approve_po', 'id' => QuestionGroup::APPROVE_PO],
|
||||
// ['text' => 'fill_po', 'id' => QuestionGroup::FILL_PO],
|
||||
// ];
|
||||
|
||||
const QUESTION_GROUPS = [
|
||||
QuestionGroup::_1688,
|
||||
QuestionGroup::APPROVE_PO,
|
||||
QuestionGroup::FILL_PO,
|
||||
];
|
||||
// const QUESTION_GROUPS = [
|
||||
// QuestionGroup::_1688,
|
||||
// QuestionGroup::APPROVE_PO,
|
||||
// QuestionGroup::FILL_PO,
|
||||
// ];
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
namespace App\Http\Controllers\Exports;
|
||||
|
||||
|
||||
use App\Classes\Modules\Exports\ControllersLogic\ExportQuestionsAnswersLogic;
|
||||
use App\Classes\Modules\Exports\ControllersLogic\ExportQAWithGroupsLogic;
|
||||
use App\Classes\Modules\Exports\ControllersLogic\ExportQAWithoutGroupsLogic;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -12,11 +13,21 @@ class ExportQuestionsAnswersController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ExportQuestionsAnswersLogic $logic
|
||||
* @param ExportQAWithGroupsLogic $logic
|
||||
* @return BinaryFileResponse
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function export(Request $request, ExportQuestionsAnswersLogic $logic) {
|
||||
public function exportWithGroups(Request $request, ExportQAWithGroupsLogic $logic) {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ExportQAWithoutGroupsLogic $logic
|
||||
* @return BinaryFileResponse
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function exportWithoutGroups(Request $request, ExportQAWithoutGroupsLogic $logic) {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class QuestionnaireSetsResource extends JsonResource
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'group' => $this->group,
|
||||
'group' => explode(',', $this->group),
|
||||
'version' => $this->version,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http\Resources;
|
||||
|
||||
|
||||
use App\Classes\ValueObjects\Constants\DocumentType;
|
||||
use App\Classes\ValueObjects\Constants\QuestionGroup;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use App\Models\QAAnswerOptions;
|
||||
use App\Models\QAQuestions;
|
||||
@@ -24,17 +23,13 @@ class QuestionsAnswersResource extends JsonResource
|
||||
$source = new UserSourceResource($this->userSource);
|
||||
$user = $this->source_id === 0 ? new UserResource($this->user) : null;
|
||||
$answerOption = QAAnswerOptions::where('id', $this->answer_option_id)->first();
|
||||
|
||||
$questionGroups = explode(',', $this->question->questionnaire->group);
|
||||
$user_marking = '';
|
||||
// if($user){
|
||||
// $companyModule = $user->companyModule()->first();
|
||||
// $user_marking = $companyModule ? $companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference : "";
|
||||
// }
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'question_id' => $this->question_id,
|
||||
'question_groups' => QuestionGroup::QUESTION_GROUPS,
|
||||
'question_groups' => $questionGroups,
|
||||
'questionnaire' => new QuestionnaireSetsResource($this->question->questionnaire),
|
||||
'question_title' => $question ? $question->question_title : null,
|
||||
'question_type' => $question ? $question->question_type : 0,
|
||||
|
||||
@@ -22,7 +22,7 @@ class QAWorkFlowSeeder extends Seeder
|
||||
[
|
||||
'name' => 'Admin Work Flow',
|
||||
'description' => 'Admin Work Flow',
|
||||
'group' => 'workflow',
|
||||
'group' => '1688,approve_po,fill_po',
|
||||
'version' => 1,
|
||||
'questions' => [
|
||||
[
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<div class="row parentContainer m-b-10">
|
||||
<div class="col p-l-0">
|
||||
<div class="row m-l-15 m-r-5 p-t-10 b-a align-items-center pointer shadow bg-white rounded b-white">
|
||||
<div class="col-12">
|
||||
<div class="row m-b-10">
|
||||
<div class="col-2">{{ item.id }} <br> {{ item.created_at }} <br> {{ item.source_email }}</div>
|
||||
<div class="col-1">{{ item.questionnaire.version }} <br> {{ item.questionnaire.description }}</div>
|
||||
<div class="col-2">{{ item.question_title }}</div>
|
||||
<div class="col-1">{{ parsedAnswer === 'go_back' ? '' : item.answer }}</div>
|
||||
<div class="col-2">{{ parsedAnswer }}</div>
|
||||
<div class="col-1" style="display: flex; flex-wrap: nowrap; gap: 5px;">
|
||||
<div v-if="item.documents != null" style="display: flex; flex-wrap: nowrap; gap: 5px;">
|
||||
<div
|
||||
v-for="file in item.documents.files"
|
||||
v-bind:key="file.id"
|
||||
class="col-auto no-padding">
|
||||
<document-file-viewer-component :file="file">
|
||||
<template slot="button">
|
||||
<button class="btn btn-xs btn-default bg-master-lightest b-rad-none no-border">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
</template>
|
||||
</document-file-viewer-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">{{ item.time }}</div>
|
||||
<div class="col-1">
|
||||
<a :href="route('booking.details', JSON.parse(item.question_metadata).marking)" target="_blank" v-if="JSON.parse(item.question_metadata)">
|
||||
{{ JSON.parse(item.question_metadata).marking }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col parentContainer position-static">
|
||||
<div class="row align-items-center justify-content-end">
|
||||
<!-- <div class="col-auto position-static no-padding requestModal" data-type="deleteBillGroup">
|
||||
<div class="btn bg-grey no-border">
|
||||
<i class="fa fa-times text-danger"></i>
|
||||
</div>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" type="deleteBillGroup">
|
||||
<general-confirmation-form-component
|
||||
contentText="Are you sure you want to delete this Bill Group?"
|
||||
modalType="delete"
|
||||
class="text-center"
|
||||
:apiRoute="route('api.transaction.group.bill.delete', item.id)"
|
||||
apiMethod="delete"
|
||||
:section="section"
|
||||
>
|
||||
</general-confirmation-form-component>
|
||||
</modal-component>
|
||||
</div> -->
|
||||
<div class="col-auto no-padding" v-show="showExpandedIcon">
|
||||
<div class="btn btn-sm btn-default b-rad-none no-border" @click="expand()">
|
||||
<i class="fa fa-download" :class="[{'fa-angle-up': expanded}, {'fa-angle-down': !expanded}]"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto no-padding" v-if="loading && item.question_groups.includes(item.answer_value)">
|
||||
<div class="btn btn-sm btn-default b-rad-none no-border">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-b-10" v-show="expanded" v-if="item.question_groups.includes(item.answer_value)">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row align-items-center m-t-10 p-t-10 p-b-10 b-t b-grey muted all-caps fs-10">
|
||||
<div class="col-1">Id</div>
|
||||
<div class="col-2">Question Text</div>
|
||||
<div class="col-1">Order/Booking/Transfer</div>
|
||||
<div class="col-1">Answer Text</div>
|
||||
<div class="col-2">Answer Value</div>
|
||||
<div class="col-1">Documents Uploaded</div>
|
||||
<div class="col-1">Time(seconds)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<list-component style="min-height: auto;" :section="section" :endpoint="route('api.questionnaires.qa.list')" :options="options">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<question-answer-inner-component :data="data"></question-answer-inner-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import componentHandler from '../../../general/mixins/componentHandler';
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
section: 'qaListQuestions-' + this.data.reference + '-' + this.data.id,
|
||||
expanded: false,
|
||||
options: {
|
||||
'order_by': {column: 'created_at', DESC: false},
|
||||
'per_page': 20,
|
||||
},
|
||||
showExpandedIcon: false,
|
||||
loading: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
pendingQueue(inComplete){
|
||||
if(!inComplete){
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
expandedList(newValue){
|
||||
if (Array.isArray(newValue)) {
|
||||
if(newValue.length > 0){
|
||||
this.showExpandedIcon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
expandedList () {
|
||||
return this.$store.getters.getListData(this.section);
|
||||
},
|
||||
pendingQueue() {
|
||||
return this.$store.getters.isInCompleteQueue(this.section);
|
||||
},
|
||||
parsedAnswer() {
|
||||
try {
|
||||
const parsed = this.item && this.item.answer_value ? JSON.parse(this.item.answer_value) : null;
|
||||
return parsed && parsed.text ? parsed.text : this.item.answer_value;
|
||||
} catch (error) {
|
||||
return this.item.answer_value;
|
||||
}
|
||||
},
|
||||
},
|
||||
created(){
|
||||
this.options['reference'] = this.item.reference;
|
||||
this.options['id_after'] = [this.item.id, this.item.question_groups];
|
||||
},
|
||||
methods: {
|
||||
expand(){
|
||||
this.expanded = !this.expanded;
|
||||
},
|
||||
|
||||
},
|
||||
mixins: [componentHandler]
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.spinner {
|
||||
border: 2px solid rgba(0, 0, 0, 0.1);
|
||||
border-left-color: #000;
|
||||
border-radius: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation: spin 1s linear infinite;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="row parentContainer m-b-10">
|
||||
<div class="col p-l-0">
|
||||
<div class="row m-l-15 p-t-10 b-a align-items-center pointer shadow bg-white rounded b-white">
|
||||
<div class="row m-l-15 m-r-5 p-t-10 b-a align-items-center pointer shadow bg-white rounded b-white">
|
||||
<div class="col-12">
|
||||
<div class="row m-b-10">
|
||||
<div class="col-1">{{ item.id }}</div>
|
||||
@@ -75,7 +75,7 @@
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
section: 'listQuestionAnswerInner-' + this.data.reference + '-' + this.data.id,
|
||||
section: 'qaListQuestionGroups-' + this.data.reference + '-' + this.data.id,
|
||||
expanded: false,
|
||||
options: {
|
||||
'order_by': {column: 'created_at', DESC: false},
|
||||
|
||||
+32
-38
@@ -1,45 +1,39 @@
|
||||
<template>
|
||||
<div class="row parentContainer">
|
||||
<div class="col-1">{{ item.id }}</div>
|
||||
<div class="col-2">{{ item.question_title }}</div>
|
||||
<div class="col-1">
|
||||
<a :href="route('booking.details', JSON.parse(item.question_metadata).marking)"
|
||||
target="_blank">{{ JSON.parse(item.question_metadata).marking }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-1">{{ parsedAnswer === 'go_back' ? '' : item.answer }}</div>
|
||||
<div class="col-2">{{ parsedAnswer }}</div>
|
||||
<div class="col-1" style="display: flex; flex-wrap: nowrap; gap: 5px;">
|
||||
<div v-if="item.documents != null" style="display: flex; flex-wrap: nowrap; gap: 5px;">
|
||||
<div
|
||||
v-for="file in item.documents.files"
|
||||
v-bind:key="file.id"
|
||||
class="col-auto no-padding">
|
||||
<document-file-viewer-component :file="file">
|
||||
<template slot="button">
|
||||
<button class="btn btn-xs btn-default bg-master-lightest b-rad-none no-border">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
</template>
|
||||
</document-file-viewer-component>
|
||||
<div class="row parentContainer m-b-10">
|
||||
<div class="col">
|
||||
<div class="row m-l-0 m-r-0 p-t-10 b-a align-items-center pointer shadow bg-white rounded b-white">
|
||||
<div class="col-12">
|
||||
<div class="row m-b-10">
|
||||
<div class="col-1">{{ item.id }}</div>
|
||||
<div class="col-2">{{ item.question_title }}</div>
|
||||
<div class="col-1">
|
||||
<a :href="route('booking.details', JSON.parse(item.question_metadata).marking)" target="_blank" v-if="JSON.parse(item.question_metadata)">
|
||||
{{ JSON.parse(item.question_metadata).marking }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-1">{{ parsedAnswer === 'go_back' ? '' : item.answer }}</div>
|
||||
<div class="col-2">{{ parsedAnswer }}</div>
|
||||
<div class="col-1" style="display: flex; flex-wrap: nowrap; gap: 5px;">
|
||||
<div v-if="item.documents != null" style="display: flex; flex-wrap: nowrap; gap: 5px;">
|
||||
<div
|
||||
v-for="file in item.documents.files"
|
||||
v-bind:key="file.id"
|
||||
class="col-auto no-padding">
|
||||
<document-file-viewer-component :file="file">
|
||||
<template slot="button">
|
||||
<button class="btn btn-xs btn-default bg-master-lightest b-rad-none no-border">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
</template>
|
||||
</document-file-viewer-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">{{ item.time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">{{ item.time }}</div>
|
||||
|
||||
<!-- <div class="col-1">
|
||||
<div v-if="item.documents != null">
|
||||
<div v-for="file in item.documents.files" v-bind:key="file.id" class="col-auto no-padding m-r-5">
|
||||
<document-file-viewer-component :file="file">
|
||||
<template slot="button">
|
||||
<button class="btn btn-xs btn-default bg-master-lightest b-rad-none no-border">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
</template>
|
||||
</document-file-viewer-component>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<validation-wrapper-component selectable :validator="$v.filterQuestionnaireSet">
|
||||
<label>Questionnaire Set Version</label>
|
||||
<selectable-component :endpoint="route('api.questionnaires.list')" :section="section + 'QuestionnaireSet'" valueColumn="id" :labelColumn="['name', 'version']" v-model="filterQuestionnaireSet"></selectable-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<validation-wrapper-component selectable :validator="$v.filterUserId">
|
||||
<label>Users</label>
|
||||
<selectable-component :endpoint="route('api.account.user.list') + '?filters=' + JSON.stringify(userListOptions)" :section="section + 'UserList'" valueColumn="id" :labelColumn="['name', 'email']" v-model="filterUserId"></selectable-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<validation-wrapper-component :validator="$v.filterAnswerText">
|
||||
<label class="all-caps">Answer Text</label>
|
||||
<input type="text" class="form-control" v-model.lazy="filterAnswerText">
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-10">
|
||||
<div class="col-md-4">
|
||||
<validation-wrapper-component :validator="$v.filterStartDate">
|
||||
<label class="all-caps">Start Date</label>
|
||||
<date-picker-component v-model.lazy="filterStartDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<validation-wrapper-component :validator="$v.filterEndDate">
|
||||
<label class="all-caps">End Date</label>
|
||||
<date-picker-component v-model.lazy="filterEndDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-end m-t-10">
|
||||
<div class="col-auto p-l-0">
|
||||
<open-link-in-new-tab-component custom-class="btn btn-sm b-rad-none fs-14" :url="route('api.questionnaires.qa.export.without.groups') + '?filters=' + JSON.stringify(this.options)" :is-url-protected="true" :onClick="exportAction">
|
||||
<i class="fa fa-download lh-40"></i> Download
|
||||
</open-link-in-new-tab-component>
|
||||
</div>
|
||||
<div class="col-auto p-l-0">
|
||||
<div class="btn b-rad-none" @click="resetSarch">
|
||||
<i class="fa fa-refresh lh-40"></i> Clear
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto p-l-0">
|
||||
<div class="btn btn-primary b-rad-none" @click="onSelected">
|
||||
<i class="fa fa-search lh-40"></i> Search
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center m-t-10 p-t-10 p-b-10 b-t b-grey muted all-caps fs-10">
|
||||
<div class="col-2">Id</div>
|
||||
<div class="col-1">Version/Question Set</div>
|
||||
<div class="col-2">Question Text</div>
|
||||
<div class="col-1">Answer Text</div>
|
||||
<div class="col-2">Answer Value</div>
|
||||
<div class="col-1">Documents Uploaded</div>
|
||||
<div class="col-1">Time(seconds)</div>
|
||||
<div class="col-1">Order/Booking/Transfer</div>
|
||||
</div>
|
||||
</div>
|
||||
<list-component style="min-height: 600px;" :key="currentKey" :section="section + 'ListQuestions'" :endpoint="route('api.questionnaires.qa.list')" :options="options">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<question-answer-2-component :key="data.id" :data="data"></question-answer-2-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
export default {
|
||||
props: {
|
||||
section:{
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
filterUserId: "",
|
||||
filterQuestionnaireSet: "",
|
||||
filterStartDate: "",
|
||||
filterEndDate: "",
|
||||
filterAnswerText: "",
|
||||
userListOptions: {
|
||||
'type_in': this.$store.getters.isSuperAdmin ? [1, 2] : [2],
|
||||
},
|
||||
options: {
|
||||
'per_page': 10,
|
||||
'order_by': {column: 'created_at', DESC: true},
|
||||
},
|
||||
currentKey: 1,
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
filterUserId: {},
|
||||
filterQuestionnaireSet: {},
|
||||
filterStartDate: {},
|
||||
filterEndDate: {},
|
||||
filterAnswerText: {},
|
||||
},
|
||||
methods: {
|
||||
onSelected(userId){
|
||||
this.updateOptions();
|
||||
this.currentKey+=1;
|
||||
},
|
||||
updateOptions(){
|
||||
if(this.filterUserId){
|
||||
this.options['user_id'] = this.filterUserId;
|
||||
}
|
||||
if(this.filterQuestionnaireSet){
|
||||
this.options['has_questionnaire'] = this.filterQuestionnaireSet;
|
||||
}
|
||||
if(this.filterStartDate){
|
||||
this.options['start_date'] = this.filterStartDate;
|
||||
}
|
||||
if(this.filterEndDate){
|
||||
this.options['end_date'] = this.filterEndDate;
|
||||
}
|
||||
if(this.filterAnswerText){
|
||||
this.options['answer_like'] = this.filterAnswerText;
|
||||
}
|
||||
},
|
||||
exportAction(){
|
||||
this.updateOptions();
|
||||
return route('api.questionnaires.qa.export.without.groups') + '?filters=' + JSON.stringify(this.options);
|
||||
},
|
||||
resetSarch() {
|
||||
this.filterUserId = "",
|
||||
this.filterQuestionGroup = "",
|
||||
this.filterQuestionnaireSet = "",
|
||||
this.filterStartDate = "",
|
||||
this.filterEndDate = "",
|
||||
this.filterAnswerText = "",
|
||||
delete this.options['user_id'];
|
||||
delete this.options['has_questionnaire'];
|
||||
delete this.options['start_date'];
|
||||
delete this.options['end_date'];
|
||||
delete this.options['answer_like'];
|
||||
this.currentKey+=1;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
+15
-15
@@ -40,7 +40,7 @@
|
||||
</div>
|
||||
<div class="row justify-content-end m-t-10">
|
||||
<div class="col-auto p-l-0">
|
||||
<open-link-in-new-tab-component custom-class="btn btn-sm b-rad-none fs-14" :url="route('api.questionnaires.qa.export') + '?filters=' + JSON.stringify(this.options)" :is-url-protected="true" :onClick="exportAction">
|
||||
<open-link-in-new-tab-component custom-class="btn btn-sm b-rad-none fs-14" :url="route('api.questionnaires.qa.export.with.groups') + '?filters=' + JSON.stringify(this.options)" :is-url-protected="true" :onClick="exportAction">
|
||||
<i class="fa fa-download lh-40"></i> Download
|
||||
</open-link-in-new-tab-component>
|
||||
</div>
|
||||
@@ -66,7 +66,7 @@
|
||||
<div class="col-1">Created Date</div>
|
||||
</div>
|
||||
</div>
|
||||
<list-component style="min-height: 600px;" :key="currentKey" :section="'list' + section" :endpoint="route('api.questionnaires.qa.list')" :options="options">
|
||||
<list-component style="min-height: 600px;" :key="currentKey" :section="section + 'ListQuestionGroups'" :endpoint="route('api.questionnaires.qa.list')" :options="options" v-if="questionGroups.length > 0">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<question-answer-component :key="data.id" :data="data"></question-answer-component>
|
||||
</template>
|
||||
@@ -84,10 +84,6 @@
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
questionGroups: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
@@ -102,13 +98,14 @@
|
||||
options: {
|
||||
'per_page': 10,
|
||||
'order_by': {column: 'created_at', DESC: true},
|
||||
'with_answers': "",
|
||||
'with_answers': [],
|
||||
},
|
||||
currentKey: 1,
|
||||
questionGroups: [],
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.submit(route('api.company.list') + '?filters=' + JSON.stringify({'business_type': 3, 'status_in': [1, 2, 0]}), 'get', 'transactionGroupsListPaymentSection', false, false)
|
||||
this.fetchQuestionnaireSets();
|
||||
},
|
||||
validations: {
|
||||
filterUserId: {},
|
||||
@@ -118,17 +115,23 @@
|
||||
filterEndDate: {},
|
||||
},
|
||||
methods: {
|
||||
fetchQuestionnaireSets(){
|
||||
this.submit(route('api.questionnaires.list') +'?filters=' + JSON.stringify({ 'per_page': 10, order_by: {column: 'id', DESC: true} }), 'get', this.section, false, false)
|
||||
},
|
||||
successHandler(response){
|
||||
this.questionGroups = response.payload.data[0].group;
|
||||
this.options.with_answers = this.questionGroups;
|
||||
},
|
||||
onSelected(userId){
|
||||
this.updateOptions();
|
||||
this.currentKey+=1;
|
||||
// this.updateList();
|
||||
},
|
||||
updateOptions(){
|
||||
if(this.filterUserId){
|
||||
this.options['user_id'] = this.filterUserId;
|
||||
}
|
||||
if(this.filterQuestionGroup){
|
||||
this.options['with_answers'] = this.filterQuestionGroup;
|
||||
this.options['with_answers'] = [this.filterQuestionGroup];
|
||||
}
|
||||
if(this.filterQuestionnaireSet){
|
||||
this.options['has_questionnaire'] = this.filterQuestionnaireSet;
|
||||
@@ -142,7 +145,7 @@
|
||||
},
|
||||
exportAction(){
|
||||
this.updateOptions();
|
||||
return route('api.questionnaires.qa.export') + '?filters=' + JSON.stringify(this.options);
|
||||
return route('api.questionnaires.qa.export.with.groups') + '?filters=' + JSON.stringify(this.options);
|
||||
},
|
||||
resetSarch() {
|
||||
this.filterUserId = "",
|
||||
@@ -150,16 +153,13 @@
|
||||
this.filterQuestionnaireSet = "",
|
||||
this.filterStartDate = "",
|
||||
this.filterEndDate = "",
|
||||
this.options['with_answers'] = "";
|
||||
this.options['with_answers'] = this.questionGroups;
|
||||
delete this.options['user_id'];
|
||||
delete this.options['has_questionnaire'];
|
||||
delete this.options['start_date'];
|
||||
delete this.options['end_date'];
|
||||
this.currentKey+=1;
|
||||
},
|
||||
// updateList(){
|
||||
// this.$refs.questionsAnswersList.updateFilters({'per_page': 10, 'has_questionnaire_group_in':['feedback'], 'user_id': this.filterUserId, order_by: {column: 'created_at', DESC: false}});
|
||||
// },
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -8,7 +8,49 @@
|
||||
|
||||
<div class="row d-none" :class="[{'d-flex': $store.getters.isAdmin}]" v-if="$store.getters.isAdmin">
|
||||
<div class="col no-padding">
|
||||
<question-answer-section-component section="questionsAnswersSection" :question-groups="{{ json_encode(\App\Classes\ValueObjects\Constants\QuestionGroup::OPTIONS_QUESTION_GROUP) }}"></question-answer-section-component>
|
||||
<div class="row tabsContainer">
|
||||
<div class="col">
|
||||
<div class="row m-l-0 m-r-0 d-flex">
|
||||
<div class="col m-r-5">
|
||||
<div class="row fs-12 text-center">
|
||||
<div class="col p-t-20 p-b-20 bg-master-lighter active tabButton" tab-name="questionGroups">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="fs-12 m-t-5 all-caps">Question Groups</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col m-r-5">
|
||||
<div class="row fs-12 text-center">
|
||||
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="questions">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="fs-12 m-t-5 all-caps">Questions</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row no-margin">
|
||||
<div class="col bg-white padding-25">
|
||||
<div class="row tabsContainer tabContent padding-25" tab-name="questionGroups">
|
||||
<div class="col">
|
||||
<question-answer-section-component section="qaQuestionGroupsSection"></question-answer-section-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row tabsContainer hide tabContent padding-25" tab-name="questions">
|
||||
<div class="col">
|
||||
<question-answer-section-2-component section="qaQuestionsWithoutGroupSection"></question-answer-section-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -9,6 +9,7 @@ Route::group(['prefix' => 'questionnaires', 'as' => 'questionnaires.', 'namespac
|
||||
|
||||
Route::group(['prefix' => 'qa', 'as' => 'qa.'], function () {
|
||||
Route::get('/list', 'ListQuestionsAnswersController@list')->name('list');
|
||||
Route::get('/export', '\\App\\Http\\Controllers\\Exports\\ExportQuestionsAnswersController@export')->name('export');
|
||||
Route::get('/export1', '\\App\\Http\\Controllers\\Exports\\ExportQuestionsAnswersController@exportWithGroups')->name('export.with.groups');
|
||||
Route::get('/export2', '\\App\\Http\\Controllers\\Exports\\ExportQuestionsAnswersController@exportWithoutGroups')->name('export.without.groups');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user