feat: 更新 @riwa/api-types 依赖至 0.0.82;新增锁仓选项组件及相关功能
This commit is contained in:
@@ -50,7 +50,7 @@
|
|||||||
"@better-scroll/core": "2.5.1",
|
"@better-scroll/core": "2.5.1",
|
||||||
"@elysiajs/eden": "^1.4.5",
|
"@elysiajs/eden": "^1.4.5",
|
||||||
"@iconify/vue": "5.0.0",
|
"@iconify/vue": "5.0.0",
|
||||||
"@riwa/api-types": "http://192.168.1.17:9527/api/riwa-eden-0.0.81.tgz",
|
"@riwa/api-types": "http://192.168.1.17:9527/api/riwa-eden-0.0.82.tgz",
|
||||||
"@sa/axios": "workspace:*",
|
"@sa/axios": "workspace:*",
|
||||||
"@sa/color": "workspace:*",
|
"@sa/color": "workspace:*",
|
||||||
"@sa/hooks": "workspace:*",
|
"@sa/hooks": "workspace:*",
|
||||||
|
|||||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -18,8 +18,8 @@ importers:
|
|||||||
specifier: 5.0.0
|
specifier: 5.0.0
|
||||||
version: 5.0.0(vue@3.5.25(typescript@5.9.3))
|
version: 5.0.0(vue@3.5.25(typescript@5.9.3))
|
||||||
'@riwa/api-types':
|
'@riwa/api-types':
|
||||||
specifier: http://192.168.1.17:9527/api/riwa-eden-0.0.81.tgz
|
specifier: http://192.168.1.17:9527/api/riwa-eden-0.0.82.tgz
|
||||||
version: '@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.81.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))'
|
version: '@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.82.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))'
|
||||||
'@sa/axios':
|
'@sa/axios':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:packages/axios
|
version: link:packages/axios
|
||||||
@@ -1083,9 +1083,9 @@ packages:
|
|||||||
'@quansync/fs@0.1.6':
|
'@quansync/fs@0.1.6':
|
||||||
resolution: {integrity: sha512-zoA8SqQO11qH9H8FCBR7NIbowYARIPmBz3nKjgAaOUDi/xPAAu1uAgebtV7KXHTc6CDZJVRZ1u4wIGvY5CWYaw==}
|
resolution: {integrity: sha512-zoA8SqQO11qH9H8FCBR7NIbowYARIPmBz3nKjgAaOUDi/xPAAu1uAgebtV7KXHTc6CDZJVRZ1u4wIGvY5CWYaw==}
|
||||||
|
|
||||||
'@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.81.tgz':
|
'@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.82.tgz':
|
||||||
resolution: {tarball: http://192.168.1.17:9527/api/riwa-eden-0.0.81.tgz}
|
resolution: {tarball: http://192.168.1.17:9527/api/riwa-eden-0.0.82.tgz}
|
||||||
version: 0.0.81
|
version: 0.0.82
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@elysiajs/eden': ^1.4.5
|
'@elysiajs/eden': ^1.4.5
|
||||||
|
|
||||||
@@ -5080,7 +5080,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
quansync: 0.3.0
|
quansync: 0.3.0
|
||||||
|
|
||||||
'@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.81.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
'@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.82.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@elysiajs/eden': 1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3))
|
'@elysiajs/eden': 1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3))
|
||||||
|
|
||||||
|
|||||||
@@ -45,3 +45,10 @@ export enum RwaSubscribeStatusEnum {
|
|||||||
allocated = '已分配',
|
allocated = '已分配',
|
||||||
cancelled = '已取消'
|
cancelled = '已取消'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum TokenizationStatusEnum {
|
||||||
|
not_issued = '未发行',
|
||||||
|
issued = '已发行',
|
||||||
|
issuing = '发行中',
|
||||||
|
failed = '发行失败'
|
||||||
|
}
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ const filterColumns: TableFilterColumns = [
|
|||||||
key: 'bankCode'
|
key: 'bankCode'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function handleAdd() {}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -104,6 +106,7 @@ const filterColumns: TableFilterColumns = [
|
|||||||
:filter-columns="filterColumns"
|
:filter-columns="filterColumns"
|
||||||
:fetch-data="fetchData"
|
:fetch-data="fetchData"
|
||||||
:scroll-x="800"
|
:scroll-x="800"
|
||||||
|
@add="handleAdd"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ const columns: TableBaseColumns = [
|
|||||||
const filterColumns: TableFilterColumns = [
|
const filterColumns: TableFilterColumns = [
|
||||||
{
|
{
|
||||||
title: '产品代码',
|
title: '产品代码',
|
||||||
key: 'Code'
|
key: 'code'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '产品名称',
|
title: '产品名称',
|
||||||
|
|||||||
166
src/views/tokenization/product/components/lock-options.vue
Normal file
166
src/views/tokenization/product/components/lock-options.vue
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, useTemplateRef } from 'vue';
|
||||||
|
import type { FormInst, FormRules } from 'naive-ui';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
import { client, safeClient } from '@/service/api';
|
||||||
|
|
||||||
|
defineOptions({ name: 'LockOptions' });
|
||||||
|
|
||||||
|
interface LockOption {
|
||||||
|
months: number;
|
||||||
|
rewardRate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
options: LockOption[];
|
||||||
|
productId: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'close'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const formRef = useTemplateRef<FormInst | null>('formRef');
|
||||||
|
const lockOptions = ref<LockOption[]>(cloneDeep(props.options));
|
||||||
|
|
||||||
|
const rules: FormRules = {};
|
||||||
|
|
||||||
|
function addLockOption() {
|
||||||
|
const newOptions = [...lockOptions.value, { months: 12, rewardRate: '0.1' }];
|
||||||
|
lockOptions.value = newOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeLockOption(index: number) {
|
||||||
|
if (lockOptions.value.length > 1) {
|
||||||
|
const newOptions = lockOptions.value.filter((_, i) => i !== index);
|
||||||
|
lockOptions.value = newOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateOption<K extends keyof LockOption>(index: number, field: K, value: LockOption[K]) {
|
||||||
|
lockOptions.value[index][field] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
formRef.value?.validate(async errors => {
|
||||||
|
if (!errors) {
|
||||||
|
await safeClient(() =>
|
||||||
|
client.api.admin.rwa.tokenization_schema.config({ productId: props.productId }).put({
|
||||||
|
lockOptions: lockOptions.value
|
||||||
|
})
|
||||||
|
);
|
||||||
|
window.$message?.success('锁仓选项更新成功');
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NForm
|
||||||
|
ref="formRef"
|
||||||
|
:model="{ lockOptions }"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="auto"
|
||||||
|
label-placement="left"
|
||||||
|
require-mark-placement="left"
|
||||||
|
>
|
||||||
|
<div class="mb-4 flex items-center justify-between">
|
||||||
|
<span class="text-base font-medium">锁仓选项</span>
|
||||||
|
<NButton secondary type="primary" @click="addLockOption">
|
||||||
|
<template #icon>
|
||||||
|
<icon-ic-round-plus class="text-icon" />
|
||||||
|
</template>
|
||||||
|
添加选项
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NSpace vertical :size="16">
|
||||||
|
<NCard
|
||||||
|
v-for="(option, index) in lockOptions"
|
||||||
|
:key="index"
|
||||||
|
size="small"
|
||||||
|
:segmented="{ content: true }"
|
||||||
|
class="rounded-8px"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span>选项 {{ index + 1 }}</span>
|
||||||
|
<NButton v-if="lockOptions.length > 1" text type="error" @click="removeLockOption(index)">
|
||||||
|
<template #icon>
|
||||||
|
<icon-ic-round-delete class="text-icon" />
|
||||||
|
</template>
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<NGrid :cols="2" :x-gap="16">
|
||||||
|
<NFormItemGi
|
||||||
|
label="锁仓月数"
|
||||||
|
:path="`lockOptions[${index}].months`"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
type: 'number',
|
||||||
|
message: '请输入锁仓月数',
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<NInputNumber
|
||||||
|
:value="option.months"
|
||||||
|
:min="1"
|
||||||
|
:max="120"
|
||||||
|
:step="1"
|
||||||
|
placeholder="请输入锁仓月数"
|
||||||
|
class="w-full"
|
||||||
|
@update:value="val => updateOption(index, 'months', val!)"
|
||||||
|
>
|
||||||
|
<template #suffix>月</template>
|
||||||
|
</NInputNumber>
|
||||||
|
</NFormItemGi>
|
||||||
|
<NFormItemGi
|
||||||
|
label="奖励率"
|
||||||
|
:path="`lockOptions[${index}].rewardRate`"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
validator: (_rule: any, value: string) => {
|
||||||
|
const num = Number(value);
|
||||||
|
if (!value || value === '') {
|
||||||
|
return new Error('请输入奖励率');
|
||||||
|
}
|
||||||
|
if (Number.isNaN(num)) {
|
||||||
|
return new Error('请输入有效的数字');
|
||||||
|
}
|
||||||
|
if (num < 0 || num > 1) {
|
||||||
|
return new Error('奖励率必须在0-1之间');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<NInputNumber
|
||||||
|
:value="Number(option.rewardRate)"
|
||||||
|
:min="0"
|
||||||
|
:max="1"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="4"
|
||||||
|
placeholder="请输入奖励率"
|
||||||
|
class="w-full"
|
||||||
|
@update:value="val => updateOption(index, 'rewardRate', String(val))"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<span class="text-12px">{{ (Number(option.rewardRate) * 100).toFixed(2) }}%</span>
|
||||||
|
</template>
|
||||||
|
</NInputNumber>
|
||||||
|
</NFormItemGi>
|
||||||
|
</NGrid>
|
||||||
|
</NCard>
|
||||||
|
</NSpace>
|
||||||
|
|
||||||
|
<NSpace justify="end" class="mt-4">
|
||||||
|
<NButton @click="$emit('close')">取消</NButton>
|
||||||
|
<NButton type="primary" @click="handleSubmit">保存锁仓选项</NButton>
|
||||||
|
</NSpace>
|
||||||
|
</NForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped></style>
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTemplateRef } from 'vue';
|
import { h, useTemplateRef } from 'vue';
|
||||||
|
import { useDateFormat } from '@vueuse/core';
|
||||||
|
import { useDialog } from 'naive-ui';
|
||||||
import { client, safeClient } from '@/service/api';
|
import { client, safeClient } from '@/service/api';
|
||||||
import type { TableBaseColumns, TableFetchData, TableFilterColumns, TableInst } from '@/components/table';
|
import type { TableBaseColumns, TableFetchData, TableFilterColumns, TableInst } from '@/components/table';
|
||||||
|
import { TokenizationStatusEnum } from '@/enum';
|
||||||
|
import LockOptions from './components/lock-options.vue';
|
||||||
|
|
||||||
|
const dialog = useDialog();
|
||||||
const tableInst = useTemplateRef<TableInst>('tableInst');
|
const tableInst = useTemplateRef<TableInst>('tableInst');
|
||||||
|
|
||||||
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
||||||
@@ -32,7 +37,7 @@ const columns: TableBaseColumns = [
|
|||||||
key: 'totalSupply'
|
key: 'totalSupply'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '锁定选项',
|
title: '锁仓选项',
|
||||||
key: 'lockOptions',
|
key: 'lockOptions',
|
||||||
render: (row: any) => {
|
render: (row: any) => {
|
||||||
return row.lockOptions
|
return row.lockOptions
|
||||||
@@ -40,17 +45,104 @@ const columns: TableBaseColumns = [
|
|||||||
.join('; ');
|
.join('; ');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '链类型',
|
||||||
|
key: 'chainType'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '合约地址',
|
||||||
|
key: 'contractAddress'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '交易哈希',
|
||||||
|
key: 'deployTxHash'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '关联RWA产品',
|
title: '关联RWA产品',
|
||||||
key: 'productId'
|
key: 'productId'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '发行状态',
|
||||||
|
key: 'status',
|
||||||
|
width: 120,
|
||||||
|
render: (row: any) => {
|
||||||
|
return TokenizationStatusEnum[row.status as keyof typeof TokenizationStatusEnum];
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
key: 'createdAt'
|
key: 'createdAt',
|
||||||
|
render: (row: any) => {
|
||||||
|
return useDateFormat(row.createdAt, 'YYYY-MM-DD HH:mm:ss').value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
fixed: 'right',
|
||||||
|
key: 'operation',
|
||||||
|
width: 300,
|
||||||
|
operations: (row: any) => [
|
||||||
|
{
|
||||||
|
contentText: '启用资产化',
|
||||||
|
ghost: true,
|
||||||
|
size: 'small',
|
||||||
|
visible: row.enabled === false,
|
||||||
|
onClick: async () => {
|
||||||
|
await safeClient(
|
||||||
|
client.api.admin.rwa.tokenization_schema.enable.post({
|
||||||
|
productId: row.productId,
|
||||||
|
createTradingPair: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
window.$message?.success('资产化已启用。');
|
||||||
|
tableInst.value?.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contentText: '关闭资产化',
|
||||||
|
ghost: true,
|
||||||
|
size: 'small',
|
||||||
|
visible: row.enabled === true,
|
||||||
|
onClick: async () => {
|
||||||
|
await safeClient(client.api.admin.rwa.tokenization_schema.disable({ productId: row.productId }).delete());
|
||||||
|
window.$message?.success('资产化已关闭。');
|
||||||
|
tableInst.value?.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contentText: '更新锁仓选项',
|
||||||
|
ghost: true,
|
||||||
|
size: 'small',
|
||||||
|
onClick: async () => {
|
||||||
|
handleUpdateLockOptions(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const filterColumns: TableFilterColumns = [];
|
const filterColumns: TableFilterColumns = [
|
||||||
|
{
|
||||||
|
title: '资产代码',
|
||||||
|
key: 'assetCode'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function handleUpdateLockOptions(row: any) {
|
||||||
|
const dialogInstance = dialog.create({
|
||||||
|
title: '更新锁仓选项',
|
||||||
|
content: () =>
|
||||||
|
h(LockOptions, {
|
||||||
|
options: row.lockOptions,
|
||||||
|
productId: row.productId,
|
||||||
|
onClose: () => {
|
||||||
|
dialogInstance.destroy();
|
||||||
|
tableInst.value?.reload();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
style: { width: '600px' }
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
Reference in New Issue
Block a user