React框架初始化

This commit is contained in:
myh 2024-06-05 16:10:03 +08:00
parent 40ef14af6b
commit 87132fa2ff
13 changed files with 22158 additions and 0 deletions

21
frontend/.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

2444
frontend/README.md Normal file

File diff suppressed because it is too large Load Diff

19227
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

25
frontend/package.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"antd": "3.8.1",
"elliptic": "6.4.1",
"ethereumjs-util": "5.2.0",
"ethereumjs-wallet": "0.6.2",
"merkle-tree-solidity": "1.0.8",
"react": "16.4.2",
"react-dom": "16.4.2",
"react-router-dom": "4.3.1",
"react-scripts": "1.1.4",
"secp256k1": "^4.0.3",
"truffle-contract": "3.0.6",
"web3": "0.20.6"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>IoT Device Management</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,15 @@
{
"short_name": "IoT Device Management",
"name": "IoT Device Management",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

9
frontend/src/App.css Normal file
View File

@ -0,0 +1,9 @@
@import '~antd/dist/antd.css';
.loading-spin {
text-align: center;
border-radius: 4px;
margin-bottom: 20px;
padding: 30px 50px;
margin: 10px 0;
}

190
frontend/src/App.js Normal file
View File

@ -0,0 +1,190 @@
import getWeb3 from './utils/web3';
import DeviceManager from './DeviceManager';
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import './App.css';
import Home from './components/Home';
import RegisterDevice from './components/RegisterDevice';
import ManageDevices from './components/ManageDevices';
import EditEntity from './components/EditEntity';
import LookupEntity from './components/LookupEntity';
import ManageDevice from './components/ManageDevice';
import LookupDevice from './components/LookupDevice';
import CheckSignature from './components/CheckSignature';
import { Layout, Menu, Icon, Tag, Alert, Spin } from 'antd';
const { SubMenu } = Menu;
const { Header, Content, Footer, Sider } = Layout;
class App extends Component {
constructor(props) {
super(props);
this.state = {
web3: null,
deviceManagerInstance: null,
errorMessage: '',
loading: true
}
}
async componentWillMount() {
getWeb3.then(results => {
this.setState({
web3: results.web3,
});
console.log(`Using address: ${this.state.web3.eth.accounts[0]}`);
return DeviceManager.then(instance => {
this.setState({
loading: false,
deviceManagerInstance: instance
});
console.log(`Contract address: ${instance.address}`);
}).catch(error => {
console.log(error);
this.setState({
errorMessage: error.message,
loading: false
});
});
}).catch(() => {
let errorMessage = 'Error finding web3. Please install MetaMask.';
console.log(errorMessage);
this.setState({
errorMessage: errorMessage,
loading: false
});
});
}
mainContent() {
if (!this.state.loading) {
let childComponent;
if (this.state.web3 == null || this.state.deviceManagerInstance == null) {
childComponent = <div>
<h1>Resolve the following issues to continue</h1>
<Alert
message="Error"
description={this.state.errorMessage}
type="error"
showIcon
/>
</div>
} else {
childComponent = <div>
<Route exact path="/" component={Home} />
<Route path="/edit-entity" component={EditEntity} />
<Route path="/lookup-entity/:address?" component={LookupEntity} />
<Route path="/register-device" component={RegisterDevice} />
<Route path="/manage-devices" component={ManageDevices} />
<Route path="/manage-device/:deviceId" component={ManageDevice} />
<Route path="/lookup-device" component={LookupDevice} />
<Route path="/check-signature/:signatureId" component={CheckSignature} />
</div>
}
return (
<div>
{childComponent}
</div>
);
}
}
render() {
let statusTag;
if (this.state.web3 == null) {
statusTag = <Tag color="red">Web3 missing</Tag>;
} else if (this.state.deviceManagerInstance == null) {
statusTag = <Tag color="red">Network error</Tag>;
} else {
statusTag = <Tag color="green">OK</Tag>;
}
return (
<Router>
<Layout style={{ height: "100vh" }}>
<Header className="header">
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['1']}
style={{ lineHeight: '64px' }}
>
<Menu.Item key="1">
<Link to="/" className="nav-text">IoT Device Management</Link>
</Menu.Item>
<Menu.Item key="2" style={{ float: 'right' }}>
Status: {statusTag}
</Menu.Item>
</Menu>
</Header>
<Content style={{ padding: '24px 50px' }}>
<Layout style={{ padding: '24px 0', background: '#fff' }}>
<Sider width={200} style={{ background: '#fff' }}>
<Menu
mode="inline"
defaultSelectedKeys={['']}
defaultOpenKeys={['sub1', 'sub2', 'sub3']}
style={{ height: '100%' }}
>
<SubMenu key="sub1" title={<span><Icon type="user" />Entities</span>}>
<Menu.Item key="1">
<Link to="/edit-entity" className="nav-text">Edit</Link>
</Menu.Item>
<Menu.Item key="2">
<Link to="/lookup-entity" className="nav-text">Lookup</Link>
</Menu.Item>
</SubMenu>
<SubMenu key="sub2" title={<span><Icon type="laptop" />Devices</span>}>
<Menu.Item key="3">
<Link to="/register-device" className="nav-text">Register</Link>
</Menu.Item>
<Menu.Item key="4">
<Link to="/manage-devices" className="nav-text">Manage</Link>
</Menu.Item>
<Menu.Item key="5">
<Link to="/lookup-device" className="nav-text">Lookup</Link>
</Menu.Item>
{/*
<Menu.Item key="5">
<Link to="#" className="nav-text">Filter</Link>
</Menu.Item>
*/}
</SubMenu>
{/*
<SubMenu key="sub3" title={<span><Icon type="form" />Signatures</span>}>
<Menu.Item key="6">
<Link to="#" className="nav-text">Sign</Link>
</Menu.Item>
<Menu.Item key="7">
<Link to="/check-signature" className="nav-text">Check</Link>
</Menu.Item>
</SubMenu>
*/}
</Menu>
</Sider>
<Content style={{ padding: '0 24px', minHeight: 400 }}>
<Spin spinning={this.state.loading} className="loading-spin">
{this.mainContent()}
</Spin>
</Content>
</Layout>
</Content>
<Footer style={{ textAlign: 'center' }}>
IoT Device Management &copy; 2024 物联网大作业
</Footer>
</Layout>
</Router>
);
}
}
export default App;

