Commit 714fb31c authored by zhangsan's avatar zhangsan

Initial commit

parents
Pipeline #73 failed with stages
module.exports = {
root: true,
env: {
node: true
},
extends: [
'plugin:vue/vue3-essential',
'@vue/standard'
],
parserOptions: {
parser: '@babel/eslint-parser'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'space-before-function-paren': 'off'
}
}
\ No newline at end of file
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Dependencies
node_modules
.pnpm-store
.yarn
# Build output
dist
dist-ssr
*.local
stats.html
# Editor directories and files
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.DS_Store
# Environment files
.env
.env.*
!.env.example
# Testing
coverage
/cypress/videos/
/cypress/screenshots/
# Cache files
.cache
.temp
.eslintcache
.stylelintcache
*.tsbuildinfo
# Vite
vite.config.ts.timestamp-*
# Vue
*.vue.js
*.vue.jsx
*.vue.ts
*.vue.tsx
# Temporary files
*.tmp
*.bak
*.swp
*~
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# Yarn
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
\ No newline at end of file
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
declare module 'vue' {
export interface GlobalComponents {
NavBar: typeof import('./src/components/NavBar.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
VanButton: typeof import('vant/es')['Button']
VanCard: typeof import('vant/es')['Card']
VanCell: typeof import('vant/es')['Cell']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanGoodsAction: typeof import('vant/es')['GoodsAction']
VanGoodsActionButton: typeof import('vant/es')['GoodsActionButton']
VanGoodsActionIcon: typeof import('vant/es')['GoodsActionIcon']
VanGrid: typeof import('vant/es')['Grid']
VanGridItem: typeof import('vant/es')['GridItem']
VanImage: typeof import('vant/es')['Image']
VanNavBar: typeof import('vant/es')['NavBar']
VanSearch: typeof import('vant/es')['Search']
VanSwipe: typeof import('vant/es')['Swipe']
VanSwipeItem: typeof import('vant/es')['SwipeItem']
VanTabbar: typeof import('vant/es')['Tabbar']
VanTabbarItem: typeof import('vant/es')['TabbarItem']
VanTreeSelect: typeof import('vant/es')['TreeSelect']
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>国币钱包</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
\ No newline at end of file
{
"name": "国币钱包",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite --host 0.0.0.0 --port 3006",
"build": "vite build",
"type-check": "vue-tsc --noEmit",
"preview": "vite preview"
},
"dependencies": {
"@varlet/icons": "^2.22.8",
"@varlet/touch-emulator": "^2.22.8",
"@varlet/ui": "^2.22.8",
"axios": "^1.6.2",
"core-js": "^3.30.0",
"crypto-js": "^4.2.0",
"echarts": "^5.6.0",
"nprogress": "^0.2.0",
"qrcode": "^1.5.4",
"vant": "^4.8.0",
"vue": "^3.2.47",
"vue-router": "^4.2.0"
},
"devDependencies": {
"@types/crypto-js": "^4.2.2",
"@types/node": "^18.0.0",
"@types/nprogress": "^0.2.3",
"@vant/auto-import-resolver": "^1.0.1",
"@vitejs/plugin-legacy": "^5.0.0",
"@vitejs/plugin-vue": "^4.5.0",
"postcss": "^8.4.31",
"postcss-px-to-viewport": "^1.1.1",
"sass": "^1.84.0",
"terser": "^5.24.0",
"typescript": "^5.0.4",
"unplugin-auto-import": "^0.16.7",
"unplugin-vue-components": "^0.25.2",
"vite": "^5.0.0",
"vite-plugin-bundle-obfuscator": "^1.4.1",
"vue-tsc": "^1.6.4"
},
"browserslist": [
"Android >= 4.0",
"iOS >= 8",
"Chrome >= 49",
"Firefox >= 52",
"Safari >= 10",
"> 1%",
"last 2 versions",
"not dead"
],
"resolutions": {
"@varlet/ui": "^2.22.8"
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<!DOCTYPE html>
<html lang="zh-CN">
<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,maximum-scale=1.0,user-scalable=no">
<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>
\ No newline at end of file
<template>
<div class="app">
<router-view v-slot="{ Component }">
<keep-alive :include="['home', 'category', 'user']">
<component :is="Component" />
</keep-alive>
</router-view>
<page-loading />
<van-popup v-model:show="show" :style="{ padding: '20px 0 50px' }">
<!-- <img class="yjbg123" src="@/static/yj.png" alt=""> -->
<div class="yjwarp">
<var-button class="varbtn11" @click="eventBus.popupVisible = false" block>我知道了</var-button>
<var-button class="varbtn11" @click="gotoyj" block>去填写邮寄信息</var-button>
</div>
</van-popup>
</div>
</template>
<script lang="ts" setup>
import eventBus from '@/utils/eventBus';
import PageLoading from '@/components/PageLoading.vue'
import { useRoute,useRouter } from 'vue-router';
const route = useRoute()
const router = useRouter()
const gotoyj = ()=>{
eventBus.popupVisible = false
router.push('/kpsl/cardsl')
}
const show = computed(()=>eventBus.popupVisible && route?.path != '/kpsl/cardsl')
</script>
<style lang="scss">
.yjbg123{
width: 100%;
height: auto;
}
.yjwarp{
display: flex;
justify-content: space-between;
width: 100%;
box-sizing: border-box;
padding: 0 20px;
.varbtn11{
width: 45%;
background: #3a9256;
color: #fff;
font-size: 16px;
font-weight: 700;
}
}
/* 移动端适配 */
html {
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
*{
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
}
.app {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
/* 适配刘海屏 */
@supports (padding-top: constant(safe-area-inset-top)) {
.app {
padding-top: constant(safe-area-inset-top);
padding-bottom: constant(safe-area-inset-bottom);
}
}
@supports (padding-top: env(safe-area-inset-top)) {
.app {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
}
}
</style>
\ No newline at end of file
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const showConfirmDialog: typeof import('vant/es')['showConfirmDialog']
const showDialog: typeof import('vant/es')['showDialog']
const showFailToast: typeof import('vant/es')['showFailToast']
const showNotify: typeof import('vant')['showNotify']
const showSuccessToast: typeof import('vant/es')['showSuccessToast']
const showToast: typeof import('vant/es')['showToast']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
declare module 'vue' {
export interface GlobalComponents {
GuideModal: typeof import('./components/GuideModal.vue')['default']
Kline: typeof import('./components/kline.vue')['default']
NavBar: typeof import('./components/NavBar.vue')['default']
NewsCard: typeof import('./components/NewsCard.vue')['default']
PageLoading: typeof import('./components/PageLoading.vue')['default']
PayUp: typeof import('./components/payUp.vue')['default']
ProcessFlow: typeof import('./components/ProcessFlow.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SignIn: typeof import('./components/signIn.vue')['default']
VanButton: typeof import('vant/es')['Button']
VanCell: typeof import('vant/es')['Cell']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanEmpty: typeof import('vant/es')['Empty']
VanField: typeof import('vant/es')['Field']
VanIcon: typeof import('vant/es')['Icon']
VanList: typeof import('vant/es')['List']
VanLoading: typeof import('vant/es')['Loading']
VanNavBar: typeof import('vant/es')['NavBar']
VanPopup: typeof import('vant/es')['Popup']
VanSwipe: typeof import('vant/es')['Swipe']
VanSwipeItem: typeof import('vant/es')['SwipeItem']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
VarButton: typeof import('@varlet/ui')['Button']
VarCard: typeof import('@varlet/ui')['Card']
VarForm: typeof import('@varlet/ui')['Form']
VarIcon: typeof import('@varlet/ui')['Icon']
VarInput: typeof import('@varlet/ui')['Input']
VarOption: typeof import('@varlet/ui')['Option']
VarPopup: typeof import('@varlet/ui')['Popup']
VarRadio: typeof import('@varlet/ui')['Radio']
VarRadioGroup: typeof import('@varlet/ui')['RadioGroup']
VarSelect: typeof import('@varlet/ui')['Select']
VarSpace: typeof import('@varlet/ui')['Space']
VarTab: typeof import('@varlet/ui')['Tab']
VarTabs: typeof import('@varlet/ui')['Tabs']
}
export interface ComponentCustomProperties {
vRipple: typeof import('@varlet/ui')['Ripple']
}
}
<template>
<Teleport to="body">
<Transition name="fade">
<div v-if="visible" class="guide-modal-overlay" @click.self="handleClose">
<Transition :name="transitionName" mode="out-in" @before-leave="beforeLeave" @after-leave="afterLeave">
<div class="guide-modal" :key="currentIndex">
<!-- 使用插槽或v-html展示内容 -->
<div class="guide-content">
<slot :index="currentIndex">
<div v-html="guideList[currentIndex]?.notictBody"></div>
</slot>
</div>
<div class="guide-footer">
<button class="guide-button" @click="handleAction">
{{ isLastPage ? '我知道了' : '下一页' }}
</button>
</div>
</div>
</Transition>
</div>
</Transition>
</Teleport>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
interface Props {
guideList: string[]
modelValue: boolean
}
const props = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
const currentIndex = ref(0)
const slideDirection = ref('next')
const transitionName = computed(() => `slide-${slideDirection.value}`)
const visible = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
})
const isLastPage = computed(() => currentIndex.value === props.guideList.length - 1)
const handleAction = () => {
if (isLastPage.value) {
handleClose()
} else {
slideDirection.value = 'next'
currentIndex.value++
}
}
const handleClose = () => {
visible.value = false
// 重置状态
setTimeout(() => {
currentIndex.value = 0
slideDirection.value = 'next'
}, 300)
}
const beforeLeave = () => {
document.body.style.overflow = 'hidden'
}
const afterLeave = () => {
document.body.style.overflow = ''
}
</script>
<style lang="scss" scoped>
.guide-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.guide-modal {
background: url('@/static/dialog.png') no-repeat;
background-size: 100% 100%;
width: 100%; // 调整宽度为90%
height: 80vh; // 设置高度为视口高度的70%
position: relative;
display: flex;
flex-direction: column;
overflow: hidden; // 防止内容溢出
}
.guide-content {
flex: 1;
overflow-y: auto; // 内容过多时可滚动
padding: 20px;
// 允许v-html内容继承样式
:deep(*) {
max-width: 100%;
height: auto;
}
}
.guide-button {
width: 100%; // 按钮宽度设为90%
margin: 0 auto;
display: block;
background: red;
color: #fff;
border: none;
padding: 12px 0;
font-size: 16px;
cursor: pointer;
transition: opacity 0.3s;
}
// 淡入淡出动画
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
// 滑动动画
.slide-next-enter-active,
.slide-next-leave-active,
.slide-prev-enter-active,
.slide-prev-leave-active {
transition: all 0.3s ease-out;
}
.slide-next-enter-from {
transform: translateX(100%);
opacity: 0;
}
.slide-next-leave-to {
transform: translateX(-100%);
opacity: 0;
}
.slide-prev-enter-from {
transform: translateX(-100%);
opacity: 0;
}
.slide-prev-leave-to {
transform: translateX(100%);
opacity: 0;
}
</style>
\ No newline at end of file
<template>
<van-nav-bar
:title="title"
left-arrow
@click-left="onClickLeft"
fixed
placeholder
/>
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router'
defineProps({
title: {
type: String,
default: ''
}
})
const router = useRouter()
const onClickLeft = () => {
router.back()
}
</script>
<style lang="scss" scoped>
:deep(.van-nav-bar) {
background-color: $primary-color;
.van-nav-bar__title {
color: #fff;
}
.van-icon {
color: #fff;
}
}
</style>
\ No newline at end of file
<template>
<div class="padding-box">
<div class="news-card">
<div v-for="item in props.content3" :key="item.id" class="news-item" @click="handleNewsClick(item)">
<div class="image-wrapper">
<img :src="getImageUrl(item.photo)" :alt="item.title" loading="lazy" />
</div>
<div class="content">
<h3 class="title">{{ item.title }}</h3>
<time class="subtitle">{{item.createTime}}</time>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
interface NewsItem {
id: number | string
noticeTitle: string
remark: string
// 添加其他需要的属性
}
// Props 定义
interface Props {
content3: NewsItem[]
action?: string
}
const props = withDefaults(defineProps<Props>(), {
content3: () => [],
action: ''
})
// 事件
const emit = defineEmits<{
(e: 'itemClick', item: NewsItem): void
}>()
// 获取完整图片URL
const getImageUrl = (remark: string) => {
return 'http://118.107.9.143:8080/jeecg-boot/' + remark
}
// 处理新闻点击
const handleNewsClick = (item: NewsItem) => {
emit('itemClick', item)
}
</script>
<style lang="scss" scoped>
.news-card {
margin: 7.5px 0; // 15rpx / 2
padding: 0;
border-radius: 5px; // 10rpx / 2
font-family: pingfang;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.news-item {
display: flex;
padding: 15px;
gap: 15px;
cursor: pointer;
transition: background-color 0.3s ease;
&:hover {
background-color: rgba(0, 0, 0, 0.02);
}
&:active {
background-color: rgba(0, 0, 0, 0.05);
}
&:not(:last-child) {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
}
.image-wrapper {
flex-shrink: 0;
width: 80px;
height: 80px;
border-radius: 4px;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
&:hover {
transform: scale(1.05);
}
}
}
.content {
flex: 1;
min-width: 0; // 防止文本溢出
display: flex;
flex-direction: column;
justify-content: space-between;
}
.title {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #333;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.4;
}
.subtitle {
font-size: 14px;
color: #999;
margin-top: auto;
}
</style>
\ No newline at end of file
<template>
<div v-if="loading" class="page-loading">
<van-loading type="spinner" color="#1989fa" size="36">
<span class="loading-text">{{ loadingText }}</span>
</van-loading>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useLoading } from '@/hooks/useLoading'
const { loading, loadingCount } = useLoading()
const loadingText = computed(() => loadingCount.value > 1 ? `加载中(${loadingCount.value})` : '加载中')
</script>
<style lang="scss" scoped>
.page-loading {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 16px 24px;
background: rgba(0, 0, 0, 0.6);
border-radius: 8px;
z-index: 9999;
.loading-text {
display: block;
margin-top: 8px;
color: #fff;
font-size: 14px;
}
}
</style>
\ No newline at end of file
<template>
<div class="process-flow">
<canvas ref="canvasRef" :width="canvasWidth" :height="height"></canvas>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed, watch, nextTick, onUnmounted } from 'vue'
interface Node {
text: string
}
const props = defineProps<{
nodes: Node[]
}>()
const canvasRef = ref<HTMLCanvasElement | null>(null)
const canvasWidth = computed(() => window.innerWidth - 40)
const NODES_PER_ROW = 3
const NODE_HEIGHT = 100
const NODE_WIDTH = computed(() => (canvasWidth.value - 60) / NODES_PER_ROW)
const HORIZONTAL_PADDING = 30
const NODE_RADIUS = 8
const LINE_GAP = 16
const height = computed(() => {
const rows = Math.ceil(props.nodes.length / NODES_PER_ROW)
return rows * NODE_HEIGHT + 40
})
const drawFlow = () => {
const canvas = canvasRef.value
if (!canvas) return
const ctx = canvas.getContext('2d')
if (!ctx) return
ctx.clearRect(0, 0, canvasWidth.value, height.value)
const nodeCount = props.nodes.length
if (nodeCount <= 1) return
// 先绘制连接线
for (let i = 0; i < nodeCount - 1; i++) {
drawConnection(ctx, i)
}
// 再绘制节点和文字
for (let i = 0; i < nodeCount; i++) {
const pos = getNodePosition(i)
drawNode(ctx, pos, props.nodes[i])
}
}
const drawNode = (
ctx: CanvasRenderingContext2D,
pos: { x: number; y: number },
node: Node
) => {
const x = pos.x + NODE_WIDTH.value / 2
const y = pos.y + 16
// 绘制圆点
ctx.beginPath()
ctx.arc(x, y, NODE_RADIUS, 0, Math.PI * 2)
ctx.fillStyle = '#1989fa'
ctx.fill()
ctx.strokeStyle = '#fff'
ctx.lineWidth = 2
ctx.stroke()
// 绘制文字
ctx.font = '14px Arial'
ctx.fillStyle = '#1989fa'
ctx.textAlign = 'center'
ctx.textBaseline = 'top'
ctx.fillText(node.text, x, y + 24)
}
const drawConnection = (ctx: CanvasRenderingContext2D, index: number) => {
const currentRow = Math.floor(index / NODES_PER_ROW)
const nextRow = Math.floor((index + 1) / NODES_PER_ROW)
const isRightToLeft = currentRow % 2 !== 0
const startPos = getNodePosition(index)
const endPos = getNodePosition(index + 1)
const startX = startPos.x + NODE_WIDTH.value / 2
const startY = startPos.y + 16
const endX = endPos.x + NODE_WIDTH.value / 2
const endY = endPos.y + 16
// 设置线条样式
ctx.beginPath()
ctx.strokeStyle = '#1989fa'
ctx.lineWidth = 2
if (currentRow !== nextRow) {
// 垂直连接
const midY = startY + (NODE_HEIGHT / 2)
ctx.moveTo(startX, startY + LINE_GAP)
ctx.lineTo(startX, midY)
ctx.lineTo(endX, midY)
ctx.lineTo(endX, endY - LINE_GAP)
} else {
// 水平连接
const startOffsetX = isRightToLeft ? -LINE_GAP : LINE_GAP
const endOffsetX = isRightToLeft ? LINE_GAP : -LINE_GAP
ctx.moveTo(startX + startOffsetX, startY)
ctx.lineTo(endX + endOffsetX, endY)
}
ctx.stroke()
// 绘制箭头
const angle = currentRow !== nextRow ? Math.PI / 2 : (isRightToLeft ? Math.PI : 0)
const arrowX = currentRow !== nextRow ? endX : (endX + (isRightToLeft ? LINE_GAP : -LINE_GAP))
const arrowY = currentRow !== nextRow ? endY - LINE_GAP : endY
drawArrow(ctx, arrowX, arrowY, angle)
}
const drawArrow = (
ctx: CanvasRenderingContext2D,
x: number,
y: number,
angle: number
) => {
const arrowSize = 6
ctx.save()
ctx.translate(x, y)
ctx.rotate(angle)
ctx.beginPath()
ctx.moveTo(-arrowSize, -arrowSize/2)
ctx.lineTo(0, 0)
ctx.lineTo(-arrowSize, arrowSize/2)
ctx.closePath()
ctx.fillStyle = '#1989fa'
ctx.fill()
ctx.restore()
}
const getNodePosition = (index: number) => {
const row = Math.floor(index / NODES_PER_ROW)
const isRightToLeft = row % 2 !== 0
let col = index % NODES_PER_ROW
if (isRightToLeft) {
col = NODES_PER_ROW - 1 - col
}
return {
x: col * NODE_WIDTH.value + HORIZONTAL_PADDING,
y: row * NODE_HEIGHT + 40
}
}
// 监听窗口大小变化
const handleResize = () => {
if (canvasRef.value) {
canvasRef.value.width = canvasWidth.value
nextTick(drawFlow)
}
}
onMounted(() => {
window.addEventListener('resize', handleResize)
drawFlow()
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
watch(
() => props.nodes.length,
() => {
nextTick(drawFlow)
}
)
</script>
<style scoped lang="scss">
.process-flow {
position: relative;
margin: 20px;
background: #fff;
border-radius: 12px;
width: auto;
box-sizing: border-box;
min-height: 300px;
}
</style>
\ No newline at end of file
<template>
<div ref="chartRef" :style="{ width: '100%', height: height }"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
const props = defineProps({
height: {
type: String,
default: '260px'
}
})
const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null
// 定义颜色常量
const upColor = '#00da3c'
const downColor = '#ec0000'
// 生成模拟数据
const generateMockData = () => {
const data = []
let basePrice = 1000 // 基准价格
let date = new Date('2024-01-01')
for (let i = 0; i < 30; i++) { // 生成30天数据
const open = basePrice + Math.random() * 20 - 10
const close = basePrice + Math.random() * 20 - 10
const low = Math.min(open, close) - Math.random() * 5
const high = Math.max(open, close) + Math.random() * 5
data.push([
date.toLocaleDateString(),
open.toFixed(2),
close.toFixed(2),
low.toFixed(2),
high.toFixed(2)
])
// 更新基准价格和日期
basePrice = close
date.setDate(date.getDate() + 1)
}
return data.reverse()
}
const initChart = () => {
if (!chartRef.value) return
const mockData = generateMockData()
const dates = mockData.map(item => item[0])
const data = mockData.map(item => [+item[1], +item[2], +item[3], +item[4]])
chart = echarts.init(chartRef.value)
const option = {
backgroundColor: '#fff', // 深色背景
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#1b1b1b'
}
},
backgroundColor: 'rgba(27, 27, 27, 0.9)',
borderColor: '#333',
textStyle: {
color: '#fff'
},
formatter: (params: any) => {
const data = params[0].data
return `
日期:${dates[params[0].dataIndex]}<br/>
开盘:${data[0]}<br/>
收盘:${data[1]}<br/>
最低:${data[2]}<br/>
最高:${data[3]}
`
}
},
grid: {
left: '8%',
right: '8%',
bottom: '10%',
top: '5%'
},
xAxis: {
type: 'category',
data: dates,
axisLine: {
lineStyle: {
color: '#333'
}
},
axisLabel: {
color: '#999',
fontSize: 10,
formatter: (value: string) => {
return value.split('/')[2] // 只显示日期
}
}
},
yAxis: {
scale: true,
position: 'right', // 将y轴移到右侧
axisLine: {
lineStyle: {
color: '#333'
}
},
axisLabel: {
color: '#999',
fontSize: 10,
formatter: (value: number) => {
return value.toFixed(2)
}
},
splitLine: {
show: true,
lineStyle: {
color: '#292929',
type: 'dashed'
}
}
},
series: [
{
name: 'K线',
type: 'candlestick',
data: data,
itemStyle: {
color: upColor,
color0: downColor,
borderColor: upColor,
borderColor0: downColor
}
}
],
animation: false // 关闭动画以提高性能
}
chart.setOption(option)
}
// 监听窗口大小变化
const handleResize = () => {
chart?.resize()
}
onMounted(() => {
initChart()
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
chart?.dispose()
window.removeEventListener('resize', handleResize)
})
</script>
This diff is collapsed.
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
// Props 定义
const props = defineProps({
lang: { type: String, default: 'zh' },
type: { type: String, default: 'calendar' },
checkDate: { type: Boolean, default: false },
bgweek: { type: String, default: '#e50112' },
bgday: { type: String, default: '#e50112' },
signin_but_bg: { type: String, default: '#909399' },
supplementary: { type: Boolean, default: true },
already: { type: Array, default: () => [] },
checkinDays: { type: [Number, String], default: 0 },
integral: { type: [Number, String], default: 0 },
isIntegral: { type: Boolean, default: false }
})
// Emits
const emit = defineEmits(['shift', 'change'])
// 响应式数据
const weeked = ref('')
const dayArr = ref([])
const localDate = ref('')
const currentDate = new Date()
const year = ref(currentDate.getFullYear())
const month = ref(currentDate.getMonth() + 1)
const day = ref(currentDate.getDate())
const aheadDay = ref(0)
const prv = ref(true)
const next = ref(true)
const is_day_signin = ref(false)
// 计算属性
const weekArr = computed(() =>
props.lang === 'zh' ? ['', '', '', '', '', '', ''] : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
)
const thisMonth = computed(() => currentDate.getMonth() + 1)
// 格式化数字
const formatNum = (num) => num < 10 ? `0${num}` : num
// 初始化日期
const initDate = () => {
dayArr.value = []
const totalDay = new Date(year.value, month.value, 0).getDate()
for (let i = 1; i <= totalDay; i++) {
const value = new Date(year.value, month.value - 1, i).getDay()
if (i === 1 && value !== 0) {
addBefore(value)
aheadDay.value = value
}
const dateObj = {
date: `${year.value}-${formatNum(month.value)}-${formatNum(i)}`,
day: i,
flag: false
}
dayArr.value.push(dateObj)
if (i === totalDay && value !== 6) {
addAfter(value)
}
}
}
// 补充前空白日期
const addBefore = (value) => {
const totalDay = new Date(year.value, month.value - 1, 0).getDate()
for (let i = 0; i < value; i++) {
dayArr.value.push({
date: '',
day: totalDay - (value - i) + 1
})
}
}
// 补充后空白日期
const addAfter = (value) => {
for (let i = 0; i < (6 - value); i++) {
dayArr.value.push({
date: '',
day: i + 1
})
}
}
// 签到处理
const daySign = (obj) => {
const index = aheadDay.value + day.value - 1
if (dayArr.value[index].flag) return false
dayArr.value[index].flag = true
emit('change', obj.date)
is_day_signin.value = true
showSuccessToast('已签到')
}
// 补签处理
const signToday = (obj, index) => {
if (props.type === 'calendar') return
if (currentDate.getMonth() + 1 !== parseInt(obj.date.split('-')[1])) return
if (obj.date && obj.day < day.value) {
if (dayArr.value[index].flag) {
showFailToast('已签到')
} else {
if (day.value > obj.day && !props.supplementary) return
showSuccessToast(day.value > obj.day ? '补签成功' : '签到成功')
dayArr.value[index].flag = true
emit('change', obj.date)
}
}
}
// 月份切换
const changeMonth = (direction) => {
if (direction === 'prev') {
if (month.value === 1) {
year.value--
month.value = 12
} else {
month.value--
}
} else {
if (month.value === 12) {
year.value++
month.value = 1
} else {
month.value++
}
}
initDate()
updateNavigationButtons()
}
// 更新导航按钮状态
const updateNavigationButtons = () => {
prv.value = year.value >= currentDate.getFullYear() || month.value > currentDate.getMonth() + 2
next.value = year.value <= currentDate.getFullYear() || month.value < currentDate.getMonth()
}
// 监听已签到数据变化
watch(() => props.already, (newVal) => {
dayArr.value.forEach((day, index) => {
day.flag = newVal.includes(day.date)
if (day.flag && day.date === localDate.value) {
is_day_signin.value = true
}
})
}, { deep: true })
// 初始化
onMounted(() => {
initDate()
localDate.value = `${year.value}-${formatNum(month.value)}-${formatNum(day.value)}`
weeked.value = weekArr.value[currentDate.getDay()]
if (props.type !== 'calendar') {
dayArr.value.forEach(day => day.flag = false)
}
})
</script>
<template>
<div class="calendar-container">
<!-- 头部信息 -->
<div class="header">
<div class="checkin-info">
<h4>累计签到 <span>{{ checkinDays }}</span></h4>
<!-- <p>每日签到奖励10000元</p> -->
</div>
<!-- <div class="actions">
<span v-if="supplementary" class="makeup-btn" @click="$emit('shift')">
补签
</span>
</div> -->
</div>
<!-- 日历主体 -->
<div class="calendar-body">
<!-- 月份导航 -->
<div class="month-nav">
<div class="nav-btn" @click="changeMonth('prev')">
<span v-show="prv">上月</span>
</div>
<div class="current-month">{{ year }}{{ month }}</div>
<div class="nav-btn" @click="changeMonth('next')">
<span v-show="next">下月</span>
</div>
</div>
<!-- 星期栏 -->
<div class="week-row">
<div v-for="week in weekArr" :key="week" class="week-cell" :style="{ color: week === weeked ? bgweek : '' }">
{{ week }}
</div>
</div>
<!-- 日期格子 -->
<div class="date-grid">
<div v-for="(date, index) in dayArr" :key="index" class="date-cell" :class="{
'empty': date.date === '',
'selected': date.date === localDate || date.flag
}" :style="{
background: (date.date === localDate || date.flag) ? bgday : ''
}">
<!-- @click="signToday(date, index)" -->
{{ date.day }}
<div :class="{
'dot': date.flag,
'makeup': date.day < day,
'today': date.day === day
}" />
</div>
</div>
</div>
<!-- 签到按钮 -->
<div class="sign-button">
<button :disabled="thisMonth !== month" :style="{
background: is_day_signin ?
signin_but_bg :
(thisMonth === month ? bgday : signin_but_bg)
}" @click="daySign(dayArr[aheadDay + day - 1])">
签到
</button>
</div>
</div>
</template>
<style lang="scss" scoped>
.calendar-container {
width: 100%;
display: flex;
flex-direction: column;
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background: #fff;
border-radius: 10px;
margin-bottom: 8px;
.checkin-info {
h4 {
font-weight: 600;
font-size: 18px;
line-height: 25px;
span {
color: #e50112;
margin: 0 5px;
font-size: 16px;
}
}
p {
font-size: 14px;
line-height: 20px;
color: #e50112;
}
}
.makeup-btn {
font-size: 12px;
color: #e50112;
border: 1px solid #e50112;
padding: 5px 10px;
border-radius: 16px;
&:active {
opacity: 0.8;
}
}
}
.calendar-body {
padding: 10px 20px;
background: #fff;
border-radius: 12px;
.month-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin: 15px 0;
.nav-btn {
min-width: 35px;
cursor: pointer;
&:active {
opacity: 0.8;
}
}
}
.week-row {
display: flex;
justify-content: space-between;
.week-cell {
width: 35px;
height: 35px;
display: flex;
align-items: center;
justify-content: center;
}
}
.date-grid {
display: flex;
flex-wrap: wrap;
.date-cell {
width: 35px;
height: 35px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
&.empty {
color: #999;
}
&.selected {
color: #fff;
border-radius: 50%;
}
.dot {
width: 5px;
height: 5px;
border-radius: 50%;
position: absolute;
bottom: 5%;
left: 50%;
transform: translateX(-50%);
background: #fff;
}
}
}
}
.sign-button {
display: flex;
justify-content: center;
margin-top: 40px;
button {
width: 325px;
height: 40px;
border-radius: 10px;
border: none;
outline: none;
color: #fff;
font-size: 16px;
&:active {
opacity: 0.9;
}
&:disabled {
opacity: 0.6;
}
}
}
}
</style>
\ No newline at end of file
import { App } from 'vue'
import { onMounted, onUnmounted, onActivated, onDeactivated } from 'vue'
import { $loading } from '@/hooks/useLoading'
// 全局组合式函数
export function onPageShow(fn: () => void | Promise<void>) {
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
fn()
}
}
onMounted(() => {
fn()
document.addEventListener('visibilitychange', handleVisibilityChange, false)
})
onUnmounted(() => {
document.removeEventListener('visibilitychange', handleVisibilityChange, false)
})
onActivated(() => {
fn()
document.addEventListener('visibilitychange', handleVisibilityChange, false)
})
onDeactivated(() => {
document.removeEventListener('visibilitychange', handleVisibilityChange, false)
})
}
export function onPageHide(fn: () => void) {
const handleVisibilityChange = () => {
if (document.visibilityState === 'hidden') {
fn()
}
}
onMounted(() => {
document.addEventListener('visibilitychange', handleVisibilityChange, false)
})
onUnmounted(() => {
fn()
document.removeEventListener('visibilitychange', handleVisibilityChange, false)
})
onActivated(() => {
document.addEventListener('visibilitychange', handleVisibilityChange, false)
})
onDeactivated(() => {
fn()
document.removeEventListener('visibilitychange', handleVisibilityChange, false)
})
}
// 注册全局组合式函数
export function setupGlobalComposables(app: App) {
// 添加到全局属性中
app.config.globalProperties.$onPageShow = onPageShow
app.config.globalProperties.$onPageHide = onPageHide
app.config.globalProperties.$loading = $loading
}
\ No newline at end of file
import { ref, onMounted } from "vue";
import request from "@/utils/request";
import eventBus from "@/utils/eventBus";
export interface UserInfo {
sysUser: {
identityId: string;
realname: string;
username: string;
yqm: string;
};
// ... 其他字段
}
const userInfo = ref<UserInfo | null>(null);
export const useUserInfo = () => {
const getUserInfo = async () => {
try {
const token = sessionStorage.getItem("token");
if (!token) return null;
// 先从 sessionStorage 获取
// const cached = sessionStorage.getItem("userInfo");
// if (cached) {
// userInfo.value = JSON.parse(cached);
// return userInfo.value;
// }
// 如果没有则请求接口
const res: any = await request.get("/business/businessWallet/getInfo");
if (res?.code === 200) {
userInfo.value = res.result;
sessionStorage.setItem("userInfo", JSON.stringify(res.result));
if (userInfo.value?.sysUser?.a9 == 2) {
eventBus.popupVisible = true; // 显示弹窗
} else {
eventBus.popupVisible = false; // 隐藏弹窗
}
return res.result;
}
return null;
} catch (error) {
console.error("获取用户信息失败:", error);
return null;
}
};
// 更新用户信息
const updateUserInfo = (newInfo: Partial<UserInfo>) => {
if (userInfo.value) {
userInfo.value = { ...userInfo.value, ...newInfo };
sessionStorage.setItem("userInfo", JSON.stringify(userInfo.value));
}
};
// 检查实名认证状态
const checkAuthStatus = () => {
if (userInfo.value?.sysUser?.identityId === "true") {
return true;
}
return false;
};
// 清除用户信息
const clearUserInfo = () => {
userInfo.value = null;
sessionStorage.removeItem("userInfo");
sessionStorage.removeItem("token");
};
return {
userInfo,
getUserInfo,
updateUserInfo,
checkAuthStatus,
clearUserInfo,
};
};
import { ref } from 'vue'
const loading = ref(false)
const loadingCount = ref(0)
export function useLoading() {
const showLoading = () => {
loadingCount.value++
loading.value = true
}
const hideLoading = () => {
loadingCount.value = Math.max(0, loadingCount.value - 1)
if (loadingCount.value === 0) {
loading.value = false
}
}
return {
loading,
loadingCount,
showLoading,
hideLoading
}
}
// 全局方法
export const $loading = {
show: () => useLoading().showLoading(),
hide: () => useLoading().hideLoading()
}
\ No newline at end of file
import { onMounted, onUnmounted, onActivated, onDeactivated } from 'vue'
export function usePageHook(options: {
onPageShow?: () => void | Promise<void>
onPageHide?: () => void
}) {
const { onPageShow, onPageHide } = options
// 处理页面显示
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
onPageShow?.()
} else {
onPageHide?.()
}
}
onMounted(() => {
// 首次加载执行
onPageShow?.()
// 添加可见性监听
document.addEventListener('visibilitychange', handleVisibilityChange)
})
onUnmounted(() => {
// 移除监听
document.removeEventListener('visibilitychange', handleVisibilityChange)
})
// keep-alive 激活/停用时触发
onActivated(() => {
onPageShow?.()
})
onDeactivated(() => {
onPageHide?.()
})
}
\ No newline at end of file
<template>
<div class="base-layout">
<router-view />
</div>
</template>
<script setup lang="ts">
</script>
\ No newline at end of file
<template>
<div class="header-layout">
<div class="header">
<van-nav-bar
:title="$route.meta.title"
left-arrow
@click-left="onClickLeft"
/>
</div>
<div class="content">
<router-view />
</div>
</div>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
const router = useRouter();
const onClickLeft = () => {
router.back();
};
</script>
<style lang="scss" scoped>
.header-layout {
min-height: 100vh;
display: flex;
flex-direction: column;
.header {
height: 46px;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
}
.content {
flex: 1;
margin-top: 46px;
height: calc(100vh - 46px);
overflow-y: auto;
background-color: var(--bg-color);
}
}
</style>
\ No newline at end of file
<template>
<div class="tabbar-layout">
<div class="content">
<router-view v-slot="{ Component }">
<component :is="Component"/>
</router-view>
</div>
<div class="tab-view">
<div
v-for="item in tabItems"
:key="item.path"
:class="route.name === item.name ? 'tab-item tab-item-active' : 'tab-item'"
@click="handleChange(item.path)"
>
<img class="tab-item-icon" v-if="route.name === item.name" :src="item.iconActive" alt="">
<img class="tab-item-icon" v-else :src="item.icon" alt="">
<span>{{ item.title }}</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useRouter, useRoute } from 'vue-router';
import tab1 from '@/static/tabbar/1.png';
import tab1Active from '@/static/tabbar/a1.png';
import tab2 from '@/static/tabbar/2.png';
import tab2Active from '@/static/tabbar/a2.png';
import tab3 from '@/static/tabbar/3.png';
import tab3Active from '@/static/tabbar/a3.png';
import tab4 from '@/static/tabbar/4.png';
import tab4Active from '@/static/tabbar/a4.png';
const router = useRouter();
const route = useRoute();
const tabItems = [
{ name: 'home', path: '/home', title: '首页', icon: tab1, iconActive: tab1Active },
{ name: 'smtx', path: '/smtx', title: '实名提现', icon: tab2, iconActive: tab2Active },
{ name: 'gbjy', path: '/gbjy', title: '国币交易', icon: tab3, iconActive: tab3Active },
{ name: 'user', path: '/user', title: '我的', icon: tab4, iconActive: tab4Active },
];
const handleChange = (path: string) => {
router.push(path);
};
</script>
<style lang="scss" scoped>
.tabbar-layout {
height: 100vh;
display: flex;
flex-direction: column;
.content {
height: calc(100% - 50px);
overflow-y: auto;
background-color: var(--bg-color);
}
.tab-view {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 50px;
display: flex;
justify-content: space-around;
align-items: center;
background-color: #fff;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
z-index: 999;
.tab-item {
flex: 1;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.tab-item-icon{
width: 25px;
height: 25px;
}
span {
margin-top: 3px;
font-size: 14px;
color: #666;
}
}
.tab-item-active {
flex: 1;
text-align: center;
span {
color: red;
}
}
}
}
</style>
\ No newline at end of file
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import Varlet from '@varlet/ui'
import '@varlet/ui/es/style'
import '@varlet/touch-emulator'
import '@/styles/index.scss'
const app = createApp(App)
app.use(router)
app.use(Varlet)
app.mount('#app')
\ No newline at end of file
import { createRouter, createWebHashHistory } from "vue-router";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { generateRoutes } from "@/utils/generateRoutes";
import { useUserInfo } from "@/composables/useUserInfo";
import request from "@/utils/request";
const routes = generateRoutes();
const router = createRouter({
history: createWebHashHistory(),
routes,
});
NProgress.configure({ showSpinner: false });
const { getUserInfo } = useUserInfo();
router.beforeEach(async (to, from, next) => {
NProgress.start();
document.title = (to.meta.title as string) || "数字化能";
// 检查版本更新
// if (process.env.NODE_ENV === "production") {
// try {
// let result = await checkVersion();
// console.log(result);
// const { version } = await checkVersion();
// console.log(version);
// if (version) {
// const storedVersion = sessionStorage.getItem("app_version");
// if (version !== storedVersion) {
// sessionStorage.setItem("app_version", version);
// if (to.path !== "/login") {
// window.location.reload();
// }
// }
// }
// } catch (error) {
// console.error("Version check failed:", error);
// }
// }
const token = sessionStorage.getItem("token");
// 登录页面判断
if (to.path === "/login") {
if (token) {
next("/");
return;
}
} else {
if (!token && to.path !== "/register") {
next("/login");
return;
}
}
next();
// 获取用户信息
if (token) {
await getUserInfo();
}
if (process.env.NODE_ENV === "production") {
request.get('/business/businessConfig/queryConfigByCode?code=appVersion').then(res => {
if (res.code == 200) {
if (res?.result?.appVersion !== sessionStorage.getItem('appVersion')) {
sessionStorage.setItem('appVersion', res?.result?.appVersion)
if(to.path !== '/login') {
window.location.reload()
}
}
}
})
}
});
router.afterEach(() => {
NProgress.done();
});
export default router;
import axios from 'axios'
import request from '@/utils/request'
export interface VersionResponse {
version: string
}
// 这里使用 nginx 配置的代理路径
export const checkVersion = async (): Promise<VersionResponse> => {
const response = await request.get<VersionResponse>('/business/businessConfig/queryConfigByCode?code=appVersion')
return response.data
}
\ No newline at end of file
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
\ No newline at end of file
src/static/cbg.png

