Split desktop and mobile layouts with shared page data so APIs fetch once per context.
Add layout shells, desktop views, module-level page caches, and UI fixes for auth, home, wallet, transactions, address, and related pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { computed, inject, onMounted, provide, ref, type InjectionKey } from 'vue'
|
||||
import router from '@/router'
|
||||
import { loading } from '@/utils'
|
||||
import { usePrefix } from '@/utils/usePrefix'
|
||||
import { createFund, editFund, getFundById } from '@/api/fund'
|
||||
import { message } from 'ant-design-vue/es'
|
||||
import { useFundUserStore } from '@/store/fundStore'
|
||||
import type { Fund } from '@/models/fund'
|
||||
import homeImg from '@/assets/img/cash_home.svg'
|
||||
import giftImg from '@/assets/img/cash_gift.svg'
|
||||
import circulationImg from '@/assets/img/cash_circulation.svg'
|
||||
import loveImg from '@/assets/img/cash_love.svg'
|
||||
import repairsImg from '@/assets/img/cash_repairs.svg'
|
||||
import savingImg from '@/assets/img/cash_saving.svg'
|
||||
|
||||
export const FUND_NEW_PAGE_KEY: InjectionKey<ReturnType<typeof useFundNewPage>> =
|
||||
Symbol('fundNewPage')
|
||||
|
||||
const types = [
|
||||
{ name: 'خرید لوازم منزل' },
|
||||
{ name: 'پس انداز' },
|
||||
{ name: 'گردش' },
|
||||
{ name: 'ازدواج' },
|
||||
{ name: 'تعمیرات' },
|
||||
{ name: 'هدیه' },
|
||||
]
|
||||
|
||||
export function useFundNewPage() {
|
||||
const fundStore = useFundUserStore()
|
||||
const edit_id = computed(() => parseInt(router.currentRoute.value.query.id as string))
|
||||
const name = ref<string>('پس انداز')
|
||||
const { prefixCls } = usePrefix('input_name')
|
||||
const info = ref<Fund>()
|
||||
|
||||
const itemImg = computed(() => {
|
||||
switch (name.value) {
|
||||
case 'خرید لوازم منزل':
|
||||
return homeImg
|
||||
case 'هدیه':
|
||||
return giftImg
|
||||
case 'گردش':
|
||||
return circulationImg
|
||||
case 'ازدواج':
|
||||
return loveImg
|
||||
case 'تعمیرات':
|
||||
return repairsImg
|
||||
case 'پس انداز':
|
||||
return savingImg
|
||||
default:
|
||||
return savingImg
|
||||
}
|
||||
})
|
||||
|
||||
async function getEditInfo() {
|
||||
try {
|
||||
loading.value = true
|
||||
info.value = await getFundById(edit_id.value)
|
||||
name.value = info.value?.title ?? ''
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function ok() {
|
||||
try {
|
||||
loading.value = true
|
||||
if (!name.value) {
|
||||
message.error('ابتدا نام گنج را وارد کنید')
|
||||
return
|
||||
}
|
||||
edit_id.value
|
||||
? await editFund(edit_id.value, { title: name.value })
|
||||
: await createFund({ title: name.value })
|
||||
await fundStore.getMyFund()
|
||||
message.success(`گنج با موفقیت ${edit_id.value ? 'ویرایش' : 'ساخته'} شد`)
|
||||
router.back()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (edit_id.value) {
|
||||
getEditInfo()
|
||||
}
|
||||
})
|
||||
|
||||
const context = {
|
||||
types,
|
||||
edit_id,
|
||||
name,
|
||||
prefixCls,
|
||||
info,
|
||||
itemImg,
|
||||
ok,
|
||||
goBack,
|
||||
}
|
||||
|
||||
provide(FUND_NEW_PAGE_KEY, context)
|
||||
return context
|
||||
}
|
||||
|
||||
export function useFundNewPageContext() {
|
||||
const context = inject(FUND_NEW_PAGE_KEY)
|
||||
if (!context) {
|
||||
throw new Error('useFundNewPageContext must be used within useFundNewPage')
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="dfund-new">
|
||||
<div class="dfund-new__container">
|
||||
<header class="dfund-new-topbar">
|
||||
<button type="button" class="dfund-new-topbar__back" @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" size="18" />
|
||||
بازگشت
|
||||
</button>
|
||||
<div class="dfund-new-topbar__meta">
|
||||
<p class="dfund-new-topbar__eyebrow">گنج</p>
|
||||
<h1 class="dfund-new-topbar__title">
|
||||
{{ edit_id ? `ویرایش گنج ${name}` : 'صندوق جدید' }}
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<section class="dfund-new__card dfund-surface">
|
||||
<div class="dfund-new__preview">
|
||||
<img :src="itemImg" alt="" class="dfund-new__preview-img" />
|
||||
</div>
|
||||
|
||||
<div class="dfund-new__field" :class="[prefixCls]">
|
||||
<label class="dfund-new__label">عنوان گنج</label>
|
||||
<van-field
|
||||
v-model="name"
|
||||
label=""
|
||||
placeholder="عنوان را وارد کنید"
|
||||
input-align="center"
|
||||
:show-word-limit="true"
|
||||
maxlength="25"
|
||||
rows="1"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="dfund-new__tags">
|
||||
<button
|
||||
v-for="item in types"
|
||||
:key="item.name"
|
||||
type="button"
|
||||
class="dfund-new__tag"
|
||||
:class="{ 'dfund-new__tag--active': item.name === name }"
|
||||
@click="name = item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<BasicButton class="dfund-new__submit" type="primary" :disabled="loading" @click="ok()">
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<span v-else>{{ edit_id ? 'ویرایش گنج' : 'ساخت گنج' }}</span>
|
||||
</BasicButton>
|
||||
</section>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { useFundNewPageContext } from '../composables/useFundNewPage'
|
||||
|
||||
const { types, edit_id, name, prefixCls, itemImg, ok, goBack } = useFundNewPageContext()
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input_name';
|
||||
|
||||
.@{prefix} {
|
||||
.van-field__value {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.van-field__body {
|
||||
@apply w-full mr-5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,194 +1,23 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-white wrap-fix py-3 px-3 text-primary font-bold drop-shadow flex h-12 z-20 justify-between">
|
||||
<div class="flex ">
|
||||
<div @click="router.back()" class="cursor-pointer">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1"/>
|
||||
</div>
|
||||
<div class="mr-2">{{edit_id? `ویرایش گنج ${name}`: 'صندوق جدید'}}</div>
|
||||
</div>
|
||||
<div @click="router.back()">
|
||||
<!-- <BasicIcon icon="vuesax-linear:setting-4"/>-->
|
||||
</div>
|
||||
</div>
|
||||
<a-spin :spinning="loading">
|
||||
<div class="pt-20 flex flex-col justify-center items-center">
|
||||
<div class="bg-sky-100 w-[120px] aspect-square flex justify-center rounded-xl"><img :src="itemImg" alt=""></div>
|
||||
<!-- <div class="mt-1 text-xs">تغییر عکس</div>-->
|
||||
<div class="flex mt-3 w-full relative px-5" :class="[prefixCls]">
|
||||
<!-- <div class="text-primary font-bold mx-auto items-center">پس انداز</div>
|
||||
<div class="absolute left-5 text-gray-400 text-xs">7/25</div>-->
|
||||
<van-field
|
||||
v-model="name"
|
||||
label=""
|
||||
class="font-bold"
|
||||
placeholder="عنوان را وارد کنید"
|
||||
input-align="center"
|
||||
:show-word-limit="true"
|
||||
maxlength="25"
|
||||
rows="1"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex overflow-x-scroll gap-2 whitespace-nowrap max-w-[320px] mt-2 px-3">
|
||||
<!-- <BasicTags
|
||||
:items="types"
|
||||
color="green"
|
||||
:has-add="false"
|
||||
/>-->
|
||||
<!-- <BasicButton v-for="item in types" size="small">{{item.name}}</BasicButton>-->
|
||||
<div v-for="item in types"
|
||||
class="border-1 px-3 py-2 flex-nowrap rounded text-xs color-transition background-color-transition"
|
||||
:key="item.name"
|
||||
:class="item.name === name? 'bg-primary text-white':'bg-gray-200 text-gray-600'"
|
||||
@click="name = item.name">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="mt-2 font-bold flex text-xs items-center text-gray-500">
|
||||
<div class="ml-1 text-base text-primary">{{ router.currentRoute.value.query.amount }}</div>
|
||||
گرم
|
||||
</div>
|
||||
<div class="text-gray-400">موجودی صندوق {{itemName}}</div>
|
||||
<div class="w-full p-5">
|
||||
<div class="w-full flex gap-3">
|
||||
<BasicButton class="w-full !bg-light" icon="vuesax-linear:add-square" icon-size="18">برداشت</BasicButton>
|
||||
<BasicButton class="w-full !bg-light" icon="vuesax-linear:arrow-up" icon-size="18">واریز</BasicButton>
|
||||
</div>
|
||||
<div class="text-lg font-bold mt-5">تراکنش ها</div>
|
||||
<div class="mt-5 pb-17">
|
||||
<Item v-for="item in items" :is-up="item.isUp" :has-transition="item.hasTransition" :key="item"/>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="wrap-fix flex justify-center bottom-23 px-5 z-200" @click="ok()">
|
||||
<BasicButton class="rounded w-full px-5 py-2 text-center" type="primary" :disabled="loading">
|
||||
<a-spin v-if="loading" size="small"/>
|
||||
<div v-else>{{edit_id? 'ویرایش گنج':'ساخت گنج'}}</div>
|
||||
</BasicButton>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
<div class="fund-new-page-root">
|
||||
<DesktopFundNewView v-show="isDesktop" />
|
||||
<MobileFundNewView v-show="!isDesktop" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import { useFundNewPage } from './composables/useFundNewPage'
|
||||
import DesktopFundNewView from './desktop/DesktopFundNewView.vue'
|
||||
import MobileFundNewView from './mobile/MobileFundNewView.vue'
|
||||
|
||||
import router from "@/router";
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import homeImg from "@/assets/img/cash_home.svg";
|
||||
import giftImg from "@/assets/img/cash_gift.svg";
|
||||
import circulationImg from "@/assets/img/cash_circulation.svg";
|
||||
import loveImg from "@/assets/img/cash_love.svg";
|
||||
import repairsImg from "@/assets/img/cash_repairs.svg";
|
||||
import savingImg from "@/assets/img/cash_saving.svg";
|
||||
import {usePrefix} from "@/utils/usePrefix";
|
||||
import {loading} from "@/utils";
|
||||
import {createFund, editFund, getFundById} from "@/api/fund";
|
||||
import {message} from "ant-design-vue/es";
|
||||
import {useFundUserStore} from "@/store/fundStore";
|
||||
import BasicButton from "@/components/BasicPacks/BasicButton.vue";
|
||||
import type {Fund} from "@/models/fund";
|
||||
|
||||
const fundStore = useFundUserStore()
|
||||
|
||||
|
||||
const types = [
|
||||
{
|
||||
name: 'خرید لوازم منزل'
|
||||
},
|
||||
{
|
||||
name: 'پس انداز'
|
||||
},
|
||||
{
|
||||
name: 'گردش'
|
||||
},
|
||||
{
|
||||
name: 'ازدواج'
|
||||
},
|
||||
{
|
||||
name: 'تعمیرات'
|
||||
},
|
||||
{
|
||||
name: 'هدیه'
|
||||
},
|
||||
]
|
||||
|
||||
const edit_id = computed(() => {
|
||||
return parseInt(router.currentRoute.value.query.id as string)
|
||||
})
|
||||
const name = ref<string>('پس انداز')
|
||||
const {prefixCls} = usePrefix('input_name')
|
||||
const info = ref<Fund>()
|
||||
|
||||
async function getEditInfo() {
|
||||
try {
|
||||
loading.value = true
|
||||
info.value = await getFundById(edit_id.value)
|
||||
name.value = info.value?.title?? ''
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (edit_id.value) {
|
||||
getEditInfo()
|
||||
}
|
||||
})
|
||||
|
||||
const itemImg = computed(() => {
|
||||
switch (name.value) {
|
||||
case 'خرید لوازم منزل':
|
||||
return homeImg
|
||||
case 'هدیه':
|
||||
return giftImg
|
||||
case 'گردش':
|
||||
return circulationImg
|
||||
case 'ازدواج':
|
||||
return loveImg
|
||||
case 'تعمیرات':
|
||||
return repairsImg
|
||||
case 'پس انداز':
|
||||
return savingImg
|
||||
default:
|
||||
return savingImg
|
||||
}
|
||||
})
|
||||
|
||||
async function ok() {
|
||||
try {
|
||||
loading.value = true
|
||||
// console.log(name.value)
|
||||
name.value ? edit_id.value? await editFund(edit_id.value,{title: name.value}) :await createFund({title: name.value}) : () => {
|
||||
message.error('ابتدا نام گنج را وارد کنید')
|
||||
return
|
||||
}
|
||||
await fundStore.getMyFund()
|
||||
message.success(`گنج با موفقیت ${edit_id.value? 'ویرایش':'ساخته'} شد`)
|
||||
router.back()
|
||||
// name.value? message.warn('ss'): message.error('ابتدا نام صندوق را وارد کنید')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
useFundNewPage()
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input_name';
|
||||
|
||||
.@{prefix} {
|
||||
.van-field__value {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.van-field__body {
|
||||
@apply w-full mr-5;
|
||||
}
|
||||
<style scoped>
|
||||
.fund-new-page-root {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="bg-white wrap-fix py-3 px-3 text-primary font-bold drop-shadow flex h-12 z-20 justify-between"
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="cursor-pointer" @click="goBack()">
|
||||
<BasicIcon icon="vuesax-linear:arrow-right-1" />
|
||||
</div>
|
||||
<div class="mr-2">{{ edit_id ? `ویرایش گنج ${name}` : 'صندوق جدید' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-spin :spinning="loading">
|
||||
<div class="pt-20 flex flex-col justify-center items-center">
|
||||
<div class="bg-sky-100 w-[120px] aspect-square flex justify-center rounded-xl">
|
||||
<img :src="itemImg" alt="" />
|
||||
</div>
|
||||
<div class="flex mt-3 w-full relative px-5" :class="[prefixCls]">
|
||||
<van-field
|
||||
v-model="name"
|
||||
label=""
|
||||
class="font-bold"
|
||||
placeholder="عنوان را وارد کنید"
|
||||
input-align="center"
|
||||
:show-word-limit="true"
|
||||
maxlength="25"
|
||||
rows="1"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex overflow-x-scroll gap-2 whitespace-nowrap max-w-[320px] mt-2 px-3">
|
||||
<div
|
||||
v-for="item in types"
|
||||
:key="item.name"
|
||||
class="border-1 px-3 py-2 flex-nowrap rounded text-xs color-transition background-color-transition"
|
||||
:class="item.name === name ? 'bg-primary text-white' : 'bg-gray-200 text-gray-600'"
|
||||
@click="name = item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrap-fix flex justify-center bottom-23 px-5 z-200" @click="ok()">
|
||||
<BasicButton class="rounded w-full px-5 py-2 text-center" type="primary" :disabled="loading">
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<div v-else>{{ edit_id ? 'ویرایش گنج' : 'ساخت گنج' }}</div>
|
||||
</BasicButton>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { loading } from '@/utils'
|
||||
import { useFundNewPageContext } from '../composables/useFundNewPage'
|
||||
|
||||
const { types, edit_id, name, prefixCls, itemImg, ok, goBack } = useFundNewPageContext()
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input_name';
|
||||
|
||||
.@{prefix} {
|
||||
.van-field__value {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.van-field__body {
|
||||
@apply w-full mr-5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user