View File

@ -0,0 +1,28 @@
import getWeb3 from './utils/web3';
import TruffleContract from 'truffle-contract';
import DeviceManagerArtifact from './artifacts/DeviceManager.json';
let web3;
let DeviceManager = new Promise(function (resolve, reject) {
getWeb3.then(results => {
web3 = results.web3;
const deviceManager = TruffleContract(DeviceManagerArtifact);
deviceManager.setProvider(web3.currentProvider);
return deviceManager.deployed().then(instance => {
console.log('Initiating DeviceManager instance...');
resolve(instance);
}).catch(error => {
reject(error);
});
}).catch(error => {
reject(error);
});
});
export function getDefaultAccount() {
return web3.eth.accounts[0];
}
export default DeviceManager;

7
frontend/src/index.js Normal file
View File

@ -0,0 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

View File

@ -0,0 +1,117 @@
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://goo.gl/SC7cgQ'
);
});
} else {
// Is not local host. Just register service worker
registerValidSW(swUrl);
}
});
}
}
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

View File

@ -0,0 +1,35 @@
import Web3 from 'web3'
let getWeb3 = new Promise(function (resolve, reject) {
window.addEventListener('load', function () {
let results;
let web3 = window.web3;
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use Mist/MetaMask's provider.
web3 = new Web3(web3.currentProvider);
results = {
web3: web3
};
console.log('Injected web3 detected.');
resolve(results)
} else {
let provider = new Web3.providers.HttpProvider('http://127.0.0.1:8545');
web3 = new Web3(provider);
results = {
web3: web3
};
console.log('No web3 instance injected, using Local web3.');
// should be resolved, leave reject for dev as there should always be metamask installed
reject(results);
}
})
})
export default getWeb3;