999 KB

src/static/cbg1.png

999 KB

src/static/common/1.png

21.2 KB

src/static/common/2.png

25 KB

src/static/common/3.png

656 Bytes

src/static/common/4.png

390 Bytes

src/static/common/44.png

79.2 KB

src/static/common/77.png

19.1 KB

src/static/common/azxz.png

27.8 KB

src/static/common/iosxz.png

27.4 KB

<svg xmlns="http://www.w3.org/2000/svg" width="39" height="39" viewBox="0 0 39 39">
<g id="组_124315" data-name="组 124315" transform="translate(-167 -179)">
<path id="直线_4727" data-name="直线 4727" d="M36,1.5H0A1.5,1.5,0,0,1-1.5,0,1.5,1.5,0,0,1,0-1.5H36A1.5,1.5,0,0,1,37.5,0,1.5,1.5,0,0,1,36,1.5Z" transform="translate(168.5 198.5)" fill="#777"/>
<path id="直线_4728" data-name="直线 4728" d="M36,1.5H0A1.5,1.5,0,0,1-1.5,0,1.5,1.5,0,0,1,0-1.5H36A1.5,1.5,0,0,1,37.5,0,1.5,1.5,0,0,1,36,1.5Z" transform="translate(186.5 180.5) rotate(90)" fill="#777"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="9" viewBox="0 0 14 9">
<path id="多边形_2" data-name="多边形 2" d="M6.211,1.015a1,1,0,0,1,1.579,0l4.955,6.371A1,1,0,0,1,11.955,9H2.045a1,1,0,0,1-.789-1.614Z" fill="#333"/>
</svg>
src/static/common/tianjia.png

