fix(settings): fix variable slot dropdown and saving multi-variables
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
<div class="flex-grow-1">
|
||||
<h2 class="text-lg font-bold text-color m-0 mb-1">قالبهای پیامک</h2>
|
||||
<p class="text-sm text-muted m-0 line-height-3">
|
||||
شناسه قالب و تعداد و نام متغیرهای sms.ir را بر اساس قالب تعریف شده در پنل پیامک تنظیم کنید. میتوانید هر تعداد متغیر که میخواهید تعریف یا حذف نمایید.
|
||||
شناسه قالب و تعداد و نام متغیرهای sms.ir را بر اساس قالب پنل پیامک تنظیم کنید. میتوانید هر تعداد متغیر که میخواهید تعریف یا حذف نمایید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -77,7 +77,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!templateForm[template.key].variables || templateForm[template.key].variables.length === 0"
|
||||
v-if="!templateForm[template.key]?.variables || templateForm[template.key]?.variables.length === 0"
|
||||
class="p-3 text-center border-1 border-dashed border-round surface-card text-muted text-xs line-height-3"
|
||||
>
|
||||
هیچ متغیری برای این قالب تعریف نشده است. پیامک بدون متغیر ارسال خواهد شد.
|
||||
@@ -87,13 +87,13 @@
|
||||
<div
|
||||
v-for="(variable, vIdx) in templateForm[template.key].variables"
|
||||
:key="variable.id || vIdx"
|
||||
class="flex flex-column sm:flex-row sm:align-items-center gap-2 p-2 border-round surface-card border-1 border-color"
|
||||
class="flex flex-column md:flex-row md:align-items-center gap-3 p-3 border-round surface-card border-1 border-color"
|
||||
>
|
||||
<div class="flex align-items-center gap-2 sm:w-14rem flex-shrink-0">
|
||||
<span class="text-xs text-muted font-bold ml-1">{{ vIdx + 1 }}.</span>
|
||||
<div class="flex flex-column gap-1 md:w-16rem flex-shrink-0">
|
||||
<span class="text-xs text-muted font-semibold">مقدار ارسالی از سیستم:</span>
|
||||
<Select
|
||||
v-model="variable.slot"
|
||||
:options="template.availableSlots || []"
|
||||
:options="getAvailableSlots(template.key)"
|
||||
optionLabel="label"
|
||||
optionValue="slot"
|
||||
placeholder="انتخاب مقدار داده"
|
||||
@@ -102,29 +102,32 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex-grow-1 flex align-items-center gap-2">
|
||||
<InputText
|
||||
v-model.trim="variable.name"
|
||||
class="w-full text-sm"
|
||||
dir="ltr"
|
||||
:placeholder="getSlotDefaultName(template, variable.slot) || 'نام متغیر در sms.ir'"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<Tag
|
||||
:value="`#${variable.name || getSlotDefaultName(template, variable.slot) || '...'}#`"
|
||||
severity="secondary"
|
||||
class="text-xs flex-shrink-0 font-mono"
|
||||
/>
|
||||
<Button
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
class="p-button-sm flex-shrink-0"
|
||||
title="حذف متغیر"
|
||||
@click="removeVariable(template.key, vIdx)"
|
||||
/>
|
||||
<div class="flex-grow-1 flex flex-column gap-1">
|
||||
<span class="text-xs text-muted font-semibold">نام متغیر در sms.ir:</span>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<InputText
|
||||
v-model.trim="variable.name"
|
||||
class="w-full text-sm"
|
||||
dir="ltr"
|
||||
:placeholder="getSlotDefaultName(template.key, variable.slot) || 'نام متغیر در sms.ir'"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<Tag
|
||||
:value="`#${variable.name || getSlotDefaultName(template.key, variable.slot) || '...'}#`"
|
||||
severity="secondary"
|
||||
class="text-xs flex-shrink-0 font-mono"
|
||||
/>
|
||||
<Button
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
class="p-button-sm flex-shrink-0"
|
||||
title="حذف متغیر"
|
||||
@click="removeVariable(template.key, vIdx)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -278,6 +281,45 @@ const selectedFileName = ref('');
|
||||
const isImporting = ref(false);
|
||||
const importResult = ref(null);
|
||||
|
||||
const TEMPLATE_SLOT_DEFS = {
|
||||
accountCreated: [
|
||||
{ slot: 'username', label: 'نام کاربری', defaultName: 'user' },
|
||||
{ slot: 'password', label: 'رمز عبور', defaultName: 'password' },
|
||||
{ slot: 'fullName', label: 'نام و نام خانوادگی', defaultName: 'name' },
|
||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||
],
|
||||
classRegistered: [
|
||||
{ slot: 'className', label: 'نام کلاس', defaultName: 'className' },
|
||||
{ slot: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
||||
{ slot: 'fullName', label: 'نام کارآموز', defaultName: 'fullName' },
|
||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||
],
|
||||
classReminder: [
|
||||
{ slot: 'className', label: 'نام کلاس', defaultName: 'className' },
|
||||
{ slot: 'time', label: 'ساعت برگزاری', defaultName: 'time' },
|
||||
{ slot: 'place', label: 'مکان برگزاری', defaultName: 'place' },
|
||||
{ slot: 'courseName', label: 'نام دوره', defaultName: 'courseName' },
|
||||
{ slot: 'fullName', label: 'نام کاربر', defaultName: 'fullName' },
|
||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'mobile' }
|
||||
],
|
||||
invoiceCreated: [
|
||||
{ slot: 'amount', label: 'مبلغ صورتحساب (تومان)', defaultName: 'PAYMENT_PRICE' },
|
||||
{ slot: 'fullName', label: 'نام کارآموز', defaultName: 'FULLNAME' },
|
||||
{ slot: 'course', label: 'نام دوره / کلاس', defaultName: 'COURSE' },
|
||||
{ slot: 'phoneNumber', label: 'شماره همراه', defaultName: 'MOBILE' }
|
||||
]
|
||||
};
|
||||
|
||||
const getAvailableSlots = (templateKey) => {
|
||||
return TEMPLATE_SLOT_DEFS[templateKey] || [];
|
||||
};
|
||||
|
||||
const getSlotDefaultName = (templateKey, slotKey) => {
|
||||
const slots = getAvailableSlots(templateKey);
|
||||
const found = slots.find((s) => s.slot === slotKey);
|
||||
return found?.defaultName || '';
|
||||
};
|
||||
|
||||
const lockedAtLabel = computed(() => {
|
||||
if (!lockedAt.value) return '';
|
||||
const date = new Date(lockedAt.value);
|
||||
@@ -285,30 +327,24 @@ const lockedAtLabel = computed(() => {
|
||||
return `قفل شده در ${date.toLocaleString('fa-IR')}`;
|
||||
});
|
||||
|
||||
const getSlotDefaultName = (template, slotKey) => {
|
||||
const slot = (template?.availableSlots || []).find((s) => s.slot === slotKey);
|
||||
return slot?.defaultName || '';
|
||||
};
|
||||
|
||||
const onSlotChange = (templateKey, vIdx) => {
|
||||
const form = templateForm.value[templateKey];
|
||||
if (!form || !form.variables[vIdx]) return;
|
||||
const template = smsTemplates.value.find((t) => t.key === templateKey);
|
||||
const currentVar = form.variables[vIdx];
|
||||
if (!currentVar.name) {
|
||||
currentVar.name = getSlotDefaultName(template, currentVar.slot);
|
||||
const defaultName = getSlotDefaultName(templateKey, currentVar.slot);
|
||||
if (!currentVar.name || currentVar.name === 'param') {
|
||||
currentVar.name = defaultName;
|
||||
}
|
||||
};
|
||||
|
||||
const addVariable = (templateKey) => {
|
||||
const form = templateForm.value[templateKey];
|
||||
if (!form) return;
|
||||
const template = smsTemplates.value.find((t) => t.key === templateKey);
|
||||
const availableSlots = template?.availableSlots || [];
|
||||
const availableSlots = getAvailableSlots(templateKey);
|
||||
|
||||
const existingSlots = new Set((form.variables || []).map((v) => v.slot));
|
||||
const unusedSlot = availableSlots.find((s) => !existingSlots.has(s.slot));
|
||||
const selectedSlot = unusedSlot || availableSlots[0] || { slot: 'param', defaultName: 'param' };
|
||||
const selectedSlot = unusedSlot || availableSlots[0] || { slot: 'amount', defaultName: 'PAYMENT_PRICE' };
|
||||
|
||||
form.variables.push({
|
||||
id: `var_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
||||
@@ -408,16 +444,28 @@ const confirmImport = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const emptyFormEntry = (template) => ({
|
||||
templateId: template?.templateId || '',
|
||||
variables: Array.isArray(template?.variables)
|
||||
? template.variables.map((variable) => ({
|
||||
id: `var_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
||||
slot: variable.slot,
|
||||
name: variable.name || ''
|
||||
}))
|
||||
: []
|
||||
});
|
||||
const emptyFormEntry = (template) => {
|
||||
const slots = getAvailableSlots(template?.key);
|
||||
let vars = [];
|
||||
if (Array.isArray(template?.variables) && template.variables.length > 0) {
|
||||
vars = template.variables.map((variable) => ({
|
||||
id: `var_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
||||
slot: variable.slot || slots[0]?.slot || 'amount',
|
||||
name: variable.name || getSlotDefaultName(template?.key, variable.slot) || ''
|
||||
}));
|
||||
} else if (!template?.variables) {
|
||||
vars = slots.map((s) => ({
|
||||
id: `var_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
|
||||
slot: s.slot,
|
||||
name: s.defaultName
|
||||
}));
|
||||
}
|
||||
|
||||
return {
|
||||
templateId: template?.templateId || '',
|
||||
variables: vars
|
||||
};
|
||||
};
|
||||
|
||||
const applySmsTemplates = (payload) => {
|
||||
const data = payload?.data?.data || payload?.data || payload || {};
|
||||
@@ -449,12 +497,12 @@ const saveSmsTemplates = async () => {
|
||||
smsTemplates.value.forEach((template) => {
|
||||
const entry = templateForm.value[template.key] || emptyFormEntry(template);
|
||||
smsTemplatesPayload[template.key] = {
|
||||
templateId: entry.templateId || '',
|
||||
templateId: String(entry.templateId || '').trim(),
|
||||
variables: (entry.variables || [])
|
||||
.filter((v) => v.slot)
|
||||
.filter((v) => v.slot && String(v.name || '').trim())
|
||||
.map((v) => ({
|
||||
slot: v.slot,
|
||||
name: v.name || getSlotDefaultName(template, v.slot) || v.slot
|
||||
name: String(v.name).trim().replace(/^#+|#+$/g, '')
|
||||
}))
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user