Commit 12b506ce authored by xhx's avatar xhx

时间框架

parents
module.exports = {
"env": {
"browser": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:vue/essential",
"plugin:@typescript-eslint/eslint-recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": [
"vue",
"@typescript-eslint"
],
"rules": {
}
};
\ No newline at end of file
.DS_Store
/node_modules
npm-debug.log
.vscode
.editorconfig
.idea/
package-lock.json
yarn.lock
yarn-error.log
dist/
\ No newline at end of file
# ycc
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Lints and fixes files
```
yarn lint
https://github.com/satoshilabs/slips/blob/master/slip-0044.md
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
{
"name": "ycc",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@33cn/chain33-rpc-api": "^1.5.29",
"@33cn/wallet-base": "^1.0.12",
"@trevoreyre/autocomplete-vue": "^2.2.0",
"animejs": "^3.2.1",
"ant-design-vue": "^1.7.5",
"bip39": "^3.0.4",
"core-js": "^3.6.5",
"crypto-js": "^4.0.0",
"dexie": "^3.0.3",
"ethereumjs-tx": "^2.1.2",
"ethereumjs-util": "^7.0.10",
"ethereumjs-wallet": "^1.0.1",
"jsqr": "^1.4.0",
"lodash": "^4.17.21",
"quagga": "^0.12.1",
"register-service-worker": "^1.7.1",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vue-toast-mobile": "^2.0.0",
"vuescroll": "^4.17.3",
"vuex": "^3.4.0",
"web3": "^1.3.6"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"@types/animejs": "^3.1.3",
"@types/crypto-js": "^4.0.1",
"@types/lodash": "^4.14.170",
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-pwa": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-typescript": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^9.8.6",
"babel-loader": "^8.2.2",
"babel-plugin-import": "^1.13.3",
"babel-plugin-lodash": "^3.3.4",
"css-loader": "^5.2.6",
"eslint": "^6.8.0",
"eslint-plugin-vue": "^7.10.0",
"postcss": "^7.0.35",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.1.2",
"typescript": "~4.1.5",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.46.0",
"webpack-cli": "^4.7.0"
},
"description": "## Project setup ``` yarn install ```",
"main": "babel.config.js",
"keywords": [],
"author": "",
"license": "ISC"
}
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
\ No newline at end of file
This diff is collapsed.
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
</svg>
<!DOCTYPE html>
<html lang="">
<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">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
User-agent: *
Disallow:
<template>
<div id="app">
<router-view v-if="cabilityChecked"></router-view>
<div v-else>loading</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'Home',
data(){
return{
cabilityChecked:true
}
},
async mounted(){
// const config ={
// url: 'https://mainnet.infura.io/v3/',
// id:'ab632ac39b8d4aff98d65429af748550'
// }
// let a = ETH_PROVIDER(config)
// const fee = await a.provider.eth.getBalance('0xfc55a938a349dc526a4d633a8395a82ca661820f')
// console.log(fee);
this.appReady()
},
methods:{
appReady(){
// web3.ready,
// Vue.prototype.$ETHweb3 = ETH_PROVIDER('b186ce03905e4f759fb7243fac5fc0df')
// db.ready,
// this.cabilityChecked = true
}
}
});
</script>
This diff is collapsed.
<template>
<div class="card flex flex-col">
<div class="header ">
<div class='w-full relative'>
<img src="@/assets/demo.png" class="object-cover h-36 object-center w-full rounded-tl-xl rounded-tr-xl">
<div class='cover w-full h-36 absolute top-0 left-0 z-40 bg-black bg-opacity-20'>
</div>
<div class='overlay w-full h-36 absolute top-0 left-0 z-50 p-5 '>
<div>离投票截止还有约</div>
<div></div>
</div>
</div>
</div>
<div class="bottom bg-app-blue-3 rounded-bl-xl rounded-br-xl ">
<div class="bottom-upside border-b border-gray-400">
<div class="px-5 py-3">
<div class='py-2'>这里是投票项目的名称</div>
<div class=" text-xs text-app-white">这里是投票项目的介绍</div>
</div>
</div>
<div class=" bottom-footside flex items-center justify-between px-5">
<div class='text-xs text-app-white'>当前票数<span class="ml-3 text-lg text-white">230</span></div>
<div>
<app-btn text='投票' class="bg-app-blue-2 rounded" border="border-none"></app-btn>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
},
methods:{
},
components:{
'app-btn':()=>import('@/components/common/Btn.vue')
}
});
</script>
<template>
<div class="card flex flex-col">
<div class="header bg-app-blue-4 flex items-center justify-between px-5 py-3 rounded-tl-xl rounded-tr-xl ">
<div class="medals w-16"></div>
<div class=" text-sm text-left justify-items-start">
<div>社区名称一</div>
<div>当前票数 <span>57217348918</span></div>
</div>
<div>
<app-btn text='投票' class="bg-app-blue-2 rounded" border="border-none"></app-btn>
</div>
</div>
<div class="bottom bg-app-blue-3 rounded-bl-xl rounded-br-xl ">
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
},
methods:{
},
components:{
'app-btn':()=>import('@/components/common/Btn.vue')
}
});
</script>
<template>
<div>
<img src="@/assets/loading.gif" alt="" />
<div class="text-center text-xs absolute top-16 left-14 mt-5">
<span v-for="(item, index) in text" :key="index" ref="text">{{
item
}}</span>
</div>
</div>
</template>
<script lang="ts">
const MAX_VALUE = 1;
const MIN_VALUE = 0.3;
import Vue from 'vue';
export default Vue.extend({
data() {
return {
text: "loading...",
timerIDs: [] as number[],
timerID: 0,
};
},
mounted() {
const list = this.$refs.text as HTMLSpanElement[];
this.startWave(list, 140, 0.2);
},
beforeDestroy() {
clearInterval(this.timerID);
},
methods: {
startWave(
list: HTMLSpanElement[],
timeOfswitchLightToNext: number,
stepValue: number
) {
const len = list.length;
let indexOfMax = 0;
const id = window.setInterval(() => {
list.forEach((el: HTMLSpanElement, index: number) => {
const distance1 = Math.abs(indexOfMax - index);
const distance2 = (function () {
const min = indexOfMax < index ? indexOfMax : index;
const max = indexOfMax > index ? indexOfMax : index;
return min + len - max;
})();
const minDistance = Math.min(distance1, distance2);
const curValue = MAX_VALUE - minDistance * stepValue;
this.changeOpacity(el, curValue < MIN_VALUE ? MIN_VALUE : curValue);
});
indexOfMax = (indexOfMax + 1) % len;
}, timeOfswitchLightToNext);
this.timerID = id;
},
changeOpacity(el: HTMLSpanElement, value: number) {
el.setAttribute("style", `opacity: ${value.toString()}`);
},
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div>
<div class="text-sm px-6 py-2 text-center cursor-pointer rounded my-3" :class="getSize && border" @click="eventEmit">
{{text}}
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'AppIcon',
props: {
size: String,
disabled: {
type:Boolean,
default:false
},
text:{
type: String,
required: true
},
border:{
type: String,
default:'border border-app-dark-4'
}
},
methods:{
eventEmit(v:any){
if(this.disabled){
return
}
this.$emit('btnClicked',v)
}
},
computed:{
getSize(){
switch (this.size) {
case 'full':
return 'w-full'
default:
return 'w-20';
}
}
}
});
</script>
<template>
<div class="cell flex justify-between py-3 border-t border-b border-app-dark-3 px-2">
<div class="left">hahah</div>
<div class="right">
<a-switch default-checked />
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Switch } from 'ant-design-vue'
Vue.use(Switch)
export default Vue.extend({
props: {
size: String,
type: {
type:String,
default:'select'
},
disabled:{
type:Boolean,
default:false
},
text:{
type: String,
required: true
},
theme:{
type: String,
default:'default'
}
},
methods:{
eventEmit(v:any){
if(this.disabled){
return
}
this.$emit('btnClicked',v)
}
},
computed:{
getSize(){
switch (this.size) {
case 'full':
return 'w-full'
default:
return 'w-20';
}
}
}
});
</script>
<template>
<div v-if="!customize">
<a-icon :type="type" :class="color" />
</div>
<div v-else>
<app-icon :type="type" :class="color" :style='{fontSize:size}'></app-icon>
</div>
</template>
<script lang="ts">
import Vue,{Component} from 'vue';
import { Icon } from 'ant-design-vue';
Vue.use(Icon)
const AppIcon = Icon.createFromIconfontCN({
scriptUrl:'/iconfont.js' // generated by iconfont.cn
});
export default Vue.extend({
props: {
type: String,
customize:{
type:Boolean,
default:false
},
size:{
type:String,
default:'16px'
},
color:{
type:String,
default:' text-white'
}
},
components:{
'app-icon':AppIcon as Component
}
});
</script>
<template>
<div class="app-selector relative">
<div class="selector-input border pl-2 border-app-white w-48 py-2 rounded flex justify-around align-middle items-center" @click="toggleOptions">
<div class="input-value flex-grow text-xs">
<div class="flex align-middle">
<div v-if="selectedItem.icon" class="flex-grow-0 self-center">
<app-icon :type="'icon-'+selectedItem.icon" customize size='text-lg'></app-icon>
</div>
<div class='flex-grow self-center'>{{selectedValue}}</div>
</div>
</div>
<div class="input-icon flex align-middle opacity-60 flex-grow-0">
<app-icon :type="open?'up':'down'" size='text-xs'></app-icon>
</div>
</div>
<transition :css="false" @enter='handleEnter' @leave='handleLeave'>
<div class="item-list w-48 fixed" v-if="open">
<section v-for="i in listArr" :key ='i.value' class="item border border-app-dark-4 bg-opacity-95 bg-app-dark-3 text-app-dark-4 py-2 px-2 s-3" @click="selected(i)">{{i.text}}</section>
</div>
</transition>
</div>
</template>
<script lang="ts">
import anime, { AnimeInstance} from 'animejs'
import Vue,{PropType} from 'vue';
const options = {
// delay: (el:any, i:number) => i * 100,
duration: 500,
easing: "easeOutCubic"
}
interface Item {
text:string,
value?:number,
icon?:string
}
export default Vue.extend({
name: 'app-selector',
data(){
return{
open:false,
// uiAnime: {} as AnimeInstance,
selectedItem:{},
selectedValue:'',
coinIcon:''
}
},
props:{
listArr:{
type: Array as PropType<Item[]>,
required: true
},
defaultItem:{
type: Boolean,
default:false
}
},
components:{
'app-icon':()=>import('@/components/Icon.vue')
},
mounted(){
if(this.defaultItem){
this.selectedItem = this.listArr[0]
this.selectedValue = this.listArr[0].text
this.$emit('selected', this.selectedItem)
}
},
methods:{
handleEnter(el:any,done:any){
const section =
Array.from(el.querySelectorAll('section'))
anime({
targets:section,
tanslateY:[-50,0],
opacity:[0,1],
...options,
complete:done
})
},
handleLeave: (el:any, done:any) => {
const sections = Array.from(el.querySelectorAll("section"))
anime({
targets: sections.reverse(),
translateY: 0,
opacity: 0,
...options,
complete: done
})
},
selected(item:any){
if(item.text === this.selectedValue){
this.open = !this.open;
return;
}
this.selectedValue = item.text
this.selectedItem = item
this.$emit('selected', item)
if(this.open){
this.open = !this.open
}
},
toggleOptions(){
this.open = !this.open
},
}
});
</script>
<template>
<div class="text-lg">
{{text}}
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'Title',
props: {
text:{
type: String,
required: true
}
},
});
</script>
<template>
<div class="time-box flex justify-center items-center">
<div class="time-items font-semibold" :style="fontStyle">{{ day }}</div>
<p class="text text-xs"></p>
<div class="time-items font-semibold" :style="fontStyle">{{ hour }}</div>
<p class="text text-xs"></p>
<div class="time-items font-semibold" :style="fontStyle">{{ min }}</div>
<p class="text text-xs"></p>
<div class="time-items font-semibold" :style="fontStyle">{{ sec }}</div>
<p class="text text-xs"></p>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
data() {
return {
day: '00',
hour: '00',
min: '00',
sec: '00',
time: 0,
timer: 0
}
},
props: {
times: {
type: [String, Date, Number]
},
fontStyle: {
type: Object
}
},
methods: {
getTimes() {
const r = +this.time - Date.now()
const day = +parseInt(r / (1000 * 60 * 60 * 24) + '')
this.day = day >= 10 ? day + '' : '0' + day
const hour = +parseInt(r / (1000 * 60 * 60) % 24 + '')
this.hour = hour >= 10 ? hour + '' : '0' + hour
const min = +parseInt(r / (1000 * 60) % 60 + '')
this.min = min >= 10 ? min + '' : '0' + min
const sec = +parseInt((r - (day * 24 * 60 * 60 * 1000) - hour * (1000 * 60 * 60) - min * (1000 * 60)) / 1000 + '')
this.sec = sec >= 10 ? sec + '' : '0' + sec
}
},
mounted() {
this.time = +this.times
if (this.timer) clearInterval(this.timer)
this.timer = window.setInterval(() => {
this.time--
this.getTimes()
}, 1000)
}
})
</script>
<style scoped>
.time-items {
padding: 4px;
background: #191C73;
}
.time-box {
}
</style>
\ No newline at end of file
import {CoinList} from '@/types/appTypes'
export const ERC20_COINS = [
{
name:'ethereum',
cn_title:'以太坊',
alis:'ETH',
main_chain:true
},
{
name:'Tether',
cn_title:'泰达币',
alis:'USDT',
c_addr:'0xdac17f958d2ee523a2206206994597c13d831ec7',
main_chain:false
},
{
name:'USD Coin',
cn_title:'',
alis:'USDC',
c_addr:'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
main_chain:false
},
{
name:'Uniswap',
cn_title:'',
alis:'UNI',
c_addr:'0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
main_chain:false
},
{
name:'Chainlink',
cn_title:'',
alis:'LINK',
c_addr:'0x514910771af9ca656af840dff83e8264ecf986ca',
main_chain:false
},
{
name:'Polygon',
cn_title:'',
alis:'MATIC',
c_addr:'0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0',
main_chain:false
},
{
name:'Binance USD',
cn_title:'',
alis:'BUSD',
c_addr:'0x4Fabb145d64652a948d72533023f6E7A623C7C53',
main_chain:false
},
{
name:'Wrapped Bitcoin',
cn_title:'',
alis:'WBTC',
c_addr:'0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
main_chain:false
},
{
name:'Dai',
cn_title:'',
alis:'DAI',
c_addr:'0x6b175474e89094c44da98b954eedeac495271d0f',
main_chain:false
},
{
name:'Aave',
cn_title:'',
alis:'AAVE',
c_addr:'0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9',
main_chain:false
},
{
name:'SHIBA INU',
cn_title:'',
alis:'SHIB',
c_addr:'0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce',
main_chain:false
},
{
name:'Maker',
cn_title:'',
alis:'MKR',
c_addr:'0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
main_chain:false
},
{
name:'Crypto.com Coin',
cn_title:'',
alis:'CRO',
c_addr:'0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b',
main_chain:false
},
{
name:'FTX Token',
cn_title:'',
alis:'FTT',
c_addr:'0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9',
main_chain:false
}
]
const CHAIN33_COINS = [
{
name:'btyuan',
cn_title:'比特元',
alis:'BTY',
main_chain:true
}
]
const binanceList = [
{
name:'Cardano',
cn_title:'',
alis:'ADA',
c_addr:'0x3ee2200efb3400fabb9aacf31297cbdd1d435d47',
main_chain:false
},
{
name:'XRP',
cn_title:'',
alis:'XRP',
c_addr:'0x1d2f0da169ceb9fc7b3144628db156f3f6c60dbe',
main_chain:false
},
{
name:'Dogecoin',
cn_title:'',
alis:'DOGE',
c_addr:'0xba2ae424d960c26247dd6c32edc70b295c744c43',
main_chain:false
},
{
name:'Polkadot',
cn_title:'',
alis:'DOT',
c_addr:'0x7083609fce4d1d8dc0c979aab8c869ea2c873402',
main_chain:false
},
{
name:'Bitcoin Cash',
cn_title:'',
alis:'BCH',
c_addr:'0x8fF795a6F4D97E7887C79beA79aba5cc76444aDf',
main_chain:false
},
{
name:'Litecoin',
cn_title:'',
alis:'LTC',
c_addr:'0x4338665cbb7b2485a8855a139b75d5e34ab0db94',
main_chain:false
},
{
name:'EOS',
cn_title:'',
alis:'EOS',
c_addr:'0x56b6fb708fc5732dec1afc8d8556423a2edccbd6',
main_chain:false
},
{
name:'Filecoin',
cn_title:'',
alis:'FIL',
c_addr:'0x0d8ce2a99bb6e3b7db580ed848240e4a0f9ae153',
main_chain:false
},
{
name:'PancakeSwap',
cn_title:'',
alis:'CAKE',
c_addr:'0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82',
main_chain:false
},
]
\ No newline at end of file
export const currences = [
{
tag:'USD',
symbol:"$"
},
{ tag:'RMB', symbol:"¥"}
];
\ No newline at end of file
// 静态数据的存放地址
\ No newline at end of file
import Web3 from 'web3'
interface Web3Obj{
provider:Web3
id?:string
url:string
port?:string
}
interface ProviderConfig{
id?:string
url:string
port?:string
}
/**
* @description 默认使用infura
* @param id 用户账户 必填
* @param url provider地址
* @param version 版本号
* @returns
*/
export const ETH_PROVIDER = (config:ProviderConfig):Web3Obj=>{
let {id,url,port} = config
id = id?id:''
url = url?url:'https://ropsten.infura.io/v3/'
port = port?port:''
const provider = new Web3(url+port+id)
return {provider,id,url,port}
}
// /**
// * @description 默认使用infura
// * @param id 用户账户 必填
// * @param url provider地址
// * @param version 版本号
// * @returns
// */
// export const BIAN_PROVIDER = (id?: string,port=':443',url='https://bsc-dataseed1.binance.org/')=>{
// const provider = new Web3(url+port+id)
// return {provider,id,url,port}
// }
\ No newline at end of file
import Dexie, { IndexableType, Table } from 'dexie';
import { decryptCiphertext, encryptPlaintext } from './util';
import { Account, Chains, Excer } from "@/types/appTypes"
export const data_config = {
name:'MxM_wallet',
version:1,
tables:{
account:'++id,encryptedPrivateKey,publicKey,address,excer',
processes:'++id,coin_name,amount,execer,is_main,c_addr,status',
coin:'++id,name,excer,is_main,c_addr,amount,process_amount'
}
}
export class DB extends Dexie {
account: Table<Account, IndexableType>
processes: Table<Chains, IndexableType>
constructor() {
super(data_config.name);
this.version(data_config.version).stores(data_config.tables);
this.account = this.table('account');
this.processes = this.table('processes');
}
async getAccountList(): Promise<Account[]> {
const arr = await this.account.toArray();
return arr;
}
addAccount(key: string, { privateKey, publicKey, address , excer }: { privateKey: string, publicKey: string, address: string, excer: Excer }) {
return this.account.add({
encryptedPrivateKey: encryptPlaintext(key, privateKey),
publicKey,
address,
excer
})
}
/**
* @description 用地址获取账户
* @param address
* @returns
*/
async getAccount(address: string): Promise<Account | undefined> {
const account = await this.account.where('address').equals(address).first();
return account
}
async getPrivateKey(address: string, key: string): Promise<string | undefined> {
const account = await this.getAccount(address)
if (account) {
const encryptedPrivateKey = account.encryptedPrivateKey
const privateKey = decryptCiphertext(key, encryptedPrivateKey)
return privateKey;
}
return undefined
}
deleteAccount(address: string) {
return this.account.where('address').equals(address).delete()
}
}
import CryptoJS from "crypto-js";
export function encryptPlaintext(key: string, plaintext: string) {
const obj = {
plaintext,
mark: true,
}
return AES_ECB_ENCRYPT(JSON.stringify(obj), key);
}
export function decryptCiphertext(key: string, ciphertext: string) {
const str = AES_ECB_DECRYPT(ciphertext, key);
try {
const obj = JSON.parse(str)
if (obj.mark === true) {
return obj.plaintext;
} else {
throw new Error('密码错误')
}
} catch (err) {
throw new Error('密码错误')
}
}
/**
* AES-256-ECB对称加密
* @param text {string} 要加密的明文
* @param secretKey {string} 密钥,43位随机大小写与数字
* @returns {string} 加密后的密文,Base64格式
*/
function AES_ECB_ENCRYPT(text: string, secretKey: string) {
const keyHex = CryptoJS.enc.Base64.parse(secretKey);
const messageHex = CryptoJS.enc.Utf8.parse(text);
const encrypted = CryptoJS.AES.encrypt(messageHex, keyHex, {
"mode": CryptoJS.mode.ECB,
"padding": CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
/**
* AES-256-ECB对称解密
* @param textBase64 {string} 要解密的密文,Base64格式
* @param secretKey {string} 密钥,43位随机大小写与数字
* @returns {string} 解密后的明文
*/
function AES_ECB_DECRYPT(textBase64: string, secretKey: string) {
const keyHex = CryptoJS.enc.Base64.parse(secretKey);
const decrypt = CryptoJS.AES.decrypt(textBase64, keyHex, {
"mode": CryptoJS.mode.ECB,
"padding": CryptoJS.pad.Pkcs7
});
return CryptoJS.enc.Utf8.stringify(decrypt);
}
\ No newline at end of file
<template>
<div class="Layout font-sans text-base bg-app-drak-1 page text-white">
<!-- <header>header</header> -->
<app-overlay></app-overlay>
<div class='content'>
<slot>
<router-view></router-view>
</slot>
</div>
<app-navigator></app-navigator>
<!-- <footer>mxmwebsite</footer> -->
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'Layout',
components:{
'app-overlay':()=>import('./overlay.vue'),
'app-navigator':()=>import('./navigator.vue')
}
});
</script>
<style scoped>
.Layout{
height:100%;
width: 100%;
position: relative;
overflow-y: scroll;
overflow-x: hidden;
}
.page{
height: 100vh;
width: 100vw;
}
</style>
\ No newline at end of file
<template>
<div class="flex fixed w-full justify-around bg-app-blue-1 " :class="getPosition">
<div v-for="(i,index) in navRoutes" :key="index" class="py-3 flex flex-col text-center " @click="navigating(i,index)">
<div class="self-center">
<app-icon customize :type='i.meta.icon' size='20px' :color='index===activedIndex?"text-app-yellow-1":" text-white"'></app-icon>
</div>
<div class=" pt-1 text-xs self-center" :class='index===activedIndex?"text-app-yellow-1":" text-white"'>{{i.meta.text}}</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import {routes} from '@/router/index'
import Icon from '@/components/common/Icon.vue'
interface NavItem{
component:any;
meta:{
icon:string;
text:string;
};
name:string;
path:string;
}
export default Vue.extend({
name: 'navgator',
data(){
return{
activedIndex:0,
navRoutes : routes[0].children as NavItem[]
}
},
props:{
position:{
type:String,
default:'bot'
}
},
mounted(){
const indexNumber = this.navRoutes.findIndex(i=>{
console.log(i);
return i.path === this.$route.path
})
if(this.navRoutes[this.activedIndex].path != this.$route.path){
this.activedIndex = indexNumber
}
},
components:{
'app-icon':Icon
},
methods:{
navigating(item:any,index:number){
if(this.$route.path != item.path){
this.activedIndex = index
this.$router.push(item.path);
}else{
return
}
}
},
computed:{
getPosition(){
let value = ''
switch(this.position){
case 'bot':
value ='bottom-0'
break
case 'top':
value= 'top-0'
break
}
return value
},
}
});
</script>
<template>
<div class="over-lay ">
<a-drawer
placement="top"
height='100%'
:closable='false'
:drawerStyle='{
backgroundColor:"#080F17",
color:"#C6CBD9"
}'
:visible="getOverlayData.show"
@close="onClose"
>
<div class="header flex text-app-white border-b border-app-dark-3 pb-3 justify-between">
<div>{{getOverlayData.data.title}}</div>
<div @click='onClose'>close</div>
</div>
<div class='wallet'>
</div>
<div class='setting'>
<div class="cell flex justify-between py-3 border-t border-b border-app-dark-3 px-2">
<div class="left">hahah</div>
<div class="right">valuevaule</div>
</div>
</div>
</a-drawer>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Drawer } from 'ant-design-vue'
Vue.use(Drawer)
export default Vue.extend({
methods:{
onClose(){
let show = this.$store.state.app.overlay.show
if(show){
this.$store.commit('app/TOGGLE_STATUS')
this.$store.commit('app/SET_OVERLAY',{})
}
},
},
computed:{
getOverlayData:function(){
return this.$store.state.app.overlay
}
}
});
</script>
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './style.css'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
import Vue from 'vue'
import { DB } from "@/db/db"
declare module 'vue/types/vue' {
interface Vue {
// $web3: Web3;
$db: DB;
// $bweb3:Web3;
}
}
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.\n' +
'For more details, visit https://goo.gl/AFskqB'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import ModeOne from '../layouts/index.vue'
Vue.use(VueRouter)
export const routes: Array<RouteConfig> = [
{
path: '/',
name: 'App_Main',
component: ModeOne,
redirect:'/Home',
children:[
{
path: '/Home',
name: 'Home',
component: ()=>import('@/views/Home.vue'),
meta:{
text: '英雄版',
icon: 'icon-yingxiongbang'
}
},
{
path: '/Square',
name: 'Square',
component: ()=>import('@/views/Square.vue'),
meta:{
text: '广场',
icon: 'icon-guangchang'
}
},
{
path: '/Initiate',
name: 'Initiate',
component: ()=>import('@/views/Initiate.vue'),
meta:{
text: '发起提案',
icon: 'icon-faqi'
}
},
{
path: '/Mine',
name: 'Mine',
component: ()=>import('@/views/Mine.vue'),
meta:{
text: '我的',
icon: 'icon-wode'
}
},
]
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
接口的统一出口文件
\ No newline at end of file
import Vue, { VNode } from 'vue'
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any
}
}
}
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
const stateData = {
overlay:{
show:false,
data:{
title:'默认'
}
}
}
interface overlayData {
title:string
}
export type AppType = typeof stateData
export const appStore = {
namespaced: true,
state: () => ({
...stateData
}),
mutations: {
TOGGLE_STATUS(state:AppType){
state.overlay.show = !state.overlay.show
},
SET_OVERLAY(state:AppType,payload:overlayData){
Object.assign(state.overlay.data,payload)
}
},
actions: {
},
getters: {
}
};
// export const navBar = {
// wechat:false,
// mobileMenuBar:false
// }
const stateData = {
status:0,
mncode:''
}
export type AuthType = typeof stateData
export const authStore = {
namespaced: true,
state: () => ({
...stateData
}),
mutations: {
SET_STATUS(state:AuthType,payload:number){
state.status = payload
console.log(state.status);
},
SET_MNCODE(state:AuthType,payload:string){
state.mncode = payload
}
},
actions: {
},
getters: {
}
};
// export type NavBar = typeof navBar.state
\ No newline at end of file
import Vue from 'vue'
import Vuex from 'vuex'
import { authStore } from './auth'
import { appStore } from './app'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
auth:authStore,
app:appStore
}
})
@tailwind base;
@tailwind components;
@tailwind utilities;
*{
padding: 0;
margin:0
}
body{
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
overflow: hidden;
}
#app{
height: 100%;
width: 100%;
}
.list {
height: calc(100vh - 390px) ;
overflow-y: scroll;
}
\ No newline at end of file
export interface iAccount{
address: string;
privateKey: string;
publicKey: string;
excer: Excer
}
export interface Account {
id?: number;
address: string;
encryptedPrivateKey: string;
publicKey: string;
excer:number
}
export enum WalletType{
RECOMMEND,
ERC20,
CHAIN33
}
export enum Excer {
ETH,
BTY
}
// 0 eth , 1 bty
export interface Wallet {
address: string;
privateKey: string;
publicKey: string;
excer:Excer
}
export interface Chains{
id?:string,
name:string,
url?:string
}
export interface Coin {
name:string,
cn_name?:string,
alis:string,
avatar?:string,
amount?:number,
price?:number,
total?:number,
c_name?:string,
is_main:boolean,
c_addr?:string,
}
export type CoinList = Coin[]
\ No newline at end of file
declare module '@33cn/wallet-base';
declare module "@33cn/chain33-rpc-api";
\ No newline at end of file
<template>
<div class="flex flex-col">
首页
<timebox :times="'1623237600000'" />
</div>
</template>
<script lang="ts">
import timebox from "@/components/timebox.vue";
import Vue from "vue";
export default Vue.extend({
components: { timebox },
name: "Home",
data() {
return {
};
},
});
</script>
<template>
<div class="flex flex-col">
发起
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "Initiate",
data() {
return {
};
},
});
</script>
<template>
<div class="flex flex-col">
我的
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "Mine",
data() {
return {
};
},
});
</script>
<template>
<div class="flex flex-col">
<div class=" h-260px bg-red-500 relative">
头部图片/可以用背景图片
<div class='w-full absolute bottom-1 '>
<div class=' w-11/12 mx-auto h-10 bg-blue-900 text-white'>
搜索input
</div>
</div>
</div>
<div class="list-contianer w-11/12 mx-auto">
<div class="sub-title flex items-center justify-between py-5">
<div>投票列表</div>
<div @click="doFilter"><app-icon type="icon-shaixuan" customize color=' text-white' ></app-icon></div>
</div>
<div class="list w-full">
<app-card class=" mb-2"></app-card>
<app-card2></app-card2>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "Square",
data() {
return {
};
},
components:{
'app-icon':()=>import('@/components/common/Icon.vue'),
'app-card':()=>import('@/components/Card.vue'),
'app-card2':()=>import('@/components/Card_two.vue')
},
methods:{
doFilter(){
console.log(123);
}
}
});
</script>
This diff is collapsed.
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
module.exports = {
// ...other vue-cli plugin options...
pwa: {
name: 'My App',
themeColor: '#4DBA87',
msTileColor: '#000000',
appleMobileWebAppCapable: 'yes',
appleMobileWebAppStatusBarStyle: 'black',
manifestOptions:{
display: 'standalone',
theme_color: '#333333'
},
// configure the workbox plugin
workboxPluginMode: 'InjectManifest',
workboxOptions: {
// swSrc is required in InjectManifest mode.
swSrc: 'dev/sw.js',
// ...other Workbox options...
}
}
}
\ No newline at end of file
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