feat(settings): montzar_product_id as select from partner product API

Load products from /admin/montzar/products with searchable select UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-19 14:02:48 +03:30
co-authored by Cursor
parent 022796738d
commit 46c397804f
4 changed files with 118 additions and 1 deletions
+19
View File
@@ -44,3 +44,22 @@ export interface ZaarboxProductsResponse {
export const getZaarboxProducts = async () =>
await useAxios.get<ZaarboxProductsResponse>('/admin/zaarbox/products')
export interface MontzarProductOption {
id: string
name: string
price: number
buy: number
sell: number
}
export interface MontzarProductsResponse {
code: number
message: string
data: {
items: MontzarProductOption[]
}
}
export const getMontzarProducts = async () =>
await useAxios.get<MontzarProductsResponse>('/admin/montzar/products')
@@ -0,0 +1,89 @@
<template>
<a-select
:value="selectValue"
:disabled="disabled"
:loading="loading"
allow-clear
show-search
placeholder="انتخاب محصول همکار"
class="w-full"
option-filter-prop="label"
@update:value="onSelectChange"
>
<a-select-option
v-for="item in allOptions"
:key="item.id"
:value="item.id"
:label="`${item.name} ${item.id}`"
>
<div class="leading-snug">
<div>
{{ item.name }}
<span v-if="item.price > 0" class="text-gray-500">({{ formatPrice(item.price) }} ریال)</span>
<span v-else class="text-gray-400">(بدون قیمت)</span>
</div>
<div class="text-xs text-gray-400 direction-ltr text-right">#{{ item.id }}</div>
</div>
</a-select-option>
</a-select>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { getMontzarProducts, type MontzarProductOption } from '@/api/price'
const props = withDefaults(
defineProps<{
modelValue: string
disabled?: boolean
}>(),
{ disabled: false }
)
const emit = defineEmits<{ 'update:value': [value: string] }>()
const loading = ref(false)
const options = ref<MontzarProductOption[]>([])
const selectValue = computed(() => {
const current = String(props.modelValue ?? '').trim()
return current || undefined
})
const allOptions = computed(() => {
const current = String(props.modelValue ?? '').trim()
if (!current || options.value.some((item) => item.id === current)) {
return options.value
}
return [
{ id: current, name: `محصول #${current}`, price: 0, buy: 0, sell: 0 },
...options.value,
]
})
function formatPrice(value: number): string {
return value.toLocaleString('en-US')
}
onMounted(() => {
void loadOptions()
})
async function loadOptions() {
loading.value = true
try {
const response = await getMontzarProducts()
options.value = response?.data?.items ?? []
} catch (e) {
console.error(e)
options.value = []
} finally {
loading.value = false
}
}
function onSelectChange(val: string | undefined) {
emit('update:value', val ?? '')
}
</script>
@@ -36,6 +36,13 @@
@update:value="emit('update:value', $event)"
/>
<MontzarProductIdField
v-else-if="isMontzarProductId"
:model-value="modelValue"
:disabled="disabled"
@update:value="emit('update:value', $event)"
/>
<TemplateTextField
v-else-if="isTemplateField"
:model-value="modelValue"
@@ -128,6 +135,7 @@
</template>
<script setup lang="ts">
import MontzarProductIdField from './MontzarProductIdField.vue'
import MainWalletProductsField from './MainWalletProductsField.vue'
import PartnerServerUrlsField from './PartnerServerUrlsField.vue'
import SettingToggle from './SettingToggle.vue'
@@ -175,6 +183,7 @@ const fieldType = computed<SettingFieldType>(() =>
)
const isZaarboxPriceKey = computed(() => props.settingKey === 'zaarbox_price_key')
const isMontzarProductId = computed(() => props.settingKey === 'montzar_product_id')
const isMainWalletProducts = computed(() => props.settingKey === 'main_wallet_products')
const isSupportMessengers = computed(() => props.settingKey === 'support_messengers')
const isPartnerServerUrls = computed(() => props.settingKey === 'zaarbox_api_url')
@@ -713,7 +713,7 @@ const KEY_HELP_FALLBACK: Record<string, string> = {
montzar_password:
'رمز عبور حساب اتصال به سرویس همکار قیمت. محرمانه نگه دارید.',
montzar_product_id:
'شناسه محصول مرجع در سرویس همکار قیمت.',
'محصول مرجع آبشده در API همکار — از لیست محصولات همکار انتخاب کنید.',
montzar_base_url:
'آدرس پایه سرور سرویس همکار (بدون اسلش انتهایی).',
zaarbox_api_url: