WIP: user-vance-dev #2

Closed
Ghost wants to merge 3 commits from user-vance-dev into dev
10 changed files with 2264 additions and 128 deletions

View File

@ -77,7 +77,8 @@
"react-helmet-async": "^1.0.4",
"umi": "^3.5.0",
"umi-serve": "^1.9.10",
"web3": "^1.7.5"
"web3": "^1.7.5",
"xlsx": "0.15.3"
},
"devDependencies": {
"@ant-design/pro-cli": "^2.0.2",

View File

@ -22,8 +22,10 @@ const form = createForm({});
const AddNftContractModal = ({ onOk, onCancel, ...rest }: AddNftContractModalPropsType) => {
const handleOk = () => {
const formState = form.getFormState();
onOk(formState.values);
form.submit(async () => {
const formState = form.getFormState();
onOk(formState.values);
});
};
const handleCancel = () => {
onCancel();
@ -35,24 +37,31 @@ const AddNftContractModal = ({ onOk, onCancel, ...rest }: AddNftContractModalPro
<SchemaField>
<SchemaField.String
name="contract_name"
title="名称"
title="合约名称"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.Number
name="contract_address"
title="合约"
<SchemaField.String
name="address"
title="合约地址"
required
x-decorator="FormItem"
x-component="NumberPicker"
x-component="Input"
/>
<SchemaField.Number
<SchemaField.String
name="description"
title=""
title="描述"
required
x-decorator="FormItem"
x-component="NumberPicker"
x-component="Input"
/>
<SchemaField.String
name="contract_symbol"
title="合约符号"
required
x-decorator="FormItem"
x-component="Input"
/>
</SchemaField>
</Form>

View File

@ -1,8 +1,9 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { message } from 'antd';
// import { fetchTableData } from '@/utils/table';
import { fetchTableData } from '@/utils/table';
import AddNftContractModal from './components/AddNftContract';
import { getContractData, createContract } from '@/services/nft/contract';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
@ -35,6 +36,7 @@ const Address: React.FC = () => {
<Table
columns={columns}
rowKey="id"
search={false}
actionRef={tableRef}
toolBarActions={[
{
@ -45,19 +47,19 @@ const Address: React.FC = () => {
},
},
]}
// request={async (params) => {
// // return fetchTableData(, params);
// }}
request={async (params) => {
return fetchTableData(getContractData, params);
}}
/>
<AddNftContractModal
visible={NftModal}
visible={visible}
onCancel={function () {
setNftModal(false);
setVisible(false);
}}
onOk={async function (val: any): Promise<void> {
try {
const params = { ...val };
// await creatNftAddress(params);
await createContract(params);
message.success('添加成功');
} catch (e) {
console.log(e);

View File

@ -1,9 +1,19 @@
import React, { useRef } from 'react';
import React, { useRef, useEffect } from 'react';
import { createForm } from '@formily/core';
import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal';
import Upload from '@/components/Upload';
import { Button, message } from 'antd';
// import { fetchTableData } from '@/utils/table';
import { Form, FormItem, Input, NumberPicker } from '@formily/antd';
import {
Form,
FormItem,
Input,
NumberPicker,
ArrayItems,
FormButtonGroup,
ArrayTable,
} from '@formily/antd';
interface AddNftModalPropsType extends ModalProps {
onOk: (val: any) => void;
@ -15,6 +25,10 @@ const SchemaField = createSchemaField({
FormItem,
Input,
NumberPicker,
Upload,
ArrayItems,
FormButtonGroup,
ArrayTable,
},
});
@ -22,8 +36,20 @@ const form = createForm({});
const AddNftModal = ({ onOk, onCancel, ...rest }: AddNftModalPropsType) => {
const handleOk = () => {
const formState = form.getFormState();
onOk(formState.values);
form.submit(async () => {
const formState = form.getFormState();
onOk(formState.values);
});
};
const handleAddResoruce = () => {
const resourceList = form.getFieldState('contacts').value;
if (resourceList.length >= 1) {
message.warning('只能添加1个属性');
return;
}
form.setFieldState('contacts', (state) => {
state.value = [...resourceList, {}];
});
};
const handleCancel = () => {
onCancel();
@ -34,34 +60,107 @@ const AddNftModal = ({ onOk, onCancel, ...rest }: AddNftModalPropsType) => {
<Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField>
<SchemaField.String
name="nft_name"
name="name"
title="名称"
required
x-decorator="FormItem"
x-validator={{ required: true }}
x-component="Input"
x-decorator="FormItem"
/>
<SchemaField.Number
name="contract"
title="合约"
required
x-validator={{ required: true }}
x-decorator="FormItem"
x-component="NumberPicker"
x-component="Input"
/>
<SchemaField.Number
name="description"
title="描述"
required
x-validator={{ required: true }}
x-decorator="FormItem"
x-component="NumberPicker"
x-component="Input"
/>
<SchemaField.Number
name="img"
<SchemaField.String
name="image"
title="图片"
required
x-validator={{ required: true }}
x-decorator="FormItem"
x-component="NumberPicker"
x-component="Upload"
/>
<SchemaField.String
name="avatar"
title="avatar"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.Array
name="contacts"
title="属性"
required
// x-validator={[{ required: true }]}
x-decorator="FormItem"
x-component="ArrayItems"
>
<SchemaField.Object x-component="ArrayItems.Item">
<SchemaField.Void x-decorator="FormItem" />
<SchemaField.Void
name="popover"
title=""
required
x-decorator="Editable.Popover"
x-component="FormLayout"
x-component-props={{
layout: 'vertical',
}}
x-reactions={[
{
fulfill: {
schema: {
title: '{{$self.query(".name").value() }}',
},
},
},
]}
>
<SchemaField.String
name="trait_type"
required
title="类型"
x-validator={{ required: true }}
x-decorator="FormItem"
x-component="Input"
x-component-props={{
style: {
width: 300,
},
}}
/>
<SchemaField.String
name="value"
title="值"
required
x-decorator="FormItem"
x-component="Input"
x-component-props={{
style: {
width: 300,
},
}}
/>
</SchemaField.Void>
<SchemaField.Void x-decorator="FormItem" x-component="ArrayItems.Remove" />
</SchemaField.Object>
</SchemaField.Array>
</SchemaField>
<FormButtonGroup.FormItem style={{ marginBottom: 20 }}>
<Button type="dashed" onClick={handleAddResoruce} block>
</Button>
</FormButtonGroup.FormItem>
</Form>
</Modal>
);

View File

@ -0,0 +1,160 @@
import React, { useRef, useEffect } from 'react';
import { createForm } from '@formily/core';
import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal';
import Upload from '@/components/Upload';
import { Button, message } from 'antd';
import { Form, FormItem, Input, NumberPicker, ArrayItems, FormButtonGroup } from '@formily/antd';
interface EditNftModalPropsType extends ModalProps {
onOk: (val: any) => void;
onCancel: () => void;
modalData: any;
}
const SchemaField = createSchemaField({
components: {
FormItem,
Input,
NumberPicker,
Upload,
ArrayItems,
FormButtonGroup,
},
});
const form = createForm({});
const EditNftModal = ({ onOk, onCancel, modalData, ...rest }: EditNftModalPropsType) => {
useEffect(() => {
form.setInitialValues(modalData);
});
const handleOk = () => {
form.submit(async () => {
const formState = form.getFormState();
onOk(formState.values);
});
};
const handleAddResoruce = () => {
const resourceList = form.getFieldState('contacts').value;
if (resourceList.length >= 1) {
message.warning('只能添加1个属性');
return;
}
form.setFieldState('contacts', (state) => {
state.value = [...resourceList, {}];
});
};
const handleCancel = () => {
onCancel();
};
return (
<Modal title="添加NFT" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField>
<SchemaField.String name="name" title="名称" x-decorator="FormItem" x-component="Input" />
<SchemaField.String
name="token_id"
title="tokenID"
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="contract"
title="合约"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="description"
title="描述"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="image"
title="图片"
required
x-decorator="FormItem"
x-component="Upload"
/>
<SchemaField.String
name="avatar"
title="avatar"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.Array
name="contacts"
title="属性"
required
// x-validator={[{ required: true }]}
x-decorator="FormItem"
x-component="ArrayItems"
>
<SchemaField.Object x-component="ArrayItems.Item">
<SchemaField.Void x-decorator="FormItem" />
<SchemaField.Void
name="popover"
title=""
required
x-decorator="Editable.Popover"
x-component="FormLayout"
x-component-props={{
layout: 'vertical',
}}
x-reactions={[
{
fulfill: {
schema: {
title: '{{$self.query(".name").value() }}',
},
},
},
]}
>
<SchemaField.String
name="trait_type"
required
title="类型"
x-validator={{ required: true }}
x-decorator="FormItem"
x-component="Input"
x-component-props={{
style: {
width: 300,
},
}}
/>
<SchemaField.String
name="value"
title="值"
required
x-decorator="FormItem"
x-component="Input"
x-component-props={{
style: {
width: 300,
},
}}
/>
</SchemaField.Void>
<SchemaField.Void x-decorator="FormItem" x-component="ArrayItems.Remove" />
</SchemaField.Object>
</SchemaField.Array>
</SchemaField>
<FormButtonGroup.FormItem style={{ marginBottom: 20 }}>
<Button type="dashed" onClick={handleAddResoruce} block>
</Button>
</FormButtonGroup.FormItem>
</Form>
</Modal>
);
};
export default EditNftModal;

View File

@ -1,27 +1,75 @@
import React, { useRef, useState } from 'react';
import { message, Button, Upload, Space, Row } from 'antd';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { message } from 'antd';
// import { fetchTableData } from '@/utils/table';
import { RcFile } from 'antd/lib/upload';
import XLSX from 'xlsx';
import { fetchTableData } from '@/utils/table';
import EditNftModal from './components/EditNftModel';
import AddNftModal from './components/AddNftModel';
import PaySelectModal from '@/widget/PaySelectModal';
import { getNftData, createNft, editNft, getTokenId } from '@/services/nft/nft';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
const [NftModal, setNftModal] = useState(false);
const [visible, setVisible] = useState(false);
const [editVisible, setEditVisible] = useState(false);
const tableRef = useRef<ActionType>();
const [payVisible, setPayVisible] = useState(false);
const [nftData, setNFTData] = useState({});
const handleEdit = (row: any) => {
setNFTData(row);
setEditVisible(true);
tableRef.current?.reload();
};
const onImportExcel = (file: RcFile, FileList: RcFile[]) => {
let resData = [{}];
const fileReader = new FileReader();
fileReader.readAsBinaryString(file);
fileReader.onload = (event) => {
try {
const result = event.target?.result;
const workbook = XLSX.read(result, { type: 'binary' });
for (const sheet in workbook.Sheets) {
if (workbook.Sheets.hasOwnProperty(sheet)) {
resData = XLSX.utils.sheet_to_json(workbook.Sheets[sheet]);
break;
}
}
console.log(resData);
} catch (e) {
message.error('文件类型不正确');
console.log('文件类型不正确', e);
}
};
return false;
};
const columns: ProColumns<any>[] = [
{
title: '合约名称',
dataIndex: 'time',
dataIndex: 'contract',
width: '10%',
hideInSearch: true,
},
{
title: '导入分配NFT',
dataIndex: 'share',
hideInTable: true,
renderFormItem: (item, { type, defaultRender, ...rest }, form) => {
return (
<Upload beforeUpload={onImportExcel} onRemove={() => {}}>
<Button type="link"></Button>
</Upload>
);
},
},
{
title: 'NFT名称',
dataIndex: 'address',
dataIndex: 'Nft_name',
hideInSearch: true,
width: '20%',
},
{
title: '描述',
dataIndex: 'description',
hideInSearch: true,
width: '20%',
},
@ -31,33 +79,60 @@ const Address: React.FC = () => {
width: 150,
hideInSearch: true,
},
{
title: 'image',
dataIndex: 'image',
width: 150,
hideInSearch: true,
},
{
title: 'avatar',
dataIndex: 'avatar',
width: 150,
hideInSearch: true,
},
{
title: '操作',
valueType: 'option',
width: 180,
render: (_, row) => [
<a
key="edit"
onClick={() => {
handleEdit(row);
}}
>
</a>,
],
},
];
return (
<div>
<div>
<h3 className="part-title">NFT</h3>
<Space>
<Button
type="primary"
onClick={() => {
setVisible(true);
}}
>
NFT
</Button>
<Upload beforeUpload={onImportExcel} onRemove={() => {}}>
<Button type="primary">NFT</Button>
</Upload>
</Space>
</div>
<Table
columns={columns}
rowKey="id"
search={false}
actionRef={tableRef}
toolBarActions={[
{
type: 'add',
text: '添加NFT',
onConfirm: () => {
setVisible(true);
},
},
{
type: 'add',
text: '分发NFT',
onConfirm: () => {
setNftModal(true);
},
},
]}
// request={async (params) => {
// // return fetchTableData(, params);
// }}
request={async (params) => {
return fetchTableData(getNftData, params);
}}
/>
<AddNftModal
visible={visible}
@ -67,8 +142,30 @@ const Address: React.FC = () => {
onOk={async function (val: any): Promise<void> {
try {
const params = { ...val };
// await creatNftAddress(params);
console.log(val);
await createNft(params);
message.success('添加成功');
setVisible(false);
tableRef.current?.reload();
} catch (e) {
console.log(e);
message.success('发生错误');
setVisible(false);
}
}}
/>
<EditNftModal
visible={editVisible}
modalData={nftData}
onCancel={function () {
setVisible(false);
}}
onOk={async function (val: any): Promise<void> {
try {
const params = { ...val };
await editNft(params);
message.success('添加成功');
tableRef.current?.reload();
} catch (e) {
console.log(e);
message.success('发生错误');
@ -79,19 +176,20 @@ const Address: React.FC = () => {
<PaySelectModal
visible={payVisible}
onCancel={function () {
setVisible(false);
setPayVisible(false);
}}
onOk={async function (val: any): Promise<void> {
try {
const params = { ...val };
// await creatNftAddress(params);
console.log(params);
message.success('添加成功');
} catch (e) {
console.log(e);
message.success('发生错误');
setVisible(false);
}
// setPayVisible(false);
// try {
// const params = { ...val };
// // await creatNftAddress(params);
// console.log(params);
// message.success('添加成功');
// } catch (e) {
// console.log(e);
// message.success('发生错误');
// setPayVisible(false);
// }
}}
/>
</div>

View File

@ -0,0 +1,17 @@
import request from '@/utils/request';
//获取获取所有合约
export const getContractData = (params) => {
return request.request({
url: '/tbg/api/v1/contract/get',
method: 'get',
params,
});
};
// 创建合约
export const createContract = (data) => {
return request.request({
url: '/tbg/api/v1/erc721/create',
method: 'post',
data,
});
};

33
src/services/nft/nft.ts Normal file
View File

@ -0,0 +1,33 @@
import request from '@/utils/request';
//获取获取所有NFT
export const getNftData = (params) => {
return request.request({
url: '/tbg/api/v1/nft/get',
method: 'get',
params,
});
};
// 创建NFT
export const createNft = (data) => {
return request.request({
url: '/tbg/api/v1/nft/create',
method: 'post',
data,
});
};
//编辑NFT
export const editNft = (data) => {
return request.request({
url: '/tbg/api/v1/nft/update',
method: 'post',
data,
});
};
// 检查TokenId
export const getTokenId = (params) => {
return request.request({
url: '/tbg/api/v1/nft/check',
method: 'get',
params,
});
};

View File

@ -1,5 +1,5 @@
import React, { useRef, useState } from 'react';
import { createForm, onFieldChange } from '@formily/core';
import { createForm, onFieldReact } from '@formily/core';
import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal';
// import { fetchTableData } from '@/utils/table';
@ -10,7 +10,17 @@ interface PaySelectModalPropsType extends ModalProps {
onCancel: () => void;
// modalData: any;
}
const form = createForm({
effects() {
onFieldReact('input', (field) => {
if (field.query('type').value() == 2) {
field.display = 'none';
} else {
field.display = 'visible';
}
});
},
});
const SchemaField = createSchemaField({
components: {
FormItem,
@ -21,8 +31,6 @@ const SchemaField = createSchemaField({
},
});
const form = createForm({});
const PaySelectModal = ({ onOk, onCancel, ...rest }: PaySelectModalPropsType) => {
const [send, useSend] = useState(true);
@ -38,25 +46,24 @@ const PaySelectModal = ({ onOk, onCancel, ...rest }: PaySelectModalPropsType) =>
<Modal title="选择方式" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField>
<SchemaField.Number
<SchemaField.String
name="type"
title="支付方式"
required
x-decorator="FormItem"
x-component="Radio.Group"
enum={[
{ label: '秘钥支付', value: 1 },
{ label: '小狐狸钱包支付', value: 2 },
]}
x-component="Select"
x-decorator="FormItem"
/>
<SchemaField.String
name="key"
name="input"
title="秘钥"
x-decorator="FormItem"
x-component="Input"
x-component-props={{
placeholder: '请输入秘钥,若使用小狐狸支付则不需要输入',
}}
// x-component-props={{
// placeholder: '请输入秘钥,若使用小狐狸支付则不需要输入',
// }}
/>
</SchemaField>
</Form>

1802
yarn.lock

File diff suppressed because it is too large Load Diff