fix(settings): fix variable slot dropdown and saving multi-variables

This commit is contained in:
2026-08-15 22:07:19 +03:30
parent 9fbaf3c7fe
commit 407a5124ac
+80 -32
View File
@@ -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,16 +102,18 @@
/>
</div>
<div class="flex-grow-1 flex align-items-center gap-2">
<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, variable.slot) || 'نام متغیر در sms.ir'"
:placeholder="getSlotDefaultName(template.key, variable.slot) || 'نام متغیر در sms.ir'"
autocomplete="off"
/>
<Tag
:value="`#${variable.name || getSlotDefaultName(template, variable.slot) || '...'}#`"
:value="`#${variable.name || getSlotDefaultName(template.key, variable.slot) || '...'}#`"
severity="secondary"
class="text-xs flex-shrink-0 font-mono"
/>
@@ -129,6 +131,7 @@
</div>
</div>
</div>
</div>
</template>
</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) => ({
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,
name: variable.name || ''
}))
: []
});
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, '')
}))
};
});