mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-28 17:52:31 +07:00
continue dict test map done
This commit is contained in:
parent
44c9f29f09
commit
5817f74ace
@ -122,7 +122,6 @@ export const refTxtSchema = z.object({
|
|||||||
const start = toDays(data.AgeStart);
|
const start = toDays(data.AgeStart);
|
||||||
const end = toDays(data.AgeEnd);
|
const end = toDays(data.AgeEnd);
|
||||||
|
|
||||||
// if (start !== null && start > 0 && end !== null && end <= start) {
|
|
||||||
if (start !== null && end !== null && end <= start) {
|
if (start !== null && end !== null && end <= start) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
@ -136,6 +135,23 @@ export const testMapSchema = z.object({
|
|||||||
HostID: z.string().optional(),
|
HostID: z.string().optional(),
|
||||||
ClientID: z.string().optional(),
|
ClientID: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
.superRefine((data, ctx) => {
|
||||||
|
const hostID = data.HostID;
|
||||||
|
const clientID = data.ClientID;
|
||||||
|
|
||||||
|
if (hostID && clientID && hostID === clientID) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: "ClientID must be different from HostID",
|
||||||
|
path: ["ClientID"],
|
||||||
|
});
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: "HostID must be different from ClientID",
|
||||||
|
path: ["HostID"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export const testInitialForm = {
|
export const testInitialForm = {
|
||||||
TestSiteID: "",
|
TestSiteID: "",
|
||||||
@ -851,12 +867,14 @@ export const testMapFormFields = [
|
|||||||
label: "Host ID",
|
label: "Host ID",
|
||||||
required: false,
|
required: false,
|
||||||
type: "text",
|
type: "text",
|
||||||
|
validateOn: ["input"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "ClientID",
|
key: "ClientID",
|
||||||
label: "Client ID",
|
label: "Client ID",
|
||||||
required: false,
|
required: false,
|
||||||
type: "text",
|
type: "text",
|
||||||
|
validateOn: ["input"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -170,25 +170,100 @@
|
|||||||
return refTxtFormFields.map(group => ({
|
return refTxtFormFields.map(group => ({
|
||||||
...group,
|
...group,
|
||||||
rows: group.rows.map(row => ({
|
rows: group.rows.map(row => ({
|
||||||
...row,
|
...row,
|
||||||
columns: row.columns.map(col => {
|
columns: row.columns.map(col => {
|
||||||
if (col.key !== "RefTxt") return col;
|
if (col.key !== "RefTxt") return col;
|
||||||
|
|
||||||
|
if (formState.form.ResultType !== "VSET" || !formState.form.VSet) {
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
type: "textarea",
|
||||||
|
optionsEndpoint: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (formState.form.ResultType !== "VSET" || !formState.form.VSet) {
|
|
||||||
return {
|
return {
|
||||||
...col,
|
...col,
|
||||||
type: "textarea",
|
type: "select",
|
||||||
optionsEndpoint: undefined
|
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/${formState.form.VSet}`,
|
||||||
|
fullWidth: false
|
||||||
};
|
};
|
||||||
}
|
})
|
||||||
|
}))
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
const testMapFormFieldsTransformed = $derived.by(() => {
|
||||||
...col,
|
return testMapFormFields.map(group => ({
|
||||||
type: "select",
|
...group,
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/${formState.form.VSet}`,
|
rows: group.rows.map(row => ({
|
||||||
fullWidth: false
|
...row,
|
||||||
};
|
columns: row.columns.map(col => {
|
||||||
})
|
|
||||||
|
if (col.key === "HostID") {
|
||||||
|
if (mapFormState.form.HostType === "SITE") {
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
type: "select",
|
||||||
|
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
|
||||||
|
valueKey: "SiteID",
|
||||||
|
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (col.key === "ClientID") {
|
||||||
|
if (mapFormState.form.ClientType === "SITE") {
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
type: "select",
|
||||||
|
optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
|
||||||
|
valueKey: "SiteID",
|
||||||
|
labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (col.key === "HostTestCode" || col.key === "HostTestName") {
|
||||||
|
if (mapFormState.form.HostType === "SITE" && mapFormState.form.HostID) {
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
type: "select",
|
||||||
|
optionsEndpoint: `${API.BASE_URL}${API.TEST}?SiteID=${mapFormState.form.HostID}`,
|
||||||
|
valueKey: "TestSiteID",
|
||||||
|
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// kalau belum pilih HostID, kembalikan default (misal input biasa)
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
type: "text",
|
||||||
|
optionsEndpoint: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (col.key === "ClientTestCode" || col.key === "ClientTestName") {
|
||||||
|
if (mapFormState.form.ClientType === "SITE" && mapFormState.form.ClientID) {
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
type: "select",
|
||||||
|
optionsEndpoint: `${API.BASE_URL}${API.TEST}?SiteID=${mapFormState.form.ClientID}`,
|
||||||
|
valueKey: "TestSiteID",
|
||||||
|
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// kalau belum pilih HostID, kembalikan default (misal input biasa)
|
||||||
|
return {
|
||||||
|
...col,
|
||||||
|
type: "text",
|
||||||
|
optionsEndpoint: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return col;
|
||||||
|
})
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@ -343,7 +418,7 @@
|
|||||||
group
|
group
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
<Tabs.Content value="map">
|
<Tabs.Content value="map">
|
||||||
<Map {mapFormState} {testMapFormFields} bind:resetMap={resetMap}/>
|
<Map {mapFormState} testMapFormFields={testMapFormFieldsTransformed} bind:resetMap={resetMap}/>
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
<Tabs.Content value="reference">
|
<Tabs.Content value="reference">
|
||||||
<div class="w-full h-full flex items-start">
|
<div class="w-full h-full flex items-start">
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
import * as Table from "$lib/components/ui/table/index.js";
|
import * as Table from "$lib/components/ui/table/index.js";
|
||||||
import PencilIcon from "@lucide/svelte/icons/pencil";
|
import PencilIcon from "@lucide/svelte/icons/pencil";
|
||||||
import Trash2Icon from "@lucide/svelte/icons/trash-2";
|
import Trash2Icon from "@lucide/svelte/icons/trash-2";
|
||||||
|
import { untrack } from "svelte";
|
||||||
|
|
||||||
let { resetMap = $bindable(), ...props } = $props()
|
let { resetMap = $bindable(), ...props } = $props()
|
||||||
|
|
||||||
@ -15,6 +16,94 @@
|
|||||||
resetMap = () => {
|
resetMap = () => {
|
||||||
tempMap = [];
|
tempMap = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function snapshotForm() {
|
||||||
|
return untrack(() => {
|
||||||
|
const f = props.mapFormState.form;
|
||||||
|
const options = {};
|
||||||
|
for (const key in props.mapFormState.selectOptions) {
|
||||||
|
options[key] = [...props.mapFormState.selectOptions[key]];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
HostType: f.HostType ?? "",
|
||||||
|
HostID: f.HostID ?? "",
|
||||||
|
HostTestCode: f.HostTestCode ?? "",
|
||||||
|
HostTestName: f.HostTestName ?? "",
|
||||||
|
ClientType: f.ClientType ?? "",
|
||||||
|
ClientID: f.ClientID ?? "",
|
||||||
|
ClientTestCode: f.ClientTestCode ?? "",
|
||||||
|
ClientTestName: f.ClientTestName ?? "",
|
||||||
|
ConDefID: f.ConDefID ?? "",
|
||||||
|
options: options
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
props.mapFormState.reset?.();
|
||||||
|
editingId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInsert() {
|
||||||
|
const row = {
|
||||||
|
id: ++idCounter,
|
||||||
|
...snapshotForm()
|
||||||
|
};
|
||||||
|
|
||||||
|
tempMap = [...tempMap, row];
|
||||||
|
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleEdit(row) {
|
||||||
|
editingId = row.id;
|
||||||
|
|
||||||
|
untrack(() => {
|
||||||
|
const f = props.mapFormState.form;
|
||||||
|
console.log(row);
|
||||||
|
f.HostType = row.HostType;
|
||||||
|
f.HostID = row.HostID;
|
||||||
|
f.HostTestCode = row.HostTestCode;
|
||||||
|
f.HostTestName = row.HostTestName;
|
||||||
|
f.ClientType = row.ClientType;
|
||||||
|
f.ClientID = row.ClientID;
|
||||||
|
f.ClientTestCode = row.ClientTestCode;
|
||||||
|
f.ClientTestName = row.ClientTestName;
|
||||||
|
f.ConDefID = row.ConDefID;
|
||||||
|
|
||||||
|
if (row.options) {
|
||||||
|
for (const key in row.options) {
|
||||||
|
props.mapFormState.selectOptions[key] = row.options[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleUpdate() {
|
||||||
|
tempMap = tempMap.map((row) =>
|
||||||
|
row.id === editingId ? { id: row.id, ...snapshotForm() } : row
|
||||||
|
);
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancelEdit() {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemove(id) {
|
||||||
|
tempMap = tempMap.filter((row) => row.id !== id);
|
||||||
|
if (editingId === id) resetForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLabel(fieldKey, value, rowId) {
|
||||||
|
const row = tempMap.find(r => r.id === rowId);
|
||||||
|
if (row && row.options) {
|
||||||
|
const opts = row.options[fieldKey] ?? [];
|
||||||
|
const found = opts.find((o) => o.value == value);
|
||||||
|
return found ? found.label : value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col gap-4 w-full">
|
<div class="flex flex-col gap-4 w-full">
|
||||||
@ -25,14 +114,14 @@
|
|||||||
/>
|
/>
|
||||||
<div class="flex gap-2 mt-1 ms-2">
|
<div class="flex gap-2 mt-1 ms-2">
|
||||||
{#if editingId !== null}
|
{#if editingId !== null}
|
||||||
<Button size="sm" class="cursor-pointer">
|
<Button size="sm" class="cursor-pointer" onclick={handleUpdate}>
|
||||||
Update
|
Update
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="sm" variant="outline" class="cursor-pointer">
|
<Button size="sm" variant="outline" class="cursor-pointer" onclick={handleCancelEdit}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<Button size="sm" class="cursor-pointer">
|
<Button size="sm" class="cursor-pointer" onclick={handleInsert}>
|
||||||
Insert
|
Insert
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
@ -74,16 +163,17 @@
|
|||||||
<Table.Cell>{row.HostTestCode}</Table.Cell>
|
<Table.Cell>{row.HostTestCode}</Table.Cell>
|
||||||
<Table.Cell>{row.HostTestName}</Table.Cell>
|
<Table.Cell>{row.HostTestName}</Table.Cell>
|
||||||
<Table.Cell>{row.ClientType}</Table.Cell>
|
<Table.Cell>{row.ClientType}</Table.Cell>
|
||||||
<Table.Cell>{row.ClientID}</Table.Cell>
|
<Table.Cell>{row.ClientID ? getLabel("ClientID", row.ClientID, row.id) : "-"}</Table.Cell>
|
||||||
<Table.Cell>{row.ClientTestCode}</Table.Cell>
|
<Table.Cell>{row.ClientTestCode ? getLabel("ClientTestCode", row.ClientTestCode, row.id) : "-"}</Table.Cell>
|
||||||
<Table.Cell>{row.ClientTestName}</Table.Cell>
|
<Table.Cell>{row.ClientTestName ? getLabel("ClientTestName", row.ClientTestName, row.id) : "-"}</Table.Cell>
|
||||||
<Table.Cell>{row.ConDefID}</Table.Cell>
|
<Table.Cell>{row.ConDefID ? getLabel("ConDefID", row.ConDefID, row.id) : "-"}</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
class="h-7 w-7 cursor-pointer"
|
class="h-7 w-7 cursor-pointer"
|
||||||
|
onclick={() => handleEdit(row)}
|
||||||
>
|
>
|
||||||
<PencilIcon class="h-3.5 w-3.5" />
|
<PencilIcon class="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
@ -91,6 +181,7 @@
|
|||||||
size="icon"
|
size="icon"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
class="h-7 w-7 cursor-pointer"
|
class="h-7 w-7 cursor-pointer"
|
||||||
|
onclick={() => handleRemove(row.id)}
|
||||||
>
|
>
|
||||||
<Trash2Icon class="h-3.5 w-3.5" />
|
<Trash2Icon class="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -67,11 +67,6 @@
|
|||||||
formState.form[field.key] = field.defaultValue;
|
formState.form[field.key] = field.defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// function hasExactKeyword(input, keyword) {
|
|
||||||
// const regex = new RegExp(`\\b${keyword}\\b`, 'i');
|
|
||||||
// return regex.test(input);
|
|
||||||
// }
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet Fieldset({ key, label, required, type, optionsEndpoint, options, validateOn, dependsOn, endpointParamKey, valueKey, labelKey, txtKey })}
|
{#snippet Fieldset({ key, label, required, type, optionsEndpoint, options, validateOn, dependsOn, endpointParamKey, valueKey, labelKey, txtKey })}
|
||||||
@ -81,9 +76,6 @@
|
|||||||
{#if required}
|
{#if required}
|
||||||
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- {#if required || dynamicRequiredFields.includes(key)}
|
|
||||||
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
|
||||||
{/if} -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative flex flex-col items-center w-full">
|
<div class="relative flex flex-col items-center w-full">
|
||||||
@ -177,6 +169,32 @@
|
|||||||
if (key === "RefType") {
|
if (key === "RefType") {
|
||||||
handleRefTypeChange(val);
|
handleRefTypeChange(val);
|
||||||
}
|
}
|
||||||
|
if (key === "HostType") {
|
||||||
|
formState.form.HostID = "";
|
||||||
|
formState.form.HostTestCode = "";
|
||||||
|
formState.form.HostTestName = "";
|
||||||
|
formState.selectOptions.HostTestCode = [];
|
||||||
|
formState.selectOptions.HostTestName = [];
|
||||||
|
}
|
||||||
|
if (key === "HostID") {
|
||||||
|
formState.form.HostTestCode = "";
|
||||||
|
formState.form.HostTestName = "";
|
||||||
|
formState.selectOptions.HostTestCode = [];
|
||||||
|
formState.selectOptions.HostTestName = [];
|
||||||
|
}
|
||||||
|
if (key === "ClientType") {
|
||||||
|
formState.form.ClientID = "";
|
||||||
|
formState.form.ClientTestCode = "";
|
||||||
|
formState.form.ClientTestName = "";
|
||||||
|
formState.selectOptions.ClientTestCode = [];
|
||||||
|
formState.selectOptions.ClientTestName = [];
|
||||||
|
}
|
||||||
|
if (key === "ClientID") {
|
||||||
|
formState.form.ClientTestCode = "";
|
||||||
|
formState.form.ClientTestName = "";
|
||||||
|
formState.selectOptions.ClientTestCode = [];
|
||||||
|
formState.selectOptions.ClientTestName = [];
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
if (open && optionsEndpoint) {
|
if (open && optionsEndpoint) {
|
||||||
@ -305,7 +323,6 @@
|
|||||||
<InputGroup.Input type="number" bind:value={joinFields[key].YY}
|
<InputGroup.Input type="number" bind:value={joinFields[key].YY}
|
||||||
oninput={() => {
|
oninput={() => {
|
||||||
if (validateOn?.includes("input")) {
|
if (validateOn?.includes("input")) {
|
||||||
console.log('object');
|
|
||||||
// formState.validateField(key, formState.form[key], false);
|
// formState.validateField(key, formState.form[key], false);
|
||||||
formState.validateField("AgeStart");
|
formState.validateField("AgeStart");
|
||||||
formState.validateField("AgeEnd");
|
formState.validateField("AgeEnd");
|
||||||
@ -357,19 +374,10 @@
|
|||||||
key === 'FormulaCode' ? 'top-20' : 'top-8'
|
key === 'FormulaCode' ? 'top-20' : 'top-8'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<!-- {#if formState.errors[key] || dynamicRequiredFields.includes(key)}
|
|
||||||
<span class="text-destructive text-sm leading-none">
|
|
||||||
{formState.errors[key]}
|
|
||||||
</span>
|
|
||||||
{/if} -->
|
|
||||||
{#if formState.errors[key] || formState.errors[txtKey]}
|
{#if formState.errors[key] || formState.errors[txtKey]}
|
||||||
<span class="text-destructive text-sm leading-none">
|
<span class="text-destructive text-sm leading-none">
|
||||||
{formState.errors[key] ?? formState.errors[txtKey]}
|
{formState.errors[key] ?? formState.errors[txtKey]}
|
||||||
</span>
|
</span>
|
||||||
<!-- {:else if dynamicRequiredFields.includes(key)}
|
|
||||||
<span class="text-destructive text-sm leading-none">
|
|
||||||
Required
|
|
||||||
</span> -->
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -420,42 +428,4 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="p-2 space-y-6">
|
|
||||||
{#each formFields as group}
|
|
||||||
<div class="space-y-6">
|
|
||||||
{#if group.title}
|
|
||||||
<div class="text-md 2xl:text-lg font-semibold italic">
|
|
||||||
<span class="border-b-2 border-primary">{group.title}</span>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#each group.rows as row}
|
|
||||||
<div
|
|
||||||
class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
|
|
||||||
class:md:grid-cols-1={row.columns.length === 1 && row.columns[0].fullWidth !== false}
|
|
||||||
class:md:grid-cols-2={row.columns.length === 2 || (row.columns.length === 1 && row.columns[0].fullWidth === false)}
|
|
||||||
class:md:grid-cols-3={row.columns.length === 3}
|
|
||||||
>
|
|
||||||
{#each row.columns as col}
|
|
||||||
{#if col.type === "group"}
|
|
||||||
<div
|
|
||||||
class="grid grid-cols-1 gap-6 md:gap-2"
|
|
||||||
class:md:grid-cols-1={col.columns.length === 1 && col.columns[0].fullWidth !== false}
|
|
||||||
class:md:grid-cols-2={col.columns.length === 2 || (col.columns.length === 1 && col.columns[0].fullWidth === false)}
|
|
||||||
class:md:grid-cols-3={col.columns.length === 3}
|
|
||||||
>
|
|
||||||
{#each col.columns as child}
|
|
||||||
{@render Fieldset(child)}
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
{@render Fieldset(col)}
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div> -->
|
|
||||||
Loading…
x
Reference in New Issue
Block a user