Initial commit

This commit is contained in:
2026-01-29 14:45:05 +08:00
commit cab00f6f3e
34 changed files with 5025 additions and 0 deletions

46
src/App.vue Normal file
View File

@@ -0,0 +1,46 @@
<template>
<router-view v-slot="{ Component }">
<keep-alive :include="KeepAliveList">
<component :is="Component" />
</keep-alive>
</router-view>
</template>
<script setup>
const router = useRouter()
const KeepAliveList = ref([])
router.beforeEach((to, from, next) => {
const keepAlive = to?.meta?.keepAlive
if (!router.hasRoute(to.name)) {
router.push('/error')
return
}
if (keepAlive) {
if (KeepAliveList.value.indexOf(to.name) === -1) {
KeepAliveList.value.push(to.name)
} else {
const index = KeepAliveList.value.findIndex((name) => name === from.name)
index > -1 ? KeepAliveList.value.splice(index, 1) : null
}
}
next()
})
</script>
<style lang="scss">
#app {
width: 100%;
height: 100%;
overflow: hidden;
@media only screen and (min-width: 500px) {
max-width: 500px;
margin: auto;
transform: scale(1);
}
}
</style>

BIN
src/assets/font/bebas.ttf Normal file

Binary file not shown.

20
src/assets/font/icon.css Normal file
View File

@@ -0,0 +1,20 @@
@font-face {
font-family: 'icon-font'; /* Project id 634611 (更新icon直接替换新的cdn地址即可无需下载) */
src: url('//at.alicdn.com/t/font_634611_fe4z5kh8e8n.woff2?t=1654585244447') format('woff2'),
url('//at.alicdn.com/t/font_634611_fe4z5kh8e8n.woff?t=1654585244447') format('woff'),
url('//at.alicdn.com/t/font_634611_fe4z5kh8e8n.ttf?t=1654585244447') format('truetype');
}
.icon-font {
font-family: 'icon-font' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@font-face {
font-family: 'money';
src: url('./bebas.ttf');
font-weight: normal;
font-style: normal;
}

View File

@@ -0,0 +1,96 @@
@import './normalize';
*,
*::before,
*::after {
-webkit-box-sizing: border-box;
box-sizing: border-box;
outline: none;
-webkit-tap-highlight-color: rgba(255, 0, 0, 0); // 移除移动端阴影
-webkit-overflow-scrolling: touch; //滚动回弹 ios13+
}
[data-theme='dark'] {
&,
* {
color-scheme: dark !important;
transition: background-color 300ms;
}
}
[data-theme='light'] {
&,
* {
color-scheme: light !important;
transition: background-color 300ms;
}
body {
background-color: #f5f5f5;
}
}
// 安全区域变量初始化
:root {
--safe-area-inset-top: 24px;
--safe-area-inset-right: 0px;
--safe-area-inset-bottom: 0px;
--safe-area-inset-left: 0px;
@supports (top: constant(safe-area-inset-top)) and (padding: Max(10px, 20px)) {
--safe-area-inset-top: Max(constant(safe-area-inset-top), 24px);
--safe-area-inset-right: constant(safe-area-inset-right);
--safe-area-inset-bottom: constant(safe-area-inset-bottom);
--safe-area-inset-left: constant(safe-area-inset-left);
}
@supports (top: env(safe-area-inset-top)) and (padding: Max(10px, 20px)) {
--safe-area-inset-top: Max(env(safe-area-inset-top), 24px);
--safe-area-inset-right: env(safe-area-inset-right);
--safe-area-inset-bottom: env(safe-area-inset-bottom);
--safe-area-inset-left: env(safe-area-inset-left);
}
}
.van-safe-area-top {
padding-top: var(--safe-area-inset-top) !important;
}
.van-image-preview__index,
.van-image-preview__close-icon--top-right {
top: 46px !important;
}
// 表单样式
.van-field__error-message {
text-align: right !important;
}
.van-hairline--top-bottom:after,
.van-hairline-unset--top-bottom:after {
border-width: 0 !important;
}
// 弹窗样式
.van-dialog {
width: 270px !important;
}
.van-dialog__confirm,
.van-dialog__confirm:active {
color: #14b498 !important;
}
.van-dialog__content--isolated {
min-height: 72px !important;
}
.van-dialog__message {
color: #333333;
font-size: 17px !important;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
line-height: 24px !important;
}

355
src/assets/scss/normalize.scss vendored Normal file
View File

@@ -0,0 +1,355 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
height: 100%;
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
height: 100%;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}
button {
border: 0;
}