153 Bytes

src/static/common/tip.png

5.68 KB

<svg xmlns="http://www.w3.org/2000/svg" width="14" height="9" viewBox="0 0 14 9">
<path id="多边形_4" data-name="多边形 4" d="M6.211,1.015a1,1,0,0,1,1.579,0l4.955,6.371A1,1,0,0,1,11.955,9H2.045a1,1,0,0,1-.789-1.614Z" transform="translate(14 9) rotate(180)" fill="#777"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="10.588" viewBox="0 0 12 10.588">
<path id="选择" d="M132.1,198.745l-5.032-5.242,1.29-1.059,2.91,2.337a32.472,32.472,0,0,1,7.493-6.623l.307.727a31.754,31.754,0,0,0-6.968,9.861Zm0,0" transform="translate(-127.068 -188.158)" fill="#e60012"/>
</svg>
src/static/common/zjt.png

168 Bytes

src/static/commonbg.png

999 KB

src/static/dialog.png

1010 KB

src/static/gbjy/1.png

55.5 KB

src/static/gbjy/2.png

15.4 KB

src/static/gbjy/3.png

8.88 KB

src/static/gbjy/4.png

23.8 KB

src/static/gbjy/5.png

253 KB

src/static/home/2.png

999 KB

src/static/home/3.png

