Product Conversion
This commit is contained in:
Vendored
+1
-1
@@ -14,7 +14,6 @@ declare module 'vue' {
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
AImage: typeof import('ant-design-vue/es')['Image']
|
||||
AInput: typeof import('ant-design-vue/es')['Input']
|
||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
AppCreditLink: typeof import('./src/components/AppCreditLink.vue')['default']
|
||||
@@ -45,6 +44,7 @@ declare module 'vue' {
|
||||
BasicToggleTwoItem: typeof import('./src/components/BasicPacks/BasicToggleTwoItem.vue')['default']
|
||||
Bg_main: typeof import('./src/components/bg_main.vue')['default']
|
||||
Bordered: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/bordered.vue')['default']
|
||||
CopperConvertModal: typeof import('./src/components/CopperConvertModal.vue')['default']
|
||||
DateRender: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/date-render.vue')['default']
|
||||
Demo: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/index.vue')['default']
|
||||
DialogVant: typeof import('./src/components/DialogVant.vue')['default']
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
/>
|
||||
|
||||
<GoldDayCalculatorModal />
|
||||
<CopperConvertModal />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -132,6 +133,7 @@ import { usePwaInstall } from '@/composables/usePwaInstall'
|
||||
import PwaInstallBanner from '@/components/pwa/PwaInstallBanner.vue'
|
||||
import PwaInstallGuideModal from '@/components/pwa/PwaInstallGuideModal.vue'
|
||||
import GoldDayCalculatorModal from '@/components/GoldDayCalculatorModal.vue'
|
||||
import CopperConvertModal from '@/components/CopperConvertModal.vue'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
@import (less) '../../views/base/fund/desktop/styles/desktop-fund.less';
|
||||
@import (less) '../../views/base/gold/desktop/styles/desktop-gold.less';
|
||||
@import (less) './mobile-keyboard-scroll.less';
|
||||
@import (less) '../../styles/app-premium-modal.less';
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
|
||||
@@ -13,10 +13,13 @@
|
||||
:width="props.width"
|
||||
:ok-text="props.okText"
|
||||
:cancel-text="props.cancelText"
|
||||
:wrapClassName="props.wrapClassName"
|
||||
:wrapClassName="mergedWrapClassName"
|
||||
:closable="props.closable"
|
||||
:destroy-on-close="props.destroyOnClose"
|
||||
>
|
||||
<template v-if="$slots.title" #title>
|
||||
<slot name="title" />
|
||||
</template>
|
||||
<template v-if="props.customFooter" #footer> <slot name="footer" /></template>
|
||||
<a-spin :spinning="props.loading">
|
||||
<div class="overflow-y-auto py-2 px-1 relative max-h-[83vh]" id="body">
|
||||
@@ -60,6 +63,11 @@ const props = withDefaults(defineProps<Prop>(), {
|
||||
zIndex: APP_Z_MODAL,
|
||||
})
|
||||
|
||||
const mergedWrapClassName = computed(() => {
|
||||
const extra = (props.wrapClassName ?? '').trim()
|
||||
return extra ? `app-premium-modal ${extra}` : 'app-premium-modal'
|
||||
})
|
||||
|
||||
const localValue = computed({
|
||||
get() {
|
||||
return props.visible
|
||||
@@ -67,13 +75,6 @@ const localValue = computed({
|
||||
|
||||
set(value) {
|
||||
emits('update:visible', value)
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ant-modal-content {
|
||||
border-radius: 0.6rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<BasicModal
|
||||
v-model:visible="visible"
|
||||
width="460px"
|
||||
destroy-on-close
|
||||
custom-footer
|
||||
title="تبدیل محصول"
|
||||
wrap-class-name="app-premium-modal--scroll-tall"
|
||||
@close="closeCopperConvert"
|
||||
>
|
||||
<CopperConvertCalculator />
|
||||
|
||||
<template #footer>
|
||||
<BasicButton
|
||||
type="primary"
|
||||
class="app-premium-modal__btn-primary !w-full"
|
||||
size="middle"
|
||||
@click="closeCopperConvert"
|
||||
>
|
||||
بستن
|
||||
</BasicButton>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch } from 'vue'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import CopperConvertCalculator from '@/views/base/convert/components/CopperConvertCalculator.vue'
|
||||
import {
|
||||
closeCopperConvert,
|
||||
copperConvertModalVisible,
|
||||
} from '@/composables/useCopperConvertModal'
|
||||
import { useCopperConvertPage } from '@/views/base/convert/composables/useCopperConvertPage'
|
||||
|
||||
const visible = copperConvertModalVisible
|
||||
const { refreshLivePrices, stopLivePrices } = useCopperConvertPage()
|
||||
|
||||
watch(visible, async (open) => {
|
||||
if (open) {
|
||||
await refreshLivePrices()
|
||||
} else {
|
||||
stopLivePrices()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -4,11 +4,11 @@
|
||||
width="400px"
|
||||
destroy-on-close
|
||||
custom-footer
|
||||
wrap-class-name="gold-day-calc-modal"
|
||||
wrap-class-name="app-premium-modal--scroll-tall"
|
||||
>
|
||||
<template #title>
|
||||
<div class="gold-day-calc-modal__title">
|
||||
<BasicIcon icon="vuesax-linear:calculator" size="20" class="gold-day-calc-modal__title-icon" />
|
||||
<div class="app-premium-modal__title">
|
||||
<BasicIcon icon="vuesax-linear:calculator" size="20" class="app-premium-modal__title-icon" />
|
||||
<span>ماشین حساب</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<BasicButton type="primary" class="!w-full" size="middle" @click="recalculate">
|
||||
<BasicButton type="primary" class="app-premium-modal__btn-primary !w-full" size="middle" @click="recalculate">
|
||||
محاسبه مجدد
|
||||
</BasicButton>
|
||||
</template>
|
||||
@@ -219,99 +219,3 @@ watch(visible, async (open) => {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.gold-day-calc-modal {
|
||||
.ant-modal-content {
|
||||
direction: rtl;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: min(88dvh, 640px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ant-modal-header {
|
||||
flex-shrink: 0;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
padding-left: 2.75rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.ant-modal-title {
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gold-day-calc-modal__title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.5rem;
|
||||
direction: rtl;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gold-day-calc-modal__title-icon {
|
||||
flex-shrink: 0;
|
||||
color: var(--App-secondary-color, #c9a062);
|
||||
}
|
||||
|
||||
.ant-modal-close {
|
||||
inset-inline-start: 0 !important;
|
||||
inset-inline-end: auto !important;
|
||||
right: auto !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
padding-bottom: 0.25rem;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
#body {
|
||||
max-height: min(48dvh, 360px) !important;
|
||||
overflow-y: auto !important;
|
||||
overscroll-behavior: contain;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.ant-modal-footer {
|
||||
flex-shrink: 0;
|
||||
margin-top: 0;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid rgba(148, 163, 184, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767.98px) {
|
||||
.gold-day-calc-modal {
|
||||
.ant-modal {
|
||||
max-width: calc(100vw - 1.5rem);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.ant-modal-content {
|
||||
max-height: min(86dvh, 100%);
|
||||
}
|
||||
|
||||
#body {
|
||||
max-height: min(42dvh, 280px) !important;
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
.gold-day-calc-modal #body {
|
||||
max-height: min(38dvh, 240px) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const copperConvertModalVisible = ref(false)
|
||||
|
||||
export function openCopperConvert() {
|
||||
copperConvertModalVisible.value = true
|
||||
}
|
||||
|
||||
export function closeCopperConvert() {
|
||||
copperConvertModalVisible.value = false
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/** تم یکسان مدالهای boursecu user — لوکس / پریمیوم */
|
||||
|
||||
.app-premium-modal.ant-modal-wrap {
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.app-premium-modal {
|
||||
.ant-modal-content {
|
||||
direction: rtl;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: min(92dvh, 720px);
|
||||
overflow: hidden;
|
||||
padding: 0 !important;
|
||||
border-radius: 1.125rem;
|
||||
border: 1px solid rgba(201, 160, 98, 0.35);
|
||||
box-shadow:
|
||||
0 24px 48px rgba(15, 39, 68, 0.28),
|
||||
0 0 0 1px rgba(255, 255, 255, 0.04) inset;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ant-modal-header {
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin: 0;
|
||||
min-height: 3.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0.875rem 1rem 0.875rem 3rem;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
background: linear-gradient(180deg, #faf8f5 0%, #fff 100%);
|
||||
border-bottom: 1px solid rgba(201, 160, 98, 0.2);
|
||||
border-radius: 1.125rem 1.125rem 0 0;
|
||||
}
|
||||
|
||||
.ant-modal-title {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.45;
|
||||
text-align: right;
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 800;
|
||||
color: #0f2744;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.app-premium-modal__title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.5rem;
|
||||
direction: rtl;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.app-premium-modal__title-icon {
|
||||
flex-shrink: 0;
|
||||
color: var(--App-secondary-color, #c9a062);
|
||||
}
|
||||
|
||||
.ant-modal-close {
|
||||
position: absolute;
|
||||
inset-inline-start: 0.75rem !important;
|
||||
inset-inline-end: auto !important;
|
||||
left: 0.75rem !important;
|
||||
right: auto !important;
|
||||
top: 0.875rem !important;
|
||||
margin: 0;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 999px;
|
||||
background: rgba(15, 39, 68, 0.06);
|
||||
color: #0f2744;
|
||||
transition: background 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2;
|
||||
|
||||
&:hover {
|
||||
background: rgba(15, 39, 68, 0.1);
|
||||
}
|
||||
|
||||
.ant-modal-close-x {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 1;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
padding: 0.75rem 1.125rem 0.5rem;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#body {
|
||||
max-height: min(56dvh, 440px);
|
||||
overflow-y: auto !important;
|
||||
overscroll-behavior: contain;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 0.35rem 0.125rem 0.5rem !important;
|
||||
}
|
||||
|
||||
.ant-modal-footer {
|
||||
flex-shrink: 0;
|
||||
margin: 0;
|
||||
padding: 0.75rem 1.125rem 1rem;
|
||||
border-top: 1px solid rgba(15, 39, 68, 0.08);
|
||||
background: #faf8f5;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.ant-modal-footer .ant-btn {
|
||||
min-height: 2.5rem;
|
||||
border-radius: 0.75rem !important;
|
||||
font-weight: 700;
|
||||
padding-inline: 1.25rem;
|
||||
}
|
||||
|
||||
.ant-modal-footer .ant-btn-primary,
|
||||
.app-premium-modal__btn-primary {
|
||||
border: none !important;
|
||||
background: linear-gradient(135deg, #0f2744 0%, #1a365d 55%, #234876 100%) !important;
|
||||
box-shadow: 0 8px 20px rgba(15, 39, 68, 0.22);
|
||||
}
|
||||
|
||||
.ant-modal-footer .ant-btn-default {
|
||||
border-color: rgba(15, 39, 68, 0.15) !important;
|
||||
color: #0f2744 !important;
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
&.app-premium-modal--no-header {
|
||||
.ant-modal-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-modal-close {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.app-premium-modal--scroll-tall #body {
|
||||
max-height: min(58dvh, 480px) !important;
|
||||
}
|
||||
|
||||
&.app-premium-modal--fluid-body #body {
|
||||
max-height: none !important;
|
||||
overflow: visible !important;
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0.25rem !important;
|
||||
}
|
||||
|
||||
&.app-premium-modal--wide-panel {
|
||||
.ant-modal-body {
|
||||
padding-inline: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
#body {
|
||||
max-height: calc(100dvh - 12rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767.98px) {
|
||||
.app-premium-modal {
|
||||
.ant-modal {
|
||||
max-width: calc(100vw - 1rem);
|
||||
margin: 0 auto;
|
||||
top: 1.5vh;
|
||||
}
|
||||
|
||||
&.app-premium-modal--scroll-tall #body {
|
||||
max-height: min(52dvh, 420px) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/** فرمول تبدیل کارفرما — اکسل «تبدیل کاتد و مفتول به سیم ۱.۵–۲.۵» */
|
||||
|
||||
export type CopperConvertSource = 'katod' | 'maftoul' | 'shamsh'
|
||||
|
||||
export interface CopperConvertPrices {
|
||||
katodPerKg: number
|
||||
maftoulPerKg: number
|
||||
shamshPerKg: number
|
||||
/** قیمت هر حلقه سیم ۱.۵ (ریال) */
|
||||
wireRing15: number
|
||||
/** قیمت هر حلقه سیم ۲.۵ (ریال) */
|
||||
wireRing25: number
|
||||
/** وزن هر حلقه ۱.۵ — گرم (ستون اکسل) */
|
||||
wireWeightGrams15: number
|
||||
/** وزن هر حلقه ۲.۵ — گرم؛ اگر صفر باشد فقط محاسبه ارزشی */
|
||||
wireWeightGrams25: number
|
||||
}
|
||||
|
||||
export interface CopperConvertResult {
|
||||
totalValueRial: number
|
||||
equivalentMaftoulKg: number
|
||||
/** ارزش ÷ قیمت حلقه (شیت مفتول→سیم) */
|
||||
rings15ByValue: number
|
||||
rings25ByValue: number
|
||||
/** مفتول معادل ÷ وزن حلقه */
|
||||
rings15ByWeight: number | null
|
||||
rings25ByWeight: number | null
|
||||
}
|
||||
|
||||
/** مقادیر نمونه اکسل — وقتی محصول سیم در لیست نیست */
|
||||
export const COPPER_CONVERT_WIRE_FALLBACK = {
|
||||
wireRing15: 36_000_000,
|
||||
wireRing25: 38_000_000,
|
||||
wireWeightGrams15: 2777,
|
||||
wireWeightGrams25: 0,
|
||||
} as const
|
||||
|
||||
function sourcePricePerKg(source: CopperConvertSource, prices: CopperConvertPrices): number {
|
||||
if (source === 'katod') return prices.katodPerKg
|
||||
if (source === 'maftoul') return prices.maftoulPerKg
|
||||
return prices.shamshPerKg
|
||||
}
|
||||
|
||||
function ringsByWeight(maftoulKg: number, gramsPerRing: number): number | null {
|
||||
if (maftoulKg <= 0 || gramsPerRing <= 0) return null
|
||||
return (maftoulKg * 1000) / gramsPerRing
|
||||
}
|
||||
|
||||
export function calcCopperWireConvert(
|
||||
inputKg: number,
|
||||
source: CopperConvertSource,
|
||||
prices: CopperConvertPrices,
|
||||
): CopperConvertResult | null {
|
||||
if (!Number.isFinite(inputKg) || inputKg <= 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const perKg = sourcePricePerKg(source, prices)
|
||||
if (perKg <= 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const totalValueRial = inputKg * perKg
|
||||
const equivalentMaftoulKg =
|
||||
prices.maftoulPerKg > 0 ? totalValueRial / prices.maftoulPerKg : 0
|
||||
|
||||
const rings15ByValue = prices.wireRing15 > 0 ? totalValueRial / prices.wireRing15 : 0
|
||||
const rings25ByValue = prices.wireRing25 > 0 ? totalValueRial / prices.wireRing25 : 0
|
||||
|
||||
return {
|
||||
totalValueRial,
|
||||
equivalentMaftoulKg,
|
||||
rings15ByValue,
|
||||
rings25ByValue,
|
||||
rings15ByWeight: ringsByWeight(equivalentMaftoulKg, prices.wireWeightGrams15),
|
||||
rings25ByWeight: ringsByWeight(equivalentMaftoulKg, prices.wireWeightGrams25),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
<template>
|
||||
<div class="copper-convert" dir="rtl">
|
||||
<p class="copper-convert__lead">
|
||||
وزن دارایی را وارد کنید؛ معادل مفتول و تعداد حلقه سیم ۱.۵ و ۲.۵ با قیمت روز محاسبه میشود.
|
||||
</p>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<section class="copper-convert__panel" aria-label="قیمتهای مبنا">
|
||||
<div class="copper-convert__panel-head">
|
||||
<span class="copper-convert__panel-kicker">قیمت لحظهای</span>
|
||||
<span class="copper-convert__panel-title">مبنای محاسبه</span>
|
||||
</div>
|
||||
|
||||
<div class="copper-convert__price-group">
|
||||
<span class="copper-convert__group-label">مواد اولیه (هر کیلوگرم)</span>
|
||||
<ul class="copper-convert__price-grid m-0 p-0 list-none">
|
||||
<li
|
||||
v-for="row in metalPriceRows"
|
||||
:key="row.label"
|
||||
class="copper-convert__chip"
|
||||
:class="{ 'copper-convert__chip--muted': row.missing }"
|
||||
>
|
||||
<span class="copper-convert__chip-label">{{ row.label }}</span>
|
||||
<span class="copper-convert__chip-value" dir="ltr">{{ row.value }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="copper-convert__price-group copper-convert__price-group--wire">
|
||||
<span class="copper-convert__group-label">سیم (هر حلقه)</span>
|
||||
<ul class="copper-convert__price-grid copper-convert__price-grid--wire m-0 p-0 list-none">
|
||||
<li
|
||||
v-for="row in wirePriceRows"
|
||||
:key="row.label"
|
||||
class="copper-convert__chip copper-convert__chip--accent"
|
||||
>
|
||||
<span class="copper-convert__chip-label">{{ row.label }}</span>
|
||||
<span class="copper-convert__chip-value" dir="ltr">{{ row.value }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="copper-convert__form">
|
||||
<label class="copper-convert__field-label">نوع دارایی</label>
|
||||
<div class="copper-convert__pills" role="tablist">
|
||||
<button
|
||||
v-for="opt in sourceOptions"
|
||||
:key="opt.value"
|
||||
type="button"
|
||||
role="tab"
|
||||
class="copper-convert__pill"
|
||||
:class="{ 'copper-convert__pill--active': source === opt.value }"
|
||||
:aria-selected="source === opt.value"
|
||||
@click="source = opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="copper-convert__weight">
|
||||
<label class="copper-convert__field-label" for="copper-convert-kg">مقدار</label>
|
||||
<div class="copper-convert__weight-wrap">
|
||||
<input
|
||||
id="copper-convert-kg"
|
||||
v-model="inputKg"
|
||||
class="copper-convert__weight-input"
|
||||
type="text"
|
||||
inputmode="decimal"
|
||||
placeholder="مثلاً ۱۰"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<span class="copper-convert__weight-unit">کیلوگرم</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="result" class="copper-convert__result">
|
||||
<div class="copper-convert__result-head">
|
||||
<span class="copper-convert__result-kicker">خروجی</span>
|
||||
<span class="copper-convert__result-title">نتیجه تبدیل</span>
|
||||
</div>
|
||||
|
||||
<div class="copper-convert__rings">
|
||||
<article class="copper-convert__ring-card">
|
||||
<span class="copper-convert__ring-badge">۱.۵ mm²</span>
|
||||
<p class="copper-convert__ring-count" dir="ltr">{{ formatRings(result.rings15ByValue) }}</p>
|
||||
<p class="copper-convert__ring-caption">حلقه سیم</p>
|
||||
<p
|
||||
v-if="result.rings15ByWeight != null"
|
||||
class="copper-convert__ring-sub"
|
||||
dir="ltr"
|
||||
>
|
||||
≈ {{ formatRings(result.rings15ByWeight) }} بر اساس وزن حلقه
|
||||
</p>
|
||||
</article>
|
||||
<article class="copper-convert__ring-card">
|
||||
<span class="copper-convert__ring-badge">۲.۵ mm²</span>
|
||||
<p class="copper-convert__ring-count" dir="ltr">{{ formatRings(result.rings25ByValue) }}</p>
|
||||
<p class="copper-convert__ring-caption">حلقه سیم</p>
|
||||
<p
|
||||
v-if="result.rings25ByWeight != null"
|
||||
class="copper-convert__ring-sub"
|
||||
dir="ltr"
|
||||
>
|
||||
≈ {{ formatRings(result.rings25ByWeight) }} بر اساس وزن حلقه
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="copper-convert__summary">
|
||||
<div class="copper-convert__summary-row">
|
||||
<span>ارزش معادل</span>
|
||||
<strong dir="ltr">{{ formatRial(result.totalValueRial) }} <small>ریال</small></strong>
|
||||
</div>
|
||||
<div class="copper-convert__summary-row">
|
||||
<span>معادل مفتول</span>
|
||||
<strong dir="ltr">{{ formatKg(result.equivalentMaftoulKg) }} <small>کیلو</small></strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<p v-else-if="inputKg && !loading" class="copper-convert__warn">
|
||||
مقدار معتبر وارد کنید و از فعال بودن قیمت کاتد/مفتول در سامانه مطمئن شوید.
|
||||
</p>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useCopperConvertPageContext } from '../composables/useCopperConvertPage'
|
||||
import type { CopperConvertSource } from '@/utils/copperWireConvert'
|
||||
|
||||
const { loading, source, inputKg, result, priceRows } = useCopperConvertPageContext()
|
||||
|
||||
const sourceOptions = computed(() => [
|
||||
{ label: 'کاتد', value: 'katod' as CopperConvertSource },
|
||||
{ label: 'مفتول', value: 'maftoul' as CopperConvertSource },
|
||||
{ label: 'شمش', value: 'shamsh' as CopperConvertSource },
|
||||
])
|
||||
|
||||
const metalPriceRows = computed(() => priceRows.value.slice(0, 3))
|
||||
const wirePriceRows = computed(() => priceRows.value.slice(3))
|
||||
|
||||
function formatRial(value: number) {
|
||||
return Math.round(value).toLocaleString('en-US')
|
||||
}
|
||||
|
||||
function formatKg(value: number) {
|
||||
if (value >= 100) return value.toFixed(1)
|
||||
if (value >= 10) return value.toFixed(2)
|
||||
return value.toFixed(3)
|
||||
}
|
||||
|
||||
function formatRings(value: number) {
|
||||
if (value >= 100) return value.toFixed(1)
|
||||
if (value >= 10) return value.toFixed(2)
|
||||
return value.toFixed(3)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.copper-convert {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.copper-convert__lead {
|
||||
margin: 0 0 0.125rem;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.65;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.copper-convert__panel {
|
||||
position: relative;
|
||||
padding: 0.75rem 0.875rem 0.7rem;
|
||||
border-radius: 1rem;
|
||||
background: linear-gradient(145deg, #0f2744 0%, #152f4f 48%, #1a365d 100%);
|
||||
border: 1px solid rgba(201, 160, 98, 0.35);
|
||||
box-shadow:
|
||||
0 12px 28px rgba(15, 39, 68, 0.22),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.copper-convert__panel::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
inset-inline-end: -30px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(232, 180, 140, 0.28) 0%, transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.copper-convert__panel-head {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.copper-convert__panel-kicker {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
color: rgba(201, 160, 98, 0.95);
|
||||
}
|
||||
|
||||
.copper-convert__panel-title {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 800;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.copper-convert__price-group {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: 0.65rem;
|
||||
}
|
||||
|
||||
.copper-convert__price-group--wire {
|
||||
margin-bottom: 0;
|
||||
padding-top: 0.65rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.copper-convert__group-label {
|
||||
display: block;
|
||||
margin-bottom: 0.45rem;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
color: rgba(226, 232, 240, 0.75);
|
||||
}
|
||||
|
||||
.copper-convert__price-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.copper-convert__price-grid--wire {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.copper-convert__chip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
min-width: 0;
|
||||
padding: 0.45rem 0.5rem;
|
||||
border-radius: 0.65rem;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.copper-convert__chip--accent {
|
||||
background: rgba(201, 160, 98, 0.12);
|
||||
border-color: rgba(201, 160, 98, 0.35);
|
||||
}
|
||||
|
||||
.copper-convert__chip--muted .copper-convert__chip-value {
|
||||
color: rgba(248, 250, 252, 0.45);
|
||||
}
|
||||
|
||||
.copper-convert__chip-label {
|
||||
font-size: 0.625rem;
|
||||
line-height: 1.45;
|
||||
color: rgba(226, 232, 240, 0.85);
|
||||
}
|
||||
|
||||
.copper-convert__chip-value {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
color: #f8fafc;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.copper-convert__form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.65rem;
|
||||
margin-top: 0.125rem;
|
||||
padding: 0.75rem 0.875rem;
|
||||
border-radius: 1rem;
|
||||
background: #faf8f5;
|
||||
border: 1px solid rgba(201, 160, 98, 0.22);
|
||||
}
|
||||
|
||||
.copper-convert__field-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.copper-convert__pills {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.35rem;
|
||||
padding: 0.25rem;
|
||||
border-radius: 999px;
|
||||
background: #eef2f6;
|
||||
}
|
||||
|
||||
.copper-convert__pill {
|
||||
appearance: none;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
padding: 0.5rem 0.35rem;
|
||||
font-family: inherit;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
color: #64748b;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.copper-convert__pill--active {
|
||||
color: #0f2744;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 8px rgba(15, 39, 68, 0.12);
|
||||
}
|
||||
|
||||
.copper-convert__weight-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.35rem;
|
||||
padding: 0.55rem 0.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(15, 39, 68, 0.12);
|
||||
box-shadow: inset 0 1px 2px rgba(15, 39, 68, 0.04);
|
||||
}
|
||||
|
||||
.copper-convert__weight-input {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 800;
|
||||
color: #0f2744;
|
||||
text-align: right;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.copper-convert__weight-input::placeholder {
|
||||
color: #94a3b8;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.copper-convert__weight-unit {
|
||||
flex-shrink: 0;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 800;
|
||||
color: #c9a062;
|
||||
}
|
||||
|
||||
.copper-convert__result {
|
||||
margin-top: 0.125rem;
|
||||
padding: 0.875rem;
|
||||
border-radius: 1rem;
|
||||
background: linear-gradient(180deg, #fff 0%, #faf8f5 100%);
|
||||
border: 1px solid rgba(201, 160, 98, 0.35);
|
||||
box-shadow: 0 8px 24px rgba(15, 39, 68, 0.08);
|
||||
}
|
||||
|
||||
.copper-convert__result-head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.copper-convert__result-kicker {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
color: #c9a062;
|
||||
}
|
||||
|
||||
.copper-convert__result-title {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 800;
|
||||
color: #0f2744;
|
||||
}
|
||||
|
||||
.copper-convert__rings {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.copper-convert__ring-card {
|
||||
position: relative;
|
||||
padding: 0.75rem 0.5rem;
|
||||
border-radius: 0.85rem;
|
||||
text-align: center;
|
||||
background: linear-gradient(160deg, #0f2744 0%, #1a365d 100%);
|
||||
border: 1px solid rgba(201, 160, 98, 0.4);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.copper-convert__ring-card::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset-inline-start: 50%;
|
||||
bottom: -24px;
|
||||
width: 80px;
|
||||
height: 48px;
|
||||
transform: translateX(-50%);
|
||||
background: radial-gradient(ellipse, rgba(201, 160, 98, 0.35) 0%, transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.copper-convert__ring-badge {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.35rem;
|
||||
padding: 0.15rem 0.45rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
color: #0f2744;
|
||||
background: rgba(201, 160, 98, 0.95);
|
||||
}
|
||||
|
||||
.copper-convert__ring-count {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.copper-convert__ring-caption {
|
||||
margin: 0.15rem 0 0;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
color: rgba(226, 232, 240, 0.85);
|
||||
}
|
||||
|
||||
.copper-convert__ring-sub {
|
||||
margin: 0.35rem 0 0;
|
||||
font-size: 0.625rem;
|
||||
color: rgba(201, 160, 98, 0.9);
|
||||
}
|
||||
|
||||
.copper-convert__summary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.45rem;
|
||||
padding-top: 0.65rem;
|
||||
border-top: 1px dashed rgba(15, 39, 68, 0.15);
|
||||
}
|
||||
|
||||
.copper-convert__summary-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.copper-convert__summary-row strong {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 800;
|
||||
color: #0f2744;
|
||||
}
|
||||
|
||||
.copper-convert__summary-row strong small {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.copper-convert__warn {
|
||||
margin: 0;
|
||||
padding: 0.65rem 0.75rem;
|
||||
border-radius: 0.75rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.6;
|
||||
color: #9a3412;
|
||||
background: #fff7ed;
|
||||
border: 1px solid rgba(234, 88, 12, 0.2);
|
||||
}
|
||||
|
||||
@media (max-width: 380px) {
|
||||
.copper-convert__price-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,175 @@
|
||||
import {
|
||||
computed,
|
||||
inject,
|
||||
provide,
|
||||
ref,
|
||||
type ComputedRef,
|
||||
type InjectionKey,
|
||||
type Ref,
|
||||
} from 'vue'
|
||||
import { getProducts } from '@/api/products'
|
||||
import type { Product } from '@/models/products'
|
||||
import {
|
||||
COPPER_CONVERT_WIRE_FALLBACK,
|
||||
calcCopperWireConvert,
|
||||
type CopperConvertPrices,
|
||||
type CopperConvertResult,
|
||||
type CopperConvertSource,
|
||||
} from '@/utils/copperWireConvert'
|
||||
import { LEGACY_GROUP_KATOD, LEGACY_GROUP_MAFTOL, normalizeProductGroupType } from '@/utils/productCategories'
|
||||
import { getProductBuyPrice } from '@/utils/productPrice'
|
||||
import { getLastPrices, startLastPricePolling, stopLastPricePolling } from '@/utils/price'
|
||||
import { persianToEnglishDigits } from '@/utils/persianDigits'
|
||||
|
||||
export const COPPER_CONVERT_PAGE_KEY: InjectionKey<CopperConvertPageContext> =
|
||||
Symbol('copperConvertPageContext')
|
||||
|
||||
export interface CopperConvertPageContext {
|
||||
loading: Ref<boolean>
|
||||
source: Ref<CopperConvertSource>
|
||||
inputKg: Ref<string>
|
||||
prices: ComputedRef<CopperConvertPrices>
|
||||
result: ComputedRef<CopperConvertResult | null>
|
||||
priceRows: ComputedRef<{ label: string; value: string; missing?: boolean }[]>
|
||||
}
|
||||
|
||||
function parseKg(raw: string): number {
|
||||
const s = persianToEnglishDigits(String(raw ?? ''))
|
||||
.replace(/,/g, '')
|
||||
.replace(/[^\d.]/g, '')
|
||||
const n = Number.parseFloat(s)
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
|
||||
function titleIncludes(product: Product, part: string) {
|
||||
return (product.title ?? '').includes(part)
|
||||
}
|
||||
|
||||
function isKatodProduct(product: Product) {
|
||||
const group = normalizeProductGroupType(product.group_type)
|
||||
return group === LEGACY_GROUP_KATOD || titleIncludes(product, 'کاتد')
|
||||
}
|
||||
|
||||
function isMaftolProduct(product: Product) {
|
||||
const group = normalizeProductGroupType(product.group_type)
|
||||
return group === LEGACY_GROUP_MAFTOL || titleIncludes(product, 'مفتول')
|
||||
}
|
||||
|
||||
function isShamshProduct(product: Product) {
|
||||
const group = normalizeProductGroupType(product.group_type)
|
||||
return group.includes('شمش') || titleIncludes(product, 'شمش')
|
||||
}
|
||||
|
||||
function wireCrossSection(product: Product): '1.5' | '2.5' | null {
|
||||
const t = product.title ?? ''
|
||||
if (/1\.5|۱\.۵/.test(t)) return '1.5'
|
||||
if (/2\.5|۲\.۵/.test(t)) return '2.5'
|
||||
return null
|
||||
}
|
||||
|
||||
function isWireProduct(product: Product) {
|
||||
const t = `${product.group_type ?? ''} ${product.title ?? ''}`
|
||||
return t.includes('سیم') || wireCrossSection(product) != null
|
||||
}
|
||||
|
||||
function pickProduct(
|
||||
products: Product[],
|
||||
matcher: (p: Product) => boolean,
|
||||
): Product | undefined {
|
||||
return products.find((p) => p.active && matcher(p))
|
||||
}
|
||||
|
||||
function resolveWireRingPrice(product: Product | undefined, fallback: number): number {
|
||||
if (!product) return fallback
|
||||
const price = getProductBuyPrice(product)
|
||||
return price > 0 ? price : fallback
|
||||
}
|
||||
|
||||
export function useCopperConvertPage() {
|
||||
const loading = ref(true)
|
||||
const source = ref<CopperConvertSource>('katod')
|
||||
const inputKg = ref('')
|
||||
const catalog = ref<Product[]>([])
|
||||
|
||||
const katodProduct = computed(() => pickProduct(catalog.value, isKatodProduct))
|
||||
const maftolProduct = computed(() => pickProduct(catalog.value, isMaftolProduct))
|
||||
const shamshProduct = computed(() => pickProduct(catalog.value, isShamshProduct))
|
||||
const wire15Product = computed(() =>
|
||||
pickProduct(catalog.value, (p) => isWireProduct(p) && wireCrossSection(p) === '1.5'),
|
||||
)
|
||||
const wire25Product = computed(() =>
|
||||
pickProduct(catalog.value, (p) => isWireProduct(p) && wireCrossSection(p) === '2.5'),
|
||||
)
|
||||
|
||||
const prices = computed<CopperConvertPrices>(() => ({
|
||||
katodPerKg: katodProduct.value ? getProductBuyPrice(katodProduct.value) : 0,
|
||||
maftoulPerKg: maftolProduct.value ? getProductBuyPrice(maftolProduct.value) : 0,
|
||||
shamshPerKg: shamshProduct.value ? getProductBuyPrice(shamshProduct.value) : 0,
|
||||
wireRing15: resolveWireRingPrice(wire15Product.value, COPPER_CONVERT_WIRE_FALLBACK.wireRing15),
|
||||
wireRing25: resolveWireRingPrice(wire25Product.value, COPPER_CONVERT_WIRE_FALLBACK.wireRing25),
|
||||
wireWeightGrams15: COPPER_CONVERT_WIRE_FALLBACK.wireWeightGrams15,
|
||||
wireWeightGrams25: COPPER_CONVERT_WIRE_FALLBACK.wireWeightGrams25,
|
||||
}))
|
||||
|
||||
const result = computed(() =>
|
||||
calcCopperWireConvert(parseKg(inputKg.value), source.value, prices.value),
|
||||
)
|
||||
|
||||
const priceRows = computed(() => {
|
||||
const p = prices.value
|
||||
const row = (label: string, amount: number) => ({
|
||||
label,
|
||||
value: amount > 0 ? `${Math.round(amount).toLocaleString('en-US')} ریال` : '—',
|
||||
missing: amount <= 0,
|
||||
})
|
||||
return [
|
||||
row('قیمت کاتد (هر کیلو)', p.katodPerKg),
|
||||
row('قیمت مفتول (هر کیلو)', p.maftoulPerKg),
|
||||
row('قیمت شمش (هر کیلو)', p.shamshPerKg),
|
||||
row('قیمت حلقه سیم ۱.۵', p.wireRing15),
|
||||
row('قیمت حلقه سیم ۲.۵', p.wireRing25),
|
||||
]
|
||||
})
|
||||
|
||||
async function loadCatalog() {
|
||||
loading.value = true
|
||||
try {
|
||||
await getLastPrices()
|
||||
const list = await getProducts()
|
||||
catalog.value = Array.isArray(list) ? list : []
|
||||
} catch {
|
||||
catalog.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshLivePrices() {
|
||||
startLastPricePolling()
|
||||
await loadCatalog()
|
||||
}
|
||||
|
||||
function stopLivePrices() {
|
||||
stopLastPricePolling()
|
||||
}
|
||||
|
||||
const ctx: CopperConvertPageContext = {
|
||||
loading,
|
||||
source,
|
||||
inputKg,
|
||||
prices,
|
||||
result,
|
||||
priceRows,
|
||||
}
|
||||
|
||||
provide(COPPER_CONVERT_PAGE_KEY, ctx)
|
||||
return { ...ctx, refreshLivePrices, stopLivePrices, loadCatalog }
|
||||
}
|
||||
|
||||
export function useCopperConvertPageContext() {
|
||||
const ctx = inject(COPPER_CONVERT_PAGE_KEY)
|
||||
if (!ctx) {
|
||||
throw new Error('useCopperConvertPageContext requires useCopperConvertPage')
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { openCopperConvert } from '@/composables/useCopperConvertModal'
|
||||
import { getBoursecuActionIconSrc } from '@/utils/config'
|
||||
import type { HomeQuickActionItem } from '../types'
|
||||
|
||||
@@ -42,6 +43,6 @@ export const boursecuQuickActions: HomeQuickActionItem[] = [
|
||||
label: 'تبدیل',
|
||||
icon: 'vuesax-linear:refresh-circle',
|
||||
iconSrc: getBoursecuActionIconSrc('convert'),
|
||||
route: { name: 'buyProduct' },
|
||||
handler: () => openCopperConvert(),
|
||||
},
|
||||
]
|
||||
@@ -138,14 +138,8 @@
|
||||
}
|
||||
|
||||
.dproducts-order-panel {
|
||||
:deep(.ant-modal-content) {
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.ant-modal-body) {
|
||||
max-height: calc(100vh - 180px);
|
||||
overflow-y: auto;
|
||||
padding: 0 24px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<BasicModal
|
||||
v-else
|
||||
v-model:visible="showFilter"
|
||||
wrap-class-name="dproducts-order-panel"
|
||||
wrap-class-name="dproducts-order-panel app-premium-modal--wide-panel"
|
||||
:title="selectedProduct?.title ?? 'ثبت سفارش'"
|
||||
width="560px"
|
||||
destroy-on-close
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
width="440px"
|
||||
destroy-on-close
|
||||
custom-footer
|
||||
wrap-class-name="user-edit-modal"
|
||||
wrap-class-name="app-premium-modal--fluid-body"
|
||||
:loading="loading"
|
||||
>
|
||||
<div class="user-edit-modal__status" :class="isLegal.color">
|
||||
@@ -112,36 +112,6 @@ const {
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.user-edit-modal {
|
||||
.ant-modal-content {
|
||||
border-radius: 16px;
|
||||
padding-top: 0.75rem;
|
||||
}
|
||||
|
||||
.ant-modal-header {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.ant-modal-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
#body {
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.user-edit-modal__status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
v-model:visible="localVisible"
|
||||
custom-footer
|
||||
:closable="false"
|
||||
wrap-class-name="deposit-guide-modal-wrap"
|
||||
wrap-class-name="app-premium-modal--no-header"
|
||||
width="min(92vw, 380px)"
|
||||
>
|
||||
<div class="deposit-guide">
|
||||
@@ -102,7 +102,11 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<BasicButton type="primary" class="deposit-guide__confirm w-full" @click="localVisible = false">
|
||||
<BasicButton
|
||||
type="primary"
|
||||
class="app-premium-modal__btn-primary deposit-guide__confirm w-full"
|
||||
@click="localVisible = false"
|
||||
>
|
||||
متوجه شدم
|
||||
</BasicButton>
|
||||
</template>
|
||||
@@ -305,20 +309,3 @@ watch(
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.deposit-guide-modal-wrap {
|
||||
.ant-modal-content {
|
||||
border-radius: 1rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.ant-modal-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-modal-footer {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user