fix bug
This commit is contained in:
@@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<div class="partner-urls-field">
|
||||||
|
<div
|
||||||
|
v-for="(row, index) in rows"
|
||||||
|
:key="index"
|
||||||
|
class="partner-urls-field__row"
|
||||||
|
>
|
||||||
|
<span class="partner-urls-field__index">{{ index + 1 }}</span>
|
||||||
|
|
||||||
|
<a-input
|
||||||
|
:value="row.url"
|
||||||
|
:disabled="disabled"
|
||||||
|
allow-clear
|
||||||
|
dir="ltr"
|
||||||
|
class="partner-urls-field__url"
|
||||||
|
:placeholder="index === 0 ? 'آدرس اصلی، مثلاً https://price.zaarbox.ir/api/free' : 'آدرس جایگزین (اختیاری)'"
|
||||||
|
@update:value="(val) => updateRow(index, String(val ?? ''))"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
danger
|
||||||
|
:disabled="disabled || rows.length <= 1"
|
||||||
|
aria-label="حذف"
|
||||||
|
@click="removeRow(index)"
|
||||||
|
>
|
||||||
|
حذف
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-button
|
||||||
|
v-if="rows.length < MAX"
|
||||||
|
type="dashed"
|
||||||
|
block
|
||||||
|
:disabled="disabled"
|
||||||
|
class="partner-urls-field__add"
|
||||||
|
@click="addRow"
|
||||||
|
>
|
||||||
|
افزودن آدرس سرور
|
||||||
|
</a-button>
|
||||||
|
|
||||||
|
<p class="partner-urls-field__hint">
|
||||||
|
اگر آدرس اول پاسخ ندهد، بهترتیب سراغ آدرسهای بعدی میرود. حداکثر {{ MAX }} آدرس.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import {
|
||||||
|
formatPartnerServerUrls,
|
||||||
|
parsePartnerServerUrlsDraft,
|
||||||
|
PARTNER_SERVER_URLS_MAX,
|
||||||
|
type PartnerUrlRow,
|
||||||
|
} from './settingTypes'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
modelValue: string
|
||||||
|
disabled?: boolean
|
||||||
|
}>(),
|
||||||
|
{ disabled: false },
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits<{ 'update:value': [value: string] }>()
|
||||||
|
|
||||||
|
const MAX = PARTNER_SERVER_URLS_MAX
|
||||||
|
|
||||||
|
const rows = ref<PartnerUrlRow[]>(parsePartnerServerUrlsDraft(props.modelValue))
|
||||||
|
let skipExternalSync = false
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(value) => {
|
||||||
|
if (skipExternalSync) {
|
||||||
|
skipExternalSync = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows.value = parsePartnerServerUrlsDraft(value)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
function commit(nextRows: PartnerUrlRow[]) {
|
||||||
|
rows.value = nextRows
|
||||||
|
skipExternalSync = true
|
||||||
|
emit('update:value', formatPartnerServerUrls(nextRows))
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRow(index: number, url: string) {
|
||||||
|
const next = rows.value.map((row, i) => (i === index ? { ...row, url } : row))
|
||||||
|
commit(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRow() {
|
||||||
|
if (rows.value.length >= MAX) return
|
||||||
|
commit([...rows.value, { url: '' }])
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeRow(index: number) {
|
||||||
|
const next = rows.value.filter((_, i) => i !== index)
|
||||||
|
commit(next.length > 0 ? next : [{ url: '' }])
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.partner-urls-field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-urls-field__row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 24px 1fr auto;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-urls-field__index {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-urls-field__hint {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.partner-urls-field__row {
|
||||||
|
grid-template-columns: 20px 1fr auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -17,6 +17,13 @@
|
|||||||
@update:value="emit('update:value', $event)"
|
@update:value="emit('update:value', $event)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<PartnerServerUrlsField
|
||||||
|
v-else-if="isPartnerServerUrls"
|
||||||
|
:model-value="modelValue"
|
||||||
|
:disabled="disabled"
|
||||||
|
@update:value="emit('update:value', $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
<MainWalletProductsField
|
<MainWalletProductsField
|
||||||
v-else-if="isMainWalletProducts"
|
v-else-if="isMainWalletProducts"
|
||||||
:model-value="modelValue"
|
:model-value="modelValue"
|
||||||
@@ -116,6 +123,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import MainWalletProductsField from './MainWalletProductsField.vue'
|
import MainWalletProductsField from './MainWalletProductsField.vue'
|
||||||
|
import PartnerServerUrlsField from './PartnerServerUrlsField.vue'
|
||||||
import SupportMessengersField from './SupportMessengersField.vue'
|
import SupportMessengersField from './SupportMessengersField.vue'
|
||||||
import ZaarboxPriceKeyField from './ZaarboxPriceKeyField.vue'
|
import ZaarboxPriceKeyField from './ZaarboxPriceKeyField.vue'
|
||||||
import {
|
import {
|
||||||
@@ -154,6 +162,7 @@ const fieldType = computed<SettingFieldType>(() =>
|
|||||||
const isZaarboxPriceKey = computed(() => props.settingKey === 'zaarbox_price_key')
|
const isZaarboxPriceKey = computed(() => props.settingKey === 'zaarbox_price_key')
|
||||||
const isMainWalletProducts = computed(() => props.settingKey === 'main_wallet_products')
|
const isMainWalletProducts = computed(() => props.settingKey === 'main_wallet_products')
|
||||||
const isSupportMessengers = computed(() => props.settingKey === 'support_messengers')
|
const isSupportMessengers = computed(() => props.settingKey === 'support_messengers')
|
||||||
|
const isPartnerServerUrls = computed(() => props.settingKey === 'zaarbox_api_url')
|
||||||
|
|
||||||
const selectItems = computed(() =>
|
const selectItems = computed(() =>
|
||||||
parseSelectOptions({
|
parseSelectOptions({
|
||||||
|
|||||||
@@ -55,11 +55,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import {
|
import {
|
||||||
formatSupportMessengers,
|
formatSupportMessengers,
|
||||||
parseSelectOptions,
|
parseSelectOptions,
|
||||||
parseSupportMessengers,
|
parseSupportMessengersDraft,
|
||||||
supportMessengerIdPlaceholder,
|
supportMessengerIdPlaceholder,
|
||||||
type SupportMessengerEntryDraft,
|
type SupportMessengerEntryDraft,
|
||||||
} from './settingTypes'
|
} from './settingTypes'
|
||||||
@@ -74,26 +74,29 @@ const props = withDefaults(
|
|||||||
|
|
||||||
const emit = defineEmits<{ 'update:value': [value: string] }>()
|
const emit = defineEmits<{ 'update:value': [value: string] }>()
|
||||||
|
|
||||||
const messengerOptions = computed(() =>
|
const messengerOptions = parseSelectOptions({
|
||||||
parseSelectOptions({
|
key: 'support_messenger',
|
||||||
key: 'support_messenger',
|
description: 'bale,telegram,whatsapp,rubika,eitaa,soroush',
|
||||||
description: 'bale,telegram,whatsapp,rubika,eitaa,soroush',
|
type: 'select',
|
||||||
type: 'select',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const rows = computed<SupportMessengerEntryDraft[]>({
|
|
||||||
get() {
|
|
||||||
const parsed = parseSupportMessengers(props.modelValue)
|
|
||||||
if (parsed.length > 0) return parsed
|
|
||||||
return [{ messenger: 'bale', id: '' }]
|
|
||||||
},
|
|
||||||
set(nextRows) {
|
|
||||||
emit('update:value', formatSupportMessengers(nextRows))
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const rows = ref<SupportMessengerEntryDraft[]>(parseSupportMessengersDraft(props.modelValue))
|
||||||
|
let skipExternalSync = false
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(value) => {
|
||||||
|
if (skipExternalSync) {
|
||||||
|
skipExternalSync = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows.value = parseSupportMessengersDraft(value)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
function commit(nextRows: SupportMessengerEntryDraft[]) {
|
function commit(nextRows: SupportMessengerEntryDraft[]) {
|
||||||
|
rows.value = nextRows
|
||||||
|
skipExternalSync = true
|
||||||
emit('update:value', formatSupportMessengers(nextRows))
|
emit('update:value', formatSupportMessengers(nextRows))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,23 +60,36 @@ export function isSupportMessengerType(value: string | undefined | null): boolea
|
|||||||
return SUPPORT_MESSENGER_TYPES.includes(type as (typeof SUPPORT_MESSENGER_TYPES)[number])
|
return SUPPORT_MESSENGER_TYPES.includes(type as (typeof SUPPORT_MESSENGER_TYPES)[number])
|
||||||
}
|
}
|
||||||
|
|
||||||
/** پارس setting `support_messengers` — JSON یا legacy تکمورد */
|
/** پارس setting `support_messengers` — JSON یا legacy تکمورد (فقط موارد کامل) */
|
||||||
export function parseSupportMessengers(value: string | undefined | null): SupportMessengerEntryDraft[] {
|
export function parseSupportMessengers(value: string | undefined | null): SupportMessengerEntryDraft[] {
|
||||||
|
return parseSupportMessengersDraft(value).filter(
|
||||||
|
(row) => isSupportMessengerType(row.messenger) && row.id !== '',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** پارس برای UI — ردیفهای ناقص (بدون id) هم نگه داشته میشوند */
|
||||||
|
export function parseSupportMessengersDraft(
|
||||||
|
value: string | undefined | null,
|
||||||
|
): SupportMessengerEntryDraft[] {
|
||||||
const raw = (value ?? '').trim()
|
const raw = (value ?? '').trim()
|
||||||
if (!raw) return []
|
if (!raw) return [{ messenger: 'bale', id: '' }]
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decoded = JSON.parse(raw)
|
const decoded = JSON.parse(raw)
|
||||||
if (!Array.isArray(decoded)) return []
|
if (!Array.isArray(decoded) || decoded.length === 0) {
|
||||||
|
return [{ messenger: 'bale', id: '' }]
|
||||||
|
}
|
||||||
|
|
||||||
return decoded
|
const rows = decoded
|
||||||
.map((row) => ({
|
.map((row) => ({
|
||||||
messenger: String(row?.messenger ?? '').trim().toLowerCase(),
|
messenger: String(row?.messenger ?? '').trim().toLowerCase(),
|
||||||
id: String(row?.id ?? '').trim(),
|
id: String(row?.id ?? '').trim(),
|
||||||
}))
|
}))
|
||||||
.filter((row) => isSupportMessengerType(row.messenger) && row.id !== '')
|
.filter((row) => isSupportMessengerType(row.messenger))
|
||||||
|
|
||||||
|
return rows.length > 0 ? rows : [{ messenger: 'bale', id: '' }]
|
||||||
} catch {
|
} catch {
|
||||||
return []
|
return [{ messenger: 'bale', id: '' }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +105,47 @@ export function formatSupportMessengers(entries: SupportMessengerEntryDraft[]):
|
|||||||
return JSON.stringify(normalized, null, 0)
|
return JSON.stringify(normalized, null, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PartnerUrlRow = { url: string }
|
||||||
|
|
||||||
|
export const PARTNER_SERVER_URLS_MAX = 5
|
||||||
|
|
||||||
|
/** پارس setting `montzar_base_url` برای UI — JSON آرایه، یا مقدار تکی/legacy با کاما/خط جدید */
|
||||||
|
export function parsePartnerServerUrlsDraft(value: string | undefined | null): PartnerUrlRow[] {
|
||||||
|
const raw = (value ?? '').trim()
|
||||||
|
if (!raw) return [{ url: '' }]
|
||||||
|
|
||||||
|
let urls: string[] = []
|
||||||
|
try {
|
||||||
|
const decoded = JSON.parse(raw)
|
||||||
|
if (Array.isArray(decoded)) {
|
||||||
|
urls = decoded.map((item) =>
|
||||||
|
typeof item === 'string' ? item.trim() : String(item?.url ?? '').trim(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw new Error('not-array')
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
urls = raw.split(/[\r\n,]+/).map((part) => part.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
urls = urls.filter((u) => u !== '')
|
||||||
|
const rows = urls.slice(0, PARTNER_SERVER_URLS_MAX).map((url) => ({ url }))
|
||||||
|
return rows.length > 0 ? rows : [{ url: '' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** خروجی ذخیره: تکی → رشتهٔ ساده (سازگاری قبل)، چندتایی → JSON آرایه */
|
||||||
|
export function formatPartnerServerUrls(rows: PartnerUrlRow[]): string {
|
||||||
|
const urls = rows
|
||||||
|
.map((row) => (row.url ?? '').trim().replace(/\/+$/, ''))
|
||||||
|
.filter((url) => url !== '')
|
||||||
|
|
||||||
|
const unique = [...new Set(urls)].slice(0, PARTNER_SERVER_URLS_MAX)
|
||||||
|
|
||||||
|
if (unique.length === 0) return ''
|
||||||
|
if (unique.length === 1) return unique[0]
|
||||||
|
return JSON.stringify(unique, null, 0)
|
||||||
|
}
|
||||||
|
|
||||||
export function supportMessengerIdPlaceholder(messenger?: string): string {
|
export function supportMessengerIdPlaceholder(messenger?: string): string {
|
||||||
switch ((messenger ?? '').trim().toLowerCase()) {
|
switch ((messenger ?? '').trim().toLowerCase()) {
|
||||||
case 'whatsapp':
|
case 'whatsapp':
|
||||||
@@ -453,6 +507,8 @@ const KEY_HELP_FALLBACK: Record<string, string> = {
|
|||||||
'شناسه محصول مرجع در سرویس همکار قیمت.',
|
'شناسه محصول مرجع در سرویس همکار قیمت.',
|
||||||
montzar_base_url:
|
montzar_base_url:
|
||||||
'آدرس پایه سرور سرویس همکار (بدون اسلش انتهایی).',
|
'آدرس پایه سرور سرویس همکار (بدون اسلش انتهایی).',
|
||||||
|
zaarbox_api_url:
|
||||||
|
'آدرس سرور(های) فید قیمت (/api/free). تا ۵ آدرس میتوانید اضافه کنید؛ اگر آدرس اول پاسخ ندهد بهترتیب سراغ بعدی میرود. آدرس فعلی در ردیف اول حفظ میشود.',
|
||||||
montzar_open_buy:
|
montzar_open_buy:
|
||||||
'روشن: ثبت سفارش خرید از طریق قیمت همکار مجاز است (وضعیت واقعی از سرویس خارجی خوانده میشود).',
|
'روشن: ثبت سفارش خرید از طریق قیمت همکار مجاز است (وضعیت واقعی از سرویس خارجی خوانده میشود).',
|
||||||
montzar_open_sell:
|
montzar_open_sell:
|
||||||
|
|||||||
Reference in New Issue
Block a user