Commit 513ea508 authored by hanfeng zhang's avatar hanfeng zhang

Merge branch 'main' of gitlab.33.cn:HF_web/NFT

parents 8a505487 649c6831
......@@ -16,6 +16,7 @@
"core-js": "^3.6.5",
"epic-spinners": "^1.1.0",
"lodash": "^4.17.21",
"md5": "^2.3.0",
"register-service-worker": "^1.7.1",
"validator": "^13.6.0",
"vant": "^2.12.22",
......@@ -30,6 +31,7 @@
"devDependencies": {
"@types/async": "^3.2.7",
"@types/lodash": "^4.14.170",
"@types/md5": "^2.3.1",
"@types/validator": "^13.6.3",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
......
......@@ -42,6 +42,7 @@
<input v-else-if="type === 'input-num'"
:value="inputValue"
type="number"
:disabled="disabled"
@input="handleInput"
class="bg-transparent"
:placeholder="placeholder"
......@@ -50,6 +51,7 @@
<div class="flex flex-row items-center">
<input
@click="eventEmit(type)"
:disabled="true"
v-if="$store.state.create.pickedList.length === 0"
type="text"
class="bg-transparent"
......@@ -94,7 +96,7 @@
>
{{ name }}
</div>
<div :data-clipboard-text="name" ref="btn" @click="handleClickCopy">
<div :data-clipboard-text="name" ref="btn" @click="handleClickCopy" class="ml-1">
<app-icon name="icon-fuzhi" size="18px"></app-icon>
</div>
</div>
......
<template>
<div class="el-skeleton is-animated">
<div class="el-skeleton__item w-full" :class="_class" :style="_style"></div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
props: ["_class", "_style"],
});
</script>
<style lang="less" scoped>
.el-skeleton__item {
background: #f2f2f2;
display: inline-block;
border-radius: 4px;
}
.el-skeleton.is-animated .el-skeleton__item {
background: linear-gradient(90deg, #0c0b31 25%, #282740 37%, #0c0b31 63%);
background-size: 400% 100%;
animation: el-skeleton-loading 1.4s ease infinite;
}
@keyframes el-skeleton-loading {
0% {
background-position: 100% 50%;
}
to {
background-position: 0 50%;
}
}
</style>
\ No newline at end of file
<template>
<div>
<SkeletonRect _class="oneSkeleton" />
<div class="flex justify-between mt-2">
<div v-for="n in 4" :key="n">
<SkeletonRect _class="circleSkeleton" />
<SkeletonRect _class="paraSkeleton" />
</div>
</div>
<div class="flex justify-between mt-3 items-center">
<SkeletonRect _class="circle2Skeleton" class="mr-2" />
<div class="flex-grow mr-6">
<SkeletonRect _class="paraSkeleton" />
<SkeletonRect _class="paraSkeleton" />
</div>
</div>
<div class="mt-3">
<SkeletonRect _class="para2Skeleton" />
<SkeletonRect _class="para2Skeleton" />
<SkeletonRect _class="para2Skeleton" />
<SkeletonRect _class="para2Skeleton" />
</div>
<SkeletonRect _class="twoSkeleton mt-8" />
</div>
</template>
<script>
import Vue from "vue";
import SkeletonRect from "./Rect.vue";
export default Vue.extend({
components: {
SkeletonRect,
},
});
</script>
<style lang="less">
.oneSkeleton {
height: 191px;
}
.circleSkeleton {
width: 64px !important;
height: 64px !important;
border-radius: 100% !important;
}
.circle2Skeleton {
width: 48px !important;
height: 48px !important;
border-radius: 100% !important;
}
.paraSkeleton {
height: 20px;
}
.para2Skeleton {
height: 30px;
}
.twoSkeleton {
height: 400px;
}
</style>
\ No newline at end of file
import { Common } from './common'
import { NFTService } from './nftService'
import { NFTService } from './nftService/nftService'
import {UserService} from './userService'
......
import { Service } from './Service'
import { Service } from '../Service'
import { token } from '@/util/userInfoUtils'
import { iSaveData } from './types'
export class NFTService extends Service {
router = {
getMyList: {
......@@ -23,6 +24,10 @@ export class NFTService extends Service {
path: '/label/list',
dataType: 'application/x-www-form-urlencoded',
},
ossPolicy: {
path: '/oss/policy',
dataType: 'application/x-www-form-urlencoded',
},
getMd5: { path: '/nft/file/md5', dataType: 'multipart/form-data' },
save: { path: '/nft/save', dataType: 'multipart/form-data' },
publish: { path: '/nft/publish', dataType: 'application/json' },
......@@ -30,69 +35,67 @@ export class NFTService extends Service {
path: '/category/list',
dataType: 'application/x-www-form-urlencoded',
},
editCollection:{
editCollection: {
path: '/collection/add',
dataType: 'application/x-www-form-urlencoded'
dataType: 'application/x-www-form-urlencoded',
},
getCollectionList:{
getCollectionList: {
path: '/collection/list',
dataType: 'application/x-www-form-urlencoded',
}
},
}
constructor() {
super()
}
private getAuth(){
return 'Bearer '+ token.getToken()
private getAuth() {
return 'Bearer ' + token.getToken()
}
/**
* 获取NFT的详细信息
* @param id
* @returns
* @param id
* @returns
*/
async getNFTdetail(id: number):Promise<any>{
return await this.service.get(this.router.detail.path+'/'+id,{
headers: {
Authorization: this.getAuth(),
'Content-Type': this.router.detail.dataType,
},
})
async getNFTdetail(id: number): Promise<any> {
return await this.service.get(this.router.detail.path + '/' + id, {
headers: {
Authorization: this.getAuth(),
'Content-Type': this.router.detail.dataType,
},
})
}
/**
* 操作用户的收藏夹
* @param id
* @returns
* @param id
* @returns
*/
async editCollection(id:number){
return await this.service.post(this.router.editCollection.path,{},{
headers: {
Authorization: this.getAuth(),
'Content-Type': this.router.editCollection.dataType,
async editCollection(id: number) {
return await this.service.post(
this.router.editCollection.path,
{},
{
headers: {
Authorization: this.getAuth(),
'Content-Type': this.router.editCollection.dataType,
},
params: {
id: id,
},
},
params:{
id:id
}
})
)
}
async getCollection():Promise<any[]>{
return await this.service.get(this.router.getCollectionList.path,{
async getCollection(): Promise<any[]> {
return await this.service.get(this.router.getCollectionList.path, {
headers: {
Authorization: this.getAuth(),
'Content-Type': this.router.editCollection.dataType,
}
},
})
}
/**
*
* @returns 获取剧目主题表
......@@ -107,7 +110,7 @@ export class NFTService extends Service {
}
/**
* 获取题材类型
* @returns
* @returns
*/
async getCategory(): Promise<any[]> {
return await this.service.get(this.router.getCategory.path)
......@@ -118,7 +121,7 @@ export class NFTService extends Service {
* @param categoryId
* @returns
*/
async getMyList(categoryId?: number):Promise<any> {
async getMyList(categoryId?: number): Promise<any> {
return await this.service.get(this.router.getMyList.path, {
headers: {
Authorization: this.getAuth(),
......@@ -181,7 +184,7 @@ export class NFTService extends Service {
/**
* 获取md5
* @param id
*
*/
async getMd5(file: File) {
const fd = new FormData()
......@@ -195,6 +198,35 @@ export class NFTService extends Service {
}
/**
* 完成OSS签名
*/
async ossPolicy() {
const ret = await this.service.get(this.router.ossPolicy.path, {
headers: {
Authorization: this.getAuth(),
'Content-Type': this.router.ossPolicy.dataType,
},
})
return ret
}
async uploadFileToOss(file: File, data: any) {
const { accessid, dir, expire, host, policy, signature } = data as any
const fd = new FormData()
fd.append('name', file.name)
fd.append('key', dir + '${filename}')
fd.append('policy', policy)
fd.append('OSSAccessKeyId', accessid)
fd.append('success_action_status', '200')
fd.append('signature', signature)
fd.append('file', file)
return await fetch(host, {
method: 'POST',
body: fd,
})
}
/**
* 发布
* @param id
*/
......@@ -217,27 +249,13 @@ export class NFTService extends Service {
* @param id
*/
async save(
author: string,
categoryId: number,
fileHash: string,
isArchives: number,
name: string,
synopsis: string,
theme: string,
file: File,
isGrant: number,
) {
async save(data: iSaveData) {
const fd = new FormData()
fd.append('author', author)
fd.append('categoryId', categoryId.toString())
fd.append('fileHash', fileHash)
fd.append('isArchives', isArchives.toString())
fd.append('name', name)
fd.append('synopsis', synopsis)
fd.append('theme', theme)
fd.append('file', file)
fd.append('isGrant', String(isGrant))
Object.keys(data).forEach((keyName) => {
const value = data[keyName as keyof iSaveData]
fd.append(keyName, typeof value === 'number' ? String(value) : value)
})
return (await this.service.post(this.router.save.path, fd, {
headers: {
......
export interface iSaveData {
author: string
categoryId: number
fileHash: string
isArchives: number
name: string
synopsis: string
theme: string
isGrant: number
fileUrl?: string
fileName?:string
}
import Vue from 'vue'
import { Common } from './service/common'
import { Service } from './service/index'
import { NFTService } from './service/nftService'
import { NFTService } from './service/nftService/nftService'
import { UserService } from './service/userService'
import { UTIL_INTERFACE } from '@/util/util.types'
import VueRouter, { Route } from 'vue-router'
......
*{
margin: 0;
padding: 0
* {
margin: 0;
padding: 0;
}
body{
background-color:#1D2649;
body {
background-color: #1d2649;
}
.van-tabs__nav{
background-color: transparent !important;
.van-tabs__nav {
background-color: transparent !important;
}
.van-tabs__line{
display: none;
.van-tabs__line {
display: none;
}
.van-tab--active{
color: #EEF1F6 !important;
.van-tab--active {
color: #eef1f6 !important;
}
.van-badge{
background-color:#ED6F6F !important;
.van-badge {
background-color: #ed6f6f !important;
}
.list-container{
height: 100vh - 390px;
overflow-y: scroll;
.list-container {
height: 100vh - 390px;
overflow-y: scroll;
}
.van-overlay{
background-color: rgba(10,14,35,.95);
.van-overlay {
background-color: rgba(10, 14, 35, 0.95);
}
.fade-enter-active,
......@@ -38,81 +37,86 @@ body{
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
transition: all 0.3s ease;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
.step-progress__step--valid span{
font-size: 12px !important;
}
.step-progress__step span{
font-size: 12px !important;
}
.step-progress__step-label,
.step-progress__step--active .step-progress__step-label, .step-progress__step--active span{
font-size: 12px !important;
}
.page-scroll{
height: calc(100vh - 65px);
overflow-y: scroll;
}
.list-scroll{
height: calc(100vh - 400px);
overflow-y: scroll;
}
.myNFT-list-scroll{
height: calc(100vh - 290px);
overflow-y: scroll;
}
.collection-list{
height: calc(100vh - 60px);
overflow-y: scroll;
}
transform: translateX(10px);
opacity: 0;
}
.step-progress__step--valid span {
font-size: 12px !important;
}
.step-progress__step span {
font-size: 12px !important;
}
.step-progress__step-label,
.step-progress__step--active .step-progress__step-label,
.step-progress__step--active span {
font-size: 12px !important;
}
.van-dialog{
background-color: #1D2649;
.page-scroll {
height: calc(100vh - 65px);
overflow-y: scroll;
}
.list-scroll {
height: calc(100vh - 400px);
overflow-y: scroll;
}
.myNFT-list-scroll {
height: calc(100vh - 290px);
overflow-y: scroll;
}
.collection-list {
height: calc(100vh - 60px);
overflow-y: scroll;
}
.van-dialog {
background-color: #1d2649;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #8899b3;
.van-dialog__content,
.van-dialog__message,
.van-dialog__message--has-title {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #8899B3;
.van-dialog__content,.van-dialog__message, .van-dialog__message--has-title{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #EEF1F6;
}
.van-hairline--top, .van-dialog__footer, .van-button{
background-color: #1D2649;
}
.van-button__text{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #0078FF;
}
color: #eef1f6;
}
.van-hairline--top,
.van-dialog__footer,
.van-button {
background-color: #1d2649;
}
.van-button__text {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #0078ff;
}
}
.van-popup{
.van-action-sheet__gap{
.van-popup {
.van-action-sheet__gap {
background-color: #131934;
}
.van-action-sheet__item,.van-action-sheet__cancel{
background-color: #1D2649;
.van-action-sheet__item,
.van-action-sheet__cancel {
background-color: #1d2649;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #EEF1F6;
color: #eef1f6;
}
.van-action-sheet__cancel:active, .van-action-sheet__item:active{
.van-action-sheet__cancel:active,
.van-action-sheet__item:active {
background-color: #394267;
}
}
......@@ -120,4 +124,4 @@ body{
.van-popup .van-action-sheet__item, .van-popup .van-action-sheet__cancel{
padding:25px 0;
border-bottom: 1px solid rgba(255,255,255,.15);
}
\ No newline at end of file
}
<template>
<div class="register">
<div class="title text-font-white mt-5 mb-16 text-2xl">{{ title }}</div>
<div class="register pt-5">
<div class="flex justify-between items-center text-base">
<img src="@/assets/img/cmp_logo.png" class="h-12" alt="" />
<div class=" text-font-white header-text">注册/登录</div>
</div>
<div class="title text-font-white mt-10 mb-16 title-text">{{ title }}</div>
<PhoneInput
:placeholder="phoneConfig.placeholder"
:maxlength="phoneConfig.maxLen"
......@@ -367,3 +371,17 @@ export default Vue.extend({
},
});
</script>
<style scoped>
.header-text{
font-size: 16px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #EEF1F6;
}
.title-text{
font-size: 30px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #EEF1F6;
}
</style>
\ No newline at end of file
......@@ -145,6 +145,7 @@
key="count"
text="数量"
:value="1"
:disabled="true"
type="input-num"
class="text-font-white my-3"
@cellOnChange="
......@@ -175,6 +176,7 @@
</template>
<script lang="ts">
import { iSaveData } from "@/service/nftService/types";
import { Dialog } from "vant";
import Vue from "vue";
import { mapMutations, mapState } from "vuex";
......@@ -247,11 +249,12 @@ export default Vue.extend({
}),
validation(): boolean {
let disabled = true;
const { value_name, value_publisher } = this.createNFT;
const { value_name, value_publisher, value_des } = this.createNFT;
if (this.currentStep === 1) {
if (
value_name &&
value_publisher &&
value_des &&
this.$store.state.create.pickedList.length !== 0
) {
disabled = false;
......@@ -313,46 +316,75 @@ export default Vue.extend({
what(item: Function) {
item(this.$router.push("/Nft/create/pick"));
},
async publishNft() {
/* 加密上链的下一步点击回调 */
this.loading3 = true;
try {
await this.$service.nftService.publish({
fileHash: this.fileHash,
id: this.publish.id,
wallet: this.publish.wallet,
nftId: this.publish.nftId,
});
this.$router.back();
} catch (err) {
console.log(err);
}
this.loading3 = false;
},
async uploadFileToOss(file: File): Promise<string> {
const ossRet = (await this.$service.nftService.ossPolicy()) as any;
await this.$service.nftService.uploadFileToOss(file, ossRet);
const { dir, host } = ossRet;
return `${host}/${dir}/${file.name}`;
},
async encryptAndPushToChain() {
this.loading2 = true;
let mistake = false;
try {
let data = {
author: this.createNFT.value_publisher,
categoryId: 1,
name: this.createNFT.value_name,
synopsis: this.createNFT.value_des,
theme: this.pickedList.map((i: any) => i.text as string).toString(),
} as iSaveData;
if (this.createNFT.archives === 0) {
data = {
...data,
fileHash: this.fileHash,
isArchives: this.createNFT.archives,
};
} else if (this.createNFT.archives === 1) {
const fileUrl = await this.uploadFileToOss(this.file);
data = {
...data,
isArchives: this.createNFT.archives,
fileHash: this.fileHash,
fileUrl: fileUrl,
fileName: this.file.name,
isGrant: this.createNFT.grant,
};
}
const { id, nftId, wallet, fileHash } =
await this.$service.nftService.save(data);
this.publish.fileHash = fileHash;
this.publish.nftId = nftId;
this.publish.id = id;
this.publish.wallet = wallet;
} catch (err) {
mistake = true;
}
this.loading2 = false;
if (mistake) return;
},
async currentStepChange(val: number) {
if (this.currentStep === 2 && val === 1) {
this.loading2 = true;
let mistake = false;
try {
const { id, nftId, wallet, fileHash } =
await this.$service.nftService.save(
this.createNFT.value_publisher,
1,
this.fileHash,
this.createNFT.archives,
this.createNFT.value_name,
this.createNFT.value_des,
this.pickedList.map((i: any) => i.text as string).toString(),
this.file,
this.createNFT.grant
);
this.publish.fileHash = fileHash;
this.publish.nftId = nftId;
this.publish.id = id;
this.publish.wallet = wallet;
} catch (err) {
mistake = true;
}
this.loading2 = false;
if (mistake) return;
await this.encryptAndPushToChain();
} else if (this.currentStep === 3 && val === 1) {
this.loading3 = true;
try {
await this.$service.nftService.publish({
fileHash: this.fileHash,
id: this.publish.id,
wallet: this.publish.wallet,
nftId: this.publish.nftId,
});
this.$router.back();
} catch (err) {
console.log(err);
}
this.loading3 = false;
await this.publishNft();
}
if (this.currentStep < this.mySteps.length + 1) {
this.currentStep += val;
......
......@@ -78,6 +78,7 @@
import Vue from "vue";
import { Uploader, Loading } from "vant";
import { mapMutations, mapState } from "vuex";
import md5 from "md5";
enum uploadStatus {
NULL,
......@@ -120,15 +121,22 @@ export default Vue.extend({
}),
async afterRead(file: File) {
try {
const ab = await file.arrayBuffer();
const fileMd5 = md5(Buffer.from(ab));
this.status = uploadStatus.uploading;
const ret = await this.$service.nftService.getMd5(file);
// const ossRet = await this.$service.nftService.ossPolicy();
// const uploadRet = await this.$service.nftService.uploadFileToOss(
// file,
// ossRet
// );
this.setState({
fileName: file.name,
fileHash: ret,
fileHash: fileMd5,
file: file,
});
this.status = uploadStatus.success;
} catch (err) {
console.log(err, "show err");
this.status = uploadStatus.failed;
}
},
......
......@@ -4,6 +4,7 @@
loading....
</div> -->
<div class="w-11/12 mx-auto mt-6 text-font-white">
<SkeletonNftDetail v-if="false"/>
<app-collectionCard :colletionData='nftData'></app-collectionCard>
<div class="app-icons mx-auto grid grid-cols-4 my-6" v-if="isOwner">
<div
......@@ -127,6 +128,7 @@
<script lang="ts">
import Vue from "vue";
import SkeletonNftDetail from "@/components/common/Skeleton/SkeletonNftDetail.vue"
const apps = [
{
text: "版权认证",
......@@ -173,6 +175,7 @@ export default Vue.extend({
'app-btn':()=>import('@/components/common/Btn.vue'),
// 'app-scrollbar':()=>import('@/components/common/ScrollBar.vue'),
"app-collectionCard": () => import("@/components/CollectionCard.vue"),
SkeletonNftDetail,
},
methods:{
async setMyCollection():Promise<void>{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment