├── .env.development ├── .env.production ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── ci_check.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Changelog.md ├── LICENSE ├── README.md ├── babel.config.js ├── build └── index.js ├── docs └── images │ └── menu_logo_wecross.png ├── jest.config.js ├── mock ├── conn.js ├── index.js ├── mock-server.js ├── resource.js ├── status.js ├── transaction.js ├── ua.js ├── user.js └── utils.js ├── package.json ├── plop-templates ├── component │ ├── index.hbs │ └── prompt.js ├── store │ ├── index.hbs │ └── prompt.js ├── utils.js └── view │ ├── index.hbs │ └── prompt.js ├── plopfile.js ├── public ├── favicon.ico └── index.html ├── release_note.txt ├── src ├── .travis.yml ├── App.vue ├── api │ ├── common.js │ ├── conn.js │ ├── resource.js │ ├── status.js │ ├── transaction.js │ ├── ua.js │ └── user.js ├── assets │ ├── 404_images │ │ ├── 404.png │ │ └── 404_cloud.png │ ├── QRCode.jpg │ ├── app.png │ ├── chain.png │ ├── check-fail.svg │ ├── check-pass.svg │ ├── favicon.svg │ ├── icon-bc.svg │ ├── icon-ly.svg │ ├── icon-sw.svg │ ├── icon-zy.svg │ ├── issue.png │ ├── nav-logo.svg │ ├── router.png │ └── wecross.svg ├── components │ ├── Breadcrumb │ │ └── index.vue │ ├── ChainExplorer │ │ └── index.vue │ ├── Clipboard │ │ └── index.vue │ ├── Hamburger │ │ └── index.vue │ ├── HeaderSearch │ │ └── index.vue │ ├── ResourceExplorer │ │ └── index.vue │ ├── ResourceShower │ │ └── index.vue │ ├── ResourceTransfer │ │ └── index.vue │ ├── SvgIcon │ │ └── index.vue │ └── TransactionListExplorer │ │ └── index.vue ├── icons │ ├── index.js │ ├── svg │ │ ├── chicken.svg │ │ ├── exit-fullscreen.svg │ │ ├── eye-open.svg │ │ ├── eye.svg │ │ ├── fullscreen.svg │ │ ├── password.svg │ │ ├── qrcode.svg │ │ ├── question.svg │ │ ├── search.svg │ │ ├── table.svg │ │ ├── user-avatar.svg │ │ └── user.svg │ └── svgo.yml ├── layout │ ├── components │ │ ├── AppMain.vue │ │ ├── Navbar.vue │ │ ├── Sidebar │ │ │ ├── FixiOSBug.js │ │ │ ├── Item.vue │ │ │ ├── Link.vue │ │ │ ├── Logo.vue │ │ │ ├── SidebarItem.vue │ │ │ └── index.vue │ │ └── index.js │ ├── index.vue │ └── mixin │ │ └── ResizeHandler.js ├── main.js ├── permission.js ├── router │ └── index.js ├── store │ ├── getters.js │ ├── index.js │ └── modules │ │ ├── app.js │ │ ├── permission.js │ │ ├── transaction.js │ │ └── user.js ├── styles │ ├── element-ui.scss │ ├── element-variables.scss │ ├── index.scss │ ├── intro.scss │ ├── mixin.scss │ ├── sidebar.scss │ ├── transition.scss │ └── variables.scss ├── utils │ ├── auth.js │ ├── authcode.js │ ├── chainAccountIntro.js │ ├── clipboard.js │ ├── errorcode.js │ ├── get-page-title.js │ ├── index.js │ ├── messageBox.js │ ├── pem.js │ ├── request.js │ ├── resource.js │ ├── rsa.js │ ├── sm3.js │ ├── transaction.js │ └── validate.js └── views │ ├── 404.vue │ ├── access │ └── index.vue │ ├── account │ ├── changePassword.vue │ └── index.vue │ ├── document │ └── index.vue │ ├── homepage │ └── index.vue │ ├── login │ └── index.vue │ ├── register │ └── index.vue │ ├── resource │ ├── resourceDeployment.vue │ ├── resourceManager.vue │ └── resourceSteps │ │ ├── resourceDeploySteps.js │ │ └── resourceManagerSteps.js │ ├── router │ ├── routerGuide.vue │ └── routerManager.vue │ └── transaction │ ├── components │ └── TransactionForm.vue │ ├── rawTransaction.vue │ ├── transactionManager.vue │ ├── transactionSteps │ ├── transactionManagerSteps.js │ └── xaTransactionStep.js │ ├── xaTransaction.vue │ └── xaTransactionList.vue ├── tests └── unit │ ├── .eslintrc.js │ └── utils │ ├── formatTime.spec.js │ ├── param2Obj.spec.js │ ├── parseTime.spec.js │ └── validate.spec.js └── vue.config.js /.env.development: -------------------------------------------------------------------------------- 1 | # just a flag 2 | ENV = 'development' 3 | 4 | # base api 5 | VUE_APP_BASE_API = '' 6 | VUE_APP_MOCK_API = '/dev-api' -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | # just a flag 2 | ENV = 'production' 3 | 4 | # base api 5 | VUE_APP_BASE_API = '/' 6 | 7 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | src/assets 3 | public 4 | dist 5 | -------------------------------------------------------------------------------- /.github/workflows/ci_check.yml: -------------------------------------------------------------------------------- 1 | name: CI Check 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | check: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v2-beta 11 | with: 12 | node-version: '10' 13 | - name: npm install 14 | run: npm install 15 | - name: Build production 16 | run: npm install && npm run build:prod 17 | - name: Test 18 | run: npm run test:ci 19 | 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | package-lock.json 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # safelist 2 | branches: 3 | only: 4 | - /.*/ 5 | 6 | matrix: 7 | fast_finish: true 8 | include: 9 | 10 | - language: node_js 11 | node_js: 10 12 | script: npm install && npm run build:prod && npm run test:ci 13 | os: linux 14 | dist: xenial 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献代码 2 | 3 | 非常感谢能有心为WeCross贡献代码! 4 | 5 | ## 分支策略 6 | 7 | 项目采用[git-flow](https://jeffkreeftmeijer.com/git-flow/)的分支策略。 8 | 9 | * master:最新的稳定分支 10 | * dev:待发布的稳定分支 11 | * feature-xxxx:一个正在开发xxxx特性分支 12 | * bugfix-xxxx:一个正在修bug xxxx的分支 13 | 14 | ## 贡献方法 15 | 16 | ### Issue 17 | 18 | 可直接去[issues page](https://github.com/WeBankBlockchain/WeCross-WebApp/issues)提issue。 19 | 20 | ### 修复bug 21 | 22 | 1. Fork本仓库到个人仓库 23 | 2. 从个人仓库的master分支拉出一个bugfix-xxxx分支 24 | 3. 在bugfix-xxxx上修复bug 25 | 4. 测试修复的bug 26 | 5. PR(Pull Request)到本仓库的dev分支 27 | 6. 等待社区review这个PR 28 | 7. PR合入,bug修复完成! 29 | 30 | ### 开发新特性 31 | 32 | 1. Fork本仓库到个人仓库 33 | 2. 从个人仓库的dev分支拉出一个feature-xxxx分支 34 | 3. 在feature-xxxx上进行特性开发 35 | 4. 不定期的从本仓库的dev分支pull最新的改动到feature-xxxx分支 36 | 5. 测试新特性 37 | 6. PR(Pull Request)到本参考的dev分支 38 | 7. 等待社区review这个PR 39 | 8. PR合入,特性开发完成! 40 | 41 | ## 代码格式化 42 | 43 | 代码格式化gradle插件[google-java-format-gradle-plugin](https://github.com/sherter/google-java-format-gradle-plugin). 44 | 45 | 执行任务 `googleJavaFormat`格式化java文件。 46 | ``` 47 | ./gradlew goJF 48 | ``` 49 | 执行任务 `verifyGoogleJavaFormat`验证java文件是否格式化完成 50 | ``` 51 | ./gradlew verGJF 52 | ``` 53 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | ### v1.4.0 2 | 3 | (2024-03-01) 4 | 5 | **新增** 6 | 7 | - 适配 `systemStatus` 的GET接口,获取系统信息在首页展示 https://github.com/WeBankBlockchain/WeCross-WebApp/pull/180 8 | - 事务列表页面新增按链查询的功能,优化事务查询效率 https://github.com/WeBankBlockchain/WeCross-WebApp/pull/182 9 | 10 | ### v1.3.1 11 | 12 | (2023-07-31) 13 | 14 | **新增** 15 | 16 | * 新增对FISCO BCOS 3.x版本WASM合约的部署调用 17 | 18 | ### v1.3.0 19 | 20 | (2023-03-15) 21 | 22 | **新增** 23 | 24 | * 新增对FISCO BCOS 3.x版本的支持 25 | * 新增Email登陆注册检查的功能 26 | 27 | ### v1.2.1 28 | 29 | (2021-12-15) 30 | 31 | (无改动,配合其他组件同步更新版本) 32 | 33 | ### v1.2.0 34 | 35 | (2021-08-20) 36 | 37 | **新增** 38 | 39 | * 资源访问控制功能,管理员可通过网页管理台给用户授权可访问的资源 40 | 41 | ### v1.1.1 42 | 43 | (2021-04-02) 44 | 45 | **更改** 46 | 47 | * 增加内容复制按钮 48 | * 用户操作优化 49 | * 展示效果优化 50 | 51 | ### v1.1.0 52 | 53 | (2020-02-02) 54 | 55 | **新增** 56 | 57 | * 添加修改密码功能 58 | * 添加页面帮助指引 59 | 60 | **更新** 61 | 62 | * 体验优化 63 | * 问题修复 64 | 65 | ### v1.0.0 66 | 67 | (2020-12-17) 68 | 69 | **功能** 70 | 71 | * WeCross管理台:提供可视化的跨链管理服务 72 | 73 | **新增** 74 | 75 | * 注册与登录页:注册跨链账户,登录管理平台 76 | * 平台首页:展示跨链网络信息以及系统配置信息 77 | * 账户管理页:跨链账户生命周期管理 78 | * 路由管理页:互联的跨链路由管理 79 | * 资源管理页:跨链资源展示以及资源调用 80 | * 交易管理页:跨链交易列表以及交易详情展示 81 | * 事务管理页:事务列表展示以及事务操作 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](docs/images/menu_logo_wecross.png) 2 | 3 | # WeCross-WebApp 4 | 5 | [![Latest release](https://img.shields.io/github/release/WeBankBlockchain/WeCross-WebApp.svg)](https://github.com/WeBankBlockchain/WeCross-WebApp/releases/latest) [![License](https://img.shields.io/github/license/WeBankBlockchain/WeCross-WebApp)](https://www.apache.org/licenses/LICENSE-2.0) [![Language](https://img.shields.io/badge/Language-Vue-blue.svg)](https://vuejs.org/index.html) 6 | 7 | WeCross WebApp是[WeCross](https://github.com/WeBankBlockchain/WeCross)可视化跨链管理平台。 8 | 9 | ## 关键特性 10 | 11 | - 跨链路由、跨链账户、跨链资源、跨链交易以及跨链事务的可视化管理 12 | - 跨链网络信息以及跨链路由系统信息的获取和展示 13 | 14 | ## 部署与使用 15 | 16 | WeCross跨链管理平台的部署和使用可参考[使用文档](https://wecross.readthedocs.io/zh_CN/latest/docs/manual/webApp.html)。 17 | 18 | ## 源码编译 19 | 20 | **环境要求**: 21 | 22 | - [node.js](https://nodejs.org/en/) 8.10及以上 23 | 24 | **编译命令**: 25 | 26 | ```shell 27 | # 初始化 28 | npm install 29 | 30 | # 编译及热重载 31 | npm run dev 32 | 33 | # 编译并最小化生产 34 | npm run build:prod 35 | 36 | # 使用lint修复代码 37 | npm run lint 38 | ``` 39 | 40 | ## 项目贡献 41 | 42 | 欢迎参与WeCross社区的维护和建设: 43 | 44 | - 提交代码(Pull requests),可参考[代码贡献流程](CONTRIBUTING.md)以及[wiki指南](https://github.com/WeBankBlockchain/WeCross/wiki/%E8%B4%A1%E7%8C%AE%E4%BB%A3%E7%A0%81) 45 | - [提问和提交BUG](https://github.com/WeBankBlockchain/WeCross/issues/new) 46 | 47 | 您将成为贡献者,感谢各位贡献者的付出: 48 | 49 | https://github.com/WeBankBlockchain/WeCross-WebApp/graphs/contributors 50 | 51 | ## 开源社区 52 | 53 | 参与meetup:[活动日历](https://github.com/WeBankBlockchain/WeCross/wiki#%E6%B4%BB%E5%8A%A8%E6%97%A5%E5%8E%86) 54 | 55 | 学习知识、讨论方案、开发新特性:[联系微信小助手,加入跨链兴趣小组(CC-SIG)](https://wecross.readthedocs.io/zh_CN/latest/docs/community/cc-sig.html#id3) 56 | 57 | ## License 58 | 59 | WeCross WebApp的开源协议为Apache License 2.0,详情参考[LICENSE](./LICENSE)。 60 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /build/index.js: -------------------------------------------------------------------------------- 1 | const { run } = require('runjs') 2 | const chalk = require('chalk') 3 | const config = require('../vue.config.js') 4 | const rawArgv = process.argv.slice(2) 5 | const args = rawArgv.join(' ') 6 | 7 | if (process.env.npm_config_preview || rawArgv.includes('--preview')) { 8 | const report = rawArgv.includes('--report') 9 | 10 | run(`vue-cli-service build ${args}`) 11 | 12 | const port = 9526 13 | const publicPath = config.publicPath 14 | 15 | var connect = require('connect') 16 | var serveStatic = require('serve-static') 17 | const app = connect() 18 | 19 | app.use( 20 | publicPath, 21 | serveStatic('./dist', { 22 | index: ['index.html', '/'] 23 | }) 24 | ) 25 | 26 | app.listen(port, function () { 27 | console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) 28 | if (report) { 29 | console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) 30 | } 31 | 32 | }) 33 | } else { 34 | run(`vue-cli-service build ${args}`) 35 | } 36 | -------------------------------------------------------------------------------- /docs/images/menu_logo_wecross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeBankBlockchain/WeCross-WebApp/ff0a2850a465d5e7167cdb70a03d45d19cbb4963/docs/images/menu_logo_wecross.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], 3 | transform: { 4 | '^.+\\.vue$': 'vue-jest', 5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 6 | 'jest-transform-stub', 7 | '^.+\\.jsx?$': 'babel-jest' 8 | }, 9 | moduleNameMapper: { 10 | '^@/(.*)$': '/src/$1' 11 | }, 12 | snapshotSerializers: ['jest-serializer-vue'], 13 | testMatch: [ 14 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 15 | ], 16 | collectCoverageFrom: ['src/unit/**/*.{js,vue}', '!src/unit/auth.js', '!src/unit/request.js', 'src/components/**/*.{js,vue}'], 17 | coverageDirectory: '/tests/unit/coverage', 18 | // 'collectCoverage': true, 19 | 'coverageReporters': [ 20 | 'lcov', 21 | 'text-summary' 22 | ], 23 | testURL: 'http://localhost/' 24 | } 25 | -------------------------------------------------------------------------------- /mock/conn.js: -------------------------------------------------------------------------------- 1 | const Mock = require('mockjs') 2 | module.exports = [{ 3 | url: '/conn/listPeers', 4 | type: 'get', 5 | response: _ => { 6 | return { 7 | ...Mock.mock({ 8 | version: '1', 9 | errorCode: 0, 10 | message: 'success', 11 | data: { 12 | size: 1000, 13 | 'data|10': [{ 14 | nodeID: '@id', 15 | address: '@integer(1,255).@integer(1,255).@integer(1,255).@integer(1,255):@integer(1, 65535)', 16 | seq: 1, 17 | chainInfos: [{ 18 | name: '@id', 19 | stubType: '@pick([\'Fabirc1.4\', \'BCOS2.0\', \'GM_BCOS2.0\'])' 20 | }] 21 | }] 22 | } 23 | }) } 24 | } 25 | }, 26 | { 27 | url: '/conn/addPeer', 28 | type: 'post', 29 | response: config => { 30 | /* 31 | peerData.items.push({ 32 | nodeID: '@id', 33 | address: config.body.data.address, 34 | seq: 1, 35 | chainInfos: [{ 36 | name: 'bcos', 37 | stubType: 'BCOS2.0' 38 | }] 39 | }) 40 | */ 41 | 42 | return { 43 | 'version': '1', 44 | 'errorCode': 0, 45 | 'message': 'success', 46 | 'peerData': { 47 | 'errorCode': 0, 48 | 'message': 'success' 49 | } 50 | } 51 | } 52 | }, { 53 | url: '/conn/removePeer', 54 | type: 'post', 55 | response: _ => { 56 | // for (var i in peerData.items) { 57 | // if (peerData.items[i].address === config.body.data.address) { 58 | // peerData.items.splice(i, 1) 59 | // break 60 | // } 61 | // } 62 | return { 63 | 'version': '1', 64 | 'errorCode': 0, 65 | 'message': 'success', 66 | 'peerData': { 67 | 'errorCode': 0, 68 | 'message': 'success' 69 | } 70 | } 71 | } 72 | }, { 73 | url: '/conn/listChains', 74 | type: 'get', 75 | response: param => { 76 | return { 77 | 'version': '1', 78 | 'errorCode': 0, 79 | 'message': 'success', 80 | data: { 81 | size: 1000, 82 | 'data|10': [{ 83 | zone: param.query.zone, 84 | 'chain|1': ['bcos@integer(1,10000)', 'bcos_gm@integer(1,10000)', 'fabric@integer(1,10000)'], 85 | 'type|1': ['BCOS2.0', 'GM_BCOS2.0', 'Fabric1.4'], 86 | blockNumber: '@integer(1,1000000)', 87 | isLocal: '@pick(true,false)', 88 | 'properties': { 89 | 'BCOS_PROPERTY_CHAIN_ID': '1', 90 | 'WeCrossProxyABI': 'xxxxxxxxx', 91 | 'BCOS_PROPERTY_GROUP_ID': '1', 92 | 'WeCrossProxy': '0x8f9a2f54ca70f6a3f50b1ed27bdccad363b126f0', 93 | 'BCOS_PROPERTY_STUB_TYPE': 'BCOS2.0', 94 | 'WeCrossHub': '0x894b85761beec3aa08b00b9012c4ccd45c43ed84' 95 | } 96 | }] 97 | } 98 | } 99 | } 100 | }, { 101 | url: '/conn/listZones', 102 | type: 'get', 103 | response: _ => { 104 | return { 105 | 'version': '1', 106 | 'errorCode': 0, 107 | 'message': 'success', 108 | data: { 109 | size: 1, 110 | 'data|10': ["@pick([\'payment\',\'load\',\'resource\'])"] 111 | } 112 | } 113 | } 114 | } 115 | ] 116 | -------------------------------------------------------------------------------- /mock/index.js: -------------------------------------------------------------------------------- 1 | const user = require('./user') 2 | const resource = require('./resource') 3 | const conn = require('./conn') 4 | const ua = require('./ua') 5 | const transaction = require('./transaction') 6 | const status = require('./status') 7 | 8 | const mocks = [ 9 | ...user, 10 | ...resource, 11 | ...conn, 12 | ...ua, 13 | ...transaction, 14 | ...status 15 | ] 16 | 17 | module.exports = { 18 | mocks 19 | } 20 | 21 | -------------------------------------------------------------------------------- /mock/mock-server.js: -------------------------------------------------------------------------------- 1 | const chokidar = require('chokidar') 2 | const bodyParser = require('body-parser') 3 | const chalk = require('chalk') 4 | const path = require('path') 5 | const Mock = require('mockjs') 6 | 7 | const mockDir = path.join(process.cwd(), 'mock') 8 | 9 | function registerRoutes(app) { 10 | let mockLastIndex 11 | const { mocks } = require('./index.js') 12 | const mocksForServer = mocks.map(route => { 13 | return responseFake(route.url, route.type, route.response) 14 | }) 15 | for (const mock of mocksForServer) { 16 | app[mock.type](mock.url, mock.response) 17 | mockLastIndex = app._router.stack.length 18 | } 19 | const mockRoutesLength = Object.keys(mocksForServer).length 20 | return { 21 | mockRoutesLength: mockRoutesLength, 22 | mockStartIndex: mockLastIndex - mockRoutesLength 23 | } 24 | } 25 | 26 | function unregisterRoutes() { 27 | Object.keys(require.cache).forEach(i => { 28 | if (i.includes(mockDir)) { 29 | delete require.cache[require.resolve(i)] 30 | } 31 | }) 32 | } 33 | 34 | // for mock server 35 | const responseFake = (url, type, respond) => { 36 | return { 37 | url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), 38 | type: type || 'get', 39 | response(req, res) { 40 | console.log('request invoke:' + req.path + ' query:' + JSON.stringify(req.query)) 41 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) 42 | } 43 | } 44 | } 45 | 46 | module.exports = app => { 47 | // parse app.body 48 | // https://expressjs.com/en/4x/api.html#req.body 49 | app.use(bodyParser.json()) 50 | app.use(bodyParser.urlencoded({ 51 | extended: true 52 | })) 53 | 54 | const mockRoutes = registerRoutes(app) 55 | var mockRoutesLength = mockRoutes.mockRoutesLength 56 | var mockStartIndex = mockRoutes.mockStartIndex 57 | 58 | // watch files, hot reload mock server 59 | chokidar.watch(mockDir, { 60 | ignored: /mock-server/, 61 | ignoreInitial: true 62 | }).on('all', (event, path) => { 63 | if (event === 'change' || event === 'add') { 64 | try { 65 | // remove mock routes stack 66 | app._router.stack.splice(mockStartIndex, mockRoutesLength) 67 | 68 | // clear routes cache 69 | unregisterRoutes() 70 | 71 | const mockRoutes = registerRoutes(app) 72 | mockRoutesLength = mockRoutes.mockRoutesLength 73 | mockStartIndex = mockRoutes.mockStartIndex 74 | 75 | console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) 76 | } catch (error) { 77 | console.log(chalk.redBright(error)) 78 | } 79 | } 80 | }) 81 | } 82 | -------------------------------------------------------------------------------- /mock/resource.js: -------------------------------------------------------------------------------- 1 | const Mock = require('mockjs') 2 | 3 | module.exports = [{ 4 | url: '/sys/listResources', 5 | type: 'post', 6 | response: config => { 7 | return { 8 | ...Mock.mock({ 9 | version: 0, 10 | errorCode: 0, 11 | message: 'success', 12 | data: { 13 | total: 1000, 14 | 'resourceDetails|10': [{ 15 | id: '@id', 16 | path: config.query.path ? config.query.path + '.@word(3,5)' : '@pick([\'payment\',\'load\',\'resource\']).@pick([\'bcos\',\'bcos_gm\',\'fabric\']).@word(3,5)', 17 | checksum: 'checksum', 18 | 'stubType|1': ['BCOS2.0', 'GM_BCOS2.0', 'Fabric1.4', 'BCOS3_ECDSA_EVM', 'BCOS3_GM_EVM'], 19 | properties: '@sentence(3,3)', 20 | distance: '@integer(0, 3)' 21 | }] 22 | } 23 | }) 24 | } 25 | } 26 | }, 27 | { 28 | url: '/customCommand', 29 | type: 'post', 30 | response: config => { 31 | return { 32 | ...Mock.mock({ 33 | 'version': 1, 34 | 'errorCode': 0, 35 | 'message': 'Success: ' + config.body.command, 36 | 'data': 'result' 37 | }) 38 | } 39 | } 40 | }, 41 | { 42 | url: '/detail', 43 | type: 'post', 44 | response: config => { 45 | return { 46 | ...Mock.mock({ 47 | 'version': 1, 48 | 'errorCode': 0, 49 | 'message': 'Success: ' + config.body.command, 50 | 'data': { 51 | 'stubType': 'BCOS2.0' 52 | } 53 | }) 54 | } 55 | } 56 | } 57 | ] 58 | -------------------------------------------------------------------------------- /mock/status.js: -------------------------------------------------------------------------------- 1 | module.exports = [{ 2 | url: '/sys/systemStatus', 3 | type: 'get', 4 | response: param => { 5 | return { 6 | 'version': '1', 7 | 'errorCode': 0, 8 | 'message': 'Success', 9 | 'data': { 10 | 'osName': 'Linux', 11 | 'osArch': 'amd64', 12 | 'osVersion': '4.4.0-17763-Microsoft', 13 | 'javaVMVersion': '11.0.9.1+1-Ubuntu-0ubuntu1.20.04', 14 | 'javaVMVendor': 'Ubuntu', 15 | 'javaVMName': 'OpenJDK 64-Bit Server VM', 16 | 'providerName': 'SUN', 17 | 'providerVersion': '11', 18 | 'providerInfo': 'SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; PKCS12, JKS & DKS keystores; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration)', 19 | 'namedGroups': 'secp256k1', 20 | 'disabledNamedGroups': null 21 | } 22 | } 23 | } 24 | }, 25 | { 26 | url: '/sys/routerStatus', 27 | type: 'get', 28 | response: param => { 29 | return { 30 | 'version': '1', 31 | 'errorCode': 0, 32 | 'message': 'Success', 33 | 'data': { 34 | 'version': '1.0.0', 35 | 'supportedStubs': 'BCOS2.0,GM_BCOS2.0', 36 | 'rpcNetInfo': '127.0.0.1:8250', 37 | 'p2pNetInfo': '0.0.0.0:25500', 38 | 'adminAccount': 'monan', 39 | 'enableAccessControl': true 40 | } 41 | } 42 | } 43 | } 44 | ] 45 | -------------------------------------------------------------------------------- /mock/ua.js: -------------------------------------------------------------------------------- 1 | const Mock = require('mockjs') 2 | 3 | module.exports = [ 4 | { 5 | url: '/auth/listAccount', 6 | type: 'post', 7 | response: _ => { 8 | return { 9 | ...Mock.mock({ 10 | version: 0, 11 | errorCode: 0, 12 | message: 'success', 13 | data: { 14 | 'username': 'org1-admin', 15 | 'uaID': '3059301306072a8648ce3d020106082a811ccf5501822d034200047cfc7f4488a171e4a80051cdf93e2febc3066181b17bccd81264b79e346affc1f684738aa565485a459bbc00f03bd1df3df7dac985e6a740a3ed5533d5a60874', 16 | 'pubKey': '3059301306072a8648ce3d020106082a811ccf5501822d034200047cfc7f4488a171e4a80051cdf93e2febc3066181b17bccd81264b79e346affc1f684738aa565485a459bbc00f03bd1df3df7dac985e6a740a3ed5533d5a60874', 17 | 'admin': true, 18 | 'version': 1, 19 | 'chainAccounts': [ 20 | { 21 | 'keyID': 0, 22 | 'identity': '0x6c51a6cef228f784636c690d8b13f956e177cc76', 23 | 'type': 'BCOS2.0', 24 | 'pubKey': '-----BEGIN PUBLIC KEY-----\nmock 1111\n-----END PUBLIC KEY-----\n', 25 | 'secKey': '-----BEGIN PRIVATE KEY-----\nmock xxxx\n-----END PRIVATE KEY-----\n', 26 | 'ext': '0x6c51a6cef228f784636c690d8b13f956e177cc76', 27 | 'isDefault': true 28 | }, 29 | { 30 | 'keyID': 3, 31 | 'identity': '-----BEGIN CERTIFICATE-----\nmock 2222\n-----END CERTIFICATE-----\n', 32 | 'type': 'Fabric1.4', 33 | 'pubKey': '-----BEGIN CERTIFICATE-----\nmock 2222\n-----END CERTIFICATE-----\n', 34 | 'secKey': '-----BEGIN PRIVATE KEY-----\nmock xxxx\n-----END PRIVATE KEY-----\n', 35 | 'ext': 'Org1MSP', 36 | 'isDefault': false 37 | }, 38 | { 39 | 'keyID': 2, 40 | 'identity': '-----BEGIN CERTIFICATE-----\nmock 3333\n-----END CERTIFICATE-----\n', 41 | 'type': 'Fabric1.4', 42 | 'pubKey': '-----BEGIN CERTIFICATE-----\nmock 3333\n-----END CERTIFICATE-----\n', 43 | 'secKey': '-----BEGIN PRIVATE KEY-----\nmock xxxx\n-----END PRIVATE KEY-----\n', 44 | 'ext': 'Org2MSP', 45 | 'isDefault': false 46 | }, 47 | { 48 | 'keyID': 1, 49 | 'identity': '-----BEGIN CERTIFICATE-----\nmock 4444\n-----END CERTIFICATE-----\n', 50 | 'type': 'Fabric1.4', 51 | 'pubKey': '-----BEGIN CERTIFICATE-----\nmock 4444\n-----END CERTIFICATE-----\n', 52 | 'secKey': '-----BEGIN PRIVATE KEY-----\nmock xxxx\n-----END PRIVATE KEY-----\n', 53 | 'ext': 'Org1MSP', 54 | 'isDefault': true 55 | } 56 | ] 57 | } 58 | }) 59 | } 60 | } 61 | }, 62 | { 63 | url: '/auth/setDefaultAccount', 64 | type: 'post', 65 | response: _ => { 66 | return { 67 | ...Mock.mock({ 68 | version: 0, 69 | errorCode: 0, 70 | message: 'success', 71 | data: { 72 | errorCode: 0, 73 | message: 'success' 74 | } 75 | }) 76 | } 77 | } 78 | }, 79 | { 80 | url: '/auth/addChainAccount', 81 | type: 'post', 82 | response: _ => { 83 | return { 84 | ...Mock.mock({ 85 | version: 0, 86 | errorCode: 0, 87 | message: 'success', 88 | data: { 89 | errorCode: 0, 90 | message: 'success' 91 | } 92 | }) 93 | } 94 | } 95 | }, 96 | { 97 | url: '/auth/removeChainAccount', 98 | type: 'post', 99 | response: _ => { 100 | return { 101 | ...Mock.mock({ 102 | version: 0, 103 | errorCode: 0, 104 | message: 'success', 105 | data: { 106 | errorCode: 0, 107 | message: 'success' 108 | } 109 | }) 110 | } 111 | } 112 | }, 113 | { 114 | url: '/auth/admin/accessControlList', 115 | type: 'get', 116 | response: _ => { 117 | return { 118 | ...Mock.mock({ 119 | version: 0, 120 | errorCode: 0, 121 | message: 'success', 122 | 'data|20': [ 123 | { 124 | 'username': '@id', 125 | 'allowChainPaths|20': [ 126 | 'payment.@id' 127 | ], 128 | 'updateTimestamp': 1624517049308 129 | } 130 | ] 131 | }) 132 | } 133 | } 134 | }, 135 | { 136 | url: '/auth/admin/accessControlList', 137 | type: 'post', 138 | response: _ => { 139 | return { 140 | ...Mock.mock({ 141 | version: 1, 142 | errorCode: 0, 143 | message: 'success', 144 | data: { 145 | errorCode: 0, 146 | message: 'success' 147 | } 148 | }) 149 | } 150 | } 151 | } 152 | ] 153 | -------------------------------------------------------------------------------- /mock/user.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | // user login 3 | { 4 | url: '/auth/login', 5 | type: 'post', 6 | response: _ => { 7 | const token = 'access-token' 8 | 9 | // mock error 10 | if (!token) { 11 | return { 12 | code: 60204, 13 | message: 'Account and password are incorrect.' 14 | } 15 | } 16 | 17 | return { 18 | 'version': '1.0', 19 | 'errorCode': 0, 20 | 'message': 'success', 21 | 'data': { 22 | 'errorCode': 0, 23 | 'message': 'success', 24 | 'credential': 'Bearer eyJpYXRtaWxsIjoxNjI0NDM3MDgwODk2LCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJvcmcxLWFkbWluIiwibmJmIjoxNjI0NDM3MDgwLCJpc3MiOiJvcmcxIiwiZXhwIjoxNjI0NDM3NjgwLCJpYXQiOjE2MjQ0MzcwODB9.0yIjh54NvVgeoOX2DqbfTEm_ukdJeF7f44lii0Unkzc', 25 | 'universalAccount': { 26 | 'username': 'org1-admin', 27 | 'uaID': '3059301306072a8648ce3d020106082a811ccf5501822d03420004c52c0d26c2fc5368127472d9f7cad96d5792c3c6781f8b9cedaffd14c45deb6eabec7b7598f0ae194262bd1b8b5b4fbf75ade010b1ad688fa3ba7112a00c5d72', 28 | 'pubKey': '3059301306072a8648ce3d020106082a811ccf5501822d03420004c52c0d26c2fc5368127472d9f7cad96d5792c3c6781f8b9cedaffd14c45deb6eabec7b7598f0ae194262bd1b8b5b4fbf75ade010b1ad688fa3ba7112a00c5d72', 29 | 'isAdmin': true 30 | } 31 | } 32 | } 33 | } 34 | }, 35 | // user logout 36 | { 37 | url: '/auth/logout', 38 | type: 'post', 39 | response: _ => { 40 | return { 41 | 'version': '1', 42 | 'errorCode': 0, 43 | 'message': 'xxx', 44 | 'data': { 45 | } 46 | } 47 | } 48 | }, 49 | 50 | // user register 51 | { 52 | url: '/auth/register', 53 | type: 'post', 54 | response: _ => { 55 | return { 56 | 'version': '1', 57 | 'errorCode': 0, 58 | 'message': 'xxx', 59 | 'data': { 60 | 'errorCode': 0, 61 | 'message': 'success', 62 | 'universalAccount': { 63 | 'username': 'xxx', 64 | 'pubKey': 'xxx', 65 | 'uaID': 'xxx' 66 | } 67 | } 68 | } 69 | } 70 | }, 71 | 72 | // user changePassword 73 | { 74 | url: '/auth/changePassword', 75 | type: 'post', 76 | response: _ => { 77 | return { 78 | 'version': '1', 79 | 'errorCode': 0, 80 | 'message': 'xxx', 81 | 'data': { 82 | 'errorCode': 0, 83 | 'message': 'success' 84 | } 85 | } 86 | } 87 | }, 88 | 89 | // user authCode 90 | { 91 | url: '/auth/authCode', 92 | type: 'get', 93 | response: _ => { 94 | return { 95 | version: '1.0', 96 | errorCode: 0, 97 | message: 'success', 98 | data: { 99 | errorCode: 0, 100 | message: 'success', 101 | authCode: { 102 | randomToken: 'ad4b480b9585eaee7368a8260e28a198119bb88073f6f3b1aa03ede49ef1214e', 103 | imageBase64: 'iVBORw0KGgoAAAANSUhEUgAAAJsAAAA8CAIAAAD+Gl+NAAADQUlEQVR42u3cMW7kMAwFUB1im9S5xQLpUi9yhhxiq82Vttw+N0q53WSAAQzDGtGfFClSGgpqknFsj58lk7Sd8vX/kn2lXi6N9u/zL/FjNqN2Pc6yvq2hIJyJOkyxf20M0XQNPkxvPUVXa0Ugl6gpmi2AaIZIa4pmGrOgqEWEnc1fNFuKZkvRbCmaLUVTdJ4mvllRt/ffP/c9Rc/b25/XQwf/8OXXE9gF+dgB8m5P0dCoxLic1zVF2ZzBUT2vo1zUbZIMghrTdRrR7WqHc+KiMs4UlYvuQ9Mxorj6o4se2EDUQ7LRGQSJUVuurA19PP+49YlFa7YNDxGtc0dHUdaStWKrLyJKSNOiNerhN1qoBBjrruKpqKJricaJiFrko0h8JBMFObVQI4oqopqWGkBUlmi/q5so8ik+6yoWBdUTGBpsMlFk/LmI0oV7Lip9A+AUTHfi9Rmj3NwUR6W995Z2xd56E2OiXDdR2WKnl1LEW/bYm3gG3lwXj3W1RAU1ffWcFcxzrn1YuOuTj4oX47pa1CJ66oIWES/0JlNYURy1dZdGsXjUCoy1khlQ0aeuq4tKXFbrBexQb5sQV3rFrnRk5yYqiHjrL9bSou/VyKbT1iklTlL36wFFkSg9kCiozgpoZdUG4gIJPpoEjsj6/COW6Xoj2MUVrAhqJaa6ySg4RokhSAxWVg7tL8qt8Q6oCI4UPe3c8N7hjre6qEXhXlbj1c1e6MgoxKwrdtVF5T6iPaB2j4iCj48HerqTeLahp6SgVV5QfJYMryIJXtt1fktCxnZ6vOxKRZ3Pj9U2BGTcKuD4FvBFdALp7kBMUSpkCMtJQ8r2vKxk2Rqpjq6tHaN3uAe1LGnZOuUHu7YsWVeK6PnoSM7WQRlGy9ouvUv4Ny1BVASHmPUn9SasUfHN4V8fuR4Xd06xUP+YtkMFOcWnMhEilCCcrEPcKbE/oy1QTy/eKkF4aw0lDieopWhgkd7Qc4DW5qYZo50fRaAlkkvFs4cY9yUg58Xjf8Fuk3BndUJrPeJDN5moaYBKh5GK/13H7rh1ifbstCCJvAyp1vZHKwMmkhQdLeo4QOWi1pyd2aoX6oOKLow68aw7XtS9yD7LGP0G/T53V67Tc1kAAAAASUVORK5CYII=' 104 | } 105 | } 106 | } 107 | } 108 | }, 109 | // user pub 110 | { 111 | url: '/auth/pub', 112 | type: 'get', 113 | response: _ => { 114 | return { 115 | version: '1.0', 116 | errorCode: 0, 117 | message: 'success', 118 | data: { 119 | errorCode: 0, 120 | message: 'success', 121 | pub: 'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAiJ0u2c/Xze3Jv+beltOfoaavZtatVmldwctq3ItZZ5w60whzKiNdrsFcQZqj2PszLbwiYsC4fEFKQIcaTiHCXDSQ1Km25ay8/c+NKprl/ruevGB1pXDnQNZhQqoaghfzijTX2bl6DJqCnuSV46sCKgKfyKm3PNPcsMUxYWC1283an3cviUvdSnZyXHN++T2Otw77EVm55CNuDpX5MkOOIPTMSAxzweC9n9dJf5sGbmzqK2Yx8Jp/9vUA+jqR8ljqKJ7Q6bLVW3/xuqAN542U8a3dvPY3RVAkLVxgnl7UIfQl5PcBIxd4W3NZM6da/ZGmp76MAq/hxpceoU7DmQntkP9mX9ExtzcUTNFTm+LERwR530YRx4P7QB3EAAujEklZrlhXVwNa3phXnZRJWm4nuJ3qQB0I2VIw9q247aSLWEkoXQWu9CyRWzt7hmxgspwCYwsMdkvs0t8zv5L1LK0i8qXLHQCrasHkoJQ16+aztSDFmrAhJKtC4JN+ACnR1kMXAz/r2o3Y+pCO/2eBSDllsYSwCMRcgFwGvmutSD5dLes+zFZusxTRZ6vVnnnob+fOZ0NAdEDG9QY4UZoUxMjqSqM2db9jQ67QlcuMuEsc7uQ7T5mWlNORBnEVCz/UIjvFKnw7XnvGWcT/hKTPKYbgkqOJ/KQ05DoF/W3VHU+inPMCAwEAAQ==' 122 | } 123 | } 124 | } 125 | }, 126 | { 127 | url: '/auth/need-mail-auth', 128 | type: 'get', 129 | response: _ => { 130 | return { 131 | version: '1.0', 132 | errorCode: 0, 133 | message: 'success', 134 | data: true 135 | } 136 | } 137 | }, 138 | { 139 | url: '/auth/mail-code', 140 | type: 'post', 141 | response: _ => { 142 | return { 143 | version: '1.0', 144 | errorCode: 0, 145 | message: 'success' 146 | } 147 | } 148 | } 149 | ] 150 | -------------------------------------------------------------------------------- /mock/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} url 3 | * @returns {Object} 4 | */ 5 | function param2Obj(url) { 6 | const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') 7 | if (!search) { 8 | return {} 9 | } 10 | const obj = {} 11 | const searchArr = search.split('&') 12 | searchArr.forEach(v => { 13 | const index = v.indexOf('=') 14 | if (index !== -1) { 15 | const name = v.substring(0, index) 16 | const val = v.substring(index + 1, v.length) 17 | obj[name] = val 18 | } 19 | }) 20 | return obj 21 | } 22 | 23 | module.exports = { 24 | param2Obj 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wecross-webapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve", 7 | "build:prod": "vue-cli-service build", 8 | "build:stage": "vue-cli-service build --mode staging", 9 | "lint": "eslint --ext .js,.vue src", 10 | "new": "plop", 11 | "test:unit": "jest --clearCache && vue-cli-service test:unit", 12 | "test:ci": "npm run lint && npm run test:unit" 13 | }, 14 | "dependencies": { 15 | "axios": "^0.21.3", 16 | "body-parser": "^1.19.0", 17 | "chalk": "^4.1.0", 18 | "chokidar": "^3.5.1", 19 | "clipboard": "^2.0.6", 20 | "connect": "^3.7.0", 21 | "core-js": "3.7.0", 22 | "echarts": "^4.9.0", 23 | "element-ui": "2.13.2", 24 | "elliptic": "^6.5.4", 25 | "fuse.js": "^6.4.6", 26 | "intro.js": "^3.2.1", 27 | "js-cookie": "2.2.0", 28 | "js-sha256": "^0.9.0", 29 | "js-sha3": "0.8.0", 30 | "jsencrypt": "^3.0.0-rc.1", 31 | "jsonlint": "1.6.3", 32 | "jszip": "^3.8.0", 33 | "normalize.css": "7.0.0", 34 | "nprogress": "0.2.0", 35 | "path-to-regexp": "2.4.0", 36 | "script-loader": "0.7.2", 37 | "sm-crypto": "0.2.1", 38 | "sortablejs": "1.8.4", 39 | "svg-sprite-loader": "^5.0.0", 40 | "uuid": "^8.3.1", 41 | "vue": "^2.6.11", 42 | "vue-count-to": "1.0.13", 43 | "vue-json-pretty": "^1.7.1", 44 | "vue-router": "3.0.2", 45 | "vue-splitpane": "1.0.4", 46 | "vue-vis-network": "1.0.2", 47 | "vuex": "3.1.0" 48 | }, 49 | "devDependencies": { 50 | "@vue/cli-plugin-babel": "~4.5.0", 51 | "@vue/cli-plugin-eslint": "~4.5.0", 52 | "@vue/cli-plugin-unit-jest": "4.4.4", 53 | "@vue/cli-service": "~4.5.0", 54 | "@vue/test-utils": "1.0.0-beta.29", 55 | "babel-eslint": "^10.1.0", 56 | "babel-jest": "^26.6.3", 57 | "babel-plugin-dynamic-import-node": "2.3.3", 58 | "eslint": "^6.7.2", 59 | "eslint-plugin-vue": "^6.2.2", 60 | "eslint-plugin-vue-libs": "^4.0.0", 61 | "html-webpack-plugin": "3.2.0", 62 | "husky": "1.3.1", 63 | "lint-staged": "8.1.5", 64 | "mockjs": "1.0.1-beta3", 65 | "plop": "2.3.0", 66 | "runjs": "4.3.2", 67 | "sass": "1.26.2", 68 | "sass-loader": "8.0.2", 69 | "script-ext-html-webpack-plugin": "2.1.3", 70 | "serve-static": "1.13.2", 71 | "vue-template-compiler": "^2.6.11" 72 | }, 73 | "engines": { 74 | "node": ">=8.10", 75 | "npm": ">= 6.4.1" 76 | }, 77 | "husky": { 78 | "hooks": { 79 | "pre-commit": "lint-staged" 80 | } 81 | }, 82 | "lint-staged": { 83 | "src/**/*.{js,vue}": [ 84 | "eslint --fix", 85 | "git add" 86 | ] 87 | }, 88 | "browserslist": [ 89 | "> 1%", 90 | "last 2 versions", 91 | "not dead" 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /plop-templates/component/index.hbs: -------------------------------------------------------------------------------- 1 | {{#if template}} 2 | 5 | {{/if}} 6 | 7 | {{#if script}} 8 | 20 | {{/if}} 21 | 22 | {{#if style}} 23 | 26 | {{/if}} 27 | -------------------------------------------------------------------------------- /plop-templates/component/prompt.js: -------------------------------------------------------------------------------- 1 | const { notEmpty } = require('../utils.js') 2 | 3 | module.exports = { 4 | description: 'generate vue component', 5 | prompts: [{ 6 | type: 'input', 7 | name: 'name', 8 | message: 'component name please', 9 | validate: notEmpty('name') 10 | }, 11 | { 12 | type: 'checkbox', 13 | name: 'blocks', 14 | message: 'Blocks:', 15 | choices: [{ 16 | name: '