feat: 添加产品管理功能,包括产品列表和添加产品表单
This commit is contained in:
146
src/views/product/components/add.vue
Normal file
146
src/views/product/components/add.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, useTemplateRef } from 'vue';
|
||||
import type { FormInst, FormRules } from 'naive-ui';
|
||||
import { client, safeClient } from '@/service/api';
|
||||
|
||||
type Body = CommonType.TreatyBody<typeof client.api.admin.subscription.products.post>;
|
||||
|
||||
defineOptions({
|
||||
name: 'ProductAdd'
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void;
|
||||
}>();
|
||||
|
||||
const formInst = useTemplateRef<FormInst>('formInst');
|
||||
const form = ref<Body>({
|
||||
name: '',
|
||||
price: '',
|
||||
cycleDays: 1,
|
||||
maturityYield: '',
|
||||
subscribeStartAt: new Date(),
|
||||
subscribeEndAt: new Date(),
|
||||
description: '',
|
||||
isActive: true,
|
||||
reformPioneerAllowance: '',
|
||||
sortOrder: 0
|
||||
});
|
||||
|
||||
const rules: FormRules = {
|
||||
name: [{ required: true, message: '请输入产品名称', trigger: ['blur', 'input'] }],
|
||||
price: [{ required: true, message: '请输入产品价格', trigger: ['blur', 'change'] }],
|
||||
maturityYield: [{ required: true, message: '请输入到期收益率', trigger: ['blur', 'change'] }],
|
||||
subscribeStartAt: [{ required: true, message: '请选择订阅时间范围', trigger: ['blur', 'change'] }]
|
||||
};
|
||||
|
||||
function handleSubmit() {
|
||||
formInst.value?.validate(async errors => {
|
||||
if (!errors) {
|
||||
await safeClient(() => client.api.admin.subscription.products.post(form.value));
|
||||
emit('close');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="my-10">
|
||||
<NForm
|
||||
ref="formInst"
|
||||
:model="form"
|
||||
label-width="140px"
|
||||
label-placement="left"
|
||||
:rules="rules"
|
||||
require-mark-placement="left"
|
||||
>
|
||||
<NFormItem path="name" label="产品名称">
|
||||
<NInput v-model:value="form.name" placeholder="请输入产品名称" />
|
||||
</NFormItem>
|
||||
|
||||
<NGrid :cols="2" :x-gap="12">
|
||||
<NFormItemGi path="price" label="产品价格">
|
||||
<NInputNumber
|
||||
:value="Number(form.price)"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
class="w-full"
|
||||
@update:value="val => (form.price = String(val))"
|
||||
>
|
||||
<template #suffix>元</template>
|
||||
</NInputNumber>
|
||||
</NFormItemGi>
|
||||
|
||||
<NFormItemGi path="cycleDays" label="周期天数">
|
||||
<NInputNumber v-model:value="form.cycleDays" :min="1" :precision="0" class="w-full">
|
||||
<template #suffix>天</template>
|
||||
</NInputNumber>
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
|
||||
<NGrid :cols="2" :x-gap="12">
|
||||
<NFormItemGi path="maturityYield" label="到期收益率">
|
||||
<NInputNumber
|
||||
:value="Number(form.maturityYield)"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="0.01"
|
||||
class="w-full"
|
||||
@update:value="val => (form.maturityYield = String(val))"
|
||||
>
|
||||
<template #suffix>%</template>
|
||||
</NInputNumber>
|
||||
</NFormItemGi>
|
||||
|
||||
<NFormItemGi path="reformPioneerAllowance" label="改革先锋津贴">
|
||||
<NInputNumber
|
||||
:value="Number(form.reformPioneerAllowance)"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
class="w-full"
|
||||
@update:value="val => (form.reformPioneerAllowance = String(val))"
|
||||
>
|
||||
<template #suffix>元</template>
|
||||
</NInputNumber>
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
|
||||
<NFormItem label="订阅时间范围">
|
||||
<NDatePicker
|
||||
:value="[form.subscribeStartAt.valueOf(), form.subscribeEndAt.valueOf()]"
|
||||
type="datetimerange"
|
||||
clearable
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
class="w-full"
|
||||
@update:value="
|
||||
val => {
|
||||
form.subscribeStartAt = new Date(val[0]);
|
||||
form.subscribeEndAt = new Date(val[1]);
|
||||
}
|
||||
"
|
||||
/>
|
||||
</NFormItem>
|
||||
|
||||
<NFormItem path="description" label="产品描述">
|
||||
<NInput v-model:value="form.description" type="textarea" placeholder="请输入产品描述" :rows="3" />
|
||||
</NFormItem>
|
||||
|
||||
<NGrid :cols="2" :x-gap="12">
|
||||
<NFormItemGi path="isActive" label="是否启用">
|
||||
<NSwitch v-model:value="form.isActive" />
|
||||
</NFormItemGi>
|
||||
|
||||
<NFormItemGi path="sortOrder" label="排序顺序">
|
||||
<NInputNumber v-model:value="form.sortOrder" :min="0" :precision="0" class="w-full" />
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
|
||||
<NSpace justify="end">
|
||||
<NButton type="primary" ghost @click="$emit('close')">取 消</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">保 存</NButton>
|
||||
</NSpace>
|
||||
</NForm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped></style>
|
||||
131
src/views/product/index.vue
Normal file
131
src/views/product/index.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<script lang="ts" setup>
|
||||
import { h, useTemplateRef } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import dayjs from 'dayjs';
|
||||
import { client, safeClient } from '@/service/api';
|
||||
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table';
|
||||
import Add from './components/add.vue';
|
||||
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
|
||||
const tableInst = useTemplateRef<TableInst>('tableInst');
|
||||
|
||||
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
||||
return safeClient(() =>
|
||||
client.api.admin.subscription.products.get({
|
||||
query: {
|
||||
...pagination,
|
||||
...filter
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const columns: TableBaseColumns = [
|
||||
{
|
||||
key: 'id',
|
||||
title: 'ID',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
title: '名称'
|
||||
},
|
||||
{
|
||||
key: 'price',
|
||||
title: '价格(元)',
|
||||
render(row) {
|
||||
return Number(row.price);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'cycleDays',
|
||||
title: '周期(天数)'
|
||||
},
|
||||
{
|
||||
key: 'maturityYield',
|
||||
title: '到期收益率',
|
||||
render(row) {
|
||||
return `${Number(row.maturityYield)}%`;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'reformPioneerAllowance',
|
||||
title: '改革先锋津贴(元)',
|
||||
render(row) {
|
||||
return Number(row.reformPioneerAllowance);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'subscribeStartAt',
|
||||
title: '订阅开始时间',
|
||||
render(row: any) {
|
||||
return dayjs(row.subscribeStartAt).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'subscribeEndAt',
|
||||
title: '订阅结束时间',
|
||||
render(row: any) {
|
||||
return dayjs(row.subscribeEndAt).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
title: '描述'
|
||||
},
|
||||
{
|
||||
key: 'isActive',
|
||||
title: '是否激活',
|
||||
render(row) {
|
||||
return row.isActive ? '是' : '否';
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'sortOrder',
|
||||
title: '排序'
|
||||
},
|
||||
{
|
||||
key: 'createdAt',
|
||||
title: '创建时间',
|
||||
render(row: any) {
|
||||
return dayjs(row.createdAt).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'operations',
|
||||
title: '操作',
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
operations: row => [
|
||||
{
|
||||
contentText: '编辑',
|
||||
size: 'small',
|
||||
onClick() {}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
function handleAdd() {
|
||||
const d = dialog.create({
|
||||
title: '添加产品',
|
||||
showIcon: false,
|
||||
content: () =>
|
||||
h(Add, {
|
||||
onClose: () => {
|
||||
d.destroy();
|
||||
tableInst.value?.reload();
|
||||
}
|
||||
}),
|
||||
style: { width: '800px' }
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TableBase ref="tableInst" :fetch-data="fetchData" :columns="columns" @add="handleAdd" />
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped></style>
|
||||
Reference in New Issue
Block a user