Browse Source

🎉 初始化项目

master
linsxw 8 months ago
commit
9c38f673cf
  1. 38
      .editorconfig
  2. 3
      .env
  3. 3
      .env.development
  4. 2
      .env.production
  5. 25
      .gitignore
  6. 1
      .husky/commit-msg
  7. 1
      .husky/pre-commit
  8. 7
      .vscode/extensions.json
  9. 53
      .vscode/settings.json
  10. 66
      build/vite/index.ts
  11. 44
      build/vite/vconsole.ts
  12. 10
      eslint.config.js
  13. 62
      index.html
  14. 20
      mock/data.ts
  15. 5
      mock/index.ts
  16. 16
      mock/modules/prose.mock.ts
  17. 97
      package.json
  18. 7707
      pnpm-lock.yaml
  19. BIN
      public/favicon.ico
  20. 18
      scripts/verifyCommit.js
  21. 48
      src/App.vue
  22. 5
      src/api/index.ts
  23. 24
      src/api/mice.ts
  24. 16
      src/api/typing.ts
  25. 12
      src/api/weixin.ts
  26. 319
      src/auto-imports.d.ts
  27. 27
      src/components.d.ts
  28. 3
      src/components/README.md
  29. 179
      src/components/chart/dark.ts
  30. 65
      src/components/chart/index.vue
  31. 15
      src/components/chart/typing.ts
  32. 5
      src/components/container/index.vue
  33. 5
      src/components/index.ts
  34. 4
      src/composables/dark.ts
  35. 11
      src/composables/mice.ts
  36. 9
      src/env.d.ts
  37. 14
      src/layout/index.vue
  38. 30
      src/main.ts
  39. 8
      src/router/README.md
  40. 34
      src/router/index.ts
  41. 33
      src/router/router.ts
  42. 7
      src/stores/index.ts
  43. 24
      src/stores/modules/app.ts
  44. 18
      src/stores/modules/counter.ts
  45. 21
      src/stores/modules/mice.ts
  46. 16
      src/stores/modules/routeTransitionName.ts
  47. 2
      src/stores/mutation-type.ts
  48. 41
      src/styles/app.less
  49. 145
      src/typed-router.d.ts
  50. 3
      src/typing.ts
  51. 9
      src/utils/local-storage.ts
  52. 82
      src/utils/request.ts
  53. 129
      src/views/index/index.vue
  54. 27
      src/views/signUp/components/FormItem.vue
  55. 28
      src/views/signUp/components/SignForm.vue
  56. 26
      src/views/signUp/index.vue
  57. 3
      tests/index.spec.ts
  58. 38
      tsconfig.json
  59. 32
      uno.config.ts
  60. 56
      vite.config.ts

38
.editorconfig

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
[*]
charset=utf-8
end_of_line=lf
insert_final_newline=false
indent_style=space
indent_size=2
[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]
indent_style=space
indent_size=2
[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}]
indent_style=space
indent_size=2
[{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}]
indent_style=space
indent_size=2
[*.svg]
indent_style=space
indent_size=2
[*.js.map]
indent_style=space
indent_size=2
[*.less]
indent_style=space
indent_size=2
[{*.vue,*.ts,*.tsx}]
indent_style=space
indent_size=2
[{.analysis_options,*.yml,*.yaml}]
indent_style=space
indent_size=2

3
.env

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
VITE_APP_PUBLIC_PATH=/
VITE_APP_PREVIEW=true
VITE_APP_API_BASE_URL=/api

3
.env.development

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
NODE_ENV=development
VITE_APP_PREVIEW=true
VITE_APP_API_BASE_URL=/api

2
.env.production

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
VITE_APP_PREVIEW=false
VITE_APP_API_BASE_URL=https://api.example.com

25
.gitignore vendored

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
stats.html
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Misc
.DS_Store

1
.husky/commit-msg

@ -0,0 +1 @@ @@ -0,0 +1 @@
node scripts/verifyCommit.js

1
.husky/pre-commit

@ -0,0 +1 @@ @@ -0,0 +1 @@
pnpm lint

7
.vscode/extensions.json vendored

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
{
"recommendations": [
"Vue.volar",
"antfu.unocss",
"simonhe.common-intellisense"
]
}

53
.vscode/settings.json vendored

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
{
// Enable the ESlint flat config support
"eslint.experimental.useFlatConfig": true,
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "never"
},
// Disable the MD033 rule
"markdownlint.config": {
"default": true,
"MD033": false
},
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off" },
{ "rule": "*-indent", "severity": "off" },
{ "rule": "*-spacing", "severity": "off" },
{ "rule": "*-spaces", "severity": "off" },
{ "rule": "*-order", "severity": "off" },
{ "rule": "*-dangle", "severity": "off" },
{ "rule": "*-newline", "severity": "off" },
{ "rule": "*quotes", "severity": "off" },
{ "rule": "*semi", "severity": "off" }
],
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
],
// Specify the UI library you need to prompt
"common-intellisense.showSlots": false,
"common-intellisense.ui": [
"vant4"
]
}

66
build/vite/index.ts

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
import vue from '@vitejs/plugin-vue'
import legacy from '@vitejs/plugin-legacy'
import vueJsx from '@vitejs/plugin-vue-jsx'
import { visualizer } from 'rollup-plugin-visualizer'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import VueRouter from 'unplugin-vue-router/vite'
import { VueRouterAutoImports } from 'unplugin-vue-router'
import { VantResolver } from 'unplugin-vue-components/resolvers'
import { unheadVueComposablesImports } from '@unhead/vue'
import VueDevTools from 'vite-plugin-vue-devtools'
import mockDevServerPlugin from 'vite-plugin-mock-dev-server'
import UnoCSS from 'unocss/vite'
import { createViteVConsole } from './vconsole'
export function createVitePlugins() {
return [
VueRouter({
routesFolder: 'src/views',
dts: 'src/typed-router.d.ts',
}),
vue(),
vueJsx(),
visualizer(),
UnoCSS(),
mockDevServerPlugin(),
legacy({
targets: ['defaults', 'not IE 11'],
}),
Components({
extensions: ['vue'],
resolvers: [VantResolver()],
include: [/\.vue$/, /\.vue\?vue/],
dts: 'src/components.d.ts',
}),
AutoImport({
include: [
/\.[tj]sx?$/,
/\.vue$/,
/\.vue\?vue/,
],
imports: [
'vue',
'vitest',
'@vueuse/core',
VueRouterAutoImports,
{
'vue-router/auto': ['useLink'],
},
unheadVueComposablesImports,
],
dts: 'src/auto-imports.d.ts',
dirs: [
'src/composables',
],
}),
createViteVConsole(),
VueDevTools(),
]
}