222
src/common/Track.js Normal file
View File

@@ -0,0 +1,222 @@
import { bindEvent, last } from 'vtils'
const Track = {
app: null,
ready: false,
App: {
created() {
Track.app = this
},
watch: {
'$route.path': {
immediate: true,
handler: async (fromPath, toPath) => {
await Track.ensureReady()
Track.app.$nextTick(async () => {
const { id, name } = await Track.injectMark()
window.loadEventPush(
fromPath,
toPath || '',
Track.app.$route.query,
{
mark_id: id,
mark_name: name
}
)
Track.app.$nextTick(() => {
window.elementAddEventListener()
})
})
}
}
}
},
ensureReady: async () => {
if (Track.ready) return
return new Promise((resolve) => {
const timer = setInterval(() => {
if (
// @ts-ignore
typeof window.Countly !== 'undefined' &&
// @ts-ignore
typeof window.anyEventPush !== 'undefined' &&
Track.app !== null
) {
clearInterval(timer)
Track.ready = true
resolve()
}
}, 60)
})
},
prepareData(data) {
return {
...(data.id && data.name
? {
control_id: data.id,
control_name: data.name,
control_value: data.value || data.name
}
: {}),
...(data.goods
? data.goods.isUniGoods
? {
content_id: data.goods.id,
content_name: data.goods.name,
resource_id: data.goods.resourceId,
resource_name: data.goods.resourceName,
resource_position_id: data.goods.resourcePositionId,
resource_position_name: data.goods.resourcePositionName,
resource_position_no: data.index || 0
}
: {
content_id: data.goods.commodityId,
content_name:
data.goods.commodityTitle ||
// 兼容订单下的商品
data.goods.name,
...(data.goods.commodityResourceId
? {
resource_id: data.goods.commodityResourceId,
resource_name: data.goods.commodityTitle,
resource_position_id: '',
resource_position_name: data.name,
resource_position_no: data.index || 0
}
: {})
}
: {}),
...(data.resource
? {
resource_id: data.resource.id,
resource_name: data.resource.title || data.resource.name || '',
resource_position_id: data.resource.stateId || '',
resource_position_name: data.resource.stateName || '',
resource_position_no: data.index || 0
}
: {}),
...(data.resourcePosition
? {
resource_position_id: data.resourcePosition.id,
resource_position_name: data.resourcePosition.name,
resource_position_no: data.index || 0
}
: {}),
...(data.mark
? {
mark_id: data.mark.id,
mark_name: data.mark.name
}
: {}),
...(data.content
? {
content_name: data.content
}
: {})
}
},
pushEvent: async (data) => {
await Track.ensureReady()
const trackData = Track.prepareData(data)
if (!trackData.mark_id && !trackData.mark_name) {
const { id, name } = await Track.injectMark()
trackData.mark_id = id
trackData.mark_name = name
}
window.anyEventPush(data.type, data.path, data.name, trackData)
},
provideMark(cb) {
return {
methods: {
provideTrackMark: cb
}
}
},
injectMark: async () => {
const currentRoute = Track.app.$route
const matched = currentRoute.matched
const currentPage = last(matched)
const currentPageInstance = currentPage?.instances.default
const provideTrackMark = currentPageInstance?.provideTrackMark
const { id = 'NONE', name = 'NONE' } =
typeof provideTrackMark === 'function' ? await provideTrackMark() : {}
return {
id,
name
}
},
install(app, options) {
Track.ensureReady().then(() => {
// @ts-ignore
countlyConfig.baseContextPath = options.appid
})
async function applyTrack(el, payload) {
await Track.ensureReady()
let data = payload.value
// @ts-ignore
if (data && !data.disabled) {
data = {
...data,
name: `${options.prefix || ''}${data.name}`,
// @ts-ignore
path: el.__track_data__?.path || window.getRoutePath()
}
el.__track_data__ = data
// 兼容曝光事件
if (data.expose !== false) {
el.setAttribute('exposure-event', data.name)
el.setAttribute(
'extend_attr',
JSON.stringify(Track.prepareData(data))
)
if (data.value !== null) {
el.setAttribute('alt', data.value)
}
}
const shouldListen = !el.dataset.track
if (shouldListen) {
el.dataset.track = '1'
el.__track_dispose__ = bindEvent(el)(
'click',
() => {
console.log(`埋点:点击「${data.name}`)
Track.pushEvent({
type: 'click',
...el.__track_data__,
value: el.innerText.trim().replace(/\s+/g, '')
})
},
{
// 必须使用捕获模式以在其他事件触发前处理(比如其他事件触发了页面跳转,就会导致问题)
capture: true,
// 使用被动模式告诉浏览器这不会产生阻塞行为
passive: true
}
)
}
}
}
function disposeTrack(el) {
// 需延时一下,不然当遇到点击跳转时页面卸载把事件也卸载了就触发不了了
setTimeout(() => {
delete el.__track_data__
el.__track_dispose__?.()
delete el.__track_dispose__
}, 0)
}
app.directive('track', {
mounted: applyTrack,
updated: applyTrack,
beforeUpdate: applyTrack,
unmounted: disposeTrack
})
console.log(1)
}
}
export default Track

