Commit 942f7039 authored by mxm-web-develop's avatar mxm-web-develop

Merge branch 'dev'

parents fd5ed1d0 a35b766c
NODE_ENV="development"
VUE_APP_URL="http://172.16.100.59:8092"
\ No newline at end of file
VUE_APP_URL="http://172.16.100.59:8092"
VUE_APP_CHAIN="http://172.16.100.247:8801"
NODE_ENV="production"
VUE_APP_URL="http://47.243.139.223:8000"
APP_TITLE="后台系统"
\ No newline at end of file
VUE_APP_CHAIN="https://mainnet.bityuan.com/api"
NODE_ENV='development'
#VUE_APP_URL="http://172.16.100.59:8090"
VUE_APP_URL="http://172.16.100.59:8092"
#VUE_APP_URL="http://172.16.100.59:8090"
\ No newline at end of file
VUE_APP_CHAIN="http://172.16.100.247:8801"
......@@ -14,6 +14,8 @@ module.exports = {
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
"@typescript-eslint/no-explicit-any": 0
"@typescript-eslint/no-explicit-any": 0,
"vue/no-unused-components": "off",
"@typescript-eslint/explicit-module-boundary-types": "off"
}
}
module.exports = {
trailingComma: 'es5', // 多行的 Object 和 Array 的最后一个元素末位加逗号
tabWidth: 2, // 一个 tab 为 4 个空格
semi: false, // JS 语句的末位不加封号
singleQuote: false, // 字符串单引号优先
printWidth: 80, // 一行代码超过 120 个字符时格式化为多行
endOfLine: 'auto',
}
......@@ -31,7 +31,15 @@ See [Configuration Reference](https://cli.vuejs.org/config/).
[文档链接](http://172.16.100.59:8090/q/swagger-ui?urls.primaryName=pool.v1.EntrustPool#/)
### 环境
node 版本 12.14.0
node 版本 12.x (12.14.0)
### 原型
[原型地址](https://modao.cc/app/de2dec5a3c3966cc036a1e236873dcbf56feab1a#screen=skqxgio647fto10)
\ No newline at end of file
[原型地址](https://modao.cc/app/de2dec5a3c3966cc036a1e236873dcbf56feab1a#screen=skqxgio647fto10)
## 测试账户
社区节点账户 cs123456 123456
单独排除在外 admin123 admin123
admin111 admin111
## 更新内容
....
### 1.1.0
- 新增日志管理
- 绑定日志
- 委托日志
- 白名单管理
- 路由菜单整理
- 用户信息查看的票数来源更换成链上数据
\ No newline at end of file
......@@ -4,8 +4,9 @@
"private": true,
"scripts": {
"dev": "vue-cli-service serve",
"build:test": "vue-cli-service build --mode test",
"build": "vue-cli-service build",
"build:test": "node version env=dev && vue-cli-service build --mode test",
"build": "node version env=production && vue-cli-service build",
"build:update": "node version env=production,version=update && vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
......
......@@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<title>后台系统</title>
</head>
<body>
<noscript>
......@@ -13,5 +13,8 @@
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
<!-- <script>console.log('v1.1.0')</script> -->
<!-- <script>console.log('dev: 1.1.0')</script> -->
<script>console.log('production: 1.1.0')</script>
</body>
</html>
......@@ -6,7 +6,6 @@
<script lang="ts">
import Vue from 'vue'
import { getStorage } from './utils/storage'
export default Vue.extend({
})
......
......@@ -8,40 +8,24 @@
<script lang="ts">
import Vue from 'vue'
import menu from '@/utils/menu'
import { routes } from '@/router/index';
export default Vue.extend({
data() {
return {
breadList: [],
breadList: [] as Array<string>,
filterList: [] as any
}
},
methods: {
getList() {
this.filterList = []
const type = 1
let c = [] as any
if (type === 1) {
c = menu.admin
} else {
c = menu.groupLeader
}
const f = this.toLine(c)
for (let i = 0; i < f.length; i++) {
for (let j = 0; j < f.length; j++) {
if (f[i].id === f[j].pid) {
this.filterList.push([f[i].name, f[j].name, f[j].url])
getList(route: Array<any>, list: Array<string>) {
for (const item of route) {
if (list.includes(item.name)) {
this.breadList.push(item.meta.name)
if (item.children) {
this.getList(item.children, list)
}
}
}
const route = this.$route.path
const res = this.filterList.filter((item: any) =>
item[item.length - 1] === route
)[0]
if (res) {
res.length = 2
}
this.breadList = res
},
toLine(data: any){
return data.reduce((arr: any[], {id, pid, name, url, list = []}: any) =>
......@@ -49,11 +33,19 @@ export default Vue.extend({
}
},
mounted() {
this.getList()
const _routes = JSON.parse(JSON.stringify(routes))
const path = this.$route.path
const pathList = path.split('/').filter(item => item)
this.breadList = []
this.getList(_routes, pathList)
},
watch: {
$route() {
this.getList()
$route(n) {
this.breadList = []
const _routes = JSON.parse(JSON.stringify(routes))
const path = n.path
const pathList = path.split('/').filter((item: string) => item)
this.getList(_routes, pathList)
}
}
})
......
<template>
<div>
<el-input type="input" v-if="show" v-model="pw">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
<el-input type="input" v-if="show" :value="value" :disabled="disabled" @input="handleChange">
<i slot="suffix" class="el-input__icon el-icon-view" @click="handleShow"></i>
</el-input>
<el-input type="password" v-if="!show" v-model="pw">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
<el-input type="password" v-if="!show" :value="value" :disabled="disabled" @input="handleChange">
<i slot="suffix" class="el-input__icon el-icon-view" @click="handleShow"></i>
</el-input>
</div>
</template>
......@@ -12,15 +12,32 @@
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
data() {
return {
show: true
computed: {
value():string {
return this.password
}
},
props: {
pw: {
password: {
type: String,
default: ''
},
show: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
}
},
methods: {
handleChange(value: string) {
const _value = value
this.$emit('update:password', _value)
},
handleShow() {
this.$emit('update:show', !this.show)
}
}
})
......
......@@ -6,32 +6,33 @@
text-color="#fff"
active-text-color="#409EFF"
router
:default-active="defaultActive">
:default-active="defaultActive"
>
<template v-for="(items, index) in menu">
<el-submenu :index="items.url" v-if="items.list" :key="index">
<el-submenu :index="items.path" v-if="items.children && items.path !== '/'" :key="index">
<template slot="title">
<i :class="items.icon" />
<span slot="title">{{items.name}}</span>
<i :class="items.meta && items.meta.icon" />
<span slot="title">{{ items.meta.name }}</span>
</template>
<template v-for="item in items.list">
<el-submenu v-if="item.list" :index="item.url" :key="item.url">
<template v-for="item in items.children">
<el-submenu v-if="item.children" :index="item.path" :key="item.path">
<template slot="title">
<i :class="item.icon"></i>
<span slot="title">{{ item.name }}</span>
<i :class="item.meta.icon"></i>
<span slot="title">{{ item.meta.name }}</span>
</template>
<el-menu-item v-for="(threeItem, i) in item.list" :key="i" :index="threeItem.url">
{{ threeItem.name }}
<el-menu-item v-for="(threeItem, i) in item.children" :key="i" :index="threeItem.path">
{{ threeItem.meta.name }}
</el-menu-item>
</el-submenu>
<el-menu-item v-else :index="item.url" :key="item.url">
<!-- <i :class="item.icon"></i> -->
<span slot="title">{{ item.name }}</span>
<el-menu-item v-else :index="item.path" :key="item.path">
<!-- <i :class="item.meta.icon"></i> -->
<span slot="title">{{ item.meta.name }}</span>
</el-menu-item>
</template>
</el-submenu>
<el-menu-item v-else :index="items.url" :key="index">
<i :class="items.icon" />
<span slot="title">{{items.name}}</span>
<el-menu-item v-else :index="items.path" :key="index">
<i :class="items.meta && items.meta.icon" />
<span slot="title">{{ items.meta.name }}</span>
</el-menu-item>
</template>
</el-menu>
......@@ -40,34 +41,63 @@
<script lang="ts">
import Vue from 'vue'
import menu from '@/utils/menu'
import { getStorage } from '@/utils/storage'
import { routes } from '@/router/index'
export default Vue.extend({
data() {
return {
menu: [] as any,
defaultActive: 'launch',
type: 1
type: 1,
}
},
computed: {},
methods: {
filter(type: number, routers: Array<any>): any {
for (let i = 0; i < routers.length; i++) {
if (!routers[i].meta.user.includes(type)) {
routers.splice(i, 1)
i--
} else {
if (routers[i].children) {
this.filter(type, routers[i].children)
}
}
}
return routers
},
init() {
const name = JSON.parse(getStorage('user') as string)?.name
this.defaultActive = this.$route.path as string
let type = 0
if (name === 'admin123') {
type = 3
} else {
type = +(getStorage('type') as string)
}
const _route = JSON.parse(JSON.stringify(routes)).slice(0, routes.length - 3)
// console.log(JSON.stringify(_route), '-------------routes')
this.menu = [...this.filter(type, _route)]
},
},
created() {
const name = JSON.parse(getStorage('user') as string)?.name
this.defaultActive = this.$route.path as string
this.type = +(getStorage('type') as string)
this.menu = name === 'admin123' ? menu.root : this.type === 2 ? menu.admin : menu.groupLeader
}
this.init()
// this.type = +(getStorage('type') as string)
// this.menu = name === 'admin123' ? menu.root : this.type === 2 ? routes.slice(0, routes.length - 3) : routes.slice(0, routes.length - 3)
// this.menu = name === 'admin123' ? menu.root : this.type === 2 ? menu.admin : menu.groupLeader
},
})
</script>
<style lang="scss" scoped>
.menu {
width: var(--navWidth);
height: calc(100vh - var(--headerHeight));
background: #333B54;
flex-shrink: 0;
text-align: left
}
/deep/ .el-menu {
border-right: none;
}
</style>
\ No newline at end of file
.menu {
width: var(--navWidth);
height: calc(100vh - var(--headerHeight));
background: #333b54;
flex-shrink: 0;
text-align: left;
}
/deep/ .el-menu {
border-right: none;
}
</style>
......@@ -3,44 +3,227 @@ import VueRouter, { RouteConfig } from 'vue-router'
Vue.use(VueRouter)
const routes: Array<RouteConfig> = [
export const routes: Array<RouteConfig> = [
{
path: '/',
name: 'App',
redirect:'/home',
component: () => import('../layout/index.vue'),
meta: {
icon: 'el-icon-s-home',
name: '首页',
user: [1,2]
},
children: [
{
path: '/home',
name: 'home',
component: () => import('@/views/Home.vue')
component: () => import('@/views/Home.vue'),
meta: {
icon: 'el-icon-s-home',
name: '首页',
user: [1,2]
},
},
// {
// path: '/info',
// name: 'info',
// component: () => import('@/views/User/Info.vue')
// },
// {
// path: '/launch',
// name: 'launch',
// component: () => import('@/views/Mining/Launch.vue')
// },
// {
// path: '/minTicket',
// name: 'minTicket',
// component: () => import('@/views/Mining/MinTicket.vue')
// },
// {
// path: '/add',
// name: 'add',
// component: () => import('@/views/Setting/Add.vue')
// },
// {
// path: '/reset',
// name: 'reset',
// component: () => import('@/views/Setting/Reset.vue')
// },
// {
// path: '/invite',
// name: 'invite',
// component: () => import('@/views/Logs/Invite.vue')
// },
// {
// path: '/trust',
// name: 'trust',
// component: () => import('@/views/Logs/Trust.vue')
// },
]
},
{
path: '/user',
name: 'user',
redirect: '/user/info',
component: () => import('../layout/index.vue'),
meta: {
name: '用户管理',
icon: 'el-icon-user',
user: [1,2]
},
children: [
{
path: '/info',
path: '/user/info',
name: 'info',
component: () => import('@/views/user/Info.vue')
component: () => import('@/views/user/Info.vue'),
meta: {
icon: '',
name: '用户信息',
user: [1,2]
}
},
]
},
{
path: '/mining',
name: 'mining',
redirect: '/mining/launch',
component: () => import('../layout/index.vue'),
meta: {
name: '票池管理',
icon: 'el-icon-s-order',
user: [1,2]
},
children: [
{
path: '/launch',
path: '/mining/launch',
name: 'launch',
component: () => import('@/views/mining/Launch.vue')
component: () => import('@/views/mining/Launch.vue'),
meta: {
name: '票池列表',
icon: '',
user: [1,2]
},
},
{
path: '/minTicket',
path: '/mining/minTicket',
name: 'minTicket',
component: () => import('@/views/mining/MinTicket.vue')
component: () => import('@/views/mining/MinTicket.vue'),
meta: {
name: '最小票数设置',
icon: '',
user: [2]
},
},
]
},
{
path: '/logs/invite',
name: 'logs',
redirect: '/logs/invite',
component: () => import('../layout/index.vue'),
meta: {
name: '记录管理',
icon: 'el-icon-s-order',
user: [1,2]
},
children: [
// {
// path: '/logs/invite',
// name: 'invite',
// component: () => import('@/views/Logs/Invite.vue'),
// meta: {
// name: '绑定记录',
// icon: '',
// user: [1,2]
// },
// },
{
path: '/add',
path: '/logs/trust',
name: 'trust',
component: () => import('@/views/Logs/Trust.vue'),
meta: {
name: '委托记录',
icon: '',
user: [1,2]
},
},
]
},
{
path: '/setting/add',
name: 'setting',
redirect: '/setting/add',
component: () => import('../layout/index.vue'),
meta: {
name: '设置',
icon: 'el-icon-setting',
user: [1,2,3]
},
children: [
{
path: '/setting/add',
name: 'add',
component: () => import('@/views/setting/Add.vue')
component: () => import('@/views/setting/Add.vue'),
meta: {
name: '添加节点',
icon: '',
user: [2,3]
},
},
{
path: '/reset',
path: '/setting/reset',
name: 'reset',
component: () => import('@/views/setting/Reset.vue')
component: () => import('@/views/setting/Reset.vue'),
meta: {
name: '修改密码',
icon: '',
user: [1,2,3]
},
},
]
},
{
path: '/whitelist',
name: 'whitelist',
component: () => import('../layout/index.vue'),
meta: {
name: '白名单',
icon: 'el-icon-document-checked',
user: [1]
},
children: [
{
path: '/whitelist/list',
name: 'list',
meta: {
name: '白名单列表',
icon: '',
user: [1]
},
component: () => import('@/views/whitelist/List.vue'),
},
{
path: '/whitelist/statistics',
name: 'statistics',
meta: {
name: '白名单数据',
icon: '',
user: [1]
},
component: () => import('@/views/whitelist/Statistics.vue'),
},
{
path: '/whitelist/details',
name: 'details',
meta: {
name: '白名单明细',
icon: '',
user: [1]
},
component: () => import('@/views/whitelist/Details.vue'),
},
]
},
{
......@@ -53,10 +236,10 @@ const routes: Array<RouteConfig> = [
name: '404',
component: () => import('@/views/404.vue')
},
// {
// path: '*',
// redirect: '/404'
// }
{
path: '*',
redirect: '/404'
}
]
const router = new VueRouter({
......
import axios from 'axios'
import { Message } from 'element-ui'
const service = axios.create({
baseURL: process.env.NODE_ENV === 'development' ? '/chain' : process.env.VUE_APP_CHAIN,
timeout: 15000
})
service.interceptors.response.use(
response => {
const res = response.data
// if the custom code is not 200, it is judged as an error.
// tryHideFullScreenLoading()
return res
}, error => {
// Do something with response error
Message({
message: error || '网络异常',
type: 'error',
duration: 3 * 1000
})
// tryHideFullScreenLoading()
return Promise.reject(error);
})
async function chainRequire(method: string, data: any[], cb: any){
return await service.request({
data:{
"jsonrpc":"2.0",
id:1,
method:method,
params:data
},
method: 'POST',
}).then(res=>{
if(cb){
return cb(res)
}
return res
}).catch((err)=>{
if(cb){
return cb(err)
}
return err
})
}
export const getBalance = (addr: string, execer: string) => {
return service.request({
data: {
id: 1,
method: 'Chain33.GetBalance',
params: [{
addresses: [
addr
],
execer: execer
}]
},
method: 'POST'
})
}
\ No newline at end of file
......@@ -4,35 +4,8 @@ import { ElLoadingComponent } from 'element-ui/types/loading'
import { getStorage, saveStorage } from '@/utils/storage'
import router from '@/router'
let loading: ElLoadingComponent
function startLoading() {
loading = Loading.service({
target: '.content-r'
})
}
function endLoading() {
loading.close()
}
let needLoadingRequestCount = 0
export function showFullScreenLoading() {
if (needLoadingRequestCount === 0) {
startLoading()
}
needLoadingRequestCount++
}
export function tryHideFullScreenLoading() {
if (needLoadingRequestCount <= 0) return
needLoadingRequestCount--
if (needLoadingRequestCount === 0) {
endLoading()
}
}
const service = axios.create({
baseURL: '/api',
......@@ -65,8 +38,9 @@ service.interceptors.response.use(
return res
}, error => {
// Do something with response error
// console.log(error.response)
if (error.response.data?.reason === 'TOKEN') {
console.log(error.response)
const REASON = error.response.data?.reason
if (REASON === 'TOKEN') {
router.push('/login')
Message({
message: '登录已过期',
......
import service from "./http";
interface poolInfo {
name: string;
desc: string;
minerAddr: string;
advantage: string;
reason: string;
friendlyName: string;
minTicket: number;
deposit: string;
selfAddr: string;
days: string;
creator?: string
}
import { poolInfo, adminInfo } from "@/type/index";
/**
* 登录
......@@ -48,11 +35,20 @@ export const getStatistic = function() {
* @param data
* @returns
*/
export const addAdmin = function(data: {name: string, addr: string, pwd: string, type: number}) {
export const addAdmin = function(data: adminInfo) {
return service.post('/admin/add-admin', data)
}
/**
* 编辑用户
* @param data
* @returns
*/
export const editAdmin = function(data: { id: string, ext: string }) {
return service.post('/admin/edit-admin', data)
}
/**
* 删除用户
* @param id
* @returns
......@@ -97,6 +93,22 @@ export const getPoolList = function(data: {page: number, pageSize: number, limit
return service.get('/admin/pool-list', {params: data})
}
export const getWhiteDailyList = function(query: {poolId: string, page: number, pageSize: number, start?: number, end?: number}) {
return service.get('/admin/white-daily-list', {params: query})
}
export const getTransList = function (query: {
page: number,
pageSize: number,
poolId?: string,
addr?: string,
start?: number,
end?: number,
type?: 0 | 1
}) {
return service.get('/admin/trans-list', {params: query})
}
/**
* 编辑
* @param data
......@@ -124,6 +136,11 @@ export const setOnline = function(data: {id: string}) {
return service.post('/admin/set-online', data)
}
/**
* 票池显隐
* @param data
* @returns
*/
export const setShow = function(data: {id: string, isShow: boolean}) {
return service.post('/admin/set-show', data)
}
......@@ -132,10 +149,19 @@ export const setSeq = function(data: {id?: string}) {
return service.post('/admin/set-seq', data)
}
/**
* 设置最小票
* @param data
* @returns
*/
export const setMinTicket = function(data: { min: string }) {
return service.post('/admin/set-minticket', data)
}
/**
* 获取最小票
* @returns
*/
export const getMinTicket = function() {
return service.get('/admin/get-minticket')
}
......@@ -161,3 +187,55 @@ export const getUserPoolList = function(data: {id: string|number}) {
export const getAdminLists = function(data: {page: number, pageSize: number}) {
return service.get('/admin/admin-list', {params: data})
}
/**
* 获取委托记录
* @param data
* @returns
*/
export const getBindLists = function(data: {page: number, pageSize: number, poolId?: number, addr: string}) {
return service.get('/admin/bind-history', {params: data})
}
/**
* 获取社区列表记录
* @param data
* @returns
*/
export const getCaptainLists = function(data: {page: number, pageSize: number}) {
return service.get('/admin/captain-list', {params: data})
}
/**
* 新增白名单
* @param data
* @returns
*/
export const addWhiteLists = function(data: {addr: string; poolId: number}) {
return service.post('/admin/add-white', data)
}
/**
* 获取白名单列表
* @param data
* @returns
*/
export const getWhiteLists = function(data: {id: number, page: number, pageSize: number}) {
return service.get('/admin/white-list', {params: data})
}
/**
* 增加例外地址
* @param data
* @returns
*/
export const addOtherLists = function(data: {id: number, except: string}) {
return service.post('/admin/add-except', data)
}
/**
* 删除白名单
* @param data
* @returns
*/
export const delWhiteList = function(data: {id: number}) {
return service.post('/admin/del-white', data)
}
export interface adminInfo {
name: string;
addr: string;
pwd: string;
type: number;
ext: string;
id?: string;
}
\ No newline at end of file
export interface Info {
captainPoolNum: number;
officalAmount: number;
totalPoolTicket: number;
miningPerson: number;
totalPopAmount: number;
todayPoPAmount: number
}
\ No newline at end of file
export interface poolInfo {
name: string;
desc: string;
minerAddr: string;
advantage: string;
reason: string;
friendlyName: string;
minTicket: number;
deposit: string;
selfAddr: string;
days: string;
creator?: string
}
\ No newline at end of file
export enum UserType {
LEADER = 1,
ADMIN,
OTHER
}
\ No newline at end of file
export { UserType } from './UserType';
export { Info } from './Info'
export { poolInfo } from './PoolInfo'
export { adminInfo } from './AdminInfo'
\ No newline at end of file
export const TICKET_COUNT = process.env.NODE_ENV !== 'production' ? 10000 : 3000
\ No newline at end of file
......@@ -28,6 +28,8 @@ import {
Icon,
Loading,
Message,
MessageBox,
DatePicker,
} from 'element-ui';
Vue.use(Avatar);
......@@ -56,9 +58,13 @@ Vue.use(BreadcrumbItem);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Icon);
Vue.use(DatePicker);
Vue.use(Loading.directive);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;
\ No newline at end of file
Vue.prototype.$message = Message;
Vue.prototype.$confirm = MessageBox.confirm
Vue.prototype.$alert = MessageBox.alert
Vue.prototype.$prompt = MessageBox.prompt
\ No newline at end of file
const menu = {
root: [
{
id: '4',
pid: '0',
name: '设置',
url: '/setting',
icon: 'el-icon-setting',
list: [
{
id: '4-1',
pid: '4',
name: '添加节点',
url: '/add',
icon: ''
},
{
id: '4-1',
pid: '4',
name: '修改密码',
url: '/reset',
icon: ''
}
]
}
],
admin: [
{
id: '1',
pid: '0',
name: '首页',
url: '/home',
icon: 'el-icon-s-home'
},
{
id: '2',
pid: '0',
name: '用户管理',
url: '/guest',
icon: 'el-icon-user',
list: [
{
id: '2-1',
pid: '2',
name: '用户信息',
url: '/info',
icon: ''
}
]
},
{
id: '3',
pid: '0',
name: '票池管理',
url: '/manage',
icon: 'el-icon-s-order',
list: [
{
id: '3-1',
pid: '3',
name: '票池列表',
url: '/launch',
icon: ''
},
{
id: '3-2',
pid: '3',
name: '最小票数设置',
url: '/minTicket',
icon: ''
}
]
},
{
id: '4',
pid: '0',
name: '设置',
url: '/setting',
icon: 'el-icon-setting',
list: [
{
id: '4-1',
pid: '4',
name: '添加节点',
url: '/add',
icon: ''
},
{
id: '4-1',
pid: '4',
name: '修改密码',
url: '/reset',
icon: ''
}
]
}
],
groupLeader: [
{
name: '首页',
url: '/home',
icon: ''
},
{
name: '用户管理',
url: '/guest',
icon: '',
list: [
{
name: '用户信息',
url: '/info',
icon: ''
}
]
},
{
name: '票池管理',
url: '/manage',
icon: '',
list: [
{
name: '票池列表',
url: '/launch',
icon: ''
}
]
},
{
name: '设置',
url: '/setting',
icon: '',
list: [
{
name: '修改密码',
url: '/reset',
icon: ''
}
]
},
]
}
export default menu
\ No newline at end of file
......@@ -7,60 +7,45 @@
<p>{{ info.captainPoolNum }}</p>
</div>
<div class="statics-block">
<p>官方已发放奖励</p>
<p>{{ info.officalAmount }}</p>
</div>
<div class="statics-block">
<p>当前所有票池总票数</p>
<p>{{ info.totalPoolTicket }}</p>
</div>
</div>
<div class="statics-line">
<div class="statics-block">
<p>参与投票用户数</p>
<p>{{ info.miningPerson }}</p>
</div>
<!-- <div class="statics-block">
</div>
<!-- <div class="statics-line">
<div class="statics-block">
<p>官方已发放奖励</p>
<p>{{ info.officalAmount }}</p>
</div>
<div class="statics-block">
<p>累计推广收益</p>
<p>{{ info.totalPopAmount }}</p>
</div>
<div class="statics-block">
<p>今日推广收益</p>
<p>{{ info.todayPoPAmount }}</p>
</div> -->
</div>
</div>
</div> -->
</div>
</template>
<script lang="ts">
// import { Component, Vue } from 'vue-property-decorator';
// @Component({
// components: {
// },
// })
// export default class Home extends Vue {}
import Vue from 'vue'
import { getStatistic } from '@/service/request'
import { Info } from '@/type/Info';
export default Vue.extend({
data() {
return {
info: {}
}
},
methods: {
getInfo() {
// ...
getStatistic().then(res => {
this.info = res.data
console.log(this.info)
})
console.log(111)
info: {} as Info
}
},
created() {
this.getInfo()
getStatistic().then(res => {
this.info = res.data
})
}
})
</script>
......
......@@ -7,14 +7,8 @@
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="form.password" show-password autocomplete="off"></el-input>
<!-- <el-input v-show="!show" v-model="form.password" type="password">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
</el-input>
<el-input v-show="show" v-model="form.password">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
</el-input> -->
<!-- <PwInput :pw.sync="form.password" /> -->
<!-- <el-input type="password" v-model="form.password" show-password autocomplete="off"></el-input> -->
<Password :password.sync="form.password" :show.sync="show" />
</el-form-item>
</el-form>
<el-button class="w-full" type="primary" @keypress.enter="login" :disabled="isLogin" @click="login">登 录</el-button>
......@@ -26,12 +20,14 @@
import Vue from 'vue'
import { saveStorage } from '@/utils/storage'
import { info, login } from '@/service/request'
import Password from '@/components/Password.vue'
export default Vue.extend({
components: {
Password
},
data() {
return {
show: true,
show: false,
form: {
name: '',
password: ''
......@@ -58,10 +54,9 @@ export default Vue.extend({
login(this.form).then((res: any) => {
if (res.data.isSucc) {
info().then((res: any) => {
// window.localStorage.setItem('user', JSON.stringify(res.data))
saveStorage('user', res.data)
saveStorage('type', res.data.type)
this.$router.push('/home')
this.form.name === 'admin123' ? this.$router.push('/setting/add') : this.$router.push('/home')
})
}
this.isLogin = false
......
<template>
<div class="invite">
<el-table
:data="list"
border
style="width: 100%">
<el-table-column
prop="ext"
label="社区节点名称">
</el-table-column>
<el-table-column
prop="id"
label="社区节点id">
</el-table-column>
</el-table>
<Pagination :total="total" :page="page" :pageSize="pageSize" @pagination="getPage" />
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Pagination from '@/components/Panigation.vue'
import { getCaptainLists } from '@/service/request'
export default Vue.extend({
components: {
Pagination
},
data() {
return {
list: [] as any,
total: 0,
page: 1,
pageSize: 10
}
},
created() {
this.getList()
},
methods: {
getPage(v: { page: number, pageSize: number }) {
this.page = v.page
this.pageSize = v.pageSize
this.getList()
},
getList() {
console.log('request')
// getCaptainLists({
// page: this.page,
// pageSize: this.pageSize
// }).then(res => {
// this.list = res.data.list
// })
}
}
})
</script>
\ No newline at end of file
<template>
<div class="invite">
<div class="search-bar">
<div class="search-l">
<span class="search-label">精确查找</span>
<el-select v-model="search.poolId" placeholder="请选择" clearable>
<el-option
v-for="item in captainList"
:key="item.id"
:label="item.ext"
:value="item.id">
</el-option>
<!-- <el-option
label="用户"
:value="1">
</el-option>
<el-option
label="推客"
:value="2">
</el-option> -->
</el-select>
<el-input class="search-input" v-model="search.addr" placeholder="请输入地址" clearable></el-input>
</div>
<div class="search-r">
<el-button type="primary" @click="filterList">查找</el-button>
</div>
</div>
<el-table
:data="list"
border
style="width: 100%">
<el-table-column
prop="addr"
label="用户地址">
</el-table-column>
<el-table-column
prop="nodeName"
label="社区节点">
</el-table-column>
<el-table-column
prop="poolName"
label="票池名称">
</el-table-column>
<el-table-column
prop="poolAddr"
label="票池地址">
</el-table-column>
<el-table-column
prop="amount"
label="票数">
</el-table-column>
<el-table-column
prop="createAt"
label="委托时间">
<template slot-scope="scope">
<div>{{ scope.row.createAt | filterTime() }}</div>
</template>
</el-table-column>
</el-table>
<Pagination :total="total" :page="page" :pageSize="pageSize" @pagination="getPage" />
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Pagination from '@/components/Panigation.vue'
import { getBindLists, getCaptainLists } from '@/service/request';
import dayjs from 'dayjs';
export default Vue.extend({
components: {
Pagination
},
data() {
return {
captainList: [] as any,
list: [] as any,
total: 0,
page: 1,
pageSize: 10,
search: {
poolId: undefined,
addr: ''
},
}
},
filters: {
filterTime(val: string) {
const timeStamp = parseInt(val + '000')
return dayjs(timeStamp).format('YYYY-MM-DD HH:mm')
}
},
created() {
this.getList()
this.getCaptain()
},
methods: {
getPage(v: { page: number, pageSize: number }) {
this.page = v.page
this.pageSize = v.pageSize
this.getList()
},
getCaptain() {
getCaptainLists({
page: this.page,
pageSize: 1000
}).then(res => {
this.captainList = res.data.list
})
},
getList() {
getBindLists({
page: this.page,
pageSize: this.pageSize,
poolId: this.search.poolId,
addr: this.search.addr
}).then(res => {
this.list = res.data.list
})
},
filterList() {
this.page = 1
this.pageSize = 10
if (!this.search.poolId) {
this.search.poolId = undefined
}
this.getList()
},
}
})
</script>
<style lang="scss" scoped>
.search-bar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
.search-l {
display: flex;
align-items: center;
.search-label {
display: inline-block;
flex-shrink: 0;
padding-right: 12px;
}
.search-input {
margin-left: 12px;
}
}
}
</style>
\ No newline at end of file
......@@ -15,6 +15,14 @@
prop="minerAddr"
label="票池地址">
</el-table-column>
<el-table-column
prop="entrustTicket"
label="委托总票数">
</el-table-column>
<el-table-column
prop="entrustPerson"
label="委托总人数">
</el-table-column>
<!-- <el-table-column
prop="selfAddr"
label="自持投票地址">
......
<template>
<div class="min-ticket">
<p>最小票数设置</p>
<el-input v-model="min" type="number" placeholder="请输入最小票数" style="width: 200px; margin-right: 8px"/>
<el-input v-model="min" type="number" placeholder="请输入最小票数(>=3)" style="width: 200px; margin-right: 8px"/>
<el-button type="primary" @click="submit">确定</el-button>
</div>
</template>
......@@ -20,6 +20,9 @@ export default Vue.extend({
if (!this.min) {
this.$message.info('请输入最小票数')
return
} else if (+this.min < 3) {
this.$message.info('最小票数不小于3')
return
}
setMinTicket({min: this.min}).then(res => {
if (res.data.isSucc) {
......
......@@ -17,6 +17,10 @@
label="用户名">
</el-table-column>
<el-table-column
prop="ext"
label="备注名">
</el-table-column>
<el-table-column
width="240"
prop="addr"
label="节点身份地址">
......@@ -26,16 +30,17 @@
label="添加日期">
<template slot-scope="scope">{{ getDateTime(scope.row.createAt) }}</template>
</el-table-column>
<el-table-column
<!-- <el-table-column
prop="address"
label="最后登录时间">
</el-table-column>
</el-table-column> -->
<el-table-column
width="90"
label="操作">
<template slot-scope="scope">
<!-- <el-button @click="statusClick(scope.row)" type="text" size="small">{{ scope.row.status === 1 ? '停用' : '启用' }}</el-button> -->
<el-button @click="delClick(scope.row)" type="text" size="small">删除</el-button>
<!-- <el-button @click="delClick(scope.row)" type="text" size="small">删除</el-button> -->
<el-button @click="editClick(scope.row)" type="text" size="small">编辑</el-button>
</template>
</el-table-column>
</el-table>
......@@ -43,7 +48,7 @@
<el-dialog title="添加节点" :close-on-click-modal="false" :visible.sync="dialogVisible">
<el-form ref="form" :model="form" :rules="rule" label-width="120px">
<el-form-item label="节点类型">
<el-select v-model="form.type" placeholder="请选择" style="width: 100%">
<el-select v-model="form.type" placeholder="请选择" style="width: 100%" :disabled="isEdit">
<el-option
label="超级节点"
:value="2">
......@@ -55,19 +60,16 @@
</el-select>
</el-form-item>
<el-form-item label="节点用户名" prop="name">
<el-input v-model="form.name"></el-input>
<el-input v-model="form.name" :disabled="isEdit"></el-input>
</el-form-item>
<el-form-item label="节点登录密码" prop="pwd">
<el-input v-show="!show" v-model="form.pwd" type="password">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
</el-input>
<el-input v-show="show" v-model="form.pwd">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
</el-input>
<!-- <el-input v-model="form.pwd" show-password></el-input> -->
<Password :password.sync="form.pwd" :show.sync="show" :disabled="isEdit" />
</el-form-item>
<el-form-item label="节点身份地址" prop="addr">
<el-input v-model="form.addr"></el-input>
<el-input v-model="form.addr" :disabled="isEdit"></el-input>
</el-form-item>
<el-form-item label="备注名" prop="ext">
<el-input v-model="form.ext"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
......@@ -76,7 +78,7 @@
</div>
</el-dialog>
<!--删除提示-->
<el-dialog
<!-- <el-dialog
title="提示"
:visible.sync="delVisible"
width="30%">
......@@ -85,6 +87,17 @@
<el-button @click="delVisible = false">取 消</el-button>
<el-button type="primary" @click="delAdmin">确 定</el-button>
</span>
</el-dialog> -->
<el-dialog title="编辑节点" :close-on-click-modal="false" :visible.sync="editVisible">
<el-form ref="form" :model="form" :rules="rule" label-width="120px">
<el-form-item label="备注名" prop="ext">
<el-input v-model="form.ext"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editVisible = false">取 消</el-button>
<el-button type="primary" @click="submitClick('form')">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
......@@ -92,24 +105,32 @@
<script lang="ts">
import Vue from 'vue'
import Pagination from '@/components/Panigation.vue'
import { addAdmin, getAdminLists, delAdmin } from '@/service/request'
import { addAdmin, getAdminLists, delAdmin, editAdmin } from '@/service/request'
import { getDateTime } from '@/utils/utils'
import Password from '@/components/Password.vue'
import { adminInfo } from '@/type/AdminInfo'
const baseForm = ():adminInfo => {
return {
name: '',
addr: '',
pwd: '',
type: 2,
ext: '',
id: ''
}
}
export default Vue.extend({
components: {
Pagination
Pagination,
Password,
},
data() {
return {
show: true,
list: [] as any,
total: 0,
dialogVisible: false,
form: {
name: '',
addr: '',
pwd: '',
type: 2
},
form: baseForm(),
rule: {
name: [
{ required: true, message: '请输入管理员名称', trigger: 'blur' },
......@@ -121,10 +142,13 @@ export default Vue.extend({
{ required: true, message: '请输入管理员地址', trigger: 'blur' },
],
},
dialogVisible: false,
isEdit: false,
editVisible: false,
delVisible: false,
page: 1,
pageSize: 10,
id: ''
total: 0,
}
},
methods: {
......@@ -141,16 +165,12 @@ export default Vue.extend({
return getDateTime(s)
},
initForm() {
this.form = {
name: '',
addr: '',
pwd: '',
type: 1
}
baseForm()
},
addItems() {
this.dialogVisible = true
this.initForm();
this.isEdit = false;
this.$nextTick(() => {
(this.$refs['form'] as any).resetFields();
})
......@@ -162,14 +182,24 @@ export default Vue.extend({
submitClick(formName: string) {
(this.$refs[formName] as any).validate((valid: any) => {
if (valid) {
addAdmin(this.form).then((res: any) => {
// if (res.code === 200) {
if (res.data?.isSucc) {
this.$message.success('添加成功')
this.getList()
this.dialogVisible = false
}
})
if (this.isEdit) {
const { ext, id } = this.form
editAdmin({ id: id as string, ext }).then(res => {
if (res.data?.isSucc) {
this.$message.success('编辑成功')
this.getList()
this.editVisible = false
}
})
} else {
addAdmin(this.form).then((res: any) => {
if (res.data?.isSucc) {
this.$message.success('添加成功')
this.getList()
this.dialogVisible = false
}
})
}
} else {
this.$message.info('请先填写表单信息')
}
......@@ -180,15 +210,18 @@ export default Vue.extend({
this.pageSize = v.pageSize
this.getList()
},
// statusClick(item: any) {
// // this.dialogVisible = true
// },
delClick(item: {id: string}) {
this.id = item.id
delClick(item: adminInfo) {
this.form = Object.assign({}, item)
this.delVisible = true
},
editClick(item: any) {
this.editVisible = true
this.isEdit = true
this.form = Object.assign({}, item)
},
delAdmin() {
delAdmin(this.id).then(res => {
const id = this.form.id as string
delAdmin(id).then(res => {
if (res.data?.isSucc) {
this.$message.success('删除成功')
this.getList()
......
......@@ -2,31 +2,27 @@
<div class="reset">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="原密码" prop="old">
<el-input v-show="!showOld" v-model="ruleForm.old" type="password">
<!-- <el-input v-show="!showOld" v-model="ruleForm.old" type="password">
<i slot="suffix" class="el-input__icon el-icon-view" @click="showOld = !showOld"></i>
</el-input>
<el-input v-show="showOld" v-model="ruleForm.old">
<i slot="suffix" class="el-input__icon el-icon-view" @click="showOld = !showOld"></i>
</el-input>
</el-input> -->
<!-- <el-input v-model="ruleForm.old" show-password autocomplete="off"></el-input> -->
<Password :password.sync="ruleForm.old" :show.sync="showOld" />
</el-form-item>
<el-form-item label="新密码" prop="new">
<el-input v-show="!show" v-model="ruleForm.new" type="password">
<!-- <el-input v-show="!show" v-model="ruleForm.new" type="password">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
</el-input>
<el-input v-show="show" v-model="ruleForm.new">
<i slot="suffix" class="el-input__icon el-icon-view" @click="show = !show"></i>
</el-input>
</el-input> -->
<!-- <el-input type="password" v-model="ruleForm.new" show-password autocomplete="off"></el-input> -->
<Password :password.sync="ruleForm.new" :show.sync="show" />
</el-form-item>
<el-form-item label="确认密码" prop="confirm">
<el-input v-show="!showCheck" v-model="ruleForm.confirm" type="password">
<i slot="suffix" class="el-input__icon el-icon-view" @click="showCheck = !showCheck"></i>
</el-input>
<el-input v-show="showCheck" v-model="ruleForm.confirm">
<i slot="suffix" class="el-input__icon el-icon-view" @click="showCheck = !showCheck"></i>
</el-input>
<!-- <el-input type="password" v-model="ruleForm.confirm" show-password autocomplete="off"></el-input> -->
<Password :password.sync="ruleForm.confirm" :show.sync="showCheck" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
......@@ -39,15 +35,19 @@
<script lang="ts">
import Vue from 'vue'
import { changePassword } from '@/service/request'
import Password from '@/components/Password.vue'
export default Vue.extend({
components: {
Password
},
data() {
var checkAge = (rule: any, value: any, callback: any) => {
var checkAge = (rule: any, value: string, callback: any) => {
if (!value) {
return callback(new Error('原密码不能为空'));
}
callback()
};
var validatePass = (rule: any, value: any, callback: any) => {
var validatePass = (rule: any, value: string, callback: any) => {
if (value === '') {
callback(new Error('请输入新密码'));
} else {
......@@ -57,7 +57,7 @@ export default Vue.extend({
callback();
}
};
var validatePass2 = (rule: any, value: any, callback: any) => {
var validatePass2 = (rule: any, value: string, callback: any) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== (this as any).ruleForm.new) {
......@@ -89,11 +89,10 @@ export default Vue.extend({
}
},
methods: {
submitForm(formName: any) {
submitForm(formName: string) {
(this.$refs[formName] as any).validate((valid: any) => {
if (valid) {
changePassword(this.ruleForm).then((res: any) => {
// if (res.code === 200) {
if (res.data.isSucc) {
this.$message.success('修改成功');
(this.$refs[formName] as any).resetFields();
......@@ -105,7 +104,7 @@ export default Vue.extend({
}
});
},
resetForm(formName: any) {
resetForm(formName: string) {
(this.$refs[formName] as any).resetFields();
}
}
......
......@@ -20,9 +20,10 @@
</div>
</div>
<div class="statistics">
<span>超级节点伞下委托总票数:{{ msg.entrustTicket || 0 }}</span>
<span>{{ }}伞下委托总票数:{{ msg.entrustTicket || 0 }}</span>
<span>推荐人数:{{ msg.invitePerson || 0 }}</span>
<span>正在投票人数:{{ msg.miningPerson || 0 }}</span>
<span v-show="search.text">当前地址伞下所委托的票总数: {{ msg.addrEntrustTicket || 0 }}</span>
</div>
<el-table
:data="list"
......@@ -59,10 +60,11 @@
<div>委托票数</div>
</div>
<template v-if="items.length > 0">
<div class="item-lines" v-for="item in items" :key="item">
<div class="item-lines" v-for="(item, index) in items" :key="index">
<div>{{ item.name }}</div>
<div>{{ item.miner }}</div>
<div>{{ item.entrustTicket }}</div>
<!-- <div>{{ item.entrustTicket }}</div> -->
<div>{{ item.ticketCount }}</div>
</div>
</template>
<div v-else class="no-content">暂无数据</div>
......@@ -70,7 +72,6 @@
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
......@@ -79,6 +80,10 @@ import Vue from 'vue'
import Pagination from '@/components/Panigation.vue'
import { getUserLists, getUserPoolList } from '@/service/request'
import { getDateTime } from '@/utils/utils'
import { getStorage } from '@/utils/storage'
import { getBalance } from '@/service/chain33';
import { TICKET_COUNT } from '@/utils/config';
import { Loading } from 'element-ui'
export default Vue.extend({
components: {
Pagination
......@@ -98,6 +103,12 @@ export default Vue.extend({
pageSize: 10
}
},
computed: {
tipName():string {
const type = +(getStorage('type') as string)
return type === 2 ? '超级节点' : '当前社区节点'
}
},
methods: {
getList() {
getUserLists({
......@@ -120,12 +131,24 @@ export default Vue.extend({
this.pageSize = 10
this.getList()
},
handleClick(item: {id: string|number}) {
handleClick(item: {id: string|number, addr: string}) {
const id = item.id
this.dialogVisible = true
getUserPoolList({id}).then(res => {
console.log(res)
this.items = res.data.list
const loading = Loading.service({
target: '.el-dialog'
})
getBalance(item.addr, 'ticket').then(res => {
this.items = (res as any).result
this.$set(this.items[0], 'ticketCount', Math.floor(((res as any).result[0].frozen / 1e8) / TICKET_COUNT) || '')
getUserPoolList({id}).then(res => {
loading.close()
this.$set(this.items[0], 'name', res.data.list[0].name || '')
this.$set(this.items[0], 'miner', res.data.list[0].miner || '')
}).catch(() => {
loading.close()
})
}).catch(() => {
loading.close()
})
},
getPage(v: { page: number, pageSize: number }) {
......@@ -154,6 +177,7 @@ export default Vue.extend({
padding-right: 12px;
}
.search-input {
width: 350px;
margin-left: 12px;
}
}
......
<template>
<div class="white-list">
<div class="search-bar">
<!-- 选择票池 -->
<el-select v-model="currPoolIndex" :loading="loading" placeholder="选择票池" style="margin-right: 15px">
<el-option v-for="(item, index) in poolList" :key="item.id" :label="item.name" :value="index"> </el-option>
</el-select>
<!-- 选择明细用户类型 -->
<el-select v-model="addressType" :disabled="loading" style="margin-right: 15px">
<el-option label="普通地址" :value="0"></el-option>
<el-option label="白名单地址" :value="1"></el-option>
</el-select>
<!-- 日期 -->
<el-date-picker
v-model="datePick"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="timestamp"
:disabled="loading"
style="margin-right: 15px"
>
</el-date-picker>
<!-- 地址 -->
<el-input placeholder="地址" v-model="address" style="width: 220px"></el-input>
<div style="flex: 1"></div>
<el-button type="primary" @click="requestWhiteDailyList">搜索</el-button>
</div>
<p v-if="transListData" style="margin-bottom: 10px">
<span style="padding-right: 10px">累积委托票数: {{transListData.totalEntrustTicket}}</span>
<span style="padding-right: 10px">累积有效票数: {{transListData.totalPopTicket}}</span>
<span>累积空投数量: {{transListData.totalAirAmount}}</span>
</p>
<el-table :data="list" :empty-text="loading ? '正在加载...' : '暂无数据'" border style="width: 100%">
<el-table-column prop="addr" label="用户地址"> </el-table-column>
<el-table-column prop="inviteAddr" label="推荐人地址"> </el-table-column>
<el-table-column prop="tickets" label="委托票数"> </el-table-column>
<el-table-column prop="amount" label="空投数量"> </el-table-column>
<el-table-column prop="jobTime" label="空投日期"> </el-table-column>
<el-table-column prop="popTicket" label="空投有效票数"> </el-table-column>
</el-table>
<Pagination :total="total" :page="page" :pageSize="pageSize" @pagination="getPage" />
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import dayjs from 'dayjs'
import Pagination from '@/components/Panigation.vue'
import { getPoolList, getTransList } from '@/service/request'
export default Vue.extend({
components: {
Pagination,
},
data() {
return {
/* 矿池列表 */
poolList: [] as any,
/** 当前选中的矿池 */
currPoolIndex: null as number | null,
/** 白名单列表 */
list: [] as any,
/** 0: 普通地址; 1: 白名单地址 */
addressType: undefined as 0 | 1 | undefined,
loading: true,
page: 1,
pageSize: 10,
total: 0,
datePick: [undefined, undefined] as [number | undefined, number | undefined],
address: '',
transListData: null as {
totalAirAmount: number
totalEntrustTicket: string
totalPopTicket: string
} | null,
}
},
created() {
this.requestPoolList()
this.requestWhiteDailyList()
},
methods: {
getPage(v: { page: number; pageSize: number }) {
this.page = v.page
this.pageSize = v.pageSize
this.requestWhiteDailyList()
},
/** 获取票池列表 */
requestPoolList() {
getPoolList({
page: 1,
pageSize: 5,
limit: 5,
})
.then((res: any) => {
if (res.data.list.length) {
this.poolList = res.data.list
}
})
.catch(() => this.$message({ type: 'error', message: '获取票池列表失败' }))
.finally(() => (this.loading = false))
},
/** 获取 (票池对应的) 白名单列表 */
async requestWhiteDailyList() {
this.loading = true
this.list = []
try {
const payload = {
page: this.page,
pageSize: this.pageSize,
} as Parameters<typeof getTransList>[0]
this.currPoolIndex !== null && (payload.poolId = this.poolList[this.currPoolIndex].id)
this.addressType !== undefined && (payload.type = this.addressType)
if (this.datePick[0] && this.datePick[1]) {
payload.start = dayjs(this.datePick[0]).unix()
payload.end = dayjs(this.datePick[1]).unix()
}
this.address && (payload.addr = this.address)
const result = await getTransList(payload)
this.list = result.data.tx
this.transListData = result.data.data
this.total = parseInt(result.data.count)
} catch {
this.$message({ type: 'error', message: '获取白名单数据失败' })
} finally {
this.loading = false
}
},
},
})
</script>
<style lang="scss" scoped>
.white-list {
.search-bar {
margin-bottom: 20px;
display: flex;
align-items: center;
}
}
</style>
<template>
<div class="white-list">
<div class="search-bar">
<el-select v-model="currPoolIndex" :disabled="loading">
<el-option v-for="(item, index) in poolList" :key="item.id" :label="item.name" :value="index"> </el-option>
</el-select>
<el-button type="primary" @click="init">添加白名单</el-button>
</div>
<el-table :data="list" :empty-text="loading ? '正在加载...' : '暂无数据'" border style="width: 100%">
<el-table-column prop="addr" label="用户地址"> </el-table-column>
<el-table-column prop="except" label="例外地址">
<template slot-scope="scope">
<div style="word-break: break-word;">{{ scope.row.excepts && scope.row.excepts.replace(/\,/g, ',\n') }}</div>
</template>
</el-table-column>
<el-table-column width="200px" label="操作">
<template slot-scope="scope">
<el-button @click="initOther(scope.row)" type="text" size="small">操作</el-button>
<el-button @click="handleRemove(scope.row)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
<Pagination :total="total" :page="page" :pageSize="pageSize" @pagination="getPage" />
<el-dialog title="新增白名单" :close-on-click-modal="false" :visible.sync="dialogVisible">
<el-form ref="form" :model="form" :rules="rule" label-width="110px">
<el-form-item label="用户地址" prop="addr">
<el-input v-model="form.addr"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitClick('form')">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="新增例外地址" :close-on-click-modal="false" :visible.sync="dialogOtherVisible">
<el-form ref="otherform" :model="otherForm" :rules="otherRule" label-width="110px">
<el-form-item label="例外地址" prop="except">
<el-input v-model="otherForm.except"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogOtherVisible = false">取 消</el-button>
<el-button type="primary" @click="handleAddOther('otherform')">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Pagination from '@/components/Panigation.vue'
import { addOtherLists, addWhiteLists, delWhiteList, getPoolList, getWhiteLists } from '@/service/request'
const baseForm = (): { addr: string } => {
return {
addr: '',
}
}
const _form = (): { except: string } => {
return {
except: '',
}
}
export default Vue.extend({
components: {
Pagination,
},
data() {
return {
list: [] as any,
/* 存放所有存在的矿池 id */
poolList: [] as any,
/** 当前选中的矿池 id */
currPoolIndex: null as number | null,
loading: true,
page: 1,
pageSize: 10,
total: 0,
dialogVisible: false,
dialogOtherVisible: false,
form: baseForm(),
otherForm: _form() as any,
rule: {
addr: [{ required: true, message: '请输入用户地址', trigger: 'blur' }],
},
otherRule: {
except: [{ required: true, message: '请输入例外地址', trigger: 'blur' }],
},
}
},
created() {
this.requestPoolList()
},
methods: {
init() {
this.dialogVisible = true
this.form = baseForm()
},
initOther(item: { id: string }) {
this.dialogOtherVisible = true
this.otherForm = { ..._form(), id: item.id }
},
getPage(v: { page: number; pageSize: number }) {
this.page = v.page
this.pageSize = v.pageSize
this.requestPoolList()
},
submitClick(formName: string) {
(this.$refs[formName] as any).validate((valid: any) => {
if (this.currPoolIndex === null) return
if (valid) {
addWhiteLists({ ...this.form, poolId: this.poolList[this.currPoolIndex].id }).then(res => {
if (res.data?.isSucc) {
this.$message.success('新增成功')
this.dialogVisible = false
this.requestWhiteList()
}
})
} else {
this.$message.info('请先填写表单信息')
}
})
},
handleAddOther(formName: string) {
(this.$refs[formName] as any).validate((valid: any) => {
if (this.currPoolIndex === null) return
if (valid) {
addOtherLists({ ...this.otherForm }).then(res => {
if (res.data?.isSucc) {
this.$message.success('新增例外地址成功')
this.dialogOtherVisible = false
this.requestWhiteList()
}
})
} else {
this.$message.info('请先填写表单信息')
}
})
},
handleRemove(item: { id: number }) {
this.$confirm('此操作将删除该条白名单, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
if (this.currPoolIndex === null) return
delWhiteList({ id: item.id }).then(res => {
if (res.data?.isSucc) {
this.$message({
type: 'success',
message: '删除成功!',
})
this.requestWhiteList()
}
})
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消删除',
})
})
},
/** 获取票池列表 */
requestPoolList() {
getPoolList({
page: 1,
pageSize: 5,
limit: 5,
}).then((res: any) => {
if (res.data.list.length) {
this.poolList = res.data.list
this.currPoolIndex = 0
}
})
},
/** 获取 (票池对应的) 白名单列表 */
async requestWhiteList() {
if (this.currPoolIndex === null) return
this.loading = true
this.list = []
try {
const result = await getWhiteLists({
page: this.page,
pageSize: this.pageSize,
id: this.poolList[this.currPoolIndex].id,
})
this.list = result.data.list
} catch {
this.$message({
type: 'error',
message: '获取白名单失败',
})
} finally {
this.loading = false
}
},
},
watch: {
async currPoolIndex() {
this.requestWhiteList()
},
},
})
</script>
<style lang="scss" scoped>
.white-list {
.search-bar {
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>
<template>
<div class="white-list">
<div class="search-bar">
<el-select v-model="currPoolIndex" :disabled="loading" style="margin-right: 15px">
<el-option v-for="(item, index) in poolList" :key="item.id" :label="item.name" :value="index"> </el-option>
</el-select>
<el-date-picker
v-model="datePick"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="timestamp"
:disabled="loading"
>
</el-date-picker>
</div>
<el-table :data="list" :empty-text="loading ? '正在加载...' : '暂无数据'" border style="width: 100%">
<el-table-column prop="addr" label="用户地址"> </el-table-column>
<el-table-column prop="inviter" label="推荐人数"> </el-table-column>
<el-table-column prop="tickets" label="累积总票数"> </el-table-column>
<el-table-column prop="totalAirAmount" label="累积空投"> </el-table-column>
<el-table-column prop="totalPopTicket" label="推广有效票数"> </el-table-column>
</el-table>
<Pagination :total="total" :page="page" :pageSize="pageSize" @pagination="getPage" />
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import dayjs from 'dayjs'
import Pagination from '@/components/Panigation.vue'
import { getPoolList, getWhiteDailyList } from '@/service/request'
export default Vue.extend({
components: {
Pagination,
},
data() {
return {
/* 矿池列表 */
poolList: [] as any,
/** 当前选中的矿池 */
currPoolIndex: null as number | null,
/** 白名单列表 */
list: [] as any,
loading: true,
page: 1,
pageSize: 10,
total: 0,
datePick: [undefined, undefined] as [number | undefined, number | undefined],
}
},
created() {
this.requestPoolList()
},
methods: {
getPage(v: { page: number; pageSize: number }) {
this.page = v.page
this.pageSize = v.pageSize
this.requestWhiteDailyList()
},
/** 获取票池列表 */
requestPoolList() {
getPoolList({
page: 1,
pageSize: 5,
limit: 5,
})
.then((res: any) => {
if (res.data.list.length) {
this.poolList = res.data.list
this.currPoolIndex = 0
}
})
.catch(() => this.$message({ type: 'error', message: '获取票池列表失败' }))
},
/** 获取 (票池对应的) 白名单列表 */
async requestWhiteDailyList() {
if (this.currPoolIndex === null) return
this.loading = true
this.list = []
try {
const payload = {
page: this.page,
pageSize: this.pageSize,
poolId: this.poolList[this.currPoolIndex].id,
} as any
if (this.datePick[0] && this.datePick[1]) {
payload.start = dayjs(this.datePick[0]).unix()
payload.end = dayjs(this.datePick[1]).unix()
}
const result = await getWhiteDailyList(payload)
this.list = result.data.list
this.total = parseInt(result.data.count)
} catch {
this.$message({ type: 'error', message: '获取白名单数据失败' })
} finally {
this.loading = false
}
},
},
watch: {
currPoolIndex: 'requestWhiteDailyList',
datePick: 'requestWhiteDailyList',
},
})
</script>
<style lang="scss" scoped>
.white-list {
.search-bar {
margin-bottom: 20px;
display: flex;
align-items: center;
}
}
</style>
const fs = require('fs')
const file = __dirname + '/public/index.html'
const envList = ['dev', 'production'] // 设置环境
const args = process.argv.slice(2)
const argsMap = new Map()
const list = args[0].split(',')
list.forEach((item) => {
if (item.split('=')[0] === 'env') {
argsMap.set('env', item.split('=')[1])
}
if (item.split('=')[0] === 'version') {
argsMap.set('version', item.split('=')[1])
}
})
const ENV = argsMap.get('env') // 获取当前环境
const getOtherEnv = () => {
return envList.filter(item => item !== ENV)
}
const getVersionPart = (data, env) => {
const regexp = new RegExp(`<script>(console.log\\(\'${env}: [\\S]*\\))<\/script>`, 'g')
return value = data.match(regexp)
}
const isComments = (data, env) => {
const regexp = new RegExp(`<!--\\s*<script>(console.log\\(\'${env}: [\\S]*\\))<\/script>\\s*-->`, 'g')
return regexp.test(data) ? regexp : false
}
const getNewVersion = (value) => {
let newVersion = ''
const args = argsMap.get('version')
const _value = value // console.log 字段
const version = _value ? _value[0].split("'")[1].replace(`${ENV}: `, '') : undefined
if (version) {
const versionList = version.split('.');
if (args) {
if (args === 'update') {
+versionList[0]++
} else {
throw new Error('Operate Error')
}
} else {
+versionList[1]++
}
newVersion = versionList.join('.')
} else {
newVersion = '1.0.0'
}
return newVersion
}
fs.readFile(file, 'utf8', (err, data) => {
if (err) throw err;
let content = data
const value = getVersionPart(content, ENV) // 获取对应环境 console
const version = getNewVersion(value)
console.log(version)
const insert = `<script>console.log('${ENV}: ${version}')</script>`
// 非当前环境执行注释
const rest = getOtherEnv()
for (const item of rest) {
const _console = getVersionPart(content, item) ? getVersionPart(content, item)[0] : undefined
if (_console && !isComments(content, item)) {
content = content.replace(_console, `<!-- ${_console} -->`)
}
}
// 当前环境更新
if (!value) {
content = content.replace(/<\/body>/g, insert + '\n</body>')
} else {
// 是否被注释
if (isComments(content, ENV)) {
content = content.replace(isComments(content, ENV), insert)
} else {
content = content.replace(value[0], insert)
}
}
fs.writeFile(file, content, (err, data) => {
if (err) throw err
})
})
\ No newline at end of file
......@@ -3,7 +3,7 @@
module.exports = {
// ...other vue-cli plugin options...
publicPath: '/manage',
publicPath: process.env.NODE_ENV === 'development' ? '/' : '/manage',
css: {
loaderOptions: {
less: {
......@@ -12,7 +12,7 @@ module.exports = {
}
},
devServer: {
proxy: { // 设置代理
proxy: {
'/api': {
target: process.env.VUE_APP_URL,
// target: 'http://172.16.100.59:8090/',
......@@ -21,6 +21,13 @@ module.exports = {
'^/api': ''
}
},
'/chain': {
target: process.env.VUE_APP_CHAIN,
changeOrigin: true,
pathRewrite: {
'^/chain': ''
}
},
}
},
// configureWebpack: config => {
......
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