44
build/vite/vconsole.ts

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
import path from 'node:path'
import { viteVConsole } from 'vite-plugin-vconsole'
export function createViteVConsole() {
return viteVConsole({
entry: [path.resolve('src/main.ts')],
enabled: false,
config: {
maxLogNumber: 1000,
theme: 'light',
},
// https://github.com/vadxq/vite-plugin-vconsole/issues/21
dynamicConfig: {
theme: `document.documentElement.classList.contains('dark') ? 'dark' : 'light'`,
},
eventListener: `
const targetElement = document.querySelector('html'); // 择要监听的元素
const observerOptions = {
attributes: true, // 监听属性变化
attributeFilter: ['class'] // 只监听class属性变化
};
// 定义回调函数来处理观察到的变化
function handleAttributeChange(mutationsList) {
for(let mutation of mutationsList) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
if (window && window.vConsole) {
window.vConsole.dynamicChange.value = new Date().getTime();
}
}
}
}
// 创建观察者实例并传入回调函数
const observer = new MutationObserver(handleAttributeChange);
// 开始观察目标元素
observer.observe(targetElement, observerOptions);
// 当不再需要观察时,停止观察
// observer.disconnect();
`,
})
}

10
eslint.config.js

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
import antfu from '@antfu/eslint-config'
export default antfu({
// enable UnoCSS support
// https://unocss.dev/integrations/vscode
unocss: true,
rules: {
curly: 'off',
},
})

62
index.html

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover, user-scalable=no"/>
<link rel="icon" href="/favicon.ico" />
<script>
// ;(function () {
// const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
// const setting = localStorage.getItem('vueuse-color-scheme') || 'auto'
// if (setting === 'dark' || (prefersDark && setting !== 'light'))
// document.documentElement.classList.toggle('dark', true)
// })()
</script>
</head>
<body>
<div id="app">
<style>
html,
body,
#app {
height: 100%;
margin: 0px;
padding: 0px;
width: 100%;
}
.__spinner-container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.__spinner {
position: relative;
width: 68px;
height: 68px;
background-color: #41b883;
animation: cube-shadow-spinner 1.8s cubic-bezier(0.75, 0, 0.5, 1)
infinite;
}
@keyframes cube-shadow-spinner {
50% {
border-radius: 50%;
transform: scale(0.5) rotate(360deg);
}
100% {
transform: scale(1) rotate(720deg);
}
}
</style>
<div class="__spinner-container">
<div class="__spinner"></div>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
<noscript>
This website requires JavaScript to function properly.
Please enable JavaScript to continue.
</noscript>
</body>
</html>

20
mock/data.ts

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
import { defineMockData } from 'vite-plugin-mock-dev-server'
// defineMockData,用于在 mock 文件中使用 data.ts 作为共享数据源。
export default defineMockData('proses', [
{ prose: '🔖 躲在某一时间,想念一段时光的掌纹;躲在某一地点,想念一个站在来路也站在去路的,让我牵挂的人。' },
{ prose: '🔖 天空一碧如洗,灿烂的阳光正从密密的松针的缝隙间射下来,形成一束束粗粗细细的光柱,把飘荡着轻纱般薄雾的林荫照得通亮。' },
{ prose: '🔖 这一次相遇,美得彻骨,美得震颤,美得孤绝,美得惊艳。' },
{ prose: '🔖 沉默的状态,能让我感觉到呼吸的自由和自己原来就处于的本色位置。' },
{ prose: '🔖 青春,是一包象征着阳光的向日葵种子,在现在洒下,就会在未来得到收获,那一株株饱含青春的花朵。' },
{ prose: '🔖 燕子去了,有再来的时候;杨柳枯了,有再青的时候;桃花谢了,有再开的时候。但是,聪明的,你告诉我,我们的日子为什么一去不复返呢?' },
{ prose: '🔖 毕业了,青春在无形之中离去,我们即将翻开人生的另一页。' },
{ prose: '🔖 成长,是每个孩子的权力,也是他们必经的征程,或平坦、或崎岖,有悲欢,有离合。' },
{ prose: '🔖 旧时光里的人和事,琐碎而零乱。我的记忆很模糊,好像大部分都成了一种温馨的符号,静静的沉在我心底。' },
{ prose: '🔖 生活是一部大百科全书,包罗万象;生活是一把六弦琴,弹奏出多重美妙的旋律:生活是一座飞马牌大钟,上紧发条,便会使人获得浓缩的生命。' },
{ prose: '🔖 毕业了,身边的朋友一个个各奔东西,开始学会自己撑起生命的暖色。' },
{ prose: '🔖 已经走到尽头的东西,重生也不过是再一次的消亡。就像所有的开始,其实都只是一个写好了的结局。' },
{ prose: '🔖 下午茶的芬香熏陶着房内的任何一个角落,午后的阳光透过窗帘的间隙洒在木制的桌面上,一份思念随着红茶顺滑至心中。' },
{ prose: '🔖 这里再不是我们的校园,当我们就此离开我们的青葱岁月。' },
{ prose: '🔖 很久找你,一直没有找到,微风吹过的时候,我深深的呼吸,才感觉到你也在陪伴着我呼吸。' },
])

5
mock/index.ts

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
import prose from './modules/prose.mock'
export default {
...prose,
}

16
mock/modules/prose.mock.ts

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
// https://github.com/pengzhanbo/vite-plugin-mock-dev-server
import { defineMock } from 'vite-plugin-mock-dev-server'
import proses from '../data'
export default defineMock({
url: '/api/project/prose',
delay: 100,
body: () => {
const prose = proses.value[Math.floor(Math.random() * 8)]
return {
code: 0,
data: prose,
msg: 'success',
}
},
})