131
src/common/ajax.js Normal file
View File

@@ -0,0 +1,131 @@
import axios from 'axios'
import {
md5Hash,
rsaEncrypt,
rsaDecrypt,
aesEncrypt,
aesDecrypt,
generateUUID,
dataSign,
generateRandomString,
getLocalStorage
} from '@dcb/utils'
const encryptionOff = Number(import.meta.env.VITE_ENCRYPTION)
const env = import.meta.env.VITE_ENV === 'development'
const STORE_OFF = Number(import.meta.env.VITE_STORE_OFF)
const RSA = import.meta.env.VITE_APP_RSA
const DATA_RSA = STORE_OFF ? import.meta.env.VITE_DATA_RSA : RSA
const martId = import.meta.env.VITE_MART_ID
const appKey = import.meta.env.VITE_KEY
const appSecret = import.meta.env.VITE_SECRET
const request = async (method, url, data, config = {}) => {
const p = env ? import.meta.env.VITE_P : decodeURI(getLocalStorage('p'))
const options = Object.assign({}, config, {
url,
method
})
console.log('入参', data)
const uuid = generateUUID()
const secret = '4RBA7^@0$@KM$5D2333'
const title = md5Hash(uuid + secret)
const aesKey = generateRandomString(16) // 生成16位随机数
const init = rsaEncrypt(aesKey, RSA)
const base = aesEncrypt(JSON.stringify(data), aesKey)
options.data = options.data || {}
/*
* @ 验签
* @wiki: http://wiki.gogpay.cn/pages/viewpage.action?pageId=75301563
* */
url = url.replace(/^https?:\/\/.+?\/([^/]+)/, '')
const timestamp = Date.now()
let asHex = ''
const header = Object.assign(
{ clientId: '03' },
STORE_OFF ? { martId, path: url, timestamp } : { path: url, timestamp }
)
for (const [key, value] of Object.entries(header)) {
asHex += key + value
}
// console.log(asHex + appSecret)
const sign = dataSign(header, appSecret)
if (method === 'post') {
if (!config.white && encryptionOff) {
options.data = {
timestamp: uuid,
title,
init,
base
}
} else {
options.data = data
}
}
options.headers = Object.assign({}, options.headers, header, {
sign,
appKey,
p
})
console.log(options.headers, STORE_OFF)
return new Promise((resolve, reject) => {
axios
.request(options)
.then((res) => {
let { data } = res
if (!data) {
return resolve(data)
}
if (method === 'post' && encryptionOff && !config.white) {
data = JSON.parse(
aesDecrypt(data.base, rsaDecrypt(data.init, DATA_RSA))
)
}
console.log('返回值', data)
resolve(data)
})
.catch((res) => {
reject(res)
})
})
}
export const ajax = {
request,
get(url, config) {
return request('get', url, null, config)
},
delete(url, config) {
return request('delete', url, null, config)
},
head(url, config) {
return request('head', url, null, config)
},
post(url, data, config) {
return request('post', url, data, config)
},
put(url, data, config) {
return request('put', url, data, config)
},
patch(url, data, config) {
return request('path', url, data, config)
},
setCommonHeader(key, value) {
window.axios.defaults.headers.common[key] = value
}
}

