US-017: Implement Daily Comments per day per test
- Add per-day comment input in monthly entry grid (comment icon per cell) - Update saveMonthly() to save rescomment field for each result - Update getMonthlyData() to return per-day comments - Store comments in results.rescomment field with soft deletes support
This commit is contained in:
parent
1374c8769f
commit
2e23fc38c3
@ -98,6 +98,7 @@ class EntryApiController extends BaseController
|
||||
foreach ($tests as $testData) {
|
||||
$testId = $testData['testId'] ?? 0;
|
||||
$resvalues = $testData['resvalue'] ?? [];
|
||||
$rescomments = $testData['rescomment'] ?? [];
|
||||
|
||||
$controlTest = $this->controlTestModel->getByControlAndTest($controlId, $testId);
|
||||
$mean = $controlTest['mean'] ?? 0;
|
||||
@ -111,12 +112,15 @@ class EntryApiController extends BaseController
|
||||
|
||||
foreach ($resvalues as $day => $value) {
|
||||
if (!empty($value)) {
|
||||
$resdate = $yearMonth . '-' . str_pad($day, 2, '0', STR_PAD_LEFT);
|
||||
$rescomment = $rescomments[$day] ?? '';
|
||||
|
||||
$resultData = [
|
||||
'control_ref_id' => $controlId,
|
||||
'test_ref_id' => $testId,
|
||||
'resdate' => $yearMonth . '-' . str_pad($day, 2, '0', STR_PAD_LEFT),
|
||||
'resdate' => $resdate,
|
||||
'resvalue' => $value,
|
||||
'rescomment' => '',
|
||||
'rescomment' => $rescomment,
|
||||
];
|
||||
|
||||
if ($operation === 'replace') {
|
||||
@ -223,9 +227,13 @@ class EntryApiController extends BaseController
|
||||
$comment = $this->commentModel->getByControlTestMonth($controlId, $testId, $yearMonth);
|
||||
|
||||
$formValues = [];
|
||||
$comments = [];
|
||||
foreach ($results as $row) {
|
||||
$day = (int)date('j', strtotime($row['resdate']));
|
||||
$formValues[$day] = $row['resvalue'];
|
||||
if (!empty($row['rescomment'])) {
|
||||
$comments[$day] = $row['rescomment'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->respond([
|
||||
@ -233,6 +241,7 @@ class EntryApiController extends BaseController
|
||||
'message' => 'fetch success',
|
||||
'data' => [
|
||||
'formValues' => $formValues,
|
||||
'comments' => $comments,
|
||||
'comment' => $comment ? $comment['comtext'] : ''
|
||||
]
|
||||
], 200);
|
||||
|
||||
@ -108,15 +108,38 @@
|
||||
<span x-text="getTestName(testId)"></span>
|
||||
</td>
|
||||
<template x-for="day in daysInMonth" :key="day">
|
||||
<td class="py-1 px-1" :class="isWeekend(day) ? 'bg-red-50' : ''">
|
||||
<td class="py-1 px-1 relative" :class="isWeekend(day) ? 'bg-red-50' : ''">
|
||||
<div class="flex items-center gap-1">
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
class="w-full px-2 py-1.5 text-center text-sm bg-white border border-slate-200 rounded focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500"
|
||||
:placeholder="'-'"
|
||||
x-model="monthlyData[testId + '_" + day + "']"
|
||||
x-model="monthlyData[testId + '_' + day]"
|
||||
@change="markDirty(testId, day)"
|
||||
>
|
||||
<button
|
||||
class="p-1 text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
|
||||
:title="monthlyData[testId + '_' + day + '_comment'] || 'Add comment'"
|
||||
@click.stop="toggleComment(testId, day)"
|
||||
>
|
||||
<i class="fa-solid fa-comment text-xs" :class="monthlyData[testId + '_' + day + '_comment'] ? 'text-blue-500' : ''"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
x-show="showCommentId === testId + '_' + day"
|
||||
x-transition
|
||||
class="absolute z-10 top-full left-0 mt-1 w-48"
|
||||
@click.outside="showCommentId = null"
|
||||
>
|
||||
<textarea
|
||||
class="w-full px-2 py-1.5 text-xs bg-white border border-slate-200 rounded shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 resize-none"
|
||||
rows="2"
|
||||
placeholder="Add comment..."
|
||||
x-model="monthlyData[testId + '_' + day + '_comment']"
|
||||
@keydown.enter.prevent
|
||||
></textarea>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
@ -191,6 +214,7 @@ document.addEventListener('alpine:init', () => {
|
||||
dirtyCells: new Set(),
|
||||
operation: 'replace',
|
||||
saveResult: null,
|
||||
showCommentId: null,
|
||||
|
||||
init() {
|
||||
this.loadDraft();
|
||||
@ -230,6 +254,15 @@ document.addEventListener('alpine:init', () => {
|
||||
this.dirtyCells.add(testId + '_' + day);
|
||||
},
|
||||
|
||||
toggleComment(testId, day) {
|
||||
const id = testId + '_' + day;
|
||||
if (this.showCommentId === id) {
|
||||
this.showCommentId = null;
|
||||
} else {
|
||||
this.showCommentId = id;
|
||||
}
|
||||
},
|
||||
|
||||
async loadControls() {
|
||||
this.errors = {};
|
||||
this.controls = [];
|
||||
@ -311,9 +344,13 @@ document.addEventListener('alpine:init', () => {
|
||||
const data = await response.json();
|
||||
if (data.status === 'success') {
|
||||
const formValues = data.data.formValues || {};
|
||||
const comments = data.data.comments || {};
|
||||
for (const [day, value] of Object.entries(formValues)) {
|
||||
this.monthlyData[testId + '_' + day] = value;
|
||||
}
|
||||
for (const [day, comment] of Object.entries(comments)) {
|
||||
this.monthlyData[testId + '_' + day + '_comment'] = comment;
|
||||
}
|
||||
if (!this.comment && data.data.comment) {
|
||||
this.comment = data.data.comment;
|
||||
}
|
||||
@ -354,17 +391,23 @@ document.addEventListener('alpine:init', () => {
|
||||
const tests = [];
|
||||
for (const testId of this.selectedTests) {
|
||||
const resvalue = {};
|
||||
const rescomment = {};
|
||||
let hasData = false;
|
||||
for (let day = 1; day <= this.daysInMonth; day++) {
|
||||
const key = testId + '_' + day;
|
||||
const value = this.monthlyData[key];
|
||||
const commentKey = testId + '_' + day + '_comment';
|
||||
const comment = this.monthlyData[commentKey];
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
resvalue[day] = value;
|
||||
hasData = true;
|
||||
}
|
||||
if (comment !== undefined && comment !== null && comment !== '') {
|
||||
rescomment[day] = comment;
|
||||
}
|
||||
}
|
||||
if (hasData) {
|
||||
tests.push({ testId, resvalue });
|
||||
tests.push({ testId, resvalue, rescomment });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user