292 KB

src/static/home/4.png

16.9 KB

src/static/home/5.png

66.9 KB

<svg xmlns="http://www.w3.org/2000/svg" width="74" height="74" viewBox="0 0 74 74">
<g id="组_124121" data-name="组 124121" transform="translate(-158 -467)">
<rect id="矩形_54153" data-name="矩形 54153" width="74" height="74" rx="16" transform="translate(158 467)" fill="#f5d94c"/>
<g id="收益_1_" data-name="收益 (1)" transform="translate(110 420.6)">
<path id="路径_4859" data-name="路径 4859" d="M93.029,78.411A12.719,12.719,0,1,0,105.748,91.13,12.708,12.708,0,0,0,93.029,78.411Zm2.843,11a1.859,1.859,0,0,0,.6.075h1.945a.533.533,0,0,1,.449.224.647.647,0,0,1,.224.449v1.422c0,.3-.224.374-.6.374H95.124a1.063,1.063,0,0,0-.449.15.411.411,0,0,0-.224.374v.973c0,.224.224.3.6.224h3.292c.374,0,.6.15.6.524v1.2c0,.374-.3.6-.823.6H95.049a.534.534,0,0,0-.524.6v2.319c0,.224-.15.3-.449.3h-1.8c-.524,0-.748-.224-.748-.6v-2.02c0-.224,0-.3-.075-.374,0-.075-.15-.075-.374-.075H87.642c-.524,0-.748-.224-.748-.748a1.316,1.316,0,0,0-.075-.449.639.639,0,0,1,0-.524,4.769,4.769,0,0,1,.15-.524.333.333,0,0,1,.449-.15h3.816c.075,0,.075-.075.075-.3V92.327c0-.224-.224-.3-.673-.3H86.969c-.15,0-.15-.15-.15-.3v-.823a1.661,1.661,0,0,0-.075-.673.582.582,0,0,1,.15-.6,1.264,1.264,0,0,1,.748-.224,2.135,2.135,0,0,0,.973,0h1.5q.337,0,.224-.224-.112-.112-.673-.9c-.374-.524-.748-1.047-1.2-1.571-.524-.673-1.047-1.347-1.721-2.17a.671.671,0,0,1,.15-1.047,4.15,4.15,0,0,1,.6-.449c.224-.15.449-.3.748-.524.374-.224.748,0,1.047.6.15.15.3.449.673.823.3.374.673.823.973,1.272a14.384,14.384,0,0,0,.973,1.272c.3.374.449.6.524.673a.687.687,0,0,0,.449.3.333.333,0,0,0,.449-.15c0-.075.224-.3.449-.748.3-.374.6-.823.973-1.347s.673-.973.973-1.422a8.054,8.054,0,0,1,.6-.823,4.479,4.479,0,0,1,.449-.524.755.755,0,0,1,.673.075,2.625,2.625,0,0,1,.6.374,2.849,2.849,0,0,1,.449.374c.449.449.524.823.374,1.122-.075.15-.3.374-.6.9-.374.449-.748.973-1.122,1.5a18.152,18.152,0,0,0-1.047,1.5,5.331,5.331,0,0,0-.524.823c.075.15.075.224.3.3ZM79.712,62.4C71.033,62.4,64,65.916,64,70.181s7.033,7.781,15.712,7.781,15.712-3.516,15.712-7.781C95.348,65.916,88.316,62.4,79.712,62.4Z" fill="#fff"/>
<path id="路径_4860" data-name="路径 4860" d="M84.65,322.486a34.8,34.8,0,0,1-4.938.374c-7.482,0-13.692-2.619-15.263-6.06A3.691,3.691,0,0,0,64,318.521c0,4.265,7.033,7.781,15.712,7.781h1.272A11.9,11.9,0,0,1,84.65,322.486Zm10.325-2.17a3.984,3.984,0,0,0,.449-1.8,4.438,4.438,0,0,0-.374-1.721,8.634,8.634,0,0,1-3.292,3.292h.673A15.274,15.274,0,0,1,94.974,320.316Z" transform="translate(0 -242.504)" fill="#fff"/>
<path id="路径_4861" data-name="路径 4861" d="M79.712,433.26c-7.482,0-13.692-2.619-15.263-6.06A3.475,3.475,0,0,0,64,428.921c0,4.19,6.659,7.557,14.963,7.781a13.138,13.138,0,0,1,1.047-3.442Z" transform="translate(0 -347.742)" fill="#fff"/>
<path id="路径_4862" data-name="路径 4862" d="M78.814,542.06c-7.108-.224-12.869-2.693-14.44-6.06A4.752,4.752,0,0,0,64,537.721c0,4.19,6.734,7.631,15.113,7.781a12.886,12.886,0,0,1-.3-2.918,1.223,1.223,0,0,1,0-.524Z" transform="translate(0 -451.454)" fill="#fff"/>
<path id="路径_4863" data-name="路径 4863" d="M64.374,646.4A4.438,4.438,0,0,0,64,648.121c0,4.265,7.033,7.781,15.712,7.781a13.242,13.242,0,0,0,1.721-.075,13.673,13.673,0,0,1-1.8-3.442C72.155,652.385,65.945,649.842,64.374,646.4Z" transform="translate(0 -556.692)" fill="#fff"/>
<path id="路径_4864" data-name="路径 4864" d="M82.779,761.11c-.973.075-2.02.15-3.068.15-7.482,0-13.692-2.619-15.263-6.06A3.475,3.475,0,0,0,64,756.921c0,4.265,7.033,7.781,15.712,7.781a30.372,30.372,0,0,0,7.108-.823A12.926,12.926,0,0,1,82.779,761.11Z" transform="translate(0 -660.404)" fill="#fff"/>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52">
<defs>
<style>
.cls-1 {
fill: #ffd065;
}
.cls-2 {
fill: #fff;
}
</style>
</defs>
<g id="组_124309" data-name="组 124309" transform="translate(-40 -555)">
<rect id="矩形_54127" data-name="矩形 54127" class="cls-1" width="52" height="52" rx="8" transform="translate(40 555)"/>
<path id="激励金账户" class="cls-2" d="M94.929,23.843a2.9,2.9,0,0,0-2.165-.957H81.839a2.915,2.915,0,0,0-2.1.881c-3.432,3.56-6.6,8.644-6.6,12.35,0,3.268,3.317,7.395,7.409,7.395H93.236c4.092,0,7.409-4.092,7.409-7.395,0-3.774-2.546-8.713-5.716-12.274Zm-4.541,5.3-1.811,3.14a.415.415,0,0,0,.378.614h.513a.415.415,0,1,1,0,.83H88.177a.445.445,0,0,0-.456.433v.2a.425.425,0,0,0,.435.415h1.314a.415.415,0,1,1,0,.83H88.155a.425.425,0,0,0-.434.415v1.054a.426.426,0,0,1-.434.416H86.5a.426.426,0,0,1-.434-.415V36.025a.426.426,0,0,0-.435-.416h-1.3a.415.415,0,1,1,0-.83h1.3a.428.428,0,0,0,.437-.415l0-.2a.444.444,0,0,0-.455-.438H84.331a.415.415,0,1,1,0-.83h.5a.415.415,0,0,0,.379-.615L83.4,29.14a.415.415,0,0,1,.379-.614h.863a.434.434,0,0,1,.387.228l1.474,2.81a.445.445,0,0,0,.776,0l1.475-2.811a.436.436,0,0,1,.387-.227H90a.419.419,0,0,1,.384.617Zm-8.062-7.786a2.254,2.254,0,0,1-1.742-.851c-1.093-1.34-2.093-2.955-2.093-4.15,0-2.958,2.325-2.48,3.979-2.5,1.417-.016,1.678-1.664,3.694-1.664,1.113,0,1.429,1.664,2.414,1.664,1.44,0,2.31-1.664,4.042-1.664A3.425,3.425,0,0,1,96,16.356a9.821,9.821,0,0,1-2.181,4.179,2.192,2.192,0,0,1-1.717.823h-9.78Z" transform="translate(-21.143 552.81)"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<defs>
<style>
.cls-1 {
fill: #fff;
stroke: #707070;
}
.cls-2 {
fill: #48b338;
}
.cls-3 {
stroke: none;
}
.cls-4 {
fill: none;
}
</style>
</defs>
<g id="微信支付" transform="translate(0 -1)">
<g id="矩形_2340" data-name="矩形 2340" class="cls-1" transform="translate(1 2)">
<rect class="cls-3" width="18" height="18"/>
<rect class="cls-4" x="0.5" y="0.5" width="17" height="17"/>
</g>
<path id="支付-微信支付" class="cls-2" d="M17.5,0H2.5A2.507,2.507,0,0,0,0,2.5v15A2.507,2.507,0,0,0,2.5,20h15A2.507,2.507,0,0,0,20,17.5V2.5A2.507,2.507,0,0,0,17.5,0ZM10,15.375A7.276,7.276,0,0,1,7.625,15c-.5.25-1.25.875-1.5,1-.5.25-.375-.25-.375-.25L6,14.25A5.242,5.242,0,0,1,3.625,9.875C3.625,6.75,6.5,4.25,10,4.25a6.947,6.947,0,0,1,5.25,2.375L9,9.5a.993.993,0,0,1-1-.125l-1-.75S6.25,8,6.625,9l1,2.25s.125.625.875.25c.625-.25,5.25-3.125,7.25-4.25a5.688,5.688,0,0,1,.625,2.5c0,3-2.875,5.625-6.375,5.625Z" transform="translate(0 1)"/>
</g>
</svg>
<svg id="银联" xmlns="http://www.w3.org/2000/svg" width="19.65" height="19.65" viewBox="0 0 19.65 19.65">
<rect id="矩形_207" data-name="矩形 207" width="19.65" height="19.65" fill="none"/>
<g id="支付宝支付" transform="translate(1.824 1.829)">
<g id="银联-2" data-name="银联" transform="translate(-1.082 -1.09)">
<path id="路径_4969" data-name="路径 4969" d="M4.077,4.153A1.4,1.4,0,0,0,3,5.035c-.1.275-1.909,8.065-1.918,8.206a.722.722,0,0,0,.606.782c.143.033,4.735.033,4.887,0a1.38,1.38,0,0,0,1-.841c.059-.158,1.926-8.1,1.926-8.231a.757.757,0,0,0-.564-.791c-.084-.017-4.668-.033-4.861-.008Z" fill="#e60012"/>
<path id="路径_4970" data-name="路径 4970" d="M8.358,4.153a1.4,1.4,0,0,0-1.077.882c-.093.275-1.909,8.065-1.909,8.206a.722.722,0,0,0,.606.782c.143.033,4.735.033,4.887,0a1.38,1.38,0,0,0,1-.841c.059-.158,1.926-8.1,1.926-8.231a.757.757,0,0,0-.563-.791c-.093-.017-4.676-.033-4.87-.008Z" fill="#00508e"/>
<path id="路径_4971" data-name="路径 4971" d="M12.824,4.153a1.4,1.4,0,0,0-1.077.882c-.092.275-1.909,8.065-1.909,8.206a.722.722,0,0,0,.606.782c.143.033,3.558.033,3.709,0a1.38,1.38,0,0,0,1-.841c.059-.158,1.926-8.1,1.926-8.231a.757.757,0,0,0-.564-.791c-.084-.025-3.919-.042-4.113-.017h.421v.008Z" fill="#00908c"/>
<path id="路径_4972" data-name="路径 4972" d="M3.934,6.683a.546.546,0,0,1-.025.108,9.026,9.026,0,0,0-.362,1.631c.067.325.547.3.715-.042.05-.092.412-1.615.412-1.723,0-.008.572,0,.572.008a.177.177,0,0,1-.008.05c-.008.025-.1.374-.2.791a3.5,3.5,0,0,1-.37,1.148c-.387.566-1.682.549-1.783-.025a13.349,13.349,0,0,1,.379-1.956,3.637,3.637,0,0,1,.673.008Zm8.6,0c.387.083.5.391.328.849s-.555.657-1.22.657c-.2,0-.185-.033-.311.591-.025.117-.05.225-.05.241a1.444,1.444,0,0,1-.6,0c.5-2.139.547-2.322.547-2.339l.008-.025h.606a5.585,5.585,0,0,1,.69.025Zm-5.189.824a.167.167,0,0,1,.143.142c0,.208-.429.35-.589.191s.168-.4.446-.333Zm-1.489.158c0,.017-.008.05-.008.075l-.008.033.1-.05c.269-.133.53-.108.614.058.05.1.042.158-.093.774-.025.108-.059.258-.067.333-.034.167-.008.158-.311.158-.261,0-.261,0-.252-.025s.034-.15.067-.308c.135-.591.143-.674.025-.674a.243.243,0,0,0-.168.067c-.017.058-.168.782-.177.849l-.017.075L5.3,9.046c-.32.008-.294.033-.227-.25a8.176,8.176,0,0,0,.177-.857c.042-.25.017-.225.252-.258.109-.017.219-.033.252-.042.084-.025.1-.017.1.025Zm4-.008c0,.017-.008.05-.008.075l-.008.042.1-.05c.521-.266.723-.05.572.633-.034.15-.076.366-.1.466a.883.883,0,0,1-.05.208,1.56,1.56,0,0,1-.522,0c0-.017.034-.15.067-.3.143-.608.143-.682.017-.682-.1,0-.151.033-.168.108-.025.092-.151.691-.168.8l-.017.092L9.3,9.055c-.32.008-.294.042-.219-.266.084-.333.143-.641.185-.866s.008-.191.219-.225c.093-.017.21-.033.252-.042.084-.042.109-.033.109,0Zm5.105-.008c.034.508.042.657.042.666a2.879,2.879,0,0,0,.16-.291c.168-.333.135-.3.32-.325.05-.008.151-.025.227-.042.185-.033.185-.05-.025.316-.286.491-.681,1.182-.824,1.432-.429.774-.429.774-.791.782l-.219.008.017-.058c.008-.033.034-.1.042-.15l.025-.092h.067c.076,0,.092-.017.16-.133a1.339,1.339,0,0,0,.084-.15c.025-.042.109-.175.177-.308l.135-.233-.034-.308c-.042-.358-.092-.782-.118-.907s-.017-.117.135-.133c.067-.008.177-.033.236-.042.16-.05.177-.05.185-.033Zm-6.342.008c.648.117.421,1.232-.286,1.39-.479.108-.807-.075-.807-.441a.909.909,0,0,1,1.093-.949Zm4.845.033a.505.505,0,0,1,.109.075c.042.042.042.042.042.017s0-.033.336-.083c.269-.042.261-.042.244.033-.109.466-.2.874-.244,1.074-.059.3-.017.266-.345.258h-.278V9.03c0-.033-.017-.05-.034-.025-.093.15-.547.092-.673-.092-.311-.466.353-1.448.841-1.223Zm-6.039.241a.362.362,0,0,1-.008.075c-.067.266-.185.807-.21.907l-.025.125-.278.008c-.328.008-.311.025-.244-.175A4.255,4.255,0,0,0,6.8,8.2c.034-.216,0-.183.244-.216.109-.017.227-.033.252-.042.067-.017.109-.017.118-.008ZM8.888,9.654a.343.343,0,0,1-.042.083.372.372,0,0,1-.042.075c.5.008.513.008.5.033l-.092.3H8.493l-.042.033c-.093.083-.58.191-.58.125l.093-.3H8.03c.118,0,.143-.025.244-.2l.084-.158a2.47,2.47,0,0,1,.53.008Zm1.1,0a.52.52,0,0,1-.025.1.373.373,0,0,0-.025.092.388.388,0,0,0,.092-.058c.185-.125.345-.15.816-.15a2.893,2.893,0,0,1,.353.008c.008.017-.269.916-.311,1a.423.423,0,0,1-.21.208l-.084.033-.479.008-.479.008-.084.283c-.168.541-.168.5.076.474.193-.017.185-.033.126.166l-.05.166H9.46c-.53.008-.6-.025-.547-.241.025-.108.631-2.089.639-2.106a2.555,2.555,0,0,1,.437.008Zm2.212,0c0,.008-.008.033-.017.067-.025.083-.025.083.084.025a3.366,3.366,0,0,1,1.169-.1h.219v.1c0,.117.008.125.109.141l.076.008-.042.15-.042.15h-.151c-.387.008-.446-.033-.454-.258V9.829l-.025.075-.025.083h-.084c-.042,0-.084,0-.084.008s-.412,1.356-.471,1.548c-.008.017,0,.025.05.025.076,0,.076,0,.05.066s-.025.075.059.075a.232.232,0,0,0,.135-.033c.059-.033.059-.025.328-.4l.109-.158h-.227c-.278,0-.252.017-.2-.15l.042-.133h.555c.05-.175.067-.225.067-.233a1.53,1.53,0,0,0-.269-.008h-.269l.084-.3h.757c.412,0,.757,0,.757.008a1.133,1.133,0,0,1-.042.15l-.042.141-.252.008-.252.008c-.042.125-.059.183-.067.2l-.008.033h.244c.286,0,.269-.017.21.15l-.042.133h-.555l-.084.1h.219l.034.2c.034.225.034.225.143.225.084,0,.084-.017.025.183L13.968,12h-.16c-.278,0-.328-.042-.379-.325l-.025-.183-.1.133c-.278.374-.294.383-.648.383-.227,0-.227,0-.193-.067.008-.033.008-.033-.059-.033s-.067,0-.084.05l-.008.05H11.84l.008-.025c.025-.083.067-.075-.446-.075-.446,0-.471,0-.463-.025l.042-.15c.05-.15.042-.15.092-.15s.042,0,.059-.058c.4-1.307.522-1.723.538-1.781l.034-.108h.236a1.037,1.037,0,0,1,.261.017Zm-2.986.716-.093.291h-.5a2.439,2.439,0,0,1-.076.233c-.008.025.008.025.252.025.143,0,.261.008.261.008a.326.326,0,0,1-.017.05,1.392,1.392,0,0,0-.042.15l-.034.108H8.442l-.059.2c-.084.283-.076.291.244.25.135-.017.126-.033.067.166l-.05.166H8.291c-.555,0-.563-.017-.412-.491.042-.15.084-.275.084-.275a1.128,1.128,0,0,0-.143-.008.458.458,0,0,1-.143-.008c.059-.208.084-.275.084-.291s.025-.025.151-.025h.143l.067-.258H7.988c-.1,0-.135,0-.135-.017s.076-.258.084-.283,1.287-.008,1.278.008Zm1.632.6c0,.017-.017.067-.025.108-.051.233-.118.283-.387.3l-.177.017a.664.664,0,0,0,0,.258l.025.033.168-.008c.093-.008.168-.008.168-.008,0,.017-.093.308-.1.316a2.954,2.954,0,0,1-.6-.017c-.1-.033-.1-.025-.093-.549l.008-.458h.429v.175h.084c.092,0,.1-.008.143-.125l.025-.067h.168C10.839,10.952,10.856,10.952,10.848,10.969Zm.791-3.562-.093.4h.126c.648.017.917-.724.286-.774l-.2-.017c-.025,0-.025.025-.118.391Zm-3.348.566c-.16.067-.311.666-.185.757.092.075.227-.05.294-.258C8.51,8.089,8.476,7.906,8.291,7.973Zm5.013.042c-.168.083-.294.674-.168.741.168.092.387-.225.387-.566C13.523,8.031,13.43,7.956,13.3,8.014ZM9.906,10l-.042.15a1.4,1.4,0,0,1-.05.15c0,.008.042-.008.1-.042a.845.845,0,0,1,.463-.108l.21-.008a.828.828,0,0,0,.042-.15A7.026,7.026,0,0,0,9.906,10Zm-.143.483-.034.133.723-.008.042-.133C9.923,10.47,9.763,10.47,9.763,10.478Zm2.288-.3a.81.81,0,0,0-.05.191l.1-.033a1.631,1.631,0,0,1,.193-.05c.05-.008.092-.017.1-.017s.084-.258.084-.266S12.4,10,12.295,10H12.11l-.059.183Zm-.135.424c0,.008-.034.092-.059.191s-.059.191-.059.191.042-.008.1-.033a1.01,1.01,0,0,1,.193-.058c.109-.017.118-.025.126-.067.008-.017.025-.083.042-.133l.034-.1H12.11a.841.841,0,0,0-.193.008Zm-.294.957.37.008c.076-.25.1-.333.1-.341l-.37-.017-.1.35Z" fill="#fff"/>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="74" height="74" viewBox="0 0 74 74">
<g id="组_124120" data-name="组 124120" transform="translate(-38 -467)">
<rect id="矩形_54154" data-name="矩形 54154" width="74" height="74" rx="16" transform="translate(38 467)" fill="#ffb538"/>
<path id="收益_2_" data-name="收益 (2)" d="M192.3,138.358l13.827-.039c.638-.074,2.993-2.8,3.536-5.688.522-2.726-1.049-3.591-4.982-3.591s-3.126,3.826-3.918,3.826c-.462,0-.881-2.937-2.674-4.183-1.285-.892-3.059,1.4-4.758,1.417-1.984.018-4.57-.234-4.57,2.684,0,2.418,2.861,5.574,3.54,5.574Zm-.569.425a.824.824,0,1,0,0,1.617h15.119a.824.824,0,1,0,0-1.617Zm15.944,3.031H191.06a20.243,20.243,0,0,0-9.974,17.524c0,8.985,8.559,11.035,18.331,11.035s17.91-2.148,17.91-11.141a20.139,20.139,0,0,0-9.648-17.418Zm-4.86,11.5a1.161,1.161,0,1,1,0,2.318h-2.473v1.161h2.473a1.161,1.161,0,1,1,0,2.318h-2.473v2.438a1.239,1.239,0,0,1-2.473,0v-2.438H195.4a1.162,1.162,0,1,1,0-2.318h2.472v-1.161H195.4a1.162,1.162,0,1,1,0-2.318h2.472v-.678l-3.468-3.145a1.11,1.11,0,0,1-.029-1.64,1.3,1.3,0,0,1,1.748-.027l3.081,2.8,3.081-2.8a1.3,1.3,0,0,1,1.748.027,1.112,1.112,0,0,1-.028,1.64l-3.66,3.318v.5h2.473Z" transform="translate(-124.086 354.525)" fill="#fff"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<defs>
<style>
.cls-1 {
fill: #fff;
}
.cls-2 {
fill: #009fe8;
}
</style>
</defs>
<g id="支付宝支付" transform="translate(2 1)">
<rect id="矩形_2341" data-name="矩形 2341" class="cls-1" width="20" height="20" rx="4" transform="translate(-2 -1)"/>
<path id="路径_4973" data-name="路径 4973" class="cls-2" d="M20,13.691V3.845A3.847,3.847,0,0,0,16.154,0H3.845A3.847,3.847,0,0,0,0,3.845V16.154A3.846,3.846,0,0,0,3.845,20H16.154a3.85,3.85,0,0,0,3.786-3.166c-1.02-.442-5.44-2.35-7.743-3.45-1.752,2.123-3.588,3.4-6.354,3.4s-4.613-1.7-4.391-3.79c.146-1.368,1.085-3.6,5.162-3.222A18.37,18.37,0,0,1,11.5,10.95a13.885,13.885,0,0,0,1.116-2.72H4.845v-.77H8.691V6.077H4V5.23H8.69V3.235a.372.372,0,0,1,.387-.312H11V5.23h5v.848H11V7.46h4.079a15.741,15.741,0,0,1-1.657,4.154c1.185.43,6.578,2.078,6.578,2.078ZM5.538,15.46c-2.923,0-3.385-1.845-3.23-2.616a2.5,2.5,0,0,1,2.625-1.77,12.19,12.19,0,0,1,5.548,1.456c-1.41,1.836-3.143,2.93-4.943,2.93Z" transform="translate(-2 -1)"/>
</g>
</svg>
src/static/smtx/fbg.png

33.7 KB

src/static/smtx/sub.png

26.3 KB

src/static/tabbar/1.png

6.9 KB

src/static/tabbar/2.png

7.46 KB

src/static/tabbar/3.png

4.71 KB

src/static/tabbar/4.png

4.79 KB

src/static/tabbar/a1.png

7.07 KB

src/static/tabbar/a2.png

7.77 KB

src/static/tabbar/a3.png

4.96 KB

src/static/tabbar/a4.png

4.87 KB

src/static/user/1.png

18.3 KB

src/static/user/2.png

28 KB

src/static/user/22.png

4.43 KB

src/static/user/23.png

4.25 KB

src/static/user/24.png

3.95 KB

src/static/user/25.png

4.42 KB

src/static/user/26.png

4.35 KB

src/static/user/27.png

3.84 KB

src/static/user/28.png

4.65 KB

src/static/user/29.png

3.59 KB

src/static/user/4.png

912 Bytes

src/static/user/mx.png

3.86 KB

src/static/user/out.png

25.1 KB

src/static/user/qbbg.png

8.91 KB

src/static/user/qbc.png

6.25 KB

src/static/user/tx.png

11.3 KB

src/static/user/user.png

13.4 KB

src/static/user/zc.png

15.8 KB

src/static/user/圆角矩形 2 拷贝 3.png

10.3 KB

// 全局样式
body {
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica,
Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB', 'Microsoft Yahei',
sans-serif;
-webkit-font-smoothing: antialiased;
}
// 修改 vant 主题色
:root:root {
--van-primary-color: var(--primary-color);
}
// 安全区域适配
.app {
@include safe-area(top);
@include safe-area(bottom);
}
// 固定底部操作栏
.fixed-bottom {
@include fixed(bottom);
@include safe-area(bottom);
background: #fff;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
}
\ No newline at end of file
// 1px 边框
@mixin border-1px($color: #eee, $style: solid, $position: bottom) {
position: relative;
&::after {
content: '';
position: absolute;
background-color: $color;
display: block;
width: 100%;
height: 1px;
transform: scaleY(0.5);
@if $position == top {
top: 0;
}
@if $position == bottom {
bottom: 0;
}
}
}
// 固定定位
@mixin fixed($position: bottom) {
position: fixed;
@if $position == top {
top: 0;
left: 0;
right: 0;
}
@if $position == bottom {
bottom: 0;
left: 0;
right: 0;
}
z-index: 999;
}
// 安全区域
@mixin safe-area($position: bottom) {
@if $position == top {
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
@if $position == bottom {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
}
// 定义混入
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
\ No newline at end of file
:root {
--primary-color: #007bff;
--bg-color: #f5f5f5;
}
// SCSS 变量
$primary-color: var(--primary-color);
$bg-color: var(--bg-color);
// 间距
$spacing-sm: 8px;
$spacing-md: 16px;
$spacing-lg: 24px;
// 字体大小
$font-size-sm: 12px;
$font-size-md: 14px;
$font-size-lg: 16px;
// 导出所有变量
:export {
primaryColor: $primary-color;
bgColor: $bg-color;
// ... 其他需要导出的变量
}
\ No newline at end of file
import { onPageShow, onPageHide } from '@/composables'
import { $loading } from '@/hooks/useLoading'
declare module 'vue' {
interface ComponentCustomProperties {
$onPageShow: typeof onPageShow
$onPageHide: typeof onPageHide
$loading: typeof $loading
}
}
// 扩展 axios 配置类型
declare module 'axios' {
interface AxiosRequestConfig {
hideLoading?: boolean
}
}
export {}
\ No newline at end of file
declare module '@varlet/ui' {
import { Plugin } from 'vue'
export const Snackbar: any
export const Space: any
export const Card: any
export const Form: any
export const Input: any
export const Button: any
export const install: Plugin
}
\ No newline at end of file
import CryptoJS from 'crypto-js'
const KEY = 'abcdefgabcdefg64'
const IV = 'abcdefgabcdefg64'
export class AESUtil {
private static KEY = CryptoJS.enc.Utf8.parse(KEY)
private static IV = CryptoJS.enc.Utf8.parse(IV)
/**
* AES 加密
*/
static encrypt(data: string): string {
try {
// 将数据转换为字节数组并进行填充
const dataBytes = CryptoJS.enc.Utf8.parse(data)
const blockSize = 16
const paddingLength = blockSize - (dataBytes.sigBytes % blockSize)
const paddingWords = []
for (let i = 0; i < paddingLength; i++) {
paddingWords.push(0)
}
const padding = CryptoJS.lib.WordArray.create(paddingWords)
const paddedData = dataBytes.concat(padding)
// 加密
const encrypted = CryptoJS.AES.encrypt(paddedData, this.KEY, {
iv: this.IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.NoPadding
})
// 转换为Base64
return encrypted.ciphertext.toString(CryptoJS.enc.Base64)
} catch (error) {
console.error('Encryption failed:', error)
throw new Error('加密失败')
}
}
/**
* AES 解密
*/
static decrypt(data: string): string {
try {
// 将Base64字符串转换为CipherParams对象
const ciphertext = CryptoJS.enc.Base64.parse(data)
const cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: ciphertext
})
// 解密
const decrypted = CryptoJS.AES.decrypt(cipherParams, this.KEY, {
iv: this.IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.NoPadding
})
// 转换为字符串并去除填充
return decrypted.toString(CryptoJS.enc.Utf8).replace(/\x00+$/, '')
} catch (error) {
console.error('Decryption failed:', error)
throw new Error('解密失败')
}
}
/**
* 测试方法
*/
static test() {
const testData = '11212121'
console.log('原始数据:', testData)
const encrypted = this.encrypt(testData)
console.log('加密后:', encrypted)
const decrypted = this.decrypt(encrypted)
console.log('解密后:', decrypted)
// 测试Java加密的数据
const javaEncrypted = '/g2wzfqvMOeazgtsUVbq1kmJawROa6mcRAzwG1/GeJ4='
console.log('Java加密数据解密:', this.decrypt(javaEncrypted))
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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