Merge pull request '区块链版本' (#501) from Nigel/forgeplus-react:master_zxh into dev_nanda

This commit is contained in:
xxq250 2023-01-12 21:32:26 +08:00
commit cd2b383b0d
16 changed files with 956 additions and 20 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.idea/
# Logs
logs
*.log

View File

@ -32,7 +32,8 @@ export function initAxiosInterceptors(props) {
// 判断网络是否连接
initOnlineOfflineListener();
var proxy = "https://testforgeplus.trustie.net";
// var proxy = "https://testforgeplus.trustie.net";
var proxy = "http://localhost:3001";
//响应前的设置
axios.interceptors.request.use(
config => {

View File

@ -0,0 +1,119 @@
import React , { useState , useEffect } from 'react';
import { Spin } from 'antd';
import { Blueback } from '../Component/layout';
import Editor from "react-monaco-editor";
import Modals from './DisposeModal';
import FileLanguage from '../Component/OpsFileLanguage';
import axios from 'axios';
function Dispose(props){
const [ spining , setSpining ] = useState(true);
const [ info , setInfo ] = useState('.trustie-pipeline.yml');
const [ visible , setVisible ] = useState(false);
const [ ymlValue , setYmlValue ] = useState("");
const [ sha , setSha ] = useState(undefined);
const [ fileLanguage , setFileLanguage ] = useState(undefined);
const [ first , setFirst ] = useState(false);
let projectsId = props.match.params.projectsId;
let owner = props.match.params.owner;
useEffect(()=>{
if(projectsId){
const url = `/${owner}/${projectsId}/get_trustie_pipeline.json`;
axios.get(url,{
params:{
project_id:projectsId
}
}).then(result=>{
if(result && result.data.content){
setInfo(result.data.name);
setYmlValue(result.data.content);
setFirst(true);
setSha(result.data.sha);
}else{
setFirst(false);
}
setSpining(false);
}).catch(error=>{
console.log(error);
})
}
},[projectsId])
//
function changeEditor(value){
setYmlValue(value);
}
//
function select_language(value,array){
setFileLanguage(value);
setYmlValue( array && array.content);
}
//
function submit(){
let url = '';
const { defaultBranch } = props;
let params = {
branch: defaultBranch,
content:ymlValue,
filepath:info,
message:''
}
if(first){
// true
url = `/${owner}/${projectsId}/update_trustie_pipeline.json`;
axios.put(url,{
...params,
sha
}).then(result=>{
if(result){
setVisible(true);
}
}).catch(error=>{
console.log(error);
})
}else{
url = `/${owner}/${projectsId}/create_file.json`;
axios.post(url,params).then(result=>{
if(result){
setVisible(true);
}
}).catch(error=>{
console.log(error);
})
}
}
function suresubmit(){
setVisible(false);
props.history.push(`/projects/${owner}/${projectsId}/devops/list`);
}
return(
<Spin spinning={spining}>
<Modals visible={visible} closeFunc={(flag)=>setVisible(flag)} sureFunc={suresubmit}></Modals>
<p>编程语言</p>
<div className="mt20 mb20">
<FileLanguage language={fileLanguage} select_language={select_language}/>
</div>
<p>配置脚本</p>
<div className="editorBody">
<p className="editorHead">{info}</p>
<Editor
height="300px"
language={"yml"}
theme={"vs-grey"}
defaultValue="请输入内容"
value={ymlValue}
options={"editor_options"}
onChange={changeEditor}
></Editor>
</div>
<Blueback onClick={submit}>确定提交</Blueback>
</Spin>
)
}
export default Dispose;

View File

@ -1,5 +1,5 @@
import React, { Component } from "react";
import { Tabs } from 'antd';
import { Tabs, Select } from 'antd';
import { Link } from "react-router-dom";
import axios from "axios";
import { getImageUrl , turnbar } from "educoder";
@ -19,6 +19,7 @@ import RenderHtml from "../../components/render-html";
import "../Order/order.scss";
import MergeLinkFooter from "./MergeLinkFooter";
const Option = Select.Option;
const TextArea = Input.TextArea;
class MessageCount extends Component {
constructor(props) {
@ -40,6 +41,11 @@ class MessageCount extends Component {
conflict_files:[],
copyVisible:false,
fix_issue_id: "",
unclosed_issue_list: [],
ownername: undefined,
reponame: undefined,
};
}
@ -53,6 +59,7 @@ class MessageCount extends Component {
SpinFlag: true,
});
this.getDetail();
this.getUnclosedIssueList();
// this.clickBody();
// 监听路由query传参实现nps调研效果
@ -89,6 +96,8 @@ class MessageCount extends Component {
getDetail = () => {
const { projectsId, mergeId, owner } = this.props.match.params;
this.state.ownername = owner;
this.state.reponame = projectsId;
const url = `/${owner}/${projectsId}/pulls/${mergeId}.json`;
axios
.get(url)
@ -149,7 +158,7 @@ class MessageCount extends Component {
SpinMerge: true,
});
const { projectsId , owner } = this.props.match.params;
const { data, title, body, mergekey, pr_status } = this.state;
const { data, title, body, mergekey, pr_status, fix_issue_id } = this.state;
const url = `/${owner}/${projectsId}/pulls/${data.pull_request.id}/pr_merge.json`;
axios
.post(url, {
@ -158,6 +167,7 @@ class MessageCount extends Component {
do: mergekey,
body: body,
title: title,
fix_issue_id: fix_issue_id,
})
.then((result) => {
if (result) {
@ -194,6 +204,47 @@ class MessageCount extends Component {
});
};
changefixissue = (e) => {
this.setState({
fix_issue_id: parseInt(e.target.value),
});
};
renderIssueList = (list) => {
if (list && list.length > 0) {
return list.map((item, index) => {
return (
<Option
key={item[0]}
value={item[0]}
>
{item[0] + ":" + item[1]}
</Option>
);
});
}
};
getUnclosedIssueList = () => {
const url = `/projects/blockchain/get_unclosed_issue_list`;
axios.get(url,{
params:{
"ownername": this.state.ownername,
"reponame": this.state.reponame
}
}).then(result=>{
if(result && result.data){
this.state.unclosed_issue_list = result.data.unclosed_issues;
}
}).catch(error=>{
console.log(error);
})
}
selectIssueChange = (selectedKeys, info) => {
this.state.fix_issue_id = selectedKeys;
};
submitmerge = () => {
if (this.state.mergekey === "rebase") {
this.setState({
@ -593,6 +644,21 @@ class MessageCount extends Component {
value={this.state.body}
onChange={this.changbodypr}
/>
{/*<Input*/}
{/* type="select"*/}
{/* placeholder="请选择解决的issue"*/}
{/* style={{ marginTop: 20 }}*/}
{/* value={this.state.fix_issue_id}*/}
{/* onChange={this.changefixissue}*/}
{/*/>*/}
<Select
id = {'select_project'}
style={{ marginTop: 20, width: "500px" }}
placeholder={"请选择解决的易修"}
onSelect={this.selectIssueChange}
>
{this.renderIssueList(this.state.unclosed_issue_list)}
</Select>
</div>
<div
className="clearfix mt15"

View File

@ -7,6 +7,8 @@ import { AlignCenter } from '../Component/layout';
import '../css/index.scss';
import './new.scss'
import { findDOMNode } from 'react-dom'
import axios from 'axios';
const Option = Select.Option;
class Index extends Component {
@ -46,11 +48,11 @@ class Index extends Component {
license_name: undefined,
ignore_name: undefined,
descNum:0,
categoreFlag:false,
languageFlag:false,
ignoreFlag:false,
licenseFlag:false,
show_div:"hidden",
}
}
componentDidMount = () => {
@ -77,7 +79,7 @@ class Index extends Component {
getOwner=()=>{
const { OIdentifier } = this.props.match.params;
const { user_id } = this.props && this.props.current_user;
const url = `/owners.json`;
axios.get(url).then(result=>{
if(result && result.data){
@ -200,8 +202,8 @@ class Index extends Component {
isSpin: true
})
const { projectsType } = this.props.match.params;
const {
project_language_id, project_category_id, license_id, ignore_id , owners_id ,
const {
project_language_id, project_category_id, license_id, ignore_id , owners_id ,
ignoreFlag,licenseFlag,categoreFlag,languageFlag
} = this.state;
const decoderPass = Base64.encode(values.password);
@ -299,6 +301,19 @@ class Index extends Component {
}
}
// add by zxh: handleBlockchainChange
handleBlockchainChange = (event) => {
if (this.state.show_div == 'hidden') {
this.setState({
show_div: "visible"
});
} else {
this.setState({
show_div: "hidden"
});
}
}
changeDesc=(e)=>{
let value = e.target.value;
this.setState({
@ -444,7 +459,7 @@ class Index extends Component {
validator:(rule, value, callback) => this.checkId(rule, value, callback, OwnerList, '拥有者')
}],
})(
<AutoComplete
<AutoComplete
style={{width:"260px",height:"35px"}}
placeholder="请选择拥有者"
onChange={(value, e) => this.ChangePlatform(value, e, 'owners', OwnerList)}
@ -483,7 +498,7 @@ class Index extends Component {
)}
</Form.Item>
<div className="pr">
<span className="toprightNum">{descNum}/200</span>
{/*<span className="toprightNum">{descNum}/200</span>*/}
<Form.Item
label="项目简介"
colon={false}
@ -496,7 +511,7 @@ class Index extends Component {
)}
</Form.Item>
</div>
{
(projectsType === "deposit" || !projectsType) &&
<React.Fragment>
@ -563,6 +578,41 @@ class Index extends Component {
<Checkbox value="limit">将项目设为私有<span className="font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
)}
</Form.Item >
{/*增加区块链选项,不要求必选,默认是选择的*/}
<Form.Item
label="确权"
style={{ margin: "0px" }}
className="privatePart"
>
{getFieldDecorator('blockchain')(
<Checkbox value="limit" onClick={this.handleBlockchainChange}>项目加入确权机制<span className="ml15 font-13 color-grey-9">(贡献确权上链并使用token机制)</span></Checkbox>
)}
</Form.Item >
<Form.Item
style={{ margin: "15px", display: "block" }}
className="privatePart"
ref={(blockchain_item => {this.blockchain_item = blockchain_item})}
>
<div class="div_flex_row" style={{visibility: this.state.show_div == "visible" ? "visible": "hidden"}}>
{getFieldDecorator('blockchain_token_all', {
rules: [{
required: false, message: '请填写项目token总数(单位:枚)'
}],
})(
<Input type={'number'} min={0} step={1} placeholder="请填写项目token总数(单位:枚)" />
)}
{getFieldDecorator('blockchain_init_token', {
rules: [{
required: false, message: '请填写项目创始人获取token总数(单位:枚)'
}],
})(
<Input type={'number'} min={0} max={100} step={1} placeholder="请填写项目创始人获去总token的百分比(%)" />
)}
</div>
</Form.Item>
{
projectsType && projectsType === "mirror" &&
<Form.Item
@ -610,7 +660,7 @@ class Index extends Component {
<Checkbox checked={languageFlag} onChange={(e)=>this.showLanguageFunc(e)}>项目语言</Checkbox>
)}
</Form.Item>
{languageFlag &&
{languageFlag &&
<Form.Item>
{getFieldDecorator('project_language', {
rules: [{

View File

@ -71,4 +71,9 @@
.newContent_inline > .ant-form-item:nth-child(2){
margin-left:0px
}
}
.div_flex_row {
display: flex;
flex-direction: row;
}

View File

@ -37,11 +37,13 @@ class Detail extends Component {
visible: false,
journal_spin: false,
edit_spin: false,
blockchain_token_num: 0,
};
}
componentDidMount = () => {
this.getDetail();
this.getBlockchainTokenNum();
};
componentDidUpdate=()=>{
@ -76,6 +78,20 @@ class Detail extends Component {
});
};
getBlockchainTokenNum = () => {
const { projectsId, orderId, owner } = this.props.match.params;
const url = `/blockchain/issue/get_token_num`;
axios.post(url,{
"issue_id": {orderId}
}).then(result=>{
if(result && result.data){
this.state.blockchain_token_num = result.data.blockchain_token_num;
}
}).catch(error=>{
console.log(error);
})
};
handleok = () => {
this.setState({
isShow: false,
@ -346,6 +362,10 @@ class Detail extends Component {
)}
</span>
</p>
<p className="grid-item-left pb15">
<span className="issue_detail_info">悬赏金额:</span>
<span>{this.state.blockchain_token_num}</span>
</p>
<p className="grid-item-left pb15">
<span className="issue_detail_info">里程碑:</span>
<span className="title_overflow">

View File

@ -13,6 +13,7 @@ const Option = Select.Option;
class order_form extends Component {
constructor(props) {
super(props);
this.getTokenProject(props.current_user.user_id, this.props.match.params.owner, this.props.match.params.projectsId);
this.state = {
branch_name: "",
issue_tag_ids: "",
@ -36,9 +37,27 @@ class order_form extends Component {
show_token: false,
cannot_edit: false,
issue_current_user: true,
issue_token_num: 0,
blockchain_token_num: 0,
atWhoLoginList:undefined
};
}
getTokenProject = (user_id, owner_login, project_name) => {
const url = `/users/blockchain/balance_project`;
axios.post(url,{
user_id: user_id,
owner_login: owner_login,
project_name: project_name
}).then(result=>{
if(result && result.data){
this.state.issue_token_num = result.data.balance;
}
}).catch(error=>{
console.log(error);
})
}
componentDidUpdate=(prevPros)=>{
if(prevPros && this.props && this.props.checkIfLogin()===false){
this.props.history.push("/403")
@ -98,7 +117,7 @@ class order_form extends Component {
if (result) {
let data ={
branch_name: result.data.branch_name,
issue_tag_ids:
issue_tag_ids:
result.data.issue_tags && result.data.issue_tags[0].id ?
String(result.data.issue_tags[0].id) : ""
,
@ -153,11 +172,11 @@ class order_form extends Component {
description:"####问题描述\n\n\n####重现问题步骤\n\n\n####截图\n\n\n####建议解决办法\n",
}
this.setState({ ...data });
this.props.form.setFieldsValue({
this.props.form.setFieldsValue({
...this.state,
fixed_version_id: milepostId || ""
fixed_version_id: milepostId || ""
});
}else if(this.props.form_type !== "new"){
this.get_detail();
}else{
@ -186,7 +205,7 @@ class order_form extends Component {
// 创建
handleSubmit = () => {
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
this.setState({
@ -212,7 +231,7 @@ class order_form extends Component {
if (values.issue_tag_ids.length > 0) {
values.issue_tag_ids = [values.issue_tag_ids];
}
const { description, start_date, due_date, issue_type , atWhoLoginList } = this.state;
const { description, start_date, due_date, issue_type , atWhoLoginList, blockchain_token_num } = this.state;
if (form_type !== "edit") {
const url = `/${owner}/${projectsId}/issues.json`;
axios.post(url, {
@ -223,6 +242,7 @@ class order_form extends Component {
due_date: due_date,
issue_type: issue_type,
receivers_login:atWhoLoginList,
blockchain_token_num: blockchain_token_num
}).then((result) => {
if (result && result.data.id) {
this.props.showNotification("任务创建成功!");
@ -370,6 +390,20 @@ class order_form extends Component {
}
};
adjustTokenNum = (e) => {
var val = e.target.value;
val = parseInt(val);
if (val > this.state.issue_token_num) {
val = this.state.issue_token_num;
e.target.value = this.state.issue_token_num;
} else {
e.target.value = val;
}
this.setState({
blockchain_token_num: val,
});
}
render() {
const { getFieldDecorator } = this.props.form;
const { projectsId , owner } = this.props.match.params;
@ -456,9 +490,21 @@ class order_form extends Component {
</div>
<div className="list-left list-left-padding issue-edit-form-right">
<div className="pd20 background-f issue-form-right">
<Form.Item label="悬赏金额">
{getFieldDecorator("issue_token_num", {rules: []})(
<Input
ref={(input) => this.input_token=input}
type={"number"}
min={0}
max={this.state.issue_token_num}
onChange={this.adjustTokenNum.bind(this)}
placeholder="定义悬赏token数量"
/>
)}
</Form.Item>
<Form.Item label="指派成员">
{getFieldDecorator("assigned_to_id", {rules: []})(
<Select
<Select
showSearch
className="searchIcon"
showArrow={true}

View File

@ -0,0 +1,152 @@
import React , { useEffect , useState } from 'react';
import axios from 'axios';
import { Select, Input, Button } from 'antd';
const Option = Select.Option;
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = 'https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.min.js';
document.head.appendChild(script);
const limit = 10;
function BlockchainExCreate(props){
const [ status , setStatus ] = useState(0);
const [ total , setTotal ] = useState(0);
const [ list , setList ] = useState([]);
const [ authorityValBox , setAuthorityValBox] = useState(false);
const [ selectKey , setSelectKey ] = useState("list");
const { selectedOption, setSelectedOption } = useState("选择交易的项目");
let user = props.current_user;
useEffect(()=>{
if(user && user.login){
getInfo();
}
}, [])
// read all the projects that the user has more than 0 tokens
function getInfo(){
const url = `/users/blockchain/balance`;
axios.get(url,{
params:{
"user_id": user.user_id
}
}).then(result=>{
if(result && result.data){
setStatus(result.data.status);
if(status == 0) {
setList(result.data.projects);
setTotal(result.data.total_count);
}
}
}).catch(error=>{
console.log(error);
})
}
function createTrade(user_id) {
const url = '/users/blockchain/create_trade';
axios.post(url, {
"user_id": user_id,
"project_id": document.getElementById("input_project").value,
"money": document.getElementById("money").value,
"token_num": document.getElementById("token_num").value,
// "description": document.getElementById("input_description").value
}).then((result) => {
if(result && result.data){
if (result.data.status == 2) {
window.location.reload();
}
}
})
}
function renderProjectList(list) {
if (list && list.length > 0) {
return list.map((item, index) => {
return (
<Option
key={index+1}
value={item[1].id+"/"+item[2]}
>
{item[0].login + "/" + item[1].name}
</Option>
);
});
}
};
function selectProjectChange(e) {
document.getElementById("money").removeAttribute("hidden");
document.getElementById("token_num").removeAttribute("hidden");
document.getElementById("submit_btn").removeAttribute("hidden");
// document.getElementById("input_description").removeAttribute("hidden");
document.getElementById("token_num").setAttribute("max", e.split('/')[1]);
document.getElementById("input_project").value=e.split('/')[0];
}
function adjustTokenNum() {
var val = document.getElementById("token_num").value;
val = parseInt(val);
var max_val = document.getElementById("token_num").getAttribute("max");
if (val > max_val) {
document.getElementById("token_num").value = max_val;
} else {
document.getElementById("token_num").value = val;
}
}
return(
<div style={{minHeight:"400px"}}>
<span className="blockchain_proj_select ml20">
<Select
id = {'select_project'}
style={{width: "220px"}}
placeholder={"选择交易的项目"}
onSelect={(e) => {selectProjectChange(e)}}
>
{renderProjectList(list)}
</Select>
</span>
<span>
<Input
id={"input_project"}
hidden={true}
/>
</span>
<span>
<Input
id={"input_project"}
hidden={true}
/>
</span>
<span className="blockchain_input_num ml20">
<Input
type={'number'}
id={"token_num"}
placeholder={"输入售卖币数量"}
hidden={true}
min={1}
onInput={() => {adjustTokenNum()}}
/>
</span>
<span className="blockchain_input_num ml20">
<Input
id={"money"}
placeholder={"输入售卖金额"}
hidden={true}
/>
</span>
<Button hidden={true} id='submit_btn' className="primary ml20" onClick={() => {createTrade(user.user_id)}}>确认</Button>
</div>
)
}
export default BlockchainExCreate;

View File

@ -0,0 +1,71 @@
import React , { useEffect , useState } from 'react';
import moment from "moment";
import { Button ,Spin , Pagination , Popconfirm } from 'antd';
import { Link } from 'react-router-dom';
import Nodata from '../Nodata';
import axios from 'axios';
const limit = 10;
function BlockchainExHistory(props){
const [ list , setList ] = useState([]);
let user = props.current_user;
useEffect(()=>{
if(user && user.login){
getInfo();
}
},[])
function getInfo(){
const url = `/users/blockchain/get_history_trades`;
axios.get(url,{
params:{
"user_id": user.user_id
}
}).then(result=>{
if(result && result.data){
setList(result.data.results);
}
}).catch(error=>{
console.log(error);
})
}
return(
<div style={{minHeight:"400px"}}>
{
list && list.length > 0 ?
<ul className="CIList">
<li>
<span>
<span hidden={true}></span>
<span className="blockchain_username ml20">{"卖家名"}</span>
<span className="blockchain_proj ml20">{"项目创建者/项目名"}</span>
<span className="blockchain_proj ml20">{"token数量:价值"}</span>
<span className="blockchain_username ml20">{"买家名"}</span>
<span className="blockchain_time ml20">{"交易创建时间"}</span>
<span className="blockchain_time ml20">{"交易截止时间"}</span>
</span>
</li>
{list.map((item,key)=>{
return(
<li key={key}>
<span>
<span id={key} hidden={true}>{item[3].id}</span>
<span className="blockchain_username ml20">{item[0].login}</span>
<span className="blockchain_proj ml20">{item[1].login + "/" + item[2].name}</span>
<span className="blockchain_proj ml20">{item[3].token_num + ":" + item[3].money}</span>
<span className="blockchain_username ml20">{item[4].login}</span>
<span className="blockchain_time ml20">{moment(item[3].created_at).format('YYYY-MM-DD HH:mm:ss')}</span>
<span className="blockchain_time ml20">{moment(item[3].updated_at).format('YYYY-MM-DD HH:mm:ss')}</span>
</span>
</li>
)
})}
</ul>
:<Nodata _html="无历史交易"/>
}
</div>
)
}
export default BlockchainExHistory;

View File

@ -0,0 +1,93 @@
import React , { useEffect , useState } from 'react';
import { Button ,Spin , Pagination , Popconfirm } from 'antd';
import { Link } from 'react-router-dom';
import Nodata from '../Nodata';
import axios from 'axios';
const limit = 10;
function BlockchainExList(props){
const [ list , setList ] = useState([]);
let user = props.current_user;
useEffect(()=>{
if(user && user.login){
getInfo();
}
},[])
function getInfo(){
const url = `/users/blockchain/get_trades`;
axios.get(url,{
}).then(result=>{
if(result && result.data){
setList(result.data.results);
}
}).catch(error=>{
console.log(error);
})
}
function trade(index) {
const url = `/users/blockchain/trade`;
axios.post(url,{
"user_id": user.user_id,
"user_id2": user.user_id,
"trade_id": document.getElementById(index).innerText
}).then(result=>{
if(result && result.data){
if (result.data.status == 2) {
window.location.reload();
}
}
}).catch(error=>{
console.log(error);
})
}
return(
<div style={{minHeight:"400px"}}>
{
list && list.length > 0 ?
<ul className="CIList">
<li>
<span>
<span hidden={true}></span>
<span className="blockchain_username ml20">卖家名</span>
<span className="blockchain_proj ml20">项目创建者/项目名</span>
<span className="blockchain_balance ml20">token数</span>
<span className="blockchain_balance ml20">售价</span>
</span>
{
<Button hidden={true}>交易</Button>
}
</li>
{list.map((item,key)=>{
return(
<li key={key}>
<span>
<span id={key} hidden={true}>{item[3].id}</span>
<span className="blockchain_username ml20">{item[0].login}</span>
<span className="blockchain_proj ml20">{item[1].login + "/" + item[2].name}</span>
<span className="blockchain_balance ml20">{item[3].token_num}</span>
<span className="blockchain_balance ml20">{item[3].money}</span>
</span>
{
<Popconfirm
title="确定交易?"
onConfirm={() => {trade(key)}}
okText="确定"
cancelText="取消"
>
<Button>交易</Button>
</Popconfirm>
}
</li>
)
})}
</ul>
:<Nodata _html="暂无交易"/>
}
</div>
)
}
export default BlockchainExList;

View File

@ -0,0 +1,38 @@
import React , { useEffect , useState } from 'react';
import { Menu } from 'antd';
import './Index.scss';
import BlockchainExCreate from './BlockchainExCre';
import BlockchainExList from './BlockchainExList';
import BlockchainExVerify from './BlockchainExVerify';
import BlockchainExHistory from './BlockchainExHistory';
function BlockchainExMenu(props){
const [ selectKey , setSelectKey ] = useState("list");
function changeKeys(e){
setSelectKey(e.key);
}
function renderMenu() {
if (selectKey === "list") {return (<BlockchainExList {...props}/>)}
else if (selectKey == 'create') {return (<BlockchainExCreate {...props}/>)}
else if (selectKey == "verify") {return (<BlockchainExVerify {...props}/>)}
else if (selectKey == "history") {return (<BlockchainExHistory {...props}/>)}
}
return(
<div>
<Menu mode="horizontal" className="menuStyle" onClick={changeKeys} selectedKeys={[selectKey]}>
<Menu.Item key="list">交易列表</Menu.Item>
<Menu.Item key="create">创建交易</Menu.Item>
<Menu.Item key="verify">确认交易</Menu.Item>
<Menu.Item key="history">历史交易</Menu.Item>
</Menu>
{
renderMenu()
}
</div>
)
}
export default BlockchainExMenu;

View File

@ -0,0 +1,99 @@
import React , { useEffect , useState } from 'react';
import { Button ,Spin , Pagination , Popconfirm } from 'antd';
import Nodata from '../Nodata';
import moment from "moment";
import axios from 'axios';
const limit = 10;
function BlockchainExVerify(props){
const [ list , setList ] = useState([]);
let user = props.current_user;
useEffect(()=>{
if(user && user.login){
getInfo();
}
},[])
function getInfo(){
const url = `/users/blockchain/get_verify_trades`;
axios.get(url,{
params:{
"user_id": user.user_id
}
}).then(result=>{
if(result && result.data){
setList(result.data.results);
}
}).catch(error=>{
console.log(error);
})
}
function verify_trade(index) {
const url = `/users/blockchain/verify_trade`;
axios.post(url,{
"user_id": user.user_id,
"trade_id": document.getElementById(index).innerText
}).then(result=>{
if(result && result.data){
if (result.data.status == 2) {
window.location.reload();
}
}
}).catch(error=>{
console.log(error);
})
}
return(
<div style={{minHeight:"400px"}}>
{
list && list.length > 0 ?
<ul className="CIList">
<li>
<span>
<span hidden={true}></span>
<span className="blockchain_username ml20">卖家名</span>
<span className="blockchain_proj ml20">项目创建者/项目名</span>
<span className="blockchain_proj ml20">token数量:价值</span>
<span className="blockchain_username ml20">买家名</span>
<span className="blockchain_time ml20">交易时间</span>
</span>
{
<Button hidden={true}></Button>
}
</li>
{list.map((item,key)=>{
return(
<li key={key}>
<span>
<span id={key} hidden={true}>{item[3].id}</span>
<span className="blockchain_username ml20">{item[0].login}</span>
<span className="blockchain_proj ml20">{item[1].login + "/" + item[2].name}</span>
<span className="blockchain_proj ml20">{item[3].token_num + ":" + item[3].money}</span>
<span className="blockchain_username ml20">{item[4].login}</span>
<span className="blockchain_time ml20">{moment(item[3].created_at).format('YYYY-MM-DD HH:mm:ss')}</span>
</span>
{
<Popconfirm
title="确认收货?"
onConfirm={() => {verify_trade(key)}}
okText="确认"
cancelText="取消"
>
<Button>确认收货</Button>
</Popconfirm>
}
</li>
)
})}
</ul>
:<Nodata _html="暂无待处理交易"/>
}
</div>
)
}
export default BlockchainExVerify;

View File

@ -0,0 +1,115 @@
import React , { useEffect , useState , forwardRef , useCallback } from 'react';
import { Button , Modal , Form , Input } from 'antd';
import { AlignCenter } from '../Component/layout';
import axios from 'axios';
import Modals from '../Component/Modal';
import PasswordAuthority from '../Component/PasswordAuthority';
import Nodata from "../Nodata";
function BlockchainTransfer(props){
const [ status , setStatus ] = useState(0);
const [ total , setTotal ] = useState(0);
const [ list , setList ] = useState([]);
const [ authorityValBox , setAuthorityValBox] = useState(false);
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
const helper = useCallback(
(label, name, rules, widget, isRequired) => (
<React.Fragment>
<span className={isRequired ? "required" : ""}>{label}</span>
<Form.Item>
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
</Form.Item>
</React.Fragment>
),
[]
);
let user = props.current_user;
useEffect(()=>{
if(user && user.login){
getInfo();
}
},[])
// read all the projects that the user has more than 0 tokens
function getInfo(){
const url = `/users/blockchain/balance`;
axios.get(url,{
params:{
"user_id": user.user_id
}
}).then(result=>{
if(result && result.data){
setStatus(result.data.status);
if(status == 0) {
setList(result.data.projects);
setTotal(result.data.total_count);
}
}
}).catch(error=>{
console.log(error);
})
}
function okAuthority(){
setAuthorityValBox(false);
}
function cancelAuthority(){
setAuthorityValBox(false);
}
function submit(owner, project, balance, id) {
const url = '/users/blockchain/transfer';
axios.post(url, {
payer_id: user.user_id,
project_id: project.id,
transfer_amount: document.getElementById("amount_" + id).value,
transfer_login: document.getElementById("login_" + id).value
}).then((result) => {
if (result && result.data) {
if (result.data.status == 2) {
window.location.reload();
}
}
})
}
return(
<div style={{minHeight:"400px"}}>
<PasswordAuthority authorityValBox={authorityValBox} successFunc={okAuthority} cancelFunc={cancelAuthority}></PasswordAuthority>
{
status == 0 && list && list.length > 0 ?
<ul className="BalanceList">
<li>
<span className="blockchain_proj green ml20">项目创建者/项目名</span>
<span className="blockchain_balance green ml20">token总量</span>
<span className="blockchain_input_to ml20">目标转账用户</span>
<span className="blockchain_input_num ml20">转账token数量</span>
<Button hidden={true}></Button>
</li>
{list.map((item,index)=>{
return(
<li key={index}>
<Form>
<span className="blockchain_proj green ml20">{item[0].login + "/" + item[1].name}</span>
<span className="blockchain_balance green ml20">{item[2]}</span>
<span className="blockchain_input_to ml20"><Input type="text" placeholder={"请输入转给哪个用户(login)"} name={"transfer_login"} id={"login_"+index} /></span>
<span className="blockchain_input_num ml20"><Input type="text" placeholder={"请输入转账token数量"} name={"transfer_amount"} id={"amount_"+index} /></span>
<Button className="primary ml20" onClick={() => {submit(item[0], item[1], item[2], index)}}>确认</Button>
</Form>
</li>
)
})}
</ul>
:<Nodata _html="暂无数据"/>
}
</div>
)
}
export default Form.create()(forwardRef(BlockchainTransfer));;

View File

@ -264,6 +264,48 @@ ul.ant-menu.menuStyle{
color: #28BD6C;
}
}
.blockchain_proj{
display: inline-block;
font-size: 12px;
height: 22px;
width: 180px;
}
.blockchain_balance{
display: inline-block;
font-size: 12px;
height: 22px;
width: 100px;
}
.blockchain_input_to{
display: inline-block;
font-size: 12px;
height: 40px;
width: 150px;
}
.blockchain_input_num{
display: inline-block;
font-size: 12px;
height: 40px;
width: 150px;
}
.blockchain_proj_select{
display: inline-block;
font-size: 12px;
height: 40px;
width: 220px;
}
.blockchain_username{
display: inline-block;
font-size: 12px;
height: 40px;
width: 60px;
}
.blockchain_time{
display: inline-block;
font-size: 12px;
height: 40px;
width: 130px;
}
.CIList{
padding:0px 30px;
min-height: 400px;

View File

@ -23,6 +23,14 @@ const InfosDevOps = Loadable({
loader: () => import("./devOpsCI"),
loading: Loading,
});
const InfosBlockchainTransfer = Loadable({
loader: () => import("./BlockchainTransfer"),
loading: Loading,
});
const InfosBlockchainExMenu = Loadable({
loader: () => import("./BlockchainExMenu"),
loading: Loading,
});
const InfosDevOpsCD = Loadable({
loader: () => import("./devOpsCD"),
loading: Loading,
@ -31,11 +39,11 @@ const InfosDevOpsCD = Loadable({
const Statistics = Loadable({
loader: () => import("./Statistics/Index"),
loading: Loading,
});
});
const GeneralView = Loadable({
loader: () => import("./GeneralView/Index"),
loading: Loading,
});
});
const InfosUser = Loadable({
loader: () => import("./InfosUser"),
loading: Loading,
@ -191,6 +199,16 @@ class Infos extends Component {
this.props.history.push(`/${user && user.login}/devops/${type}`);
}
change_blockchain_type=(type)=>{
console.log(type)
const {user} = this.state;
this.setState({
project_type: type ,
route_type: undefined
})
this.props.history.push(`/users/${user && user.login}/blockchain/${type}`);
}
undo_link = () => {
const {user } = this.state;
this.setState({