feat: 更新发行申请表单,添加订阅开始和结束时间字段,优化日期验证逻辑

This commit is contained in:
2025-12-21 03:42:45 +07:00
parent fcaf7db923
commit 101554ef5e
9 changed files with 175 additions and 97 deletions

View File

@@ -9,7 +9,7 @@ import Done from "./done.vue";
import IssuePeriod from "./issue-period.vue";
const { t } = useI18n();
const { data: categories, onFetchResponse } = await safeClient(() => client.api.rwa.issuance.categories.get());
const { data: categories, onFetchResponse } = await safeClient(() => client.api.rwa.category.categories.get());
const step = useRouteQuery<number>("step", 1, { transform: v => Number(v), mode: "push" });
const initialData: RwaIssuanceProductBody = {
@@ -23,7 +23,8 @@ const initialData: RwaIssuanceProductBody = {
editionName: "",
launchDate: new Date(),
perUserLimit: "",
subscriptionDeadline: new Date(),
subscriptionStartDate: new Date(),
subscriptionEndDate: new Date(),
totalSupply: "",
unitPrice: "",
dividendRate: "",

View File

@@ -20,7 +20,8 @@ const initialIssuePeriod: RwaIssuanceProductBody["editions"][0] = {
editionName: "",
launchDate: new Date(),
perUserLimit: "",
subscriptionDeadline: new Date(),
subscriptionStartDate: new Date(),
subscriptionEndDate: new Date(),
totalSupply: "",
unitPrice: "",
dividendRate: "",
@@ -30,6 +31,10 @@ const initialValues = ref({
editions: props.initialData || [{ ...initialIssuePeriod }],
});
const launchDate = ref(new Date().toISOString());
const subscriptionStartDate = ref(new Date().toISOString());
const subscriptionEndDate = ref(new Date().toISOString());
const schema = toTypedSchema(yup.object({
editions: yup.array().of(
yup.object({
@@ -40,17 +45,33 @@ const schema = toTypedSchema(yup.object({
if (!value)
return true;
return new Date(value) >= new Date(now.value.toDateString());
})
.test("before-subscription", t("asset.issue.apply.validation.launchBeforeSubscription"), (value) => {
if (!value || !subscriptionStartDate.value)
return true;
return new Date(value) < new Date(subscriptionStartDate.value);
}),
subscriptionStartDate: yup.string()
.required(t("asset.issue.apply.validation.subscriptionStartDateRequired"))
.test("not-past", t("asset.issue.apply.validation.subscriptionStartDateNotPast"), (value) => {
if (!value)
return true;
return new Date(value) >= new Date(now.value.toDateString());
})
.test("after-launch", t("asset.issue.apply.validation.subscriptionAfterLaunch"), (value) => {
if (!value || !launchDate.value)
return true;
return new Date(value) > new Date(launchDate.value);
}),
subscriptionEndDate: yup.string()
.required(t("asset.issue.apply.validation.subscriptionEndDateRequired"))
.test("after-start", t("asset.issue.apply.validation.subscriptionEndAfterStart"), (value) => {
if (!value || !subscriptionStartDate.value)
return true;
return new Date(value) > new Date(subscriptionStartDate.value);
}),
perUserLimit: yup.string().required(t("asset.issue.apply.validation.perUserLimitRequired")),
totalSupply: yup.string().required(t("asset.issue.apply.validation.totalSupplyRequired")),
subscriptionDeadline: yup.string()
.required(t("asset.issue.apply.validation.subscriptionDeadlineRequired"))
.test("after-launch", t("asset.issue.apply.validation.deadlineAfterLaunch"), function (value) {
const { launchDate } = this.parent;
if (!value || !launchDate)
return true;
return new Date(value) >= new Date(launchDate);
}),
unitPrice: yup.string().required(t("asset.issue.apply.validation.unitPriceRequired")),
dividendRate: yup.string().required(t("asset.issue.apply.validation.dividendRateRequired")),
}),
@@ -68,20 +89,22 @@ function handleSubmit(values: GenericObject) {
<ui-collapse v-for="(entry, idx) in fields" :key="entry.key" :title="t('asset.issue.apply.issuePeriodIndex', { index: idx + 1 })" size="small">
<div>
<Field :name="`editions[${idx}].editionName`">
<template #default="{ field }">
<template #default="{ field, errorMessage }">
<ui-input-label
v-bind="field"
:label="t('asset.issue.apply.editionName')"
:placeholder="t('asset.issue.apply.enterEditionName')"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
<ErrorMessage :name="`editions[${idx}].editionName`" />
</div>
<div>
<Field :name="`editions[${idx}].perUserLimit`" type="text">
<template #default="{ field }">
<template #default="{ field, errorMessage }">
<ui-input-label
v-bind="field"
type="number"
@@ -89,14 +112,16 @@ function handleSubmit(values: GenericObject) {
:label="t('asset.issue.apply.perUserLimit')"
:placeholder="t('asset.issue.apply.enterPerUserLimit')"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
<ErrorMessage :name="`editions[${idx}].perUserLimit`" />
</div>
<div>
<Field :name="`editions[${idx}].totalSupply`" type="text">
<template #default="{ field }">
<template #default="{ field, errorMessage }">
<ui-input-label
v-bind="field"
type="number"
@@ -104,53 +129,17 @@ function handleSubmit(values: GenericObject) {
:label="t('asset.issue.apply.totalSupply')"
:placeholder="t('asset.issue.apply.enterTotalSupply')"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
<ErrorMessage :name="`editions[${idx}].totalSupply`" />
</div>
<div>
<Field :name="`editions[${idx}].subscriptionDeadline`">
<template #default="{ setValue }">
<Field :name="`editions[${idx}].launchDate`">
<template #default="{ field }">
<ui-datetime
datetime="launchDate"
v-bind="field"
:label="t('asset.issue.apply.launchDate')"
:min="now.toISOString()"
@update:value="(val) => {
setValue(val);
}"
/>
</template>
</Field>
<ErrorMessage :name="`editions[${idx}].launchDate`" />
</template>
</Field>
</div>
<div>
<Field :name="`editions[${idx}].launchDate`">
<template #default="{ value: launchDate }">
<Field :name="`editions[${idx}].subscriptionDeadline`">
<template #default="{ field }">
<ui-datetime
datetime="subscriptionDeadline"
v-bind="field"
:label="t('asset.issue.apply.subscriptionDeadline')"
:min="launchDate ? new Date(launchDate).toISOString() : now.toISOString()"
/>
</template>
</Field>
<ErrorMessage :name="`editions[${idx}].subscriptionDeadline`" />
</template>
</Field>
</div>
<div>
<Field :name="`editions[${idx}].unitPrice`" type="text">
<template #default="{ field }">
<template #default="{ field, errorMessage }">
<ui-input-label
v-bind="field"
type="number"
@@ -158,14 +147,16 @@ function handleSubmit(values: GenericObject) {
:label="t('asset.issue.apply.unitPrice')"
:placeholder="t('asset.issue.apply.enterUnitPrice')"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
<ErrorMessage :name="`editions[${idx}].unitPrice`" />
</div>
<div>
<Field :name="`editions[${idx}].dividendRate`" type="number">
<template #default="{ field }">
<template #default="{ field, errorMessage }">
<ui-input-label
v-bind="field"
type="number"
@@ -173,9 +164,62 @@ function handleSubmit(values: GenericObject) {
:label="t('asset.issue.apply.dividendRate')"
:placeholder="t('asset.issue.apply.enterDividendRate')"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
</div>
<div>
<Field :name="`editions[${idx}].launchDate`">
<template #default="{ field, errorMessage }">
<ui-datetime
v-bind="field"
v-model="launchDate"
datetime="launchDate"
:label="t('asset.issue.apply.launchDate')"
:min="now.toISOString()"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
</div>
<div>
<Field :name="`editions[${idx}].subscriptionStartDate`">
<template #default="{ field, errorMessage }">
<ui-datetime
v-bind="field"
v-model="subscriptionStartDate"
datetime="subscriptionStartDate"
:label="t('asset.issue.apply.subscriptionStartDate')"
:min="launchDate ? new Date(launchDate).toISOString() : now.toISOString()"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
</div>
<div>
<Field :name="`editions[${idx}].subscriptionEndDate`">
<template #default="{ field, errorMessage }">
<ui-datetime
v-bind="field"
v-model="subscriptionEndDate"
datetime="subscriptionEndDate"
:label="t('asset.issue.apply.subscriptionEndDate')"
:min="subscriptionStartDate ? new Date(subscriptionStartDate).toISOString() : now.toISOString()"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</template>
</Field>
<ErrorMessage :name="`editions[${idx}].dividendRate`" />
</div>
<ion-button color="tertiary" size="small" class="ui-button" @click="remove(idx)">
@@ -191,7 +235,7 @@ function handleSubmit(values: GenericObject) {
</FieldArray>
<div class="flex justify-center space-x-4">
<ion-button expand="block" shape="round" @click="$router.back()">
<ion-button expand="block" shape="round" class="w-40" @click="$router.back()">
{{ t('asset.issue.apply.back') }}
</ion-button>
<ion-button expand="block" type="submit" class="w-full" shape="round" color="success">