Commit 8fa21601 authored by zl's avatar zl

init

parents
Pipeline #205 canceled with stages
# baseUrl
VITE_BASE_API = /api
# 开发环境启用 cdn eruda 调试工具。若不启用,将 true 修改为 false 或其他任意值即可
VITE_ENABLE_ERUDA = true
# 线上环境平台打包路径
VITE_PUBLIC_PATH = /
\ No newline at end of file
# baseUrl
VITE_BASE_API = 'https://h5.hysbx.com/api'
# 线上环境平台打包路径
VITE_PUBLIC_PATH = /
\ No newline at end of file
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
env: { node: true },
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-typescript', '@vue/eslint-config-prettier'],
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
sourceType: 'module',
jsxPragma: 'React',
ecmaFeatures: { jsx: true }
},
parser: 'vue-eslint-parser',
rules: {
'vue/multi-word-component-names': [
'error',
{
ignores: ['index'] // 需要忽略的组件名
}
]
},
overrides: [
{
files: ['*.html'],
processor: 'vue/.vue'
}
]
}
name: Build and Deploy
permissions:
contents: write
on:
push:
branches:
- master
jobs:
deploy:
concurrency: ci-${{ github.ref }}
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: '18'
registry-url: https://registry.npmjs.com/
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 7
- name: Deploy 🔧
run: |
pnpm install --no-frozen-lockfile
sed -i "s#VITE_PUBLIC_PATH = /#VITE_PUBLIC_PATH = /vue3-h5-template/#g" $(pwd)/.env.production
pnpm build
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: gh-pages
folder: dist
clean: true
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
!.vscode/vue3.2.code-snippets
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit "$1"
module.exports = {
'*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
'{!(package)*.json}': ['prettier --write--parser json'],
'package.json': ['prettier --write'],
'*.vue': ['eslint --fix', 'prettier --write', 'stylelint --fix'],
'*.{vue,css,scss,postcss,less}': ['stylelint --fix', 'prettier --write'],
'*.md': ['prettier --write']
}
{
"tabWidth": 2,
"printWidth": 140,
"bracketSpacing": true,
"singleQuote": true,
"semi": false,
"arrowParens": "avoid",
"trailingComma": "none",
"overrides": [
{
"files": "*.html",
"options": {
"parser": "html"
}
}
]
}
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}
{
"Vue3.2+快速生成模板": {
"prefix": ["<", "Vue3.2+"],
"body": [
"<script setup lang='ts'>",
"$1",
"</script>\n",
"<template>",
"\t<div>",
"\t\t$2",
"\t</div>",
"</template>\n",
"<style scoped>\n",
"</style>"
],
"description": "Vue3.2+"
}
}
module.exports = {
ignores: [commit => commit.includes('init')],
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'type-enum': [
2,
'always',
['feat', 'fix', 'perf', 'style', 'docs', 'test', 'refactor', 'build', 'ci', 'chore', 'revert', 'wip', 'workflow', 'types', 'release']
]
}
}
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
NavBar: typeof import('./src/components/NavBar/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
Tabbar: typeof import('./src/components/Tabbar/index.vue')['default']
VanArea: typeof import('vant/es')['Area']
VanButton: typeof import('vant/es')['Button']
VanCell: typeof import('vant/es')['Cell']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon']
VanImage: typeof import('vant/es')['Image']
VanNavBar: typeof import('vant/es')['NavBar']
VanNoticeBar: typeof import('vant/es')['NoticeBar']
VanPicker: typeof import('vant/es')['Picker']
VanPopup: typeof import('vant/es')['Popup']
VanSpace: typeof import('vant/es')['Space']
VanSwipeCell: typeof import('vant/es')['SwipeCell']
VanTabbar: typeof import('vant/es')['Tabbar']
VanTabbarItem: typeof import('vant/es')['TabbarItem']
VanUploader: typeof import('vant/es')['Uploader']
}
}
/// <reference types="vite/client" />
<!DOCTYPE html>
<html lang="en">
<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, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="icon" href="/favicon.ico" />
<title>好医生保险经纪</title>
</head>
<body>
<div id="app">
<style>
:root {
--EASE_INOUT_QUAD: cubic-bezier(0.455, 0.03, 0.515, 0.955);
--EASE_IN_QUAD: cubic-bezier(0.55, 0.085, 0.68, 0.53);
--EASE_OUT_QUAD: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--COLOR_UI_PHARMACY: #237db5;
--loaderPill_DURATION: 1800ms;
}
body {
font-family: 'Montserrat', sans-serif;
}
.absCenter {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.loaderPill {
text-align: center;
}
.loaderPill-anim {
height: 160px;
}
.loaderPill-anim-bounce {
animation: loaderPillBounce var(--loaderPill_DURATION) linear infinite;
}
.loaderPill-anim-flop {
transform-origin: 50% 50%;
animation: loaderPillFlop var(--loaderPill_DURATION) linear infinite;
}
.loaderPill-pill {
display: inline-block;
box-sizing: border-box;
width: 80px;
height: 30px;
border-radius: 15px;
border: 1px solid var(--COLOR_UI_PHARMACY);
background-image: linear-gradient(to right, var(--COLOR_UI_PHARMACY) 50%, #ffffff 50%);
}
.loaderPill-floor {
display: block;
text-align: center;
}
.loaderPill-floor-shadow {
display: inline-block;
width: 70px;
height: 7px;
border-radius: 50%;
background-color: color(var(--COLOR_UI_PHARMACY) alpha(26%));
transform: translateY(-15px);
animation: loaderPillScale var(--loaderPill_DURATION) linear infinite;
}
.loaderPill-text {
font-weight: bold;
color: var(--COLOR_UI_PHARMACY);
text-transform: uppercase;
}
@keyframes loaderPillBounce {
0% {
transform: translateY(123px);
animation-timing-function: var(--EASE_OUT_QUAD);
}
25% {
transform: translateY(40px);
animation-timing-function: var(--EASE_IN_QUAD);
}
50% {
transform: translateY(120px);
animation-timing-function: var(--EASE_OUT_QUAD);
}
75% {
transform: translateY(20px);
animation-timing-function: var(--EASE_IN_QUAD);
}
100% {
transform: translateY(120px);
}
}
@keyframes loaderPillFlop {
0% {
transform: rotate(0);
}
25% {
transform: rotate(90deg);
}
50% {
transform: rotate(180deg);
}
75% {
transform: rotate(450deg);
}
100% {
transform: rotate(720deg);
}
}
@keyframes loaderPillScale {
0% {
transform: translateY(-15px) scale(1, 1);
animation-timing-function: var(--EASE_OUT_QUAD);
}
25% {
transform: translateY(-15px) scale(0.7, 1);
animation-timing-function: var(--EASE_IN_QUAD);
}
50% {
transform: translateY(-15px) scale(1, 1);
animation-timing-function: var(--EASE_OUT_QUAD)
}
75% {
transform: translateY(-15px) scale(0.6, 1);
animation-timing-function: var(--EASE_IN_QUAD)
}
100% {
transform: translateY(-15px) scale(1, 1)
}
}
</style>
<div class="absCenter ">
<div class="loaderPill">
<div class="loaderPill-anim">
<div class="loaderPill-anim-bounce">
<div class="loaderPill-anim-flop">
<div class="loaderPill-pill"></div>
</div>
</div>
</div>
<div class="loaderPill-floor">
<div class="loaderPill-floor-shadow"></div>
</div>
<div class="loaderPill-text">Loading...</div>
</div>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
<script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp&key=MLVBZ-4YOLO-HXJWA-SCD4R-FQDL5-EPBGC"></script>
<script type="text/javascript" src="https://mapapi.qq.com/web/mapComponents/geoLocation/v/geolocation.min.js"></script>
<% if (ENABLE_ERUDA==="true" ) { %>
<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script>
eruda.init()
</script>
<% } %>
</body>
</html>
\ No newline at end of file
import { defineMock } from 'vite-plugin-mock-dev-server'
import Mock from 'mockjs'
export default defineMock([
{
url: '/dev-api/list/get',
delay: 1000,
body: {
code: 0,
message: 'OK',
result: Mock.mock({
'list|10': [
{
'id|+1': 1
}
]
})
}
},
{
url: '/dev-api/list/error',
delay: 1000,
body: {
code: 1,
message: 'ERROR',
result: null
}
}
])
{
"name": "hys-collect",
"engines": {
"node": ">= 16"
},
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"build:dev": "vue-tsc --noEmit && vite build --mode=development",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"lint:prettier": "prettier --write .",
"release": "standard-version",
"prepare": "husky install"
},
"dependencies": {
"@unocss/reset": "^0.57.1",
"@vant/area-data": "^1.5.1",
"@vant/use": "^1.6.0",
"@vueuse/core": "^10.5.0",
"axios": "^1.5.1",
"compressorjs": "^1.2.1",
"lodash-es": "^4.17.21",
"normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"unocss": "^0.57.1",
"vant": "^4.7.2",
"vue": "^3.3.6",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@commitlint/config-conventional": "^17.8.1",
"@rushstack/eslint-patch": "^1.5.1",
"@types/node": "^18.18.6",
"@types/nprogress": "^0.2.2",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-vue": "^4.4.0",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/tsconfig": "^0.1.3",
"autoprefixer": "^10.4.16",
"cnjm-postcss-px-to-viewport": "^1.0.0",
"commitlint": "^17.8.1",
"eslint": "^8.52.0",
"eslint-plugin-vue": "^9.18.0",
"husky": "^8.0.3",
"less": "^4.2.0",
"mockjs": "^1.1.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.31",
"prettier": "^2.8.8",
"standard-version": "^9.5.0",
"typescript": "~5.2.2",
"unplugin-vue-components": "^0.22.12",
"vite": "^4.5.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.0",
"vite-plugin-mock-dev-server": "^0.3.21",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-eslint-parser": "^9.3.2",
"vue-tsc": "^1.8.20"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"rollup"
]
}
}
}
This diff is collapsed.
module.exports = {
plugins: {
// 使用 cnjm-postcss-px-to-viewport 规避 postcss.plugin was deprecated 警告
'cnjm-postcss-px-to-viewport': {
viewportWidth: 375, // 根据设计稿设定
minPixelValue: 1, // 最小的转换数值
unitPrecision: 2 // 转化精度,转换后保留位数
},
autoprefixer: {
overrideBrowserslist: ['Android >= 4.0', 'iOS >= 7']
}
}
}
<template>
<router-view />
</template>
import { http } from '@/utils/http'
export interface UploadFileParams {
// Other parameters
data?: Recordable
// File parameter interface field name
name?: string
// file name
file: File | Blob
// file name
filename?: string
[key: string]: any
}
export function uploadApi(data: UploadFileParams) {
return http.upload({
url: '/file/upload',
method: 'post',
data
})
}
import { http } from '@/utils/http'
// export function getListApi(params?: object): Promise<ListResult> {
// return http.request({
// url: '/list/get',
// method: 'get',
// params
// })
// }
export function submitApi(data?: object) {
return http.request({
url: '/pharmacy/gschys',
method: 'post',
data
})
}
import { http } from '@/utils/http'
type ListResult = {
code: number
message: string
list: Array<any>
}
export function getListApi(params?: object): Promise<ListResult> {
return http.request({
url: '/list/get',
method: 'get',
params
})
}
export function getListApiError(data?: object): Promise<ListResult> {
return http.request({
url: '/list/error',
method: 'post',
data
})
}
<script setup lang="ts">
import { useDarkMode, useToggleDarkMode } from '@/hooks/useToggleDarkMode'
const onClickRight = () => {
useToggleDarkMode()
}
</script>
<template>
<van-nav-bar fixed placeholder @click-right="onClickRight">
<template #right>
<svg-icon class="text-[18px]" :name="useDarkMode() ? 'light' : 'dark'" />
</template>
</van-nav-bar>
</template>
<style scoped></style>
<script setup lang="ts">
import { isExternal } from '@/utils/validate'
import { computed } from 'vue'
interface Props {
name: string
className?: string
}
const props = withDefaults(defineProps<Props>(), {
name: '',
className: ''
})
const isExternalIcon = computed(() => isExternal(props.name))
const iconName = computed(() => `#icon-${props.name}`)
const svgClass = computed(() => {
if (props.className) {
return 'svg-icon ' + props.className
} else {
return 'svg-icon'
}
})
// 外链 icon
const styleExternalIcon = computed(() => {
return {
mask: `url(${props.name}) no-repeat 50% 50%`,
'-webkit-mask': `url(${props.name}) no-repeat 50% 50%`
}
})
</script>
<template>
<div v-if="isExternalIcon" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-bind="$attrs" />
<svg v-else :class="svgClass" aria-hidden="true" v-bind="$attrs">
<use :xlink:href="iconName" />
</svg>
</template>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover !important;
display: inline-block;
}
</style>
<template>
<van-tabbar v-model="active" :placeholder="true" :route="true" fixed>
<van-tabbar-item v-for="(item, index) in tabbarData" :key="index" :icon="item.icon" :to="item.to">
{{ item.title }}
</van-tabbar-item>
</van-tabbar>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
const active = ref(0)
const tabbarData = reactive([
{
icon: 'wap-home-o',
title: '主页',
to: {
name: 'Demo'
}
},
{
icon: 'gem-o',
title: '工具',
to: {
name: 'Tools'
}
},
{
icon: 'user-o',
title: '关于',
to: {
name: 'About'
}
}
])
</script>
/**
* @description: ContentType
*/
export enum ContentTypeEnum {
// form-data qs
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
// form-data upload
FORM_DATA = 'multipart/form-data;charset=UTF-8',
// json
JSON = 'application/json;charset=UTF-8'
}
/**
* @description: 与后端协定的状态 code
*/
export enum ResultEnum {
SUCCESS = 200,
ERROR = 1
}
import { useDarkModeStoreHook } from '@/store/modules/darkMode'
export function useDarkMode() {
return useDarkModeStoreHook().darkMode
}
export function useToggleDarkMode() {
useDarkModeStoreHook().toggleDarkMode()
}
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1594022623152" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6781" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M781.9 572.5V334c0-19.5-15.5-35.3-34.7-35.3H279.1c-19.1 0-34.7 15.8-34.7 35.3v477c0 19.5 15.5 35.3 34.7 35.3H683c19.1 0 98.9-64 98.9-83.5V572.5z" fill="#FCEE21" p-id="6782"></path><path d="M781.9 764.3V343.6c0-8.3-3-16-7.9-22-68.7 307.3-434 456.3-526.3 504.6 5.5 11.9 17.5 20.1 31.4 20.1H683c19.2 0 98.9-62.8 98.9-82z" fill="#F8B62D" p-id="6783"></path><path d="M781.9 569.7c-5.6 0-10.1-4.5-10.1-10.1V309.8c0-14.8-12.1-26.9-26.9-26.9h-457c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1H745c26 0 47.1 21.1 47.1 47.1v249.7c-0.1 5.7-4.6 10.2-10.2 10.2zM208.5 334.6c-5.6 0-10.1-4.5-10.1-10.1v-14.7c0-26 21.1-47.1 47.1-47.1h2.1c5.6 0 10.1 4.5 10.1 10.1s-4.5 10.1-10.1 10.1h-2.1c-14.8 0-26.9 12.1-26.9 26.9v14.7c-0.1 5.6-4.6 10.1-10.1 10.1zM482.9 856.4H245.4c-26 0-47.1-21.1-47.1-47.1V358.2c0-5.6 4.5-10.1 10.1-10.1s10.1 4.5 10.1 10.1v451.2c0 14.8 12.1 26.9 26.9 26.9h237.4c5.6 0 10.1 4.5 10.1 10.1s-4.5 10-10 10z" fill="#3E3A39" p-id="6784"></path><path d="M313.2 506.9h232.1" fill="#FCEE21" p-id="6785"></path><path d="M545.3 517H313.2c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1h232.1c5.6 0 10.1 4.5 10.1 10.1s-4.5 10.1-10.1 10.1z" fill="#3E3A39" p-id="6786"></path><path d="M313.2 603.4h188.7" fill="#FCEE21" p-id="6787"></path><path d="M501.9 613.5H313.2c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1h188.7c5.6 0 10.1 4.5 10.1 10.1s-4.5 10.1-10.1 10.1z" fill="#3E3A39" p-id="6788"></path><path d="M313.2 699.8h125.1" fill="#FCEE21" p-id="6789"></path><path d="M438.3 709.9h-125c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1h125c5.6 0 10.1 4.5 10.1 10.1s-4.6 10.1-10.1 10.1z" fill="#3E3A39" p-id="6790"></path><path d="M316.1 404h465.8" fill="#FCEE21" p-id="6791"></path><path d="M781.9 414.1H316.1c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1H782c5.6 0 10.1 4.5 10.1 10.1s-4.6 10.1-10.2 10.1z" fill="#3E3A39" p-id="6792"></path><path d="M381.9 330.3h-43.1c-2.1 0-3.8-1.7-3.8-3.8V209.9c0-2.1 1.7-3.8 3.8-3.8h43.1c2.1 0 3.8 1.7 3.8 3.8v116.7c0 2-1.7 3.7-3.8 3.7z" fill="#F8B62D" p-id="6793"></path><path d="M360.3 340.4c-19.5 0-35.4-15.9-35.4-35.4v-73.6c0-19.5 15.9-35.4 35.4-35.4s35.4 15.9 35.4 35.4V305c0.1 19.5-15.8 35.4-35.4 35.4z m0-124.2c-8.4 0-15.2 6.8-15.2 15.2V305c0 8.4 6.8 15.2 15.2 15.2 8.4 0 15.2-6.8 15.2-15.2v-73.6c0.1-8.4-6.8-15.2-15.2-15.2zM866.3 856.4h-24c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1h24c5.6 0 10.1 4.5 10.1 10.1s-4.6 10.1-10.1 10.1zM123.6 856.4H92.9c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1h30.7c5.6 0 10.1 4.5 10.1 10.1s-4.5 10.1-10.1 10.1zM803.7 856.4H155.4c-5.6 0-10.1-4.5-10.1-10.1s4.5-10.1 10.1-10.1h648.3c5.6 0 10.1 4.5 10.1 10.1s-4.5 10.1-10.1 10.1z" fill="#3E3A39" p-id="6794"></path><path d="M665.7 737.2m-127.1 0a127.1 127.1 0 1 0 254.2 0 127.1 127.1 0 1 0-254.2 0Z" fill="#FFFFFF" p-id="6795"></path><path d="M659.8 874.3c-82.6 0-149.8-67.2-149.8-149.8 0-82.6 67.2-149.8 149.8-149.8S809.5 642 809.5 724.6c0 82.5-67.1 149.7-149.7 149.7z m0-279.3c-71.5 0-129.6 58.1-129.6 129.6s58.1 129.6 129.6 129.6S789.4 796 789.4 724.6c0-71.5-58.2-129.6-129.6-129.6z" fill="#3E3A39" p-id="6796"></path><path d="M649.3 797c-2.5 0-4.9-0.9-6.7-2.6l-64.8-58.2c-4.1-3.7-4.5-10.1-0.8-14.2s10.1-4.5 14.2-0.8l56.7 50.9 77.4-101.2c3.4-4.4 9.7-5.3 14.1-1.9s5.3 9.7 1.9 14.1l-84 109.9c-1.7 2.2-4.3 3.7-7.1 3.9-0.2 0.1-0.6 0.1-0.9 0.1z" fill="#3E3A39" p-id="6797"></path><path d="M692.1 126.3c-15.1 0-27.3-12.3-27.3-27.3 0-15.1 12.3-27.3 27.3-27.3 15.1 0 27.3 12.3 27.3 27.3 0 15.1-12.2 27.3-27.3 27.3z m0-41.2c-7.7 0-13.9 6.2-13.9 13.9s6.2 13.9 13.9 13.9S706 106.7 706 99s-6.2-13.9-13.9-13.9z" fill="#47B7F8" p-id="6798"></path><path d="M249 169.9h-12v-12c0-3.2-2.6-5.8-5.8-5.8-3.2 0-5.8 2.6-5.8 5.8v12h-12c-3.2 0-5.8 2.6-5.8 5.8 0 3.2 2.6 5.8 5.8 5.8h12v12c0 3.2 2.6 5.8 5.8 5.8 3.2 0 5.8-2.6 5.8-5.8v-12h12c3.2 0 5.8-2.6 5.8-5.8 0-3.2-2.6-5.8-5.8-5.8zM853.2 286.2h-12v-12c0-3.2-2.6-5.8-5.8-5.8-3.2 0-5.8 2.6-5.8 5.8v12h-12c-3.2 0-5.8 2.6-5.8 5.8s2.6 5.8 5.8 5.8h12v12c0 3.2 2.6 5.8 5.8 5.8 3.2 0 5.8-2.6 5.8-5.8v-12h12c3.2 0 5.8-2.6 5.8-5.8s-2.6-5.8-5.8-5.8z" fill="#F7E42F" p-id="6799"></path><path d="M112.5 443.7H98.6v-13.9a6.7 6.7 0 0 0-13.4 0v13.9h-14a6.7 6.7 0 0 0 0 13.4h13.9V471a6.7 6.7 0 0 0 13.4 0v-13.9h13.9c3.7 0 6.7-3 6.7-6.7s-2.9-6.7-6.6-6.7z" fill="#F8B62D" p-id="6800"></path><path d="M340.1 109.1m-10.1 0a10.1 10.1 0 1 0 20.2 0 10.1 10.1 0 1 0-20.2 0Z" fill="#F8B62D" p-id="6801"></path><path d="M790.8 162.3m-13.4 0a13.4 13.4 0 1 0 26.8 0 13.4 13.4 0 1 0-26.8 0Z" fill="#F8B62D" p-id="6802"></path><path d="M545.3 115.7m-13.4 0a13.4 13.4 0 1 0 26.8 0 13.4 13.4 0 1 0-26.8 0Z" fill="#F7E42F" p-id="6803"></path><path d="M125.5 291.9c-15.1 0-27.3-12.3-27.3-27.3 0-15.1 12.3-27.3 27.3-27.3s27.3 12.3 27.3 27.3c0 15.1-12.3 27.3-27.3 27.3z m0-41.2c-7.7 0-13.9 6.2-13.9 13.9s6.2 13.9 13.9 13.9 13.9-6.2 13.9-13.9-6.3-13.9-13.9-13.9z" fill="#F8B62D" p-id="6804"></path><path d="M472.7 166.3c-1.5-1.4-3.8-1.4-5.3 0-0.7 0.7-1.1 1.6-1.1 2.6s0.4 1.9 1.1 2.6l11.9 11.9c0.7 0.7 1.6 1.1 2.6 1.1s1.9-0.4 2.6-1.1c1.4-1.5 1.4-3.8 0-5.3l-11.8-11.8zM504.3 197.9c-0.7-0.7-1.6-1.1-2.6-1.1s-1.9 0.4-2.6 1.1c-1.4 1.5-1.4 3.8 0 5.3l11.9 11.9c0.7 0.7 1.6 1.1 2.6 1.1s1.9-0.4 2.6-1.1c0.7-0.7 1.1-1.6 1.1-2.6s-0.4-1.9-1.1-2.6l-11.9-12zM501.6 184.6c1 0 1.9-0.4 2.6-1.1l11.9-11.9c0.7-0.7 1.1-1.6 1.1-2.6s-0.4-1.9-1.1-2.6c-1.5-1.5-3.8-1.5-5.3 0L499 178.3c-1.4 1.5-1.4 3.8 0 5.3 0.7 0.7 1.6 1 2.6 1zM479.4 197.9l-11.9 11.9c-0.7 0.7-1.1 1.6-1.1 2.6s0.4 1.9 1.1 2.6c0.7 0.7 1.6 1.1 2.6 1.1s1.9-0.4 2.6-1.1l11.9-11.9c1.4-1.5 1.4-3.8 0-5.3-1.3-1.3-3.8-1.3-5.2 0.1zM481.7 190.7c0-2.1-1.7-3.7-3.7-3.7h-16.9c-2.1 0-3.7 1.7-3.7 3.7 0 2.1 1.7 3.7 3.7 3.7H478c2 0 3.7-1.6 3.7-3.7zM522.6 187h-16.9c-2.1 0-3.7 1.7-3.7 3.7 0 2.1 1.7 3.7 3.7 3.7h16.9c2.1 0 3.7-1.7 3.7-3.7s-1.7-3.7-3.7-3.7zM491.8 156.2c-2.1 0-3.7 1.7-3.7 3.7v16.9c0 2.1 1.7 3.7 3.7 3.7 2.1 0 3.7-1.7 3.7-3.7V160c0-2.1-1.6-3.8-3.7-3.8zM491.8 200.8c-2.1 0-3.7 1.7-3.7 3.7v16.9c0 2.1 1.7 3.7 3.7 3.7 2.1 0 3.7-1.7 3.7-3.7v-16.9c0-2-1.6-3.7-3.7-3.7z" fill="#FAEE00" p-id="6805"></path><path d="M905.9 417c-1.5-1.4-3.8-1.4-5.3 0-0.7 0.7-1.1 1.6-1.1 2.6s0.4 1.9 1.1 2.6l11.9 11.9c0.7 0.7 1.6 1.1 2.6 1.1s1.9-0.4 2.6-1.1c1.4-1.5 1.4-3.8 0-5.3L905.9 417zM937.5 448.5c-0.7-0.7-1.6-1.1-2.6-1.1s-1.9 0.4-2.6 1.1c-1.4 1.5-1.4 3.8 0 5.3l11.9 11.9c0.7 0.7 1.6 1.1 2.6 1.1s1.9-0.4 2.6-1.1c0.7-0.7 1.1-1.6 1.1-2.6s-0.4-1.9-1.1-2.6l-11.9-12zM934.8 435.3c1 0 1.9-0.4 2.6-1.1l11.9-11.9c0.7-0.7 1.1-1.6 1.1-2.6s-0.4-1.9-1.1-2.6c-1.5-1.5-3.8-1.5-5.3 0L932.1 429c-1.4 1.5-1.4 3.8 0 5.3 0.8 0.6 1.7 1 2.7 1zM912.6 448.5l-11.9 11.9c-0.7 0.7-1.1 1.6-1.1 2.6s0.4 1.9 1.1 2.6c0.7 0.7 1.6 1.1 2.6 1.1s1.9-0.4 2.6-1.1l11.9-11.9c1.4-1.5 1.4-3.8 0-5.3-1.3-1.3-3.8-1.3-5.2 0.1zM914.9 441.4c0-2.1-1.7-3.7-3.7-3.7h-16.9c-2.1 0-3.7 1.7-3.7 3.7s1.7 3.7 3.7 3.7h16.9c2 0 3.7-1.7 3.7-3.7zM955.8 437.6h-16.9c-2.1 0-3.7 1.7-3.7 3.7s1.7 3.7 3.7 3.7h16.9c2.1 0 3.7-1.7 3.7-3.7s-1.7-3.7-3.7-3.7zM925 406.9c-2.1 0-3.7 1.7-3.7 3.7v16.9c0 2.1 1.7 3.7 3.7 3.7s3.7-1.7 3.7-3.7v-16.9c0.1-2-1.6-3.7-3.7-3.7zM925 451.5c-2.1 0-3.7 1.7-3.7 3.7v16.9c0 2.1 1.7 3.7 3.7 3.7s3.7-1.7 3.7-3.7v-16.9c0.1-2.1-1.6-3.7-3.7-3.7z" fill="#F8B62D" p-id="6806"></path><path d="M648.3 330.3h-43.1c-2.1 0-3.8-1.7-3.8-3.8V209.9c0-2.1 1.7-3.8 3.8-3.8h43.1c2.1 0 3.8 1.7 3.8 3.8v116.7c0 2-1.7 3.7-3.8 3.7z" fill="#F8B62D" p-id="6807"></path><path d="M626.7 340.4c-19.5 0-35.4-15.9-35.4-35.4v-73.6c0-19.5 15.9-35.4 35.4-35.4s35.4 15.9 35.4 35.4V305c0.1 19.5-15.8 35.4-35.4 35.4z m0-124.2c-8.4 0-15.2 6.8-15.2 15.2V305c0 8.4 6.8 15.2 15.2 15.2 8.4 0 15.2-6.8 15.2-15.2v-73.6c0.1-8.4-6.8-15.2-15.2-15.2z" fill="#3E3A39" p-id="6808"></path><path d="M271.3 381.9c-5.6 0-10.1-4.5-10.1-10.1V341c0-17.7 14.4-32.1 32.1-32.1h17.8c5.6 0 10.1 4.5 10.1 10.1s-4.5 10.1-10.1 10.1h-17.8c-6.6 0-12 5.4-12 12v30.8c0.1 5.5-4.4 10-10 10z" fill="#FFFFFF" p-id="6809"></path><path d="M271.3 576.4c-5.6 0-10.1-4.5-10.1-10.1V455.6c0-5.6 4.5-10.1 10.1-10.1s10.1 4.5 10.1 10.1v110.7c0 5.6-4.5 10.1-10.1 10.1z" fill="#FFFFFF" p-id="6810"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1681314397470" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2282" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M448.22 48C704.358 48 912 255.74 912 512l-0.062 7.673C907.842 772.394 701.797 976 448.22 976c-110.645 0-198.866-26.169-264.663-78.506a32 32 0 0 1-4.325-4.159c-11.419-13.256-10.058-33.192 2.962-44.78l0.399-0.35 2.742-2.383c89.13-78.201 134.016-188.043 134.66-329.525L320 512c0.253-143.557-44.635-254.831-134.665-333.822l-2.742-2.384c-13.39-11.534-14.895-31.74-3.36-45.13a32 32 0 0 1 4.324-4.158C249.354 74.17 337.575 48 448.22 48z m0 64c-78.634 0-142.266 14.443-192.055 42.56l-1.809 1.03 0.175 0.18c85.695 88.653 128.775 207.05 129.462 351.494l0.007 4.825-0.007 4.499c-0.65 143.074-42.893 260.596-126.9 348.969l-2.737 2.852 1.809 1.031c49.174 27.77 111.852 42.201 189.149 42.56h2.906c216.135 0 392.63-171.775 399.568-386.834l0.154-6.358 0.057-6.946-0.053-6.477C844.452 289.716 670.368 115.55 454.83 112.054l-6.61-0.054z" fill="#000000" p-id="2283"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1613814207456" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1123" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1021.72444445 512a495.16088889 495.16088889 0 0 1-97.57582223 299.64515555 500.62222222 500.62222222 0 0 1-250.85724444 184.22897778 30.58346667 30.58346667 0 0 1-26.2144-4.73315555 25.85031111 25.85031111 0 0 1-8.00995556-20.02488889v-139.81013334a119.05706667 119.05706667 0 0 0-34.58844444-94.29902222 473.31555555 473.31555555 0 0 0 67.72053333-11.65084444 248.30862222 248.30862222 0 0 0 62.2592-26.2144 187.50577778 187.50577778 0 0 0 53.52106667-43.69066667 209.35111111 209.35111111 0 0 0 36.40888889-69.90506667 334.2336 334.2336 0 0 0 13.83537778-100.12444444 191.87484445 191.87484445 0 0 0-52.7928889-136.53333333 176.21902222 176.21902222 0 0 0-5.09724444-135.44106667 87.01724445 87.01724445 0 0 0-53.52106666 7.28177778 341.87946667 341.87946667 0 0 0-61.16693334 29.12711111l-25.12213333 15.65582222a473.31555555 473.31555555 0 0 0-254.86222223 0c-7.28177778-5.09724445-16.384-10.55857778-28.03484444-17.84035555A371.00657778 371.00657778 0 0 0 300.82844445 220.72888889a94.29902222 94.29902222 0 0 0-57.16195556-9.10222222 178.40355555 178.40355555 0 0 0-4.73315556 136.53333333 197.70026667 197.70026667 0 0 0-52.4288 137.26151111A327.68 327.68 0 0 0 200.33991111 584.81777778a223.55057778 223.55057778 0 0 0 36.40888889 69.90506667 172.94222222 172.94222222 0 0 0 53.52106667 44.41884444 304.7424 304.7424 0 0 0 62.2592 26.2144 471.13102222 471.13102222 0 0 0 68.08462222 11.65084444 105.22168889 105.22168889 0 0 0-32.768 68.44871112 112.86755555 112.86755555 0 0 1-30.21937778 9.4663111 190.41848889 190.41848889 0 0 1-36.40888889 3.2768A78.6432 78.6432 0 0 1 274.61404445 803.27111111a124.5184 124.5184 0 0 1-36.4088889-41.50613333 109.22666667 109.22666667 0 0 0-32.03982222-34.58844445 91.7504 91.7504 0 0 0-32.768-16.01991111h-13.1072a47.33155555 47.33155555 0 0 0-19.29671111 2.91271111q-5.46133333 3.2768-3.2768 7.64586667a50.24426667 50.24426667 0 0 0 6.18951111 9.10222222 62.98737778 62.98737778 0 0 0 8.73813334 8.37404445l4.73315555 2.91271111a88.83768889 88.83768889 0 0 1 29.12711111 25.12213333 179.49582222 179.49582222 0 0 1 20.75306667 33.49617778l6.5536 15.29173333a82.28408889 82.28408889 0 0 0 29.12711111 41.14204445 109.22666667 109.22666667 0 0 0 44.05475556 18.93262222 223.18648889 223.18648889 0 0 0 45.8752 4.73315556 207.16657778 207.16657778 0 0 0 36.40888888-2.54862223l15.29173334-2.54862222v95.39128889a26.2144 26.2144 0 0 1-8.73813334 20.02488889 31.67573333 31.67573333 0 0 1-26.57848888 4.73315555 498.43768889 498.43768889 0 0 1-249.40088889-185.32124444A486.78684445 486.78684445 0 0 1 2.27555555 512a497.70951111 497.70951111 0 0 1 68.44871112-254.86222222A504.6272 504.6272 0 0 1 257.13777778 70.72426667 497.70951111 497.70951111 0 0 1 512 2.27555555a497.70951111 497.70951111 0 0 1 254.86222222 68.44871112A504.6272 504.6272 0 0 1 953.27573333 257.13777778 496.98133333 496.98133333 0 0 1 1021.72444445 512z" p-id="1124"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1681314392506" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2129" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 224c159.058 0 288 128.942 288 288S671.058 800 512 800 224 671.058 224 512s128.942-288 288-288z m0 64c-123.712 0-224 100.288-224 224s100.288 224 224 224 224-100.288 224-224-100.288-224-224-224z m0 576c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32-17.673 0-32-14.327-32-32v-64c0-17.673 14.327-32 32-32zM263.098 760.902c12.497 12.496 12.497 32.758 0 45.254l-45.254 45.255c-12.497 12.497-32.758 12.497-45.255 0s-12.497-32.758 0-45.255l45.255-45.254c12.496-12.497 32.758-12.497 45.254 0z m543.058 0l45.255 45.254c12.497 12.497 12.497 32.758 0 45.255s-32.758 12.497-45.255 0l-45.254-45.255c-12.497-12.496-12.497-32.758 0-45.254 12.496-12.497 32.758-12.497 45.254 0zM128 480c17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32H64c-17.673 0-32-14.327-32-32 0-17.673 14.327-32 32-32h64z m832 0c17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32h-64c-17.673 0-32-14.327-32-32 0-17.673 14.327-32 32-32h64zM217.844 172.589l45.254 45.255c12.497 12.496 12.497 32.758 0 45.254-12.496 12.497-32.758 12.497-45.254 0l-45.255-45.254c-12.497-12.497-12.497-32.758 0-45.255s32.758-12.497 45.255 0z m633.567 0c12.497 12.497 12.497 32.758 0 45.255l-45.255 45.254c-12.496 12.497-32.758 12.497-45.254 0-12.497-12.496-12.497-32.758 0-45.254l45.254-45.255c12.497-12.497 32.758-12.497 45.255 0zM512 32c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32-17.673 0-32-14.327-32-32V64c0-17.673 14.327-32 32-32z" fill="#000000" p-id="2130"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1613816440554" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2265" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M883.459773 504.826645a46.043165 46.043165 0 0 1-60.708766-0.937916 41.609379 41.609379 0 0 1-3.49587-58.236078l77.591261-77.932321a163.538503 163.538503 0 0 0-16.96776-229.10738c-67.359446-67.274181-166.863842-73.328004-223.053557-16.711964L439.995878 340.264961a163.538503 163.538503 0 0 0 17.053024 229.107381 41.609379 41.609379 0 0 1 0 60.367706 45.61684 45.61684 0 0 1-63.43725 0 246.330935 246.330935 0 0 1-16.967759-347.284839L593.473096 65.37021C686.753139-28.080362 845.090469-20.406501 945.959107 82.423235a246.24567 246.24567 0 0 1 15.603518 343.618438l-78.102852 78.784972z m-742.318145 13.64242a46.043165 46.043165 0 0 1 60.708766 0.937916c16.797229 15.518252 18.417266 40.927258 3.49587 58.236078l-77.59126 77.932321a163.538503 163.538503 0 0 0 16.967759 229.10738c67.359446 67.274181 166.863842 73.328004 223.053557 16.711964L584.605524 683.030749a163.538503 163.538503 0 0 0-17.053025-229.107381 41.609379 41.609379 0 0 1 0-60.367706 45.531575 45.531575 0 0 1 63.437251 0 246.330935 246.330935 0 0 1 16.967759 347.284839l-216.829204 217.170264c-93.280043 93.365308-251.617373 85.691447-352.486011-17.053025a246.24567 246.24567 0 0 1-15.603517-343.618438l78.102851-78.784972z" p-id="2266"></path></svg>
\ No newline at end of file
# replace default config
# multipass: true
# full: true
plugins:
# - name
#
# or:
# - name: false
# - name: true
#
# or:
# - name:
# param1: 1
# param2: 2
- removeAttrs:
attrs:
- 'fill'
- 'fill-rule'
<script setup lang="ts">
import tabbar from '@/components/Tabbar/index.vue'
import NavBar from '@/components/NavBar/index.vue'
import { useCachedViewStoreHook } from '@/store/modules/cachedView'
import { useDarkMode } from '@/hooks/useToggleDarkMode'
import { computed } from 'vue'
const cachedViews = computed(() => {
return useCachedViewStoreHook().cachedViewList
})
</script>
<template>
<div class="app-wrapper">
<van-config-provider :theme="useDarkMode() ? 'dark' : 'light'">
<nav-bar />
<router-view v-slot="{ Component }">
<keep-alive :include="cachedViews">
<component :is="Component" />
</keep-alive>
</router-view>
<tabbar />
</van-config-provider>
</div>
</template>
<style lang="less" scoped>
@import '@/styles/mixin.less';
.app-wrapper {
.clearfix();
position: relative;
height: 100%;
width: 100%;
}
</style>
import { createApp } from 'vue'
import { store } from './store'
// normalize.css
import 'normalize.css/normalize.css'
// 全局样式
import './styles/index.less'
import 'virtual:uno.css'
// svg icon
import 'virtual:svg-icons-register'
import 'vant/es/dialog/style'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(store)
app.use(router)
app.mount('#app')
import { createRouter, createWebHashHistory, type RouteLocationNormalized } from 'vue-router'
import routes from './routes'
import { useCachedViewStoreHook } from '@/store/modules/cachedView'
import NProgress from '@/utils/progress'
import setPageTitle from '@/utils/set-page-title'
const router = createRouter({
history: createWebHashHistory(),
routes
})
export interface toRouteType extends RouteLocationNormalized {
meta: {
title?: string
noCache?: boolean
}
}
router.beforeEach((to: toRouteType, from, next) => {
NProgress.start()
// 路由缓存
useCachedViewStoreHook().addCachedView(to)
// 页面 title
setPageTitle(to.meta.title)
next()
})
router.afterEach(() => {
NProgress.done()
})
export default router
import Layout from '@/layout/index.vue'
import type { RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
{
path: '/:channel',
name: 'Home',
meta: { title: '好医生保险经纪' },
component: () => import('@/views/home/index.vue')
},
{
path: '/result',
name: 'Result',
meta: { title: '好医生保险经纪' },
component: () => import('@/views/result/index.vue')
},
{
path: '/tab',
name: 'tab',
component: Layout,
redirect: { name: 'Tab' },
children: [
{
path: 'tab',
name: 'Tab',
component: () => import('@/views/tab/index.vue'),
meta: { title: 'TAB页面' }
}
]
}
]
export default routes
export const pageDefaultTitle = '好医生保险经纪'
import { createPinia } from 'pinia'
const store = createPinia()
export { store }
import { defineStore } from 'pinia'
import { store } from '@/store'
import type { toRouteType } from '@/router'
export const useCachedViewStore = defineStore({
id: 'cached-view',
state: () => ({
// 缓存页面 keepAlive
cachedViewList: [] as string[]
}),
actions: {
addCachedView(view: toRouteType) {
// 不重复添加
if (this.cachedViewList.includes(view.name as string)) return
if (!view?.meta?.noCache) {
this.cachedViewList.push(view.name as string)
}
},
delCachedView(view: toRouteType) {
const index = this.cachedViewList.indexOf(view.name as string)
index > -1 && this.cachedViewList.splice(index, 1)
},
delAllCachedViews() {
this.cachedViewList = [] as string[]
}
}
})
export function useCachedViewStoreHook() {
return useCachedViewStore(store)
}
import { defineStore } from 'pinia'
import { store } from '@/store'
const darkModeKey = '__dark_mode__'
const isDarkMode = () => {
const darkMode = window.localStorage.getItem(darkModeKey)
if (darkMode) {
return darkMode === 'true'
} else {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
}
export const useDarkModeStore = defineStore({
id: 'dark-mode',
state: () => ({
darkMode: isDarkMode()
}),
actions: {
toggleDarkMode() {
this.darkMode = !this.darkMode
if (this.darkMode) {
document.documentElement.classList.add('dark')
window.localStorage.setItem(darkModeKey, 'true')
} else {
document.documentElement.classList.remove('dark')
window.localStorage.setItem(darkModeKey, 'false')
}
}
}
})
export function useDarkModeStoreHook() {
return useDarkModeStore(store)
}
@import './variables.less';
html,
body,
#app {
height: 100%;
margin: 0;
padding: 0;
}
body {
font-size: 14px;
color: var(--van-text-color);
background-color: var(--color-background-2);
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
.clearfix() {
&:after {
content: '';
display: table;
clear: both;
}
}
:root:root {
--van-blue: #00a385;
--van-cell-group-inset-padding: 0 var(--van-padding-sm);
}
:root {
--theme-color: var(--van-blue);
--color-text: var(--van-text-color, #323233);
--color-background-2: var(--van-background-2, #fff);
--color-block-background: var(--van-border-color, #ebedf0);
}
html.dark {
--color-text: var(--van-text-color, #f5f5f5);
--color-background-2: var(--van-background-2, #1c1c1e);
--color-block-background: var(--van-border-color, #3a3a3c);
}
export const TEAM_LIST = [
'南疆',
'北疆',
'浙南',
'浙北',
'黔东',
'黔中',
'苏中',
'苏北',
'苏南',
'甘宁',
'甘青',
'内蒙',
'陕北',
'陕南',
'湘北',
'湘东',
'湘南',
'湘西',
'渝东',
'渝西',
'粤东',
'粤南',
'粤西',
'粤中',
'粤北',
'鲁东',
'鲁南',
'鲁西',
'鲁北',
'鲁中',
'鄂北',
'鄂东',
'鄂西',
'赣东',
'赣西',
'闽北',
'闽南',
'豫北',
'豫西',
'豫南',
'豫东',
'冀南',
'冀北',
'冀东',
'冀西',
'吉东',
'吉西',
'黑东',
'黑西',
'辽东',
'辽南',
'桂北',
'桂南',
'晋北',
'晋南',
'皖北',
'皖南',
'皖西'
]
import Axios, { type AxiosInstance, type AxiosError, type AxiosResponse, type AxiosRequestConfig } from 'axios'
import { ContentTypeEnum, ResultEnum } from '@/enums/requestEnum'
// import NProgress from '../progress'
import { showFailToast } from 'vant'
import 'vant/es/toast/style'
// 默认 axios 实例请求配置
const configDefault = {
headers: { 'Content-Type': ContentTypeEnum.JSON },
timeout: 0,
baseURL: import.meta.env.VITE_BASE_API,
data: {}
}
class Http {
// 当前实例
private static axiosInstance: AxiosInstance
// 请求配置
private static axiosConfigDefault: AxiosRequestConfig
// 请求拦截
private httpInterceptorsRequest(): void {
Http.axiosInstance.interceptors.request.use(
config => {
// NProgress.start()
// 发送请求前,可在此携带 token
// if (token) {
// config.headers['token'] = token
// }
return config
},
(error: AxiosError) => {
showFailToast(error.message)
return Promise.reject(error)
}
)
}
// 响应拦截
private httpInterceptorsResponse(): void {
Http.axiosInstance.interceptors.response.use(
(response: AxiosResponse) => {
// NProgress.done()
// 与后端协定的返回字段
const { status, msg, data } = response.data
// 判断请求是否成功
const isSuccess = data && Reflect.has(response.data, 'status') && status === ResultEnum.SUCCESS
if (isSuccess) {
return data
} else {
// 处理请求错误
showFailToast(msg)
return Promise.reject(response.data)
}
},
(error: AxiosError) => {
// NProgress.done()
// 处理 HTTP 网络错误
let message = ''
// HTTP 状态码
const status = error.response?.status
switch (status) {
case 400:
message = '请求错误'
break
case 401:
message = '未授权,请登录'
break
case 403:
message = '拒绝访问'
break
case 404:
message = `请求地址出错: ${error.response?.config?.url}`
break
case 408:
message = '请求超时'
break
case 500:
message = '服务器内部错误'
break
case 501:
message = '服务未实现'
break
case 502:
message = '网关错误'
break
case 503:
message = '服务不可用'
break
case 504:
message = '网关超时'
break
case 505:
message = 'HTTP版本不受支持'
break
default:
message = '网络连接故障'
}
showFailToast(message)
return Promise.reject(error)
}
)
}
constructor(config: AxiosRequestConfig) {
Http.axiosConfigDefault = config
Http.axiosInstance = Axios.create(config)
this.httpInterceptorsRequest()
this.httpInterceptorsResponse()
}
// 通用请求函数
public request<T>(paramConfig: AxiosRequestConfig): Promise<T> {
const config = { ...Http.axiosConfigDefault, ...paramConfig }
return new Promise((resolve, reject) => {
Http.axiosInstance
.request(config)
.then((response: any) => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
}
// 上传请求函数
public upload<T>(paramConfig: AxiosRequestConfig): Promise<T> {
const config = Object.assign(Http.axiosConfigDefault, paramConfig)
const data = config.data
const formData = new window.FormData()
const customFilename = data.name || 'file'
if (data.filename) {
formData.append(customFilename, data.file, data.filename)
} else {
formData.append(customFilename, data.file)
}
if (data.data) {
Object.keys(data.data).forEach(key => {
const value = data.data![key]
if (Array.isArray(value)) {
value.forEach(item => {
formData.append(`${key}[]`, item)
})
return
}
formData.append(key, data.data![key])
})
}
return new Promise((resolve, reject) => {
Http.axiosInstance
.request({
...config,
data: formData,
headers: { 'Content-type': ContentTypeEnum.FORM_DATA }
})
.then((response: any) => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
}
}
export const http = new Http(configDefault)
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
NProgress.configure({
// 动画方式
easing: 'ease',
// 递增进度条的速度
speed: 500,
// 是否显示加载ico
showSpinner: false,
// 自动递增间隔
trickleSpeed: 200,
// 初始化时的最小百分比
minimum: 0.3,
// 加载条的父元素
parent: '#app'
})
export default NProgress
import { pageDefaultTitle } from '@/settings'
export default function setPageTitle(routerTitle?: string): void {
window.document.title = routerTitle ? routerTitle : pageDefaultTitle
}
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path: string) {
return /^(https?:|mailto:|tel:)/.test(path)
}
/**
* @param {string} val
* @returns {Boolean}
*/
export function isIdcard(val: string) {
return /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/.test(
val
)
}
<template>
<div class="title">
<span class="font-bold">当前地址</span>
</div>
<div class="px-3">
<p class="font-bold mt-0">{{ address.area }}</p>
<p>{{ address.addr }}</p>
</div>
<div class="mx-3 pb-6">
<div class="p-1 van-hairline--surround box-border">
<div id="map"></div>
</div>
</div>
</template>
<script setup lang="ts" name="customMap">
import { onMounted, reactive } from 'vue'
import { showFailToast } from 'vant'
const emit = defineEmits(['setAddress'])
const address = reactive({
area: '',
addr: ''
})
onMounted(() => {
const geolocation = new (window as any).qq.maps.Geolocation('MLVBZ-4YOLO-HXJWA-SCD4R-FQDL5-EPBGC', 'hysapp')
const options = { timeout: 10000, failTipFlag: true }
geolocation.getLocation(onSuccess, onFail, options)
})
function onSuccess(res: any) {
const { lat, lng, province, city, district = '', addr = '' } = res
initMap([lat, lng])
address.area = `${province}${city}${district}`
address.addr = addr
emit('setAddress', res)
}
function onFail() {
showFailToast('定位失败!')
initMap()
}
function initMap(latlng: Array<string | number> = [39.98412, 116.307484]) {
//定义地图中心点坐标
const center = new (window as any).qq.maps.LatLng(latlng[0], latlng[1])
const map = new (window as any).qq.maps.Map(document.getElementById('map'), {
center: center,
zoom: 16,
disableDefaultUI: true
})
setTimeout(() => {
new (window as any).qq.maps.Marker({
position: center,
map: map
})
}, 1000)
}
</script>
<style scoped>
.title {
padding: 16px 12px;
padding-left: 24px;
position: relative;
font-size: 15px;
&::before {
content: '';
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
border-radius: 2px;
background-color: var(--theme-color);
}
}
#map {
width: 100%;
height: 240px;
border-radius: 6px;
}
</style>
<template>
<div class="w-full">
<van-cell-group border>
<van-cell v-for="(cell, index) in list" :key="index" :title="cell.form1" :label="cell.form2" @click="onEdit(cell)">
<template #icon>
<van-icon class="mt-1 mr-2" name="manager" color="#00c699" size="16" />
</template>
<template #right-icon>
<span class="pl-4" @click.stop="onRemove(index)">
<van-icon name="clear" color="#969799" size="18" />
</span>
</template>
</van-cell>
</van-cell-group>
<div class="mt-4 mr-auto w-160px">
<van-button type="primary" icon="plus" size="small" block round plain text="添加" @click="onAdd" />
</div>
<van-popup v-model:show="show" round closeable teleport="body" style="width: 88vw">
<div class="font-bold text-base text-center py-5 px-3 van-hairline--bottom">{{ formType === 'add' ? '新增' : '编辑' }}信息</div>
<van-form ref="formRef" label-width="104" colon scroll-to-error @submit="onSubmit">
<van-field
v-model="formModel.form1"
label="姓名"
name="form1"
required
clearable
placeholder="请输入姓名"
:rules="[{ required: true, message: '请输入姓名' }]"
/>
<van-field
v-model="formModel.form2"
label="身份证号"
name="form2"
required
clearable
placeholder="请输入身份证号"
:rules="[
{ required: true, message: '请输入身份证号' },
{ validator: isIdcard, message: '身份证号有误' }
]"
/>
<van-field label="身份证人像面" required :rules="[{ required: true, message: '请上传身份证人像面' }]" name="form3">
<template #input>
<van-uploader
v-model="formModel.form3"
name="form3"
:max-count="1"
:preview-size="['165px', '107px']"
upload-icon="plus"
:before-read="beforeRead"
:after-read="(file: any, detail: Recordable) => afterRead(file, detail)"
/>
</template>
</van-field>
<van-field label="身份证国徽面" required :rules="[{ required: true, message: '请上传身份证国徽面' }]" name="form4">
<template #input>
<van-uploader
v-model="formModel.form4"
name="form4"
:max-count="1"
:preview-size="['165px', '107px']"
upload-icon="plus"
:before-read="beforeRead"
:after-read="(file: any, detail: Recordable) => afterRead(file, detail)"
/>
</template>
</van-field>
<div class="mx-3 my-4">
<van-button color="linear-gradient(to bottom, #00c699, #00a385)" block round native-type="submit" text="确定" />
</div>
</van-form>
</van-popup>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { showConfirmDialog } from 'vant'
import type { FormInstance } from 'vant'
import { useCustomFieldValue } from '@vant/use'
import { useVModel } from '@vueuse/core'
import { uploadApi } from '@/api/common'
import { isIdcard } from '@/utils/validate'
import Compressor from 'compressorjs'
type FieldProps = {
modelValue: Recordable[]
}
const props = defineProps<FieldProps>()
const emit = defineEmits(['update:modelValue'])
const list = useVModel(props, 'modelValue', emit)
useCustomFieldValue(() => list.value)
const show = ref(false)
const formType = ref('add')
const formRef = ref<FormInstance>()
const defaultValues = {
form1: '',
form2: '',
form3: [],
form4: []
}
const formModel = ref<Recordable>({ ...defaultValues })
// 上传图片
const beforeRead = (file: any): any => {
return new Promise(resolve => {
new Compressor(file, {
quality: 0.6,
convertTypes: ['image/png', 'image/webp', 'image/jpeg'],
success(result: any) {
const convertFile = new File([result], result.name, { type: result.type, lastModified: Date.now() })
resolve(convertFile)
},
error(err) {
console.log(err)
}
})
})
}
const afterRead = (file: any, { name }: any) => {
console.log('%c 🦖name-112', 'font-size:12px; background:#ffc500;border-radius:5px;padding:4px;font-weight:600; color:#333;', name)
file.status = 'uploading'
file.message = '上传中...'
const data = { file: file.file }
uploadApi(data)
.then((res: any) => {
const { path } = res
formModel.value[name] = [{ url: path }]
file.status = 'done'
file.message = '上传成功'
})
.catch(() => {
file.status = 'failed'
file.message = '上传失败'
})
}
const onSubmit = () => {
list.value.push(formModel.value)
show.value = false
}
function onAdd() {
formType.value = 'add'
formModel.value = { ...defaultValues }
formRef.value?.resetValidation()
show.value = true
}
function onEdit(info: Recordable) {
formType.value = 'edit'
formModel.value = { ...info }
show.value = true
}
function onRemove(index: number) {
showConfirmDialog({
title: '提示',
message: '是否确认删除该项信息?'
})
.then(() => {
list.value.splice(index, 1)
})
.catch(() => {})
}
</script>
<style scoped></style>
This diff is collapsed.
<template>
<div class="page">
<div class="content van-safe-area-bottom">
<h1 class="mx-3">
<van-image height="32px" :src="logo" fit="contain" alt="好医生" />
</h1>
<p class="indent px-3 leading-6 text-slate-800 font-semibold">
恭喜好医生保险经纪与京东安联、国任保险、中华保险、永安保险、阳光保险、中国太平、锦泰保险、中国人民保险、富邦财险、嘉程智宇签署合作协议。
</p>
<div class="grid grid-cols-3 gap-3 px-3">
<van-image v-for="brand in brands" :key="brand" :src="brand" fit="contain" alt="好医生" />
</div>
<div class="mt-3">
<van-notice-bar left-icon="bullhorn-o" text="重要提醒: 四川欣佳能达医药有限公司将收集您的个人信息用于代您投保" />
</div>
<div class="title">
<span class="font-bold">医疗机构</span>
<span class="text-xs text-red-600">(带*号为必填项)</span>
</div>
<FormHysyf :address="address" />
<CustomMap @setAddress="setAddress" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import FormHysyf from './components/FormHysyf.vue'
import CustomMap from './components/CustomMap.vue'
import logo from '~/logo.png'
import b1 from '~/brand1.png'
import b2 from '~/brand2.png'
import b3 from '~/brand3.png'
import b4 from '~/brand4.png'
import b5 from '~/brand5.png'
import b6 from '~/brand6.png'
const brands = ref([b1, b2, b3, b4, b5, b6])
const address = ref({})
const setAddress = (addr: Recordable) => {
address.value = addr
}
</script>
<style lang="less" scoped>
.page {
width: 100%;
height: 100%;
background: url('~/bg.png') no-repeat;
background-size: 100% 100%;
overflow: hidden;
}
.content {
width: 100%;
height: 100%;
overflow: auto;
}
.title {
padding: 16px 12px;
padding-left: 24px;
position: relative;
font-size: 15px;
&::before {
content: '';
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
border-radius: 2px;
background-color: var(--theme-color);
}
}
</style>
<template>
<div class="page-result">
<van-icon class="mx-auto" name="checked" color="#07c160" size="54" />
<div class="mt-8 text-lg font-bold">您的信息已登记,谢谢!</div>
</div>
</template>
<script setup lang="ts"></script>
<style scoped>
.page-result {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 30vh;
}
</style>
<template>
<div class="px-[12px]">TAB_PAGE</div>
</template>
<script setup lang="ts" name="Tab"></script>
{
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
"compilerOptions": {
"composite": true,
"types": ["node"]
}
}
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "types/*.d.ts", "vite.config.ts"],
"exclude": ["node_modules", "dist", "**/*.js"],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"~/*": ["./src/assets/*"]
},
"ignoreDeprecations": "5.0"
},
"references": [
{
"path": "./tsconfig.config.json"
}
]
}
import type { ComponentRenderProxy, VNode, VNodeChild, ComponentPublicInstance, FunctionalComponent, PropType as VuePropType } from 'vue'
declare global {
const __APP_INFO__: {
pkg: {
name: string
version: string
dependencies: Recordable<string>
devDependencies: Recordable<string>
}
lastBuildTime: string
}
// vue
declare type PropType<T> = VuePropType<T>
declare type VueNode = VNodeChild | JSX.Element
export type Writable<T> = {
-readonly [P in keyof T]: T[P]
}
declare type Nullable<T> = T | null
declare type NonNullable<T> = T extends null | undefined ? never : T
declare type Recordable<T = any> = Record<string, T>
declare type ReadonlyRecordable<T = any> = {
readonly [key: string]: T
}
declare type Indexable<T = any> = {
[key: string]: T
}
declare type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>
}
declare type TimeoutHandle = ReturnType<typeof setTimeout>
declare type IntervalHandle = ReturnType<typeof setInterval>
declare interface ChangeEvent extends Event {
target: HTMLInputElement
}
declare interface WheelEvent {
path?: EventTarget[]
}
interface ImportMetaEnv extends ViteEnv {
__: unknown
}
declare function parseInt(s: string | number, radix?: number): number
declare function parseFloat(string: string | number): number
namespace JSX {
// tslint:disable no-empty-interface
type Element = VNode
// tslint:disable no-empty-interface
type ElementClass = ComponentRenderProxy
interface ElementAttributesProperty {
$props: any
}
interface IntrinsicElements {
[elem: string]: any
}
interface IntrinsicAttributes {
[elem: string]: any
}
}
}
declare module 'vue' {
export type JSXComponent<Props = any> = { new (): ComponentPublicInstance<Props> } | FunctionalComponent<Props>
}
declare interface Fn<T = any, R = T> {
(...arg: T[]): R
}
declare interface PromiseFn<T = any, R = T> {
(...arg: T[]): Promise<R>
}
declare type RefType<T> = T | null
declare type LabelValueOptions = {
label: string
value: any
[key: string]: string | number | boolean
}[]
declare type EmitType = (event: string, ...args: any[]) => void
declare type TargetContext = '_self' | '_blank'
declare interface ComponentElRef<T extends HTMLElement = HTMLDivElement> {
$el: T
}
declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = ComponentElRef<T> | null
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>
import { defineConfig, presetAttributify, presetUno, presetIcons } from 'unocss'
export default defineConfig({
presets: [presetUno(), presetAttributify(), presetIcons({ scale: 1.2, warn: true })],
shortcuts: [
['wh-full', 'w-full h-full'],
['f-c-c', 'flex justify-center items-center'],
['flex-col', 'flex flex-col'],
['text-ellipsis', 'truncate'],
[
'icon-btn',
'text-16 inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-primary !outline-none'
]
],
rules: [
[/^bc-(.+)$/, ([, color]) => ({ 'border-color': `#${color}` })],
['card-shadow', { 'box-shadow': '0 1px 2px -2px #00000029, 0 3px 6px #0000001f, 0 5px 12px 4px #00000017' }]
],
theme: {
colors: {
primary: 'var(--primary-color)',
dark_bg: 'var(--dark-bg)'
}
}
})
import path from 'path'
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import unocss from 'unocss/vite'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import mockDevServerPlugin from 'vite-plugin-mock-dev-server'
import vueSetupExtend from 'vite-plugin-vue-setup-extend'
import viteCompression from 'vite-plugin-compression'
import { createHtmlPlugin } from 'vite-plugin-html'
// 当前工作目录路径
const root: string = process.cwd()
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
// 环境变量
const env = loadEnv(mode, root, '')
return {
base: env.VITE_PUBLIC_PATH || '/',
plugins: [
vue(),
vueJsx(),
unocss(),
mockDevServerPlugin(),
Components({ resolvers: [VantResolver()] }), // vant 组件自动按需引入
// svg icon
createSvgIconsPlugin({
iconDirs: [path.resolve(root, 'src/icons/svg')], // 指定图标文件夹
symbolId: 'icon-[dir]-[name]' // 指定 symbolId 格式
}),
vueSetupExtend(), // 允许 setup 语法糖上添加组件名属性
viteCompression(), // 生产环境 gzip 压缩资源
createHtmlPlugin({ inject: { data: { ENABLE_ERUDA: env.VITE_ENABLE_ERUDA || 'false' } } }) // 注入模板数据
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'~': fileURLToPath(new URL('./src/assets', import.meta.url))
}
},
server: {
host: true,
// 仅在 proxy 中配置的代理前缀, mock-dev-server 才会拦截并 mock
// doc: https://github.com/pengzhanbo/vite-plugin-mock-dev-server
proxy: {
'/api': {
host: true,
target: 'https://h5.hysbx.com/api',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
secure: false
}
}
},
build: {
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
}
}
}
}
})
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