View File

@@ -0,0 +1,16 @@
/* eslint-disable no-process-env */
import { initAjax } from '@dcb/ajax'
const debug = import.meta.env.VITE_ENV
const RSA = import.meta.env.VITE_APP_RSA
const appid = import.meta.env.VITE_APP_ID
const BASE_API = import.meta.env.VITE_BASE_API
const encryptionOff = import.meta.env.VITE_ENCRYPTION
export const useAjax = function () {
const ajax = initAjax(true)
const options = { RSA, appid, BASE_API, encryptionOff, debug }
ajax.config(options)
return ajax
}

50
src/common/flexible.js Normal file
View File

@@ -0,0 +1,50 @@
// ref: https://github.com/amfe/lib-flexible/blob/2.0/index.js
;(function flexible(window, document) {
const docEl = document.documentElement
const dpr = window.devicePixelRatio || 1
// adjust body font size
const setBodyFontSize = () => {
if (document.body) {
document.body.style.fontSize = `${12 * dpr}px`
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize()
// set 1rem = viewWidth / 10
const setRemUnit = () => {
const rem =
Math.min(
// 宽度限制在 500 内
500,
docEl.clientWidth
) / 10
docEl.style.fontSize = `${rem}px`
}
setRemUnit()
// reset rem unit on page resize
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', (e) => {
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports
if (dpr >= 2) {
const fakeBody = document.createElement('body')
const testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
})(window, document)

3
src/common/index.js Normal file
View File

@@ -0,0 +1,3 @@
import { ajax } from './ajax'
export { ajax }

53
src/components/Empty.vue Normal file
View File

@@ -0,0 +1,53 @@
<template>
<div class="empty">
<img class="empty__img" :src="img" />
<div class="empty__desc" v-if="description" :style="{ color }">
{{ description }}
</div>
</div>
</template>
<script setup>
import imgEmpty from '@/assets/images/img_empty_order.png'
const props = defineProps({
description: {
type: String,
default: ''
},
img: {
type: Object,
default: imgEmpty
},
color: {
type: String,
default: '#999999'
}
})
</script>
<style scoped lang="scss">
.empty {
width: 100%;
height: 288px;
@extend %flex-center;
&__img {
width: 150px;
height: 150px;
display: block;
margin: 105px auto 0;
}
&__desc {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #999999;
line-height: 20px;
text-align: center;
margin-top: 8px;
}
}
</style>

View File

@@ -0,0 +1,148 @@
<template>
<div class="page-container" :style="{ backgroundColor: bgColor }">
<van-nav-bar :class="['nav-bar', navBgColor, isCustom ? 'custom-style' : '']" safe-area-inset-top left-arrow fixed
v-if="showNavigator" :border="false" :left-text="navBarLeftText" @click-left="handleBack">
<template #title>
<slot name="title">{{ title === '首页' ? '' : title }}</slot>
</template>
<template #right>
<slot name="nav-bar-right"></slot>
</template>
</van-nav-bar>
<slot name="body"></slot>
</div>
</template>
<script setup>
const { proxy } = getCurrentInstance()
const props = defineProps({
// nav-bar返回按钮位置的文字
navBarLeftText: {
type: String,
default: ''
},
// nav-bar标题
title: {
type: String,
default: ''
},
// 背景颜色
bgColor: {
type: String,
default: 'white'
},
// nav-bar背景颜色
navBgColor: {
type: String,
default: ''
},
// fixed情况下返回按钮背景颜色
backBgColor: {
type: String,
default: 'lightgray'
},
// 是否自定义样式
isCustom: {
type: Boolean,
default: false
},
// 是否显示导航栏
show: {
type: Boolean,
default: true
},
goback: {
type: Number,
default: 0
}
})
// 是否显示隐藏导航
const showNavigator = ref(props.show)
// 获取页面标题
const { title } = proxy.$router.currentRoute.value.meta
const handleBack = () => {
if (props.goback > 0) {
proxy.$router.go(-props.goback)
} else {
proxy.$router.back()
}
}
</script>
<style scoped lang="scss">
.page-container {
height: 100vh;
overflow-y: auto;
background-color: white;
padding-bottom: var(--safe-area-inset-bottom);
.body {
min-height: calc(100vh - 46px + var(--safe-area-inset-top));
padding-top: calc(46px + var(--safe-area-inset-top));
overflow-y: auto;
&::-webkit-scrollbar {
display: none;
}
}
.nav-bar {
background-color: transparent;
z-index: 2000;
position: fixed;
:deep(.van-icon-arrow-left) {
color: #fff;
font-size: 20px;
}
:deep(.van-nav-bar__title) {
color: #fff;
font-size: 18px;
font-weight: bold;
line-height: 22px;
opacity: 1;
}
&.style-1,
&.style-2 {
:deep(.van-icon-arrow-left) {
color: #333;
}
:deep(.van-nav-bar__title) {
color: #333;
}
}
&.style-1 {
background-color: #fff;
}
&.style-2 {
background-color: transparent;
}
&.custom-style {
background-color: rgba(22, 187, 191, 1);
:deep(.van-icon-arrow-left) {
color: #fff;
}
}
}
}
</style>

2
src/components/index.js Normal file
View File

@@ -0,0 +1,2 @@
export { default as PageContainer } from './PageContainer.vue'
export { default as Empty } from './Empty.vue'

5
src/hooks/tool.js Normal file
View File

@@ -0,0 +1,5 @@
import { reactive } from 'vue'
export const observer = reactive({
userInfo: undefined
})

13
src/main.js Normal file
View File

@@ -0,0 +1,13 @@
import { createApp } from 'vue'
import '@/assets/font/icon.css'
import '@/common/flexible'
import App from './App.vue'
import router from '@/router'
import store from '@/store'
const app = createApp(App)
app.config.globalProperties.$store = store
app.use(router)
app.mount('#app')

22
src/router/index.js Normal file
View File

@@ -0,0 +1,22 @@
import { createRouter, createWebHashHistory } from 'vue-router'
// 路由规则
const routes = [
{
path: '/home',
name: 'home', // 请和文件名一样
component: () => import('@/views/home/index.vue'),
meta: {
title: '首页', // 自动设置当前页面的标题
keepAlive: true
}
}
]
const router = createRouter({
// vueRouter@3版本的mode改成了historyhash模式配置createWebHashHistoryhistory模式配置createWebHistory
history: createWebHashHistory(),
routes
})
export default router

18
src/store/index.js Normal file
View File

@@ -0,0 +1,18 @@
import { reactive } from 'vue'
export default {
state: reactive({
userInfo: undefined
}),
mutations: {
setUserInfo(state, data) {
state.userInfo = data
}
},
commit(eventName, { data, dept }) {
data.dept.preCheck = dept.preCheck
this.mutations[eventName](this.state, data)
}
}

22
src/views/home/index.vue Normal file
View File

@@ -0,0 +1,22 @@
<template>
<van-button @click="handleClick">跳转记录</van-button>
</template>
<script setup name="home">
const router = useRouter()
// 跳转按钮操作
const handleClick = () => {
console.log('跳转记录')
}
onMounted(() => {
console.log('onMounted')
})
onActivated(() => {
console.log('onActivated')
})
</script>
<style lang="scss" scoped></style>