fixed price

This commit is contained in:
2026-06-28 21:48:48 +03:30
parent 0c36917735
commit 809bd69068
12 changed files with 377 additions and 57 deletions
@@ -1,6 +1,14 @@
<template>
<div>
<DatePicker :locale="locale" v-model:value="_date" :size="props.size" v-bind="_attrs" inputReadOnly/>
<div ref="rootRef" @click="onWrapperClick">
<DatePicker
:locale="locale"
v-model:value="_date"
:size="props.size"
v-bind="_attrs"
:open="open"
inputReadOnly
@openChange="onOpenChange"
/>
</div>
</template>
@@ -9,7 +17,7 @@ import DatePicker from './datePick'
import locale from 'ant-design-vue/es/date-picker/locale/fa_IR'
import dayjs, { Dayjs } from 'dayjs'
import { omit } from 'lodash'
import { computed, useAttrs } from 'vue'
import { computed, onBeforeUnmount, onMounted, ref, useAttrs } from 'vue'
interface Props {
value?: string | Dayjs
@@ -34,12 +42,71 @@ const emit = defineEmits<{
(e: 'onchange', val: string | null): void,
}>()
// روی iOS باز کردن تقویم از mousedown/mouseup داخلی پیکر قابل اتکا نیست.
// وضعیت باز/بسته کنترل‌شده است؛ بعد از بستن، iOS اغلب یک click/mouseup
// دیررس ارسال می‌کند که دوباره open=true می‌زند — با suppressOpen موقتاً
// نادیده گرفته می‌شود.
const open = ref(false)
const rootRef = ref<HTMLElement | null>(null)
const suppressOpen = ref(false)
let suppressOpenTimer: ReturnType<typeof setTimeout> | undefined
function isInsidePicker(target: EventTarget | null): boolean {
if (!(target instanceof Element)) return false
if (rootRef.value?.contains(target)) return true
return !!target.closest('.ant-picker-dropdown')
}
function closePicker() {
if (!open.value) return
open.value = false
armSuppressOpen()
}
function handleOutsidePointer(event: Event) {
if (!open.value) return
const target =
event instanceof TouchEvent
? event.touches[0]?.target ?? event.target
: event.target
if (isInsidePicker(target)) return
closePicker()
}
function armSuppressOpen(ms = 400) {
suppressOpen.value = true
if (suppressOpenTimer) clearTimeout(suppressOpenTimer)
suppressOpenTimer = setTimeout(() => {
suppressOpen.value = false
}, ms)
}
const onOpenChange = (val: boolean) => {
if (val && suppressOpen.value) return
open.value = val
if (!val) armSuppressOpen()
}
const onWrapperClick = (e: MouseEvent) => {
if (suppressOpen.value) return
const target = e.target as HTMLElement
if (target.closest('.ant-picker-clear')) return
if (target.closest('.ant-picker-dropdown')) return
if (open.value) {
closePicker()
return
}
open.value = true
}
const _date = computed({
set: (val) => {
let temp: string | null = null
if (val) {
temp = val.calendar('gregory').locale('en').format(props.format)
}
open.value = false
armSuppressOpen()
emit('update:value', temp)
emit('onchange', temp)
},
@@ -49,6 +116,18 @@ const _date = computed({
}
}
})
onMounted(() => {
// mousedown داخلی پیکر روی iOS/touch قابل اتکا نیست — pointerdown/touchstart بیرون را می‌گیریم
document.addEventListener('pointerdown', handleOutsidePointer, true)
document.addEventListener('touchstart', handleOutsidePointer, true)
})
onBeforeUnmount(() => {
document.removeEventListener('pointerdown', handleOutsidePointer, true)
document.removeEventListener('touchstart', handleOutsidePointer, true)
if (suppressOpenTimer) clearTimeout(suppressOpenTimer)
})
</script>
<style lang="less"></style>