97
package.json

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
{
"name": "sn-huiyi-h5",
"type": "module",
"version": "2.2.0",
"packageManager": "pnpm@8.13.1",
"description": "盛年会议",
"license": "MIT",
"scripts": {
"dev": "cross-env MOCK_SERVER_PORT=8086 vite",
"build": "vue-tsc --noEmit && vite build",
"build:dev": "vue-tsc --noEmit && vite build --mode=development",
"preview": "npm run build && vite preview",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"test": "vitest",
"release": "bumpp --commit --push --tag",
"prepare": "husky",
"cz": "git-cz"
},
"dependencies": {
"@unhead/vue": "^1.8.10",
"@vant/touch-emulator": "^1.4.0",
"@vant/use": "^1.6.0",
"@vueuse/core": "^10.7.2",
"axios": "^1.6.7",
"echarts": "^5.4.3",
"lodash-es": "^4.17.21",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"resize-detector": "^0.3.0",
"store": "^2.0.12",
"vant": "^4.8.4",
"vconsole": "^3.15.1",
"vue": "^3.4.15",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@antfu/eslint-config": "2.6.4",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.11.16",
"@types/nprogress": "^0.2.3",
"@types/store": "^2.0.5",
"@unocss/eslint-plugin": "^0.58.5",
"@unocss/preset-rem-to-px": "^0.58.5",
"@vitejs/plugin-legacy": "^5.3.0",
"@vitejs/plugin-vue": "^5.0.3",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.17",
"bumpp": "^9.3.0",
"commitizen": "^4.3.0",
"consola": "^3.2.3",
"cross-env": "^7.0.3",
"cz-emoji-chinese": "^0.3.1",
"eslint": "^8.56.0",
"husky": "^9.0.10",
"less": "^4.2.0",
"mockjs": "^1.1.0",
"postcss-mobile-forever": "^4.1.1",
"rollup": "^4.9.6",
"rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.27.0",
"typescript": "^5.3.3",
"unocss": "^0.58.5",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0",
"unplugin-vue-router": "^0.7.0",
"vite": "^5.0.12",
"vite-plugin-mock-dev-server": "^1.4.7",
"vite-plugin-vconsole": "^2.1.1",
"vite-plugin-vue-devtools": "^7.0.14",
"vitest": "^1.2.2",
"vue-tsc": "^1.8.27"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"postcss",
"esbuild"
],
"allowedVersions": {
"rollup": "^4.x"
}
}
},
"config": {
"commitizen": {
"path": "./node_modules/cz-emoji-chinese"
},
"cz-emoji-chinese": {
"skipQuestions": [
"body",
"scope"
]
}
}
}

7707
pnpm-lock.yaml

File diff suppressed because it is too large Load Diff

BIN
public/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

18
scripts/verifyCommit.js

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
import fs from 'node:fs'
import process from 'node:process'
const msg = fs.readFileSync('.git/COMMIT_EDITMSG', 'utf-8').trim()
const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/
const mergeRe = /^(Merge pull request|Merge branch)/
if (!commitRE.test(msg)) {
if (!mergeRe.test(msg)) {
console.log('git commit unpass')
console.error('git commit error, needs title(scope): desc')
process.exit(1)
}
}
else {
console.log('git commit pass')
}

48
src/App.vue

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import useAppStore from '@/stores/modules/app'
import useRouteTransitionNameStore from '@/stores/modules/routeTransitionName'
// useHead({
// title: 'Vue3 Vant Mobile',
// meta: [
// {
// name: 'description',
// content: 'Vue + Vite H5 Starter Template',
// },
// {
// name: 'theme-color',
// content: () => isDark.value ? '#00aba9' : '#ffffff',
// },
// ],
// })
const appStore = useAppStore()
const { mode } = storeToRefs(appStore)
const routeTransitionNameStore = useRouteTransitionNameStore()
const { routeTransitionName } = storeToRefs(routeTransitionNameStore)
</script>
<template>
<VanConfigProvider :theme="mode">
<router-view v-slot="{ Component, route }">
<transition :name="routeTransitionName">
<div :key="route.name" class="app-wrapper">
<component :is="Component" />
</div>
</transition>
</router-view>
</VanConfigProvider>
</template>
<style scoped>
.app-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow-y: auto;
}
</style>

5
src/api/index.ts

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
import request from '@/utils/request'
export async function queryProse(): Promise<any> {
return request('/project/prose')
}

24
src/api/mice.ts

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
import request from '@/utils/request'
/**
*
*/
export function getMiceInfo(data: any) {
return request({
url: '/backstageMice/getBackstageMice',
params: data,
})
}
/**
*
*/
export function getSignUpFormConfig(data: {
miceLink: string
flTypeId?: string | number
}) {
return request({
url: '/backstageFormlabel/info/getByMiceLinkDefault',
params: data,
})
}

16
src/api/typing.ts

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
export interface ResponseBody<T = any> {
message?: string
code?: number
data?: T
success: boolean
}
/** 统一返回结构体 */
export interface PageResult<T = any> {
data: T[]
current?: number
pageSize?: number
total?: number
success: boolean
}

12
src/api/weixin.ts

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
import request from '@/utils/request'
/**
*
*/
export function getWeixinSignature(url: string) {
return request({
method: 'post',
url: '/wx/signInfo',
data: { url },
})
}

319
src/auto-imports.d.ts vendored

@ -0,0 +1,319 @@ @@ -0,0 +1,319 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const afterAll: typeof import('vitest')['afterAll']
const afterEach: typeof import('vitest')['afterEach']
const assert: typeof import('vitest')['assert']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const beforeAll: typeof import('vitest')['beforeAll']
const beforeEach: typeof import('vitest')['beforeEach']
const chai: typeof import('vitest')['chai']
const computed: typeof import('vue')['computed']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
const computedEager: typeof import('@vueuse/core')['computedEager']
const computedInject: typeof import('@vueuse/core')['computedInject']
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
const controlledRef: typeof import('@vueuse/core')['controlledRef']
const createApp: typeof import('vue')['createApp']
const createEventHook: typeof import('@vueuse/core')['createEventHook']
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise']
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
const customRef: typeof import('vue')['customRef']
const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineLoader: typeof import('vue-router/auto')['defineLoader']
const definePage: typeof import('unplugin-vue-router/runtime')['_definePage']
const describe: typeof import('vitest')['describe']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const expect: typeof import('vitest')['expect']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getActiveHead: typeof import('@unhead/vue')['getActiveHead']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const getUrlMiceLink: typeof import('./composables/mice')['getUrlMiceLink']
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const injectHead: typeof import('@unhead/vue')['injectHead']
const injectLocal: typeof import('@vueuse/core')['injectLocal']
const isDark: typeof import('./composables/dark')['isDark']
const isDefined: typeof import('@vueuse/core')['isDefined']
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 it: typeof import('vitest')['it']
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
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/auto')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router/auto')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
const onLongPress: typeof import('@vueuse/core')['onLongPress']
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 onStartTyping: typeof import('@vueuse/core')['onStartTyping']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const preferredDark: typeof import('./composables/dark')['preferredDark']
const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive']
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
const reactivePick: typeof import('@vueuse/core')['reactivePick']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
const refDebounced: typeof import('@vueuse/core')['refDebounced']
const refDefault: typeof import('@vueuse/core')['refDefault']
const refThrottled: typeof import('@vueuse/core')['refThrottled']
const refWithControl: typeof import('@vueuse/core')['refWithControl']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const suite: typeof import('vitest')['suite']
const syncRef: typeof import('@vueuse/core')['syncRef']
const syncRefs: typeof import('@vueuse/core')['syncRefs']
const templateRef: typeof import('@vueuse/core')['templateRef']
const test: typeof import('vitest')['test']
const throttledRef: typeof import('@vueuse/core')['throttledRef']
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
const toRaw: typeof import('vue')['toRaw']
const toReactive: typeof import('@vueuse/core')['toReactive']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const toggleDark: typeof import('./composables/dark')['toggleDark']
const triggerRef: typeof import('vue')['triggerRef']
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
const unref: typeof import('vue')['unref']
const unrefElement: typeof import('@vueuse/core')['unrefElement']
const until: typeof import('@vueuse/core')['until']
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
const useAnimate: typeof import('@vueuse/core')['useAnimate']
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes']
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
const useArraySome: typeof import('@vueuse/core')['useArraySome']
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
const useAttrs: typeof import('vue')['useAttrs']
const useBase64: typeof import('@vueuse/core')['useBase64']
const useBattery: typeof import('@vueuse/core')['useBattery']
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
const useCached: typeof import('@vueuse/core')['useCached']
const useClipboard: typeof import('@vueuse/core')['useClipboard']
const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVar: typeof import('@vueuse/core')['useCssVar']
const useCssVars: typeof import('vue')['useCssVars']
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
const useCycleList: typeof import('@vueuse/core')['useCycleList']
const useDark: typeof import('@vueuse/core')['useDark']
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
const useDebounce: typeof import('@vueuse/core')['useDebounce']
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
const useDraggable: typeof import('@vueuse/core')['useDraggable']
const useDropZone: typeof import('@vueuse/core')['useDropZone']
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
const useElementHover: typeof import('@vueuse/core')['useElementHover']
const useElementSize: typeof import('@vueuse/core')['useElementSize']
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
const useEventBus: typeof import('@vueuse/core')['useEventBus']
const useEventListener: typeof import('@vueuse/core')['useEventListener']
const useEventSource: typeof import('@vueuse/core')['useEventSource']
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
const useFavicon: typeof import('@vueuse/core')['useFavicon']
const useFetch: typeof import('@vueuse/core')['useFetch']
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
const useFocus: typeof import('@vueuse/core')['useFocus']
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
const useFps: typeof import('@vueuse/core')['useFps']
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useHead: typeof import('@unhead/vue')['useHead']
const useHeadSafe: typeof import('@unhead/vue')['useHeadSafe']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
const useInterval: typeof import('@vueuse/core')['useInterval']
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
const useLink: typeof import('vue-router/auto')['useLink']
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
const useMemoize: typeof import('@vueuse/core')['useMemoize']
const useMemory: typeof import('@vueuse/core')['useMemory']
const useMounted: typeof import('@vueuse/core')['useMounted']
const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNow: typeof import('@vueuse/core')['useNow']
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
const useOnline: typeof import('@vueuse/core')['useOnline']
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
const useParallax: typeof import('@vueuse/core')['useParallax']
const useParentElement: typeof import('@vueuse/core')['useParentElement']
const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver']
const usePermission: typeof import('@vueuse/core')['usePermission']
const usePointer: typeof import('@vueuse/core')['usePointer']
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
const usePrevious: typeof import('@vueuse/core')['usePrevious']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useRoute: typeof import('vue-router/auto')['useRoute']
const useRouter: typeof import('vue-router/auto')['useRouter']
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
const useScroll: typeof import('@vueuse/core')['useScroll']
const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
const useSeoMeta: typeof import('@unhead/vue')['useSeoMeta']
const useServerHead: typeof import('@unhead/vue')['useServerHead']
const useServerHeadSafe: typeof import('@unhead/vue')['useServerHeadSafe']
const useServerSeoMeta: typeof import('@unhead/vue')['useServerSeoMeta']
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
const useShare: typeof import('@vueuse/core')['useShare']
const useSlots: typeof import('vue')['useSlots']
const useSorted: typeof import('@vueuse/core')['useSorted']
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
const useStepper: typeof import('@vueuse/core')['useStepper']
const useStorage: typeof import('@vueuse/core')['useStorage']
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
const useSupported: typeof import('@vueuse/core')['useSupported']
const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
const useThrottle: typeof import('@vueuse/core')['useThrottle']
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
const useTimeout: typeof import('@vueuse/core')['useTimeout']
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
const useTitle: typeof import('@vueuse/core')['useTitle']
const useToNumber: typeof import('@vueuse/core')['useToNumber']
const useToString: typeof import('@vueuse/core')['useToString']
const useToggle: typeof import('@vueuse/core')['useToggle']
const useTransition: typeof import('@vueuse/core')['useTransition']
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
const useVModel: typeof import('@vueuse/core')['useVModel']
const useVModels: typeof import('@vueuse/core')['useVModels']
const useVibrate: typeof import('@vueuse/core')['useVibrate']
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const vi: typeof import('vitest')['vi']
const vitest: typeof import('vitest')['vitest']
const watch: typeof import('vue')['watch']
const watchArray: typeof import('@vueuse/core')['watchArray']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
const watchDeep: typeof import('@vueuse/core')['watchDeep']
const watchEffect: typeof import('vue')['watchEffect']
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
const watchImmediate: typeof import('@vueuse/core')['watchImmediate']
const watchOnce: typeof import('@vueuse/core')['watchOnce']
const watchPausable: typeof import('@vueuse/core')['watchPausable']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
const whenever: typeof import('@vueuse/core')['whenever']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
}

27
src/components.d.ts vendored

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/* 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 {
Chart: typeof import('./components/chart/index.vue')['default']
Container: typeof import('./components/container/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
VanButton: typeof import('vant/es')['Button']
VanCell: typeof import('vant/es')['Cell']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
VanEmpty: typeof import('vant/es')['Empty']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon']
VanNavBar: typeof import('vant/es')['NavBar']
VanSpace: typeof import('vant/es')['Space']
VanSwitch: typeof import('vant/es')['Switch']
VanTag: typeof import('vant/es')['Tag']
}
}

3
src/components/README.md

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
# Components
Components in this dir will be auto-registered and on-demand, powered by [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components).

179
src/components/chart/dark.ts

@ -0,0 +1,179 @@ @@ -0,0 +1,179 @@
const contrastColor = 'rgba(255, 255, 255, 0.65)'
const backgroundColor = 'transparent'
const axisCommon = function () {
return {
axisLine: {
lineStyle: {
color: contrastColor,
},
},
splitLine: {
lineStyle: {
color: '#484753',
},
},
splitArea: {
areaStyle: {
color: ['rgba(255,255,255,0.02)', 'rgba(255,255,255,0.05)'],
},
},
minorSplitLine: {
lineStyle: {
color: '#20203B',
},
},
}
}
const colorPalette = [
'#4992ff',
'#7cffb2',
'#fddd60',
'#ff6e76',
'#58d9f9',
'#05c091',
'#ff8a45',
'#8d48e3',
'#dd79ff',
]
const theme: any = {
color: colorPalette,
backgroundColor,
axisPointer: {
lineStyle: {
color: '#817f91',
},
crossStyle: {
color: '#817f91',
},
label: {
// TODO Contrast of label backgorundColor
color: '#fff',
},
},
legend: {
textStyle: {
color: contrastColor,
},
},
textStyle: {
color: contrastColor,
},
title: {
textStyle: {
color: 'red',
},
subtextStyle: {
color: 'rgba(255, 255, 255, 0.65)',
},
},
toolbox: {
iconStyle: {
borderColor: contrastColor,
},
},
dataZoom: {
borderColor: '#71708A',
textStyle: {
color: contrastColor,
},
brushStyle: {
color: 'rgba(135,163,206,0.3)',
},
handleStyle: {
color: '#353450',
borderColor: '#C5CBE3',
},
moveHandleStyle: {
color: '#B0B6C3',
opacity: 0.3,
},
fillerColor: 'rgba(135,163,206,0.2)',
emphasis: {
handleStyle: {
borderColor: '#91B7F2',
color: '#4D587D',
},
moveHandleStyle: {
color: '#636D9A',
opacity: 0.7,
},
},
dataBackground: {
lineStyle: {
color: '#71708A',
width: 1,
},
areaStyle: {
color: '#71708A',
},
},
selectedDataBackground: {
lineStyle: {
color: '#87A3CE',
},
areaStyle: {
color: '#87A3CE',
},
},
},
visualMap: {
textStyle: {
color: contrastColor,
},
},
timeline: {
lineStyle: {
color: contrastColor,
},
label: {
color: contrastColor,
},
controlStyle: {
color: contrastColor,
borderColor: contrastColor,
},
},
calendar: {
itemStyle: {
color: backgroundColor,
},
dayLabel: {
color: contrastColor,
},
monthLabel: {
color: contrastColor,
},
yearLabel: {
color: contrastColor,
},
},
timeAxis: axisCommon(),
logAxis: axisCommon(),
valueAxis: axisCommon(),
categoryAxis: axisCommon(),
line: {
symbol: 'circle',
},
graph: {
color: colorPalette,
},
gauge: {
title: {
color: contrastColor,
},
},
candlestick: {
itemStyle: {
color: '#FD1050',
color0: '#0CF49B',
borderColor: '#FD1050',
borderColor0: '#0CF49B',
},
},
}
theme.categoryAxis.splitLine.show = false
export default theme

65
src/components/chart/index.vue

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
<script setup lang="ts">
import type { ECharts } from 'echarts'
import * as echarts from 'echarts'
import { debounce } from 'lodash-es'
import { addListener, removeListener } from 'resize-detector'
import dark from './dark'
const props = defineProps({
option: Object,
})
echarts.registerTheme('dark-chart', dark)
const chartDom = ref<HTMLDivElement>()
let chart: ECharts | null = null
const isRealDark = ref(isDark.value)
function resizeChart() {
chart?.resize()
}
const resize = debounce(resizeChart, 300)
function disposeChart() {
if (chartDom.value)
removeListener(chartDom.value, resize)
chart?.dispose()
chart = null
}
function initChart() {
disposeChart()
if (chartDom.value) {
// init echarts
chart = echarts.init(chartDom.value, isRealDark.value ? 'dark-chart' : undefined)
chart.setOption(props.option)
addListener(chartDom.value, resize)
}
}
watch(isRealDark, () => {
initChart()
}, {
flush: 'post',
})
onMounted(() => {
watch(() => props.option, () => {
chart?.setOption(props.option)
}, {
deep: true,
flush: 'post',
})
initChart()
})
onUnmounted(() => {
disposeChart()
})
</script>
<template>
<div ref="chartDom" />
</template>

15
src/components/chart/typing.ts

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
export interface SeriesDataItem {
x: any
y: any
}
export interface RadarDataItem {
label: string
name: string
value: string | number
}
export interface RadarIndicatorItem {
name: string
max: number
}

5
src/components/container/index.vue

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
<template>
<main class="h-full w-full p-16 py-60">
<slot />
</main>
</template>

5
src/components/index.ts

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
export { default as Container } from './container/index.vue'
// charts
export { default as Chart } from './chart/index.vue'
export type { SeriesDataItem, RadarDataItem, RadarIndicatorItem } from './chart/typing'

4
src/composables/dark.ts

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
// these APIs are auto-imported from @vueuse/core
export const isDark = useDark()
export const toggleDark = useToggle(isDark)
export const preferredDark = usePreferredDark()

11
src/composables/mice.ts

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
import { useRouter } from 'vue-router'
/**
* url中的miceLink
* @returns miceLink
*/
export function getUrlMiceLink(): string {
const router = useRouter()
const params = router.currentRoute.value.params as any
return params.miceLink
}

9
src/env.d.ts vendored

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
// eslint-disable-next-line ts/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}

14
src/layout/index.vue

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
<script lang="ts" setup>
import useMiceStore from '@/stores/modules/mice'
const miceInfoStore = useMiceStore()
onMounted(() => {
const miceeLink = getUrlMiceLink()
miceInfoStore.initMiceInfo(miceeLink)
})
</script>
<template>
<router-view />
</template>

30
src/main.ts

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
import { createApp } from 'vue'
import { createHead } from '@unhead/vue'
import App from '@/App.vue'
import router from '@/router'
import pinia from '@/stores'
import 'virtual:uno.css'
import '@/styles/app.less'
// Vant 桌面端适配
import '@vant/touch-emulator'
/* --------------------------------
Vant
ToastDialogNotify ImagePreview
使unplugin-vue-components
------------------------------------- */
import 'vant/es/toast/style'
import 'vant/es/dialog/style'
import 'vant/es/notify/style'
import 'vant/es/image-preview/style'
const app = createApp(App)
const head = createHead()
app.use(head)
app.use(router)
app.use(pinia)
app.mount('#app')

8
src/router/README.md

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
# `File-based Routing`
Routes will be auto-generated for Vue files in the **src/views** dir with the same file structure.
Check out [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router) for more details.
**src/views** 目录下的 Vue 文件会自动生成相同结构的路由。
查看[`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router)了解更多细节。

34
src/router/index.ts

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
import { createRouter, createWebHistory } from 'vue-router'
import NProgress from 'nprogress'
import routes from './router'
import useRouteTransitionNameStore from '@/stores/modules/routeTransitionName'
import 'nprogress/nprogress.css'
NProgress.configure({ showSpinner: true, parent: '#app' })
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_APP_PUBLIC_PATH),
routes,
})
router.beforeEach((to, from, next) => {
NProgress.start()
const routeTransitionNameStore = useRouteTransitionNameStore()
if (to.meta.level > from.meta.level)
routeTransitionNameStore.setName('slide-fadein-left')
else if (to.meta.level < from.meta.level)
routeTransitionNameStore.setName('slide-fadein-right')
else
routeTransitionNameStore.setName('')
next()
})
router.afterEach(() => {
NProgress.done()
})
export default router

33
src/router/router.ts

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
import type { RouteRecordRaw } from 'vue-router'
import Layout from '@/layout/index.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'index',
component: Layout,
// redirect: { name: "Demo" },
children: [
// 海报首页
{
path: 'index/:miceLink',
name: 'Demo',
component: () => import('@/views/index/index.vue'),
meta: {
title: '主页',
},
},
// 报名
{
path: 'signUp/:miceLink',
name: 'SignUp',
component: () => import('@/views/signUp/index.vue'),
meta: {
title: '报名',
},
},
],
},
]
export default routes

7
src/stores/index.ts

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
export default pinia

24
src/stores/modules/app.ts

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
import { defineStore } from 'pinia'
import type { ConfigProviderTheme } from 'vant'
const prefersDark
= window.matchMedia
&& window.matchMedia('(prefers-color-scheme: dark)').matches
const useAppStore = defineStore('app', () => {
const theme = prefersDark ? 'dark' : 'light'
const mode = ref<ConfigProviderTheme>(theme)
const swithMode = (val: ConfigProviderTheme) => {
mode.value = val
}
return {
mode,
swithMode,
}
}, {
persist: true,
})
export default useAppStore

18
src/stores/modules/counter.ts

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
import { defineStore } from 'pinia'
const useCounterStore = defineStore('counter', () => {
const counter = ref(0)
const increment = () => {
counter.value++
}
return {
counter,
increment,
}
}, {
persist: true,
})
export default useCounterStore

21
src/stores/modules/mice.ts

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
import { defineStore } from 'pinia'
import { getMiceInfo } from '@/api/mice'
/**
*
*/
const useMiceStore = defineStore('mice', () => {
const miceInfo = ref<any>({})
function initMiceInfo(miceLink: string) {
getMiceInfo({ miceLink }).then((res) => {
miceInfo.value = res
})
}
return {
miceInfo,
initMiceInfo,
}
})
export default useMiceStore

16
src/stores/modules/routeTransitionName.ts

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
import { defineStore } from 'pinia'
const useRouteTransitionNameStore = defineStore('route-transition-name', () => {
const routeTransitionName = ref('')
const setName = (name: string) => {
routeTransitionName.value = name
}
return {
routeTransitionName,
setName,
}
})
export default useRouteTransitionNameStore

2
src/stores/mutation-type.ts

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
export const STORAGE_TOKEN_KEY = 'access_token'
export const STORAGE_LANG_KEY = 'app_lang'

41
src/styles/app.less

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
#app {
min-height: 100vh;
position: relative;
overflow-x: hidden;
}
html {
background: var(--van-gray-1);
color-scheme: light;
}
html.dark {
background: #121212;
color-scheme: dark;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
.slide-fadein-left-enter-active,
.slide-fadein-left-leave-active,
.slide-fadein-right-enter-active,
.slide-fadein-right-leave-active {
transition: opacity 0.3s, transform 0.4s, -webkit-transform 0.4s;
}
.slide-fadein-left-enter-from,
.slide-fadein-right-leave-to {
transform: translateX(20px);
opacity: 0;
}
.slide-fadein-left-leave-to,
.slide-fadein-right-enter-from {
transform: translateX(-20px);
opacity: 0;
}

145
src/typed-router.d.ts vendored

@ -0,0 +1,145 @@ @@ -0,0 +1,145 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-router. ‼ DO NOT MODIFY THIS FILE ‼
// It's recommended to commit this file.
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
/// <reference types="unplugin-vue-router/client" />
import type {
// type safe route locations
RouteLocationTypedList,
RouteLocationResolvedTypedList,
RouteLocationNormalizedTypedList,
RouteLocationNormalizedLoadedTypedList,
RouteLocationAsString,
RouteLocationAsRelativeTypedList,
RouteLocationAsPathTypedList,
// helper types
// route definitions
RouteRecordInfo,
ParamValue,
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
// vue-router extensions
_RouterTyped,
RouterLinkTyped,
RouterLinkPropsTyped,
NavigationGuard,
UseLinkFnTyped,
// data fetching
_DataLoader,
_DefineLoaderOptions,
} from 'unplugin-vue-router/types'
declare module 'vue-router/auto/routes' {
export interface RouteNamedMap {
export interface RouteNamedMap {
'//': RouteRecordInfo<'//', '/', Record<never, never>, Record<never, never>>,
} '/signUp/': RouteRecordInfo<'/signUp/', '/signUp', Record<never, never>, Record<never, never>>,
'/signUp/components/FormItem': RouteRecordInfo<'/signUp/components/FormItem', '/signUp/components/FormItem', Record<never, never>, Record<never, never>>,
'/signUp/components/SignForm': RouteRecordInfo<'/signUp/components/SignForm', '/signUp/components/SignForm', Record<never, never>, Record<never, never>>,
}
}
declare module 'vue-router/auto' {
import type { RouteNamedMap } from 'vue-router/auto/routes'
export type RouterTyped = _RouterTyped<RouteNamedMap>
/**
* Type safe version of `RouteLocationNormalized` (the type of `to` and `from` in navigation guards).
* Allows passing the name of the route to be passed as a generic.
*/
export type RouteLocationNormalized<Name extends keyof RouteNamedMap = keyof RouteNamedMap> = RouteLocationNormalizedTypedList<RouteNamedMap>[Name]
/**
* Type safe version of `RouteLocationNormalizedLoaded` (the return type of `useRoute()`).
* Allows passing the name of the route to be passed as a generic.
*/
export type RouteLocationNormalizedLoaded<Name extends keyof RouteNamedMap = keyof RouteNamedMap> = RouteLocationNormalizedLoadedTypedList<RouteNamedMap>[Name]
/**
* Type safe version of `RouteLocationResolved` (the returned route of `router.resolve()`).
* Allows passing the name of the route to be passed as a generic.
*/
export type RouteLocationResolved<Name extends keyof RouteNamedMap = keyof RouteNamedMap> = RouteLocationResolvedTypedList<RouteNamedMap>[Name]
/**
* Type safe version of `RouteLocation` . Allows passing the name of the route to be passed as a generic.
*/
export type RouteLocation<Name extends keyof RouteNamedMap = keyof RouteNamedMap> = RouteLocationTypedList<RouteNamedMap>[Name]
/**
* Type safe version of `RouteLocationRaw` . Allows passing the name of the route to be passed as a generic.
*/
export type RouteLocationRaw<Name extends keyof RouteNamedMap = keyof RouteNamedMap> =
| RouteLocationAsString<RouteNamedMap>
| RouteLocationAsRelativeTypedList<RouteNamedMap>[Name]
| RouteLocationAsPathTypedList<RouteNamedMap>[Name]
/**
* Generate a type safe params for a route location. Requires the name of the route to be passed as a generic.
*/
export type RouteParams<Name extends keyof RouteNamedMap> = RouteNamedMap[Name]['params']
/**
* Generate a type safe raw params for a route location. Requires the name of the route to be passed as a generic.
*/
export type RouteParamsRaw<Name extends keyof RouteNamedMap> = RouteNamedMap[Name]['paramsRaw']
export function useRouter(): RouterTyped
export function useRoute<Name extends keyof RouteNamedMap = keyof RouteNamedMap>(name?: Name): RouteLocationNormalizedLoadedTypedList<RouteNamedMap>[Name]
export const useLink: UseLinkFnTyped<RouteNamedMap>
export function onBeforeRouteLeave(guard: NavigationGuard<RouteNamedMap>): void
export function onBeforeRouteUpdate(guard: NavigationGuard<RouteNamedMap>): void
export const RouterLink: RouterLinkTyped<RouteNamedMap>
export const RouterLinkProps: RouterLinkPropsTyped<RouteNamedMap>
// Experimental Data Fetching
export function defineLoader<
P extends Promise<any>,
Name extends keyof RouteNamedMap = keyof RouteNamedMap,
isLazy extends boolean = false,
>(
name: Name,
loader: (route: RouteLocationNormalizedLoaded<Name>) => P,
options?: _DefineLoaderOptions<isLazy>,
): _DataLoader<Awaited<P>, isLazy>
export function defineLoader<
P extends Promise<any>,
isLazy extends boolean = false,
>(
loader: (route: RouteLocationNormalizedLoaded) => P,
options?: _DefineLoaderOptions<isLazy>,
): _DataLoader<Awaited<P>, isLazy>
export {
_definePage as definePage,
_HasDataLoaderMeta as HasDataLoaderMeta,
_setupDataFetchingGuard as setupDataFetchingGuard,
_stopDataFetchingScope as stopDataFetchingScope,
} from 'unplugin-vue-router/runtime'
}
declare module 'vue-router' {
import type { RouteNamedMap } from 'vue-router/auto/routes'
export interface TypesConfig {
beforeRouteUpdate: NavigationGuard<RouteNamedMap>
beforeRouteLeave: NavigationGuard<RouteNamedMap>
$route: RouteLocationNormalizedLoadedTypedList<RouteNamedMap>[keyof RouteNamedMap]
$router: _RouterTyped<RouteNamedMap>
RouterLink: RouterLinkTyped<RouteNamedMap>
}
}

3
src/typing.ts

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
import type { Ref } from 'vue'
export type MaybeRef<T> = T | Ref<T>

9
src/utils/local-storage.ts

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
import store from 'store'
import expirePlugin from 'store/plugins/expire'
// plugin usage:
store.addPlugin(expirePlugin)
export { store as localStorage }
export default store

82
src/utils/request.ts

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
import type { AxiosError, InternalAxiosRequestConfig } from 'axios'
import axios from 'axios'
import { showNotify } from 'vant'
import { localStorage } from '@/utils/local-storage'
import { STORAGE_TOKEN_KEY } from '@/stores/mutation-type'
/**
* token
*/
const COMMON_TOKEN
= 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWIiLCJpc3MiOiJ6c2ktY2FzLWFkbWluIiwiZXhwIjoxNzAwNTM3OTYyLCJpYXQiOjE2MTQxMzc5NjIsImp0aSI6ImI0NTUzNDYwNTVmYTQwMmFiNjdjODY0NWE5YjcxNDMzIiwidXNlcm5hbWUiOiJmaXhlZCJ9.-LUgPPlp0yYeu1h-MR5_l-GDvJQtcwYK4bngBFgK9qY'
// 这里是用于设定请求后端时,所用的 Token KEY
// 可以根据自己的需要修改,常见的如 Access-Token,Authorization
// 需要注意的是,请尽量保证使用中横线`-` 来作为分隔符,
// 避免被 nginx 等负载均衡器丢弃了自定义的请求头
export const REQUEST_TOKEN_KEY = 'Access-Token'
// 创建 axios 实例
const request = axios.create({
// API 请求的默认前缀
baseURL: import.meta.env.VITE_APP_API_BASE_URL,
timeout: 10000, // 请求超时时间
})
export type RequestError = AxiosError<{
message?: string
result?: any
errorMessage?: string
}>
// 异常拦截处理器
function errorHandler(error: RequestError): Promise<any> {
if (error.response) {
const { data = {}, status, statusText } = error.response
// 403 无权限
if (status === 403) {
showNotify({
type: 'danger',
message: (data && data.message) || statusText,
})
}
// 401 未登录/未授权
if (status === 401 && data.result && data.result.isLogin) {
showNotify({
type: 'danger',
message: 'Authorization verification failed',
})
// 如果你需要直接跳转登录页面
// location.replace(loginRoutePath)
}
}
return Promise.reject(error)
}
// 请求拦截器
function requestHandler(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig> {
const savedToken = localStorage.get(STORAGE_TOKEN_KEY)
// 如果 token 存在
// 让每个请求携带自定义 token, 请根据实际情况修改
config.headers.token = COMMON_TOKEN
if (savedToken)
config.headers[REQUEST_TOKEN_KEY] = savedToken
return config
}
// Add a request interceptor
request.interceptors.request.use(requestHandler, errorHandler)
// 响应拦截器
function responseHandler(response: { data: any }) {
// if (response.data.data) {
// return response.data.data
// }
return response.data.data
}
// Add a response interceptor
request.interceptors.response.use(responseHandler, errorHandler)
export default request

129
src/views/index/index.vue

@ -0,0 +1,129 @@ @@ -0,0 +1,129 @@
<script setup lang="ts" name="index">
import useMiceStore from '@/stores/modules/mice'
// definePage({
// name: 'index',
// path: '/index/:miceLink',
// })
const miceInfoStore = useMiceStore()
</script>
<template>
<div>
<img
class="w-full"
fit="contain"
src="https://sn202108-1305501521.cos.ap-shanghai.myqcloud.com/202401162355044675902.jpg"
>
<!-- 会议标题 -->
<div class="van-hairline--bottom my-0 px-10 py-5 font-bold">
{{ miceInfoStore.miceInfo.miceName }}
</div>
<!-- 会议信息 -->
<div class="van-hairline--bottom p-10 text-[#666] space-y-2">
<div class="mice-info-item">
<van-icon name="clock-o" />
<van-tag plain type="primary">
报名
</van-tag>
<span>2024-01-16 23:55:04</span>
</div>
<div class="mice-info-item">
<van-icon name="clock-o" />
<van-tag plain type="primary">
活动
</van-tag>
<span>2024-01-16 23:55:04</span>
</div>
<div class="mice-info-item">
<van-icon name="location-o" />
<span>上海xxx</span>
</div>
<div class="mice-info-item">
<van-icon name="phone-o" />
<span>12345678901</span>
</div>
</div>
<!-- 报名人数 -->
<div class="sign-num van-hairline--bottom p-10 text-2xl">
<span>已报名</span>
<span>10</span>
</div>
<!-- 空白 -->
<div class="h-3 bg-[#f0f0f0]" />
<!-- 会议简介 -->
<div class="mice_info_desc">
<div class="van-hairline--bottom p-10 font-semibold">
会议简介
</div>
<div class="p-10" v-html="miceInfoStore.miceInfo.description" />
</div>
<!-- 底部操作栏 -->
<div class="bottom-actions">
<div class="bottom-item">
<van-icon name="user-o" />
<span>个人中心</span>
</div>
<div class="sign">
立即报名
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.mice-info-item {
display: flex;
align-items: center;
.van-icon {
margin-right: 5px;
}
.van-tag {
margin-right: 5px;
}
span {
font-weight: 500;
}
}
.sign-num {
display: flex;
justify-content: space-between;
font-size: 14px;
font-weight: 600;
color: #666;
}
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
display: flex;
justify-content: space-between;
box-shadow: 0 0 10px #ccc;
.bottom-item {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
flex: 1;
}
.sign {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background-color: var(--van-tag-primary-color);
color: #fff;
font-weight: 600;
}
}
</style>

27
src/views/signUp/components/FormItem.vue

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
<template>
<div>
<!-- 输入框-->
<van-field
v-model="form[item.name]"
name="用户名"
label="用户名"
placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
</div>
</template>
<script setup lang="ts">
import type { PropType } from "vue";
defineProps({
form: {
type: Object as PropType<any>,
required: true
},
item: {
type: Object as PropType<any>,
required: true
}q
});
</script>

28
src/views/signUp/components/SignForm.vue

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<template>
<van-form @submit="onSubmit" :required="true">
<van-field
v-model="form.code"
center
clearable
label="短信验证码"
placeholder="请输入短信验证码"
>
<template #button>
<van-button size="small" type="primary">发送验证码</van-button>
</template>
</van-field>
</van-form>
</template>
<script lang="ts" setup>
import { ref } from "vue";
const form = ref({
username: "",
code: ""
});
function onSubmit() {}
</script>
<style lang="scss" scoped></style>

26
src/views/signUp/index.vue

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
<template>
<div>
<img
fit="contain"
src="https://sn202108-1305501521.cos.ap-shanghai.myqcloud.com/202401162355044675902.jpg"
alt=""
/>
<SignForm />
</div>
</template>
<script setup lang="ts" name="SignUp">
import { getSignUpFormConfig } from "@/api";
import { getUrlMiceLink } from "@/utils/mice";
import { onMounted, ref } from "vue";
import SignForm from "@/views/signUp/components/SignForm.vue";
const formConfigs = ref<any[]>([]);
onMounted(() => {
const miceLink = getUrlMiceLink();
getSignUpFormConfig({ miceLink }).then((res: any) => {
formConfigs.value = res.data;
});
});
</script>

3
tests/index.spec.ts

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
it('first test', () => {
expect(1 + 1).toBe(2)
})

38
tsconfig.json

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
{
"compilerOptions": {
"target": "esnext",
"jsx": "preserve",
"lib": ["esnext", "dom", "dom.iterable", "scripthost"],
"experimentalDecorators": true,
"baseUrl": ".",
"module": "esnext",
"moduleResolution": "node",
"paths": {
"@/*": ["src/*"]
},
"types": ["node"],
"allowJs": true,
"strictNullChecks": false,
"noImplicitAny": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"importHelpers": true,
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": [
"src/App.vue",
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx",
"src/components.d.ts",
"src/auto-imports.d.ts",
"src/typed-router.d.ts",
"tests/*.ts"
]
}

32
uno.config.ts

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
import { defineConfig, presetAttributify, presetMini, presetUno } from 'unocss'
import presetRemToPx from '@unocss/preset-rem-to-px'
// 刚使用unocss的朋友,可以借助这个工具: https://to-unocss.netlify.app
export default defineConfig({
presets: [
presetUno,
presetAttributify,
// 为什么要用到这个插件?
// 模板使用 viewport 作为移动端适配方案,unocss 默认单位为 rem
// 所以需要转成 px,然后由 postcss 把 px 转成 vw/vh,完成适配
presetRemToPx({
// 这里为什么要设置基础字体大小?看下面这篇文章
// https://juejin.cn/post/7262975395620618298
baseFontSize: 4,
}),
// presetMini({
// dark: {
// dark: '.van-theme-dark',
// light: '.van-theme-light',
// },
// }),
],
shortcuts: {
// shortcuts to multiple utilities
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
'btn-green': 'text-white bg-green-500 hover:bg-green-700',
'btn-blue': 'text-white bg-blue-500 hover:bg-blue-700',
'centered': 'absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2',
},
})

56
vite.config.ts

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
import path from 'node:path'
import process from 'node:process'
import { loadEnv } from 'vite'
import type { ConfigEnv, UserConfig } from 'vite'
import viewport from 'postcss-mobile-forever'
import autoprefixer from 'autoprefixer'
import { createVitePlugins } from './build/vite'
export default ({ mode }: ConfigEnv): UserConfig => {
const root = process.cwd()
const env = loadEnv(mode, root)
return {
base: env.VITE_APP_PUBLIC_PATH,
plugins: createVitePlugins(),
server: {
host: true,
port: 3000,
proxy: {
'/api': {
// 接口请求地址
target: 'https://jihui.huiyipro.com/api',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
},
},
},
resolve: {
alias: {
'~@': path.join(__dirname, './src'),
'@': path.join(__dirname, './src'),
'~': path.join(__dirname, './src/assets'),
},
},
css: {
postcss: {
plugins: [
autoprefixer(),
viewport({
appSelector: '#app',
viewportWidth: 375,
maxDisplayWidth: 600,
}),
],
},
},
build: {
cssCodeSplit: false,
chunkSizeWarningLimit: 2048,
},
}
}
Loading…
Cancel
Save