initStore

This commit is contained in:
FrancisHu 2023-07-25 14:12:59 +08:00
commit 8358f94286
78 changed files with 6350 additions and 0 deletions

1
.env.development Normal file
View File

@ -0,0 +1 @@
VITE_BASE_URL = '/AppPeaManager'

1
.env.production Normal file
View File

@ -0,0 +1 @@
VITE_BASE_URL = '/AppPeaManager'

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}

18
README.md Normal file
View File

@ -0,0 +1,18 @@
# Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support For `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.

30
components.d.ts vendored Normal file
View File

@ -0,0 +1,30 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
TabBar: typeof import('./src/components/TabBar.vue')['default']
VanButton: typeof import('vant/es')['Button']
VanCascader: typeof import('vant/es')['Cascader']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon']
VanNavBar: typeof import('vant/es')['NavBar']
VanPicker: typeof import('vant/es')['Picker']
VanPopup: typeof import('vant/es')['Popup']
VanSwipe: typeof import('vant/es')['Swipe']
VanSwipeCell: typeof import('vant/es')['SwipeCell']
VanSwipeItem: typeof import('vant/es')['SwipeItem']
VanTabbar: typeof import('vant/es')['Tabbar']
VanTabbarItem: typeof import('vant/es')['TabbarItem']
VanUploader: typeof import('vant/es')['Uploader']
}
}

BIN
dist.zip Normal file

Binary file not shown.

53
index.html Normal file
View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, minimum-scale=1, user-scalable=no">
<title>云送体检预约</title>
<style>
/* vant组件库样式 */
.van-uploader__upload{
border-radius: 50%;
}
.van-uploader__preview-image{
border-radius: 50%;
}
.van-nav-bar__content{
background-color: #f8f8f8;
}
.van-hairline--bottom:after{
border-bottom-width: 0 !important;
}
.van-field{
border-radius: 0.8rem;
height: 1.6rem;
display: flex;
align-items: center;
}
/* .calendar_item_disable{
background-color: #c0c4cc !important;
} */
.van-cell__title{
display: flex;
flex-direction: column;
}
.van-toast{
background: rgba(0, 0, 0, 0.7) !important;
}
.van-field__error-message{
font-size: 16px !important;
}
.van-cascader__options{
height: auto !important;
}
.van-swipe-cell__right{
right: 1px !important;
}
</style>
</head>
<body style="background-color: #f8f8f8;">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

1679
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
package.json Normal file
View File

@ -0,0 +1,35 @@
{
"name": "y",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --open",
"build": "vite build",
"preview": "vite preview --open"
},
"dependencies": {
"axios": "^1.4.0",
"lib-flexible": "^0.3.2",
"pinia": "^2.1.3",
"pinia-plugin-persistedstate": "^3.1.0",
"postcss-pxtorem": "^6.0.0",
"qs": "^6.11.2",
"sass": "^1.62.1",
"scss": "^0.2.4",
"vant": "^4.4.1",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue": "^3.2.47",
"vue-router": "^4.2.2",
"vue-template-compiler": "^2.7.14",
"vue3-hash-calendar": "^1.1.3"
},
"devDependencies": {
"@types/node": "^20.2.5",
"@vitejs/plugin-vue": "^4.1.0",
"typescript": "^5.0.2",
"unplugin-vue-components": "^0.25.0",
"vite": "^4.3.9",
"vue-tsc": "^1.4.2"
}
}

1
public/vite.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

11
src/App.vue Normal file
View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>
<template>
<RouterView />
</template>
<style scoped>
</style>

10
src/api/AccountLogin.ts Normal file
View File

@ -0,0 +1,10 @@
import axios from "../utils/request";
//登录接口
const login = (params = {}) => {
return axios.post('/login', params)
}
export {
login
}

28
src/api/CareerExam.ts Normal file
View File

@ -0,0 +1,28 @@
import axios from '../utils/request'
// 获取医院信息
const getHospitalInfo = (params = {}) => {
return axios.post('/app/gethospital', params)
}
// 获取套餐详情
const getPackageDetail = (params = {}) => {
return axios.post('/app/getexamination', params)
}
// 提交体检信息表单
const submitForm = (params = {}) => {
return axios.post('/app/phyappoint', params)
}
// 获取职工套餐
const getCrewPackage = (params = {}) => {
return axios.post('/app/getworkexamination', params)
}
export {
getHospitalInfo,
getPackageDetail,
submitForm,
getCrewPackage
}

22
src/api/ExamPreOrder.ts Normal file
View File

@ -0,0 +1,22 @@
import axios from "../utils/request";
// 获取医院信息接口
const getActualHospital = (params = {}) => {
return axios.post('/app/gethospital', params)
}
// 获取套餐详情
const getPackageDetail = (params = {}) => {
return axios.post('/app/getexamination', params)
}
// 提交体检预约表单
const submitForm = (params = {}) => {
return axios.post('/app/phyappoint', params)
}
export {
getActualHospital,
getPackageDetail,
submitForm
}

16
src/api/ForgetPassword.ts Normal file
View File

@ -0,0 +1,16 @@
import axios from '../utils/request'
// 发送验证码
const sendVeriCode = (params = {}) => {
return axios.post('/app/getUserByPhone', params)
}
// 修改密码
const editNewPwd = (params = {}) => {
return axios.post('/app/resetUserPwd', params)
}
export {
sendVeriCode,
editNewPwd
}

22
src/api/Home.ts Normal file
View File

@ -0,0 +1,22 @@
import axios from "../utils/request";
// 获取用户身份状态
const getUserStatus = (params = {}) => {
return axios.post('/app/getStatus', params)
}
// 获取信息
const fetchMsgs = (params = {}) => {
return axios.post('/app/phyappoint', params)
}
// 获取是否预约过的状态
const isPreOrdered = (params = {}) => {
return axios.post('/app/getphyappoint', params)
}
export {
getUserStatus,
fetchMsgs,
isPreOrdered
}

16
src/api/MsgLogin.ts Normal file
View File

@ -0,0 +1,16 @@
import axios from "../utils/request";
// 发送手机验证码
const sendPhoneVeri = (params = {}) => {
return axios.post('/app/getUserByPhone', params)
}
// 短信验证表单提交
const logWithMsg = (params = {}) => {
return axios.post('/app/loginNoPassword', params)
}
export {
sendPhoneVeri,
logWithMsg
}

16
src/api/MyPreOrder.ts Normal file
View File

@ -0,0 +1,16 @@
import axios from "../utils/request";
// 获取体检单信息
const getPreOrderInfo = (params = {}) => {
return axios.post('/app/getpersonappointInfo', params)
}
// 取消预约接口
const cancelPort = (params = {}) => {
return axios.post('/app/cancelpoint', params)
}
export {
getPreOrderInfo,
cancelPort
}

View File

@ -0,0 +1,9 @@
import axios from '../utils/request'
const seePackage = (params = {}) => {
return axios.post('/app/getcontentByid', params)
}
export {
seePackage
}

10
src/api/user.ts Normal file
View File

@ -0,0 +1,10 @@
import axios from "../utils/request";
// 获取用户信息
const getUserInfo = (params = {}) => {
return axios.post('/app/getapplogininfo', params)
}
export {
getUserInfo
}

135
src/assets/base.css Normal file
View File

@ -0,0 +1,135 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
position: relative;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition: color 0.5s, background-color 0.5s;
line-height: 1.6;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
* {
/**
* 简单粗暴, 一劳永逸的写法
*/
padding: 0;
margin: 0;
font: inherit;
vertical-align: baseline;
}
* {
/*
* 这个属性只用于iOS, 当你点击一个链接或者通过Javascript定义的可点击元素的时候
* 它就会出现一个半透明的灰色背景
*/
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
html {
-webkit-text-size-adjust: 100%; /* 禁止字体变化 */
}
body {
font-size: 14px;
font-weight: 400;
font-family: Helvetica,Arial,sans-serif;
line-height: 1;
-webkit-overflow-scrolling: touch; /* 设置滚动容器的滚动效果 */
-webkit-font-smoothing: antialiased; /* 字体抗锯齿渲染 */
}
a, a:active, a:hover {
/**
* 某些浏览器会给 a 设置默认颜色
*/
color: unset;
text-decoration: none;
}
ol, ul, li {
/**
* 去掉列表样式
*/
list-style: none;
}
img {
border: 0;
vertical-align: middle
}
table {
/**
* 去掉 td td 之间的空隙
*/
border-collapse: collapse;
border-spacing: 0;
}
input, textarea, select {
outline: none; /*去掉fouce时边框高亮效果*/
background: unset; /*去掉默认背景*/
appearance: none;
-webkit-appearance: none; /* 去除ios输入框阴影 */
}
/* 禁止选中文本内容 */
*:not(input, select, textArea) {
-webkit-user-select: none;
}

1
src/assets/vue.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

16
src/components/TabBar.vue Normal file
View File

@ -0,0 +1,16 @@
<template>
<div>
<van-tabbar style="width: 100%;" route active-color="#24acf2">
<van-tabbar-item icon="wap-home-o" to="/home">首页</van-tabbar-item>
<van-tabbar-item icon="user-o" to="/user">个人</van-tabbar-item>
</van-tabbar>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

66
src/main.ts Normal file
View File

@ -0,0 +1,66 @@
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
import router from './router'
import 'lib-flexible'
import './assets/base.css'
import 'vant/lib/index.css'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import VueHashCalendar from 'vue3-hash-calendar'
import 'vue3-hash-calendar/es/index.css'
import {
Tabbar,
TabbarItem,
Swipe,
SwipeItem,
NavBar,
Form,
Field,
Cell,
CellGroup,
Popup,
Picker,
Calendar,
Button,
Toast,
Uploader,
Icon,
Cascader,
SwipeCell,
Badge,
NoticeBar,
Collapse,
CollapseItem
} from 'vant'
const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(router)
.use(pinia)
.use(Tabbar)
.use(TabbarItem)
.use(Swipe)
.use(SwipeItem)
.use(NavBar)
.use(Form)
.use(Field)
.use(Cell)
.use(CellGroup)
.use(Popup)
.use(Picker)
.use(Calendar)
.use(Button)
.use(Toast)
.use(Uploader)
.use(Icon)
.use(VueHashCalendar)
.use(Cascader)
.use(SwipeCell)
.use(Badge)
.use(NoticeBar)
.use(Collapse)
.use(CollapseItem)
app.mount('#app')

2
src/plugins/jquery-3.6.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

125
src/router/index.ts Normal file
View File

@ -0,0 +1,125 @@
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '../views/Home/Home.vue'
import { isLogin } from '../utils/index'
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
meta: {
needAuth: true
},
component: Home
},
{
path: '/user',
meta: {
needAuth: true
},
name: 'user',
component: () => import('../views/User/User.vue')
},
{
path: '/examPreOrder',
meta: {
needAuth: true
},
name: 'examPreOrder',
component: () => import('../views/ExamPreOrder/ExamPreOrder.vue')
},
{
path: '/examReport',
meta: {
needAuth: true
},
name: 'examReport',
component: () => import('../views/ExamReport/ExamReport.vue')
},
{
path: '/myPreOrder',
meta: {
needAuth: true
},
name: 'myPreOrder',
component: () => import('../views/MyPreOrder/MyPreOrder.vue')
},
{
path: '/careerExam',
meta: {
needAuth: true
},
name: 'careerExam',
component: () => import('../views/CareerExam/CareerExam.vue')
},
{
path: '/preOrderSucceed',
meta: {
needAuth: true
},
name: 'preOrderSucceed',
component: () => import('../views/PreOrderSucceed/PreOrderSucceed.vue')
},
{
path: '/personalInfo',
meta: {
needAuth: true
},
name: 'personalInfo',
component: () => import('../views/PersonalInfo/PersonalInfo.vue')
},
{
path: '/msgNotice',
meta: {
needAuth: true
},
name: 'msgNotice',
component: () => import('../views/MsgNotice/MsgNotice.vue')
},
{
path: '/accountLogin',
name: 'accountLogin',
component: () => import('../views/AccountLogin/AccountLogin.vue')
},
{
path: '/forgetPassword',
name: 'forgetPassword',
component: () => import('../views/ForgetPassword/ForgetPassword.vue')
},
{
path: '/msgLogin',
name: 'msgLogin',
component: () => import('../views/MsgLogin/MsgLogin.vue')
},
{
path: '/preOrderReceipt',
meta: {
needAuth: true
},
name: 'preOrderReceipt',
component: () => import('../views/PreOrderReceipt/PreOrderReceipt.vue')
}
]
})
/*
needAuth的路由加以鉴权
访token的页面需要跳转到账号登录页面
*/
router.beforeEach((to: any) => {
if (to.meta.needAuth) {
if (!isLogin()) {
return {
path: '/accountLogin'
}
}
}
})
export default router

BIN
src/static/Avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
src/static/alert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/static/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
src/static/careerExam.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
src/static/exit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
src/static/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
src/static/homeSelected.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
src/static/isCanceled.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
src/static/isExamed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
src/static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
src/static/my.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
src/static/myPreOrder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/static/mySelected.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/static/notice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
src/static/perInfo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/static/post1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

BIN
src/static/post2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

BIN
src/static/post3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

BIN
src/static/preOrder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
src/static/readyExam.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
src/static/report.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/static/rigArrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

38
src/stores/userInfo.ts Normal file
View File

@ -0,0 +1,38 @@
import { defineStore } from 'pinia'
import { getUserInfo } from '../api/user'
const userInformation = defineStore('user', {
state: () => {
return {
phyName: '',
idcard: '',
age: '',
sex: '',
telepNumber: '',
departName: ''
}
},
actions: {
// 将请求过来的个人信息赋值
initInfo (info: any) {
this.phyName = info.phyName
this.idcard = info.idcard
this.age = info.age
this.sex = info.sex
this.telepNumber = info.telepNumber
this.departName = info.departName
},
// 请求个人信息
fetchUserInfo () {
getUserInfo({
token: localStorage.getItem('token')
}).then((res: any) => {
console.log(res)
this.initInfo(res.data.obj[0])
})
}
},
persist: true
})
export default userInformation

80
src/style.css Normal file
View File

@ -0,0 +1,80 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

7
src/utils/index.ts Normal file
View File

@ -0,0 +1,7 @@
const isLogin = () => !!localStorage.getItem('token')
const getToken = () => localStorage.getItem('token')
export {
isLogin,
getToken
}

24
src/utils/request.ts Normal file
View File

@ -0,0 +1,24 @@
import axios from 'axios'
import qs from 'qs'
// import router from '../router'
axios.defaults.baseURL = import.meta.env.VITE_BASE_URL;
axios.defaults.timeout = 8000;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.interceptors.request.use(function (config) {
if(config.method === 'post' && config.data) {
config.data = qs.stringify(config.data)
}
return config;
}, function (error) {
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
return Promise.reject(error);
});
export default axios

View File

@ -0,0 +1,236 @@
<template>
<div>
<div class="background">
<div class="block_3 flex-col">
<div class="section_1 flex-col"></div>
<div class="section_2 flex-col"></div>
<div class="section_3 flex-col"></div>
</div>
</div>
<h2 class="log-tit">云送体检预约</h2>
<van-form @submit="logSub" class="log-form">
<van-field
v-model="username"
name="account"
:placeholder="accountPlaceHolder"
@focus="focusAccount"
@blur="blurAccount"
:rules="[{ required: true, message: '请填写账号!' }]"
autocomplete="off"
clearable
style="border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px; box-sizing: border-box;"
/>
<van-field
v-model="password"
name="password"
:type="pwdType"
:placeholder="pwdPlaceHolder"
@focus="focusPwd"
@blur="blurPwd"
:rules="[{ required: true, message: '请填写密码!' }]"
autocomplete="off"
clearable
style="margin-top: 0.5rem; border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px;"
>
<template #button>
<van-button
style="font-size: 16px; background-color: transparent; color: #1989fa; border: none;"
size="small"
type="primary"
>
<span v-if="pwdStatus === 0" @click="showPwd">查看</span>
<span v-if="pwdStatus === 1" @click="hidePwd">隐藏</span>
</van-button>
</template>
</van-field>
<div class="user-taps">
<span @click="jumpForget()">忘记密码</span>
<span @click="jumpMsg()">短信安全登录</span>
</div>
<div class="btn-area">
<van-button
type="primary"
native-type="submit"
style="width: 70%; border-radius: 0.5rem; font-size: 18px;"
@click="fetchLogin()"
>
登录
</van-button>
</div>
</van-form>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router'
import { login } from '../../api/AccountLogin'
import { showFailToast, showSuccessToast } from 'vant'
import './scss/index.scss'
const username = ref<any>('')
const password = ref<any>('')
const router = useRouter()
const accountPlaceHolder = ref<string>('账号')
const pwdPlaceHolder = ref<string>('密码')
const pwdType = ref<any>('password')
const pwdStatus = ref<number>(0)
//
const showPwd = () => {
pwdType.value = 'input'
pwdStatus.value = 1
}
//
const hidePwd = () => {
pwdType.value = 'password'
pwdStatus.value = 0
}
//
const focusAccount = () => {
accountPlaceHolder.value = ''
}
const focusPwd = () => {
pwdPlaceHolder.value = ''
}
//
const blurAccount = () => {
accountPlaceHolder.value = '账号'
}
const blurPwd = () => {
pwdPlaceHolder.value = '密码'
}
//
const logSub = (val: any) => {
console.log('submit', val)
}
//
const jumpForget = () => {
router.push({
path: '/forgetPassword'
})
}
//
const jumpMsg = () => {
router.push({
path: '/msgLogin'
})
}
//
const fetchLogin = () => {
login({
username: username.value,
password: password.value
}).then((res: any) => {
if (res.status === 200) {
console.log(res.status)
showSuccessToast('登录成功!')
localStorage.setItem('token', res.data.token)
localStorage.setItem('phoneNumber', username.value)
localStorage.setItem('avatarUrl', 'https://img.zcool.cn/community/0104c958b69c23a801219c77ba5da2.png?x-oss-process=image/auto-orient,1/resize,m_lfit,w_1280,limit_1/sharpen,100')
// 3h
const overDate = new Date().getTime() - 8 * 60 * 60 * 1000 + 3 * 60 * 60 * 1000
document.cookie = `loginStatus=0;expires=${new Date(overDate)}`
router.replace({
path: '/home',
query: {
pwd: password.value
}
})
} else {
showFailToast('用户名或密码错误!')
}
}).catch(() => {
showFailToast('用户名或密码错误!')
})
}
onMounted(() => {
// fetchLogin()
/* const ms = new Date().getTime() - 8 * 60 * 60 * 1000 + 10 * 1000
document.cookie = `token=114514;expires=${new Date(ms)}` */
})
</script>
<style scoped lang="scss">
.background {
width: 10rem;
height: 8rem;
background: url('../../static/bg.jpg')
100% no-repeat;
background-size: 100% 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
.section_1 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
width: 4rem;
height: 4rem;
position: absolute;
}
.section_2 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
position: absolute;
left: 0.1rem;
top: 1.2rem;
width: 6rem;
height: 6rem;
}
.section_3 {
background-color: rgba(255, 255, 255, 0.0624);
border-radius: 50%;
position: absolute;
left: 6rem;
top: 0.5rem;
width: 4rem;
height: 4rem;
}
}
.log-tit{
width: 100%;
padding-top: 4rem;
text-align: center;
font-size: 30px;
font-weight: bold;
}
.log-form{
width: 80%;
height: 8rem;
margin: 3.5rem auto;
box-sizing: border-box;
padding: 0.5rem;
.user-taps{
width: 100%;
margin-top: 0.3rem;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding: 0 0.2rem;
span{
font-size: 14px;
color: #49b3f2;
}
}
.btn-area{
width: 100%;
margin-top: 0.6rem;
display: flex;
justify-content: center;
}
}
</style>

View File

@ -0,0 +1,3 @@
:root:root{
--van-field-placeholder-text-color: #000;
}

View File

@ -0,0 +1,706 @@
<template>
<van-nav-bar
title="职业健康体检预约"
left-arrow
@click-left="onClickLeft"
/>
<van-form @submit="subForm" @failed="subFormFail" class="form-area">
<div class="upper-info">
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">选择医院</h2>
<van-field
v-model="result1"
is-link
readonly
name="hospitalId"
placeholder="点击选择医院"
@click="showHospitalPicker = true"
style="margin-bottom: 0.3rem"
autocomplete="off"
:rules="[
{
required: true,
message: '请选择一个医院!'
}
]"
/>
<van-popup v-model:show="showHospitalPicker" position="bottom">
<van-picker
:columns="hospitalColumns"
@confirm="onHospitalConfirm"
@cancel="showHospitalPicker = false"
/>
</van-popup>
<!-- <h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">检查类型</h2> -->
<!-- <van-field
v-model="result2"
is-link
name="checkId"
readonly
placeholder="点击选择套餐"
@click="showTypePicker = true"
style="margin-bottom: 0.3rem; border-radius: 0.1rem;"
autocomplete="off"
:rules="[
{
required: true,
message: '请选择一个检查类型!'
}
]"
/>
<van-popup v-model:show="showTypePicker" position="bottom">
<van-picker
:columns="typeColumns"
@confirm="onTypeConfirm"
@cancel="showTypePicker = false"
/>
</van-popup> -->
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem; " class="personal-area">
职工套餐
</h2>
<van-field
v-model="result2"
is-link
readonly
:label="personalPackageName"
label-width="3rem"
placeholder="请选择职工套餐"
@click="showCrewPicker = true"
style="margin-bottom: 0.3rem;"
:rules="[
{
required: true,
message: '请选择一个套餐!'
}
]"
/>
<van-popup
v-model:show="showCrewPicker"
position="bottom"
>
<!-- <van-picker
:columns="crewColumns"
@confirm="onCrewConfirm"
@cancel="showCrewPicker = false"
/> -->
<van-cascader
v-model="result3"
title="请选择套餐"
:options="crewColumns"
@close="cascaderClose"
@change="onChange"
/>
<div class="inner-content" v-if="showTotalTc">
<div class="btn-upper" v-for="(item, index) in selectedPackage" :key="index">
<h1 class="content-tit">
{{ item.text }}
<span style="display: flex; align-items: center;" v-if="pushBtn" @click="flodTc"> 展开 <van-icon name="arrow-down" size="26"/></span>
<span style="display: flex; align-items: center;" v-if="!pushBtn" @click="blowTc"> 收起 <van-icon name="arrow-up" size="26"/></span>
</h1>
<div v-if="showTc">
<h2>体检项目
<br>
{{ item.combinName }}
</h2>
<h2>体检内容
<br>
{{ item.combinContent }}
</h2>
<h2>体检总价<span style="color: red;">{{ item.combinPrice }}</span></h2>
</div>
<div class="cfm-btn">
<van-button type="primary" @click="closePopup">确认套餐</van-button>
</div>
</div>
</div>
<!-- <div style="text-align: center; font-size: 18px;" v-if="packageDetailStatus === 0">请选择检查类型以查看套餐</div>
<div v-if="packageDetailStatus === 1">
<h2 style="font-size: 20px; font-weight: bold; margin-bottom: 0.5rem;">{{ personalPackageName }}</h2>
<div class="package-area" v-for="(item, index) in sonPackageDetails" :key="index">
<div class="package-name">{{ item.combinName }}</div>
<div class="package-price">{{ item.combinPrice }}</div>
</div>
<div class="total-price">
<span style="padding-right: 0.3rem;">合计</span>
{{ totalPrice }}
</div>
</div> -->
</van-popup>
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">体检时间</h2>
<h2 style="font-size: 14px; margin-bottom: 0.3rem; color: #9c9898">注意一个自然周内仅限预约一次</h2>
<vue-hash-calendar
@change="calendarChange"
format="YY-MM-DD"
:min-date="minDate"
:max-date="new Date('2023/10/31')"
ref="calendar"
picker-type="date"
:disabled-date="disabledDate"
:disabled-week-view="true"
/>
</div>
<div class="hospital-info-area" v-for="(item, index) in selectedHospital" :key="index">
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.4rem;">医院信息</h2>
<div class="info">
<h4 style="margin-bottom: 0.4rem; color: #2c97ef; font-size: 20px; font-weight: bold;">{{ item.text }}</h4>
<h5>地址{{ item.address }}</h5>
<h5>营业时间{{ item.businessStart }} -- {{ item.businessEnd }}</h5>
<h5>负责人{{ item.responsible }}</h5>
<h5>联系方式{{ item.telPhone }}</h5>
</div>
</div>
<div class="btn">
<van-button
type="primary"
native-type="submit"
:disabled="disBtn"
style="width: 50%; border-radius: 0.1rem; font-size: 18px; font-weight: bold;"
>
确定预约
</van-button>
</div>
</van-form>
</template>
<script setup lang="ts">
import { onMounted, ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { showToast } from 'vant'
import { getHospitalInfo, submitForm, getCrewPackage } from '../../api/CareerExam'
//
const router = useRouter()
const result1 = ref<any>('')
const result2 = ref<any>('')
const result3 = ref<any>('')
// const date = ref<any>('')
const showHospitalPicker = ref<boolean>(false)
const showCrewPicker = ref<boolean>(false)
// const showTypePicker = ref<boolean>(false)
// const calendarShow = ref<boolean>(false)
// 使reactive
const selectedHospital = reactive<any>({})
const selectedPackage = reactive<any>({})
const hospitalName = ref<any>('')
const examType = ref<any>('')
const packageId = ref<any>('')
const personalPackageName = ref<any>('')
const mealId = ref<any>('')
// const sonPackageDetails = ref<any[]>([])
// const totalPrice = ref<number>(0)
//
// const packageDetailStatus = ref<number>(0)
//
// const cascaderShow = ref<boolean>(false)
// ---+30
const minDate = ref<any>(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()))
// const maxDate = ref<any>(new Date(new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).getFullYear(), new Date(Date.now() + 30 * 24* 60 * 60 * 1000).getMonth(), new Date(Date.now() + 30 * 24* 60 * 60 * 1000).getDate()))
const selectedDate = ref<any>('')
const showTotalTc = ref<boolean>(false)
const showTc = ref<boolean>(false)
const pushBtn = ref<boolean>(true)
const disBtn = ref<boolean>(false)
const realToday = ref<any>('')
const flodTc = () => {
showTc.value = true
pushBtn.value = false
}
const blowTc = () => {
showTc.value = false
pushBtn.value = true
}
const onClickLeft = () => {
history.back()
}
//
const getJT = (date: any) => {
const year = date.getFullYear();
const month = (date.getMonth()+1);
const day = date.getDate();
const currDate = ref<any>(``)
//
if (day < 10 && month < 10) {
currDate.value = `${year}-0${month}-0${day}`;
} else if (month >= 10 && day < 10) {
currDate.value = `${year}-${month}-0${day}`;
} else if (day >= 10 && month < 10) {
currDate.value = `${year}-0${month}-${day}`;
} else {
currDate.value = `${year}-${month}-${day}`;
}
return currDate.value
}
//
// typestartend
// dates0-11
const getNextWeekFirst = (type: any, dates = 0) => {
let now = new Date();
let nowTime = now.getTime();
let day = now.getDay();
let longTime = 24 * 60 * 60 * 1000;
let n = longTime * 7 * (dates || 0);
let dd
if (type == "start") {
dd = nowTime - (day - 1) * longTime + n;
};
if (type == "end") {
dd = nowTime + (7 - day) * longTime + n;
};
let trueDD = new Date(dd);
let y = trueDD.getFullYear();
let m = trueDD.getMonth() + 1;
let d = trueDD.getDate();
let trueM = m < 10 ? "0" + m : m;
let trueD = d < 10 ? "0" + d : d;
let trueDay = y + "-" + trueM + "-" + trueD;
return trueDay;
};
const cascaderClose = () => {
showCrewPicker.value = false
result2.value = ''
}
//
const subForm = (res: any) => {
disBtn.value = true
res.hospitalId = hospitalName.value
res.setMealId = packageId.value
res.checkId = examType.value
res.phyAppontTime = String(selectedDate.value)
res.setMealType = 3
res.combName = result2.value
console.log('提交表单', res)
if (selectedDate.value == realToday.value) {
showToast({
message: '不可以预约今天!',
icon: 'fail',
duration: 1500,
onClose: () => {
disBtn.value = false
}
})
} else {
submitForm({
hospitalId: res.hospitalId,
setMealId: mealId.value,
phyAppontTime: res.phyAppontTime,
setMealType: res.setMealType,
combName: res.combName,
token: localStorage.getItem('token')
}).then((res: any) => {
console.log(res)
if (res.data.res == 0) {
showToast({
message: '今日可预约人数已满,请重新选择日期预约!',
icon: 'fail',
duration: 2500,
onClose: () => {
disBtn.value = false
}
})
} else {
showToast({
message: '预约成功!',
icon: 'success',
duration: 1500,
onClose: () => {
router.replace({
path: '/preOrderSucceed'
})
}
})
}
}).catch(() => {
showToast({
message: '预约超时,请返回重新预约!',
icon: 'fail',
duration: 2000,
onClose: () => {
history.go(-1)
}
})
})
}
}
//
const subFormFail = (err: any) => {
console.log(err)
}
//
const hospitalColumns = ref<any[]>([])
/* const typeColumns = ref<any[]>([
{ text: '心血管', value: 1 },
{ text: '肿瘤', value: 2 },
{ text: '综合', value: 3 }
]) */
const crewColumns = ref<any[]>([])
//
const fetchHospitalInfo = () => {
getHospitalInfo({
token: localStorage.getItem('token')
}).then((res: any) => {
if (res.data.obj === 'isnull') {
showToast({
message: '请联系管理员添加医院!',
icon: 'fail',
duration: 1500
})
} else {
const newHospitalInfo = res.data.obj.map((item: any) => {
return {
text: item['hospitalName'],
value: item['id'],
address: item['address'],
businessStart: item['businessStart'],
businessEnd: item['businessEnd'],
responsible: item['responsible'],
telPhone: item['telPhone']
}
})
hospitalColumns.value = newHospitalInfo
}
})
}
//
const fetchCrewPackage = () => {
getCrewPackage({
token: localStorage.getItem('token')
}).then((res: any) => {
const data = res.data.obj
console.log(data)
const newArr = Object.keys(data)
const crewPackageNameArr = ref<any[]>([])
const crewPackageIdArr = ref<any[]>([])
const crewPackageContentArr = ref<any>('')
const crewPackageCombinNameArr = ref<any>('')
const crewPackagePriceArr = ref<any[]>([])
const innerPrice = ref<number>(0)
const totalData = ref<any[]>([])
const nameTotal = ref<any[]>([])
const contentTotal = ref<any[]>([])
for (let i = 0; i < newArr.length; i++) {
innerPrice.value = 0
crewPackageContentArr.value = ''
crewPackageCombinNameArr.value = ''
for (let j = 0; j < data[i].length; j++) {
innerPrice.value += Number(data[i][j].combinPrice)
crewPackageContentArr.value += (data[i][j].combinContent + ' , ')
crewPackageCombinNameArr.value += (data[i][j].combinName + ' , ')
}
crewPackageNameArr.value.push(data[i][i].combName)
crewPackageIdArr.value.push(data[i][i].combId)
crewPackagePriceArr.value.push(innerPrice.value)
//
nameTotal.value.push(crewPackageCombinNameArr.value.slice(0, -2))
contentTotal.value.push(crewPackageContentArr.value.slice(0, -2))
}
crewPackageNameArr.value.forEach((one: any, index: any) => {
const item = ref<any>({})
item.text = one
item.value = crewPackageIdArr.value[index]
item.combinContent = contentTotal.value[index]
item.combinName = nameTotal.value[index]
item.combinPrice = crewPackagePriceArr.value[index]
totalData.value.push(item)
const settleInfo = totalData.value.map((item: any) => {
return {
text: item['text'],
value: item['value'],
combinContent: item['combinContent'],
combinName: item['combinName'],
combinPrice: item['combinPrice']
}
})
crewColumns.value = settleInfo
})
}).catch((err: any) => {
console.log(err)
})
}
//
const closePopup = () => {
if (result2.value === '') {
showToast({
message: '未选择职工套餐!',
icon: 'fail',
duration: 1500,
onClose: () => {
result2.value = ''
}
})
} else {
showCrewPicker.value = false
}
}
// popup
const onHospitalConfirm = (res: any) => {
selectedHospital.value = {}
result1.value = res.selectedOptions[0]?.text;
showHospitalPicker.value = false;
selectedHospital.value = res.selectedOptions[0]
hospitalName.value = res.selectedOptions[0]?.value
};
//
const onChange = (res: any) => {
showTotalTc.value = true
selectedPackage.value = {}
result2.value = res.selectedOptions[0].text
mealId.value = res.selectedOptions[0].value
selectedPackage.value = res.selectedOptions[0]
};
/* const onCrewConfirm = (res: any) => {
console.log(res)
result2.value = res.selectedOptions[0]?.text;
showCrewPicker.value = false;
}; */
/* const onTypeConfirm = (res: any) => {
result2.value = res.selectedOptions[0]?.text;
examType.value = res.selectedOptions[0]?.value
showTypePicker.value = false
// dom
getPackageDetail({
checkId: JSON.stringify(res.selectedOptions[0].value),
token: localStorage.getItem('token'),
combType: 3
}).then((result: any) => {
if (result.data.obj === null) {
showToast({
message: '体检套餐为空,请联系后台管理员发布体检套餐!',
icon: 'warning-o'
})
personalPackageName.value = ''
} else {
console.log(result)
personalPackageName.value = result.data.obj.tibean[0].combName
packageId.value = result.data.obj.tibean[0].id
sonPackageDetails.value = result.data.obj.tibeanson
console.log(packageId.value)
totalPrice.value = 0
//
for (let i = 0; i < sonPackageDetails.value.length; i++) {
totalPrice.value += Number(sonPackageDetails.value[i].combinPrice)
}
packageDetailStatus.value = 1
}
}).catch((err: any) => {
console.log(err)
})
}; */
//
const calendarChange = (res: any) => {
console.log(res, '日期改变')
selectedDate.value = res
}
//
const disabledDate = (date: any) => {
const year = date.getFullYear();
const month = (date.getMonth()+1);
const day = date.getDate();
const currDate = ref<any>(``)
//
if (day < 10 && month < 10) {
currDate.value = `${year}-0${month}-0${day}`;
} else if (month >= 10 && day < 10) {
currDate.value = `${year}-${month}-0${day}`;
} else if (day >= 10 && month < 10) {
currDate.value = `${year}-0${month}-${day}`;
} else {
currDate.value = `${year}-${month}-${day}`;
}
//
const disabledDateArr = [];
//
let oneDayTime = 1000 * 60 * 60 * 24
let today = new Date() // selectedDate.value
// 7
let todayDay = today.getDay() || 7
let startDate = new Date(
today.getTime() - oneDayTime * (todayDay - 1)
)
let dateList = new Array()
/* let dayCount = new Date().getDay()
let todayTemp = new Date(startDate.getTime() + (dayCount - 1) * oneDayTime)
let tempYear = todayTemp.getFullYear()
let tempMonth = todayTemp.getMonth() + 1
let tempDay = todayTemp.getDate()
let trueToday = ref<any>('')
if (tempDay < 10 && tempMonth < 10) {
trueToday = `${tempYear}-0${tempMonth}-0${tempDay}`
} else if (tempMonth >= 10 && tempDay < 10) {
trueToday = `${tempYear}-${tempMonth}-0${tempDay}`
} else if (tempDay >= 10 && tempMonth < 10) {
trueToday = `${tempYear}-0${tempMonth}-${tempDay}`
} else {
trueToday = `${tempYear}-${tempMonth}-${tempDay}`
}
console.log(trueToday, 'sss') */
/* let trueToday = new Date()
let trueTodayYear = trueToday.getFullYear()
let trueTodayMonth = trueToday.getMonth() + 1
let trueTodayDay = trueToday.getDate()
let formatToady = ''
if (trueTodayDay < 10 && trueTodayMonth < 10) {
formatToady = `${trueTodayYear}-0${trueTodayMonth}-0${trueTodayDay}`
} else if (trueTodayMonth >= 10 && trueTodayDay < 10) {
formatToady = `${trueTodayYear}-${trueTodayMonth}-0${trueTodayDay}`
} else if (trueTodayDay >= 10 && trueTodayMonth < 10) {
formatToady = `${trueTodayYear}-0${trueTodayMonth}-${trueTodayDay}`
} else {
formatToady = `${trueTodayYear}-${trueTodayMonth}-${trueTodayDay}`
} */
//
for(let i = 0; i < 7; i++){
let temp = new Date(startDate.getTime() + i * oneDayTime)
let year = temp.getFullYear()
let month = temp.getMonth() + 1
let day = temp.getDate()
if (day < 10 && month < 10) {
dateList[i] = `${year}-0${month}-0${day}`
} else if (month >= 10 && day < 10) {
dateList[i] = `${year}-${month}-0${day}`
} else if (day >= 10 && month < 10) {
dateList[i] = `${year}-0${month}-${day}`
} else {
dateList[i] = `${year}-${month}-${day}`
}
disabledDateArr.push(dateList[i])
}
// disabledDateArr.splice(disabledDateArr.indexOf(formatToady), 1)
if (disabledDateArr.includes(currDate.value)) {
return true;
}
return false;
}
onMounted(() => {
fetchHospitalInfo()
fetchCrewPackage()
realToday.value = getJT(new Date())
console.log(getNextWeekFirst('start', 1))
})
</script>
<style scoped lang="scss">
.form-area{
width: 100%;
margin: 0.2rem auto;
.upper-info{
width: 96%;
margin: 0 auto;
background-color: #f8f8f8;
box-sizing: border-box;
padding: 0.3rem;
border-radius: 0.1rem;
.inner-content{
width: 100%;
margin-top: 0.3rem;
box-sizing: border-box;
padding: 0.3rem;
position: relative;
.btn-upper{
margin-bottom: 1.4rem;
font-size: 18px;
display: flex;
flex-direction: column;
.content-tit{
display: flex;
justify-content: space-between;
align-items: center;
}
h1{
font-size: 20px;
color: #2c97ef;
margin-bottom: 0.4rem;
font-weight: bold;
}
h2{
margin-bottom: 0.4rem;
line-height: 26px;
}
.cfm-btn{
width: 100%;
position: fixed;
left: 10px;
bottom: 10px;
margin-top: 0.5rem;
}
}
}
}
}
.hospital-info-area{
width: 94%;
margin: 0.5rem auto;
background-color: #fff;
border-radius: 0.1rem;
box-sizing: border-box;
padding: 0.3rem;
.info{
width: 100%;
height: 80%;
display: flex;
flex-direction: column;
margin: 0.1rem auto;
h5{
font-size: 16px;
margin-bottom: 0.2rem;
line-height: 20px;
}
h5:nth-child(5){
margin-bottom: 0;
}
}
}
.btn{
width: 100%;
margin: 0.5rem auto;
display: flex;
justify-content: center;
}
.package-area{
display: flex;
justify-content: space-between;
.package-name, .package-price{
font-size: 16px;
line-height: 26px;
}
}
.total-price{
display: flex;
justify-content: right;
margin-top: 1.5rem;
font-size: 18px;
}
</style>

View File

@ -0,0 +1,731 @@
<template>
<van-nav-bar
title="体检预约"
left-arrow
@click-left="onClickLeft"
/>
<van-form @submit="subForm" @failed="subFormFail" class="form-area">
<div class="upper-info">
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">选择医院</h2>
<van-field
v-model="result1"
is-link
readonly
name="hospitalId"
placeholder="点击选择医院"
@click="showHospitalPicker = true"
style="margin-bottom: 0.3rem"
autocomplete="off"
:rules="[
{
required: true,
message: '请选择一个医院!'
}
]"
/>
<van-popup
v-model:show="showHospitalPicker"
position="bottom"
>
<van-picker
:columns="hospitalColumns"
@confirm="onHospitalConfirm"
@cancel="showHospitalPicker = false"
/>
</van-popup>
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">检查类型</h2>
<van-field
v-model="result2"
is-link
readonly
name="checkId"
placeholder="点击选择检查类型"
@click="showTypePicker = true"
style="margin-bottom: 0.3rem"
autocomplete="off"
:rules="[
{
required: true,
message: '请选择一个检查类型!'
}
]"
/>
<van-popup
v-model:show="showTypePicker"
position="bottom"
>
<!-- <van-picker
:columns="typeColumns"
@confirm="onTypeConfirm"
@cancel="showTypePicker = false"
ref="typePicker"
/> -->
<van-cascader
v-model="result3"
title="请选择套餐"
:options="typeColumns"
@close="cascaderClose"
@change="onChange"
/>
<div class="inner-package" v-if="showTotalTc">
<h2 class="inner-tit">
{{ personalPackageName }}
<span style="display: flex; align-items: center;" v-if="pushBtn" @click="flodTc"> 展开 <van-icon name="arrow-down" size="26"/></span>
<span style="display: flex; align-items: center;" v-if="!pushBtn" @click="blowTc"> 收起 <van-icon name="arrow-up" size="26"/></span>
</h2>
<div style="height: 300px; overflow: auto;" v-if="showTc">
<div class="package-area" v-for="(item, index) in sonPackageDetails" :key="index">
<div class="package-name">{{ item.combinName }}</div>
<div class="package-content">项目内容{{ item.combinContent }}</div>
<div class="package-price">项目价格<span>{{ item.combinPrice }}</span></div>
</div>
<div class="total-price">
<span style="padding-right: 0.3rem;">合计</span>
<span style="color: red;">{{ totalPrice }}</span>
</div>
</div>
<div class="cfm-btn">
<van-button class="confirm-package" type="primary" @click="closePopup">确认套餐</van-button>
</div>
</div>
</van-popup>
<!-- <h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem; " class="personal-area">
个性化套餐
</h2>
<van-field
v-model="cascaderValue"
is-link
readonly
:label="personalPackageName"
label-width="3.5rem"
placeholder="点击查看个性化套餐内容"
@click="cascaderShow = true"
style="margin-bottom: 0.3rem;"
/>
<van-popup
v-model:show="cascaderShow"
round
position="bottom"
:style="{ padding: '1rem' }"
closeable
>
<div style="text-align: center; font-size: 18px;" v-if="packageDetailStatus === 0">请选择检查类型以查看套餐</div>
<div v-if="packageDetailStatus === 1">
<h2 style="font-size: 24px; font-weight: bold; margin-bottom: 0.7rem;">{{ personalPackageName }}</h2>
<h3 style="font-size: 20px; font-weight: bold; margin-bottom: 0.2rem; margin-top: 0.7rem;">个性化套餐内容</h3>
<div class="package-area" v-for="(item, index) in sonPackageDetails" :key="index">
<div class="package-name">{{ item.combinName }}</div>
<div class="package-price">{{ item.combinPrice }}</div>
</div>
<div class="total-price">
<span style="padding-right: 0.3rem;">合计</span>
<span style="color: red;">{{ totalPrice }}</span>
</div>
</div>
</van-popup> -->
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.3rem;">体检时间</h2>
<h2 style="font-size: 14px; margin-bottom: 0.3rem; color: #9c9898">注意一个自然周内仅限预约一次</h2>
<vue-hash-calendar
@change="calendarChange"
format="YY-MM-DD"
:min-date="minDate"
:max-date="new Date('2023/10/31')"
ref="calendar"
picker-type="date"
:disabled-date="disabledDate"
:disabled-week-view="true"
/>
</div>
<div class="hospital-info-area" v-for="(item, index) in selectedHospital" :key="index">
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 0.4rem;">医院信息</h2>
<div class="info">
<h4 style="margin-bottom: 0.4rem; color: #2c97ef; font-size: 20px; font-weight: bold;">{{ item.text }}</h4>
<h5>地址{{ item.address }}</h5>
<h5>营业时间{{ item.businessStart }} -- {{ item.businessEnd }}</h5>
<h5>负责人{{ item.responsible }}</h5>
<h5>联系方式{{ item.telPhone }}</h5>
</div>
</div>
<div class="btn">
<van-button
type="primary"
native-type="submit"
:disabled="disBtn"
style="width: 50%; border-radius: 0.1rem; font-size: 18px; font-weight: bold;">确定预约
</van-button>
</div>
</van-form>
</template>
<script setup lang="ts">
import { onMounted, ref, reactive } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { showToast } from 'vant'
import { getActualHospital, getPackageDetail, submitForm } from '../../api/ExamPreOrder';
//
const router = useRouter()
const route = useRoute()
const result1 = ref<any>('')
const result2 = ref<any>('')
const result3 = ref<any>('')
const showHospitalPicker = ref<boolean>(false)
const showTypePicker = ref<boolean>(false)
const personalPackageName = ref<any>('')
const sonPackageDetails = ref<any[]>([])
const basePackageDetails = ref<any[]>([])
const totalPrice = ref<number>(0)
const packageId = ref<any>('')
const hospitalName = ref<any>('')
const examType = ref<any>('')
// 使reactive
const selectedHospital = reactive<any>({})
// ---+30
const minDate = ref<any>(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()))
// const maxDate = ref<any>(new Date(new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).getFullYear(), new Date(Date.now() + 30 * 24* 60 * 60 * 1000).getMonth(), new Date(Date.now() + 30 * 24* 60 * 60 * 1000).getDate()))
// const packageDetailStatus = ref<number>(0)
//
// const cascaderValue = ref<any>('')
// const cascaderShow = ref<boolean>(false)
const selectedDate = ref<any>('')
const calendar = ref(null)
const showTotalTc = ref<boolean>(false)
const showTc = ref<boolean>(false)
const pushBtn = ref<boolean>(true)
const disBtn = ref<boolean>(false)
const realToday = ref<any>('')
const cancelWeekList = ref<any[]>([])
const flodTc = () => {
showTc.value = true
pushBtn.value = false
}
const blowTc = () => {
showTc.value = false
pushBtn.value = true
}
//
const onClickLeft = () => {
history.back()
}
//
const getJT = (date: any) => {
const year = date.getFullYear();
const month = (date.getMonth()+1);
const day = date.getDate();
const currDate = ref<any>(``)
//
if (day < 10 && month < 10) {
currDate.value = `${year}-0${month}-0${day}`;
} else if (month >= 10 && day < 10) {
currDate.value = `${year}-${month}-0${day}`;
} else if (day >= 10 && month < 10) {
currDate.value = `${year}-0${month}-${day}`;
} else {
currDate.value = `${year}-${month}-${day}`;
}
return currDate.value
}
//
// typestartend
// dates0-112
const getNextWeekFirst = (type: any, dates = 0) => {
let now = new Date();
let nowTime = now.getTime();
let day = now.getDay();
let longTime = 24 * 60 * 60 * 1000;
let n = longTime * 7 * (dates || 0);
let dd
if (type == "start") {
dd = nowTime - (day - 1) * longTime + n;
};
if (type == "end") {
dd = nowTime + (7 - day) * longTime + n;
};
let trueDD = new Date(dd);
let y = trueDD.getFullYear();
let m = trueDD.getMonth() + 1;
let d = trueDD.getDate();
let trueM = m < 10 ? "0" + m : m;
let trueD = d < 10 ? "0" + d : d;
let trueDay = y + "-" + trueM + "-" + trueD;
return trueDay;
};
//
const subForm = (res: any) => {
console.log(selectedDate.value)
disBtn.value = true
//
res.hospitalId = hospitalName.value
res.setMealId = packageId.value
res.checkId = examType.value
res.phyAppontTime = String(selectedDate.value)
res.setMealType = 2
res.combName = personalPackageName.value
console.log('提交表单', res)
if (selectedDate.value == realToday.value) {
showToast({
message: '不可以预约今天!',
icon: 'fail',
duration: 1500,
onClose: () => {
disBtn.value = false
}
})
} else {
submitForm({
hospitalId: res.hospitalId,
setMealId: res.setMealId,
checkId: res.checkId,
phyAppontTime: res.phyAppontTime,
setMealType: res.setMealType,
combName: res.combName,
token: localStorage.getItem('token')
}).then((res: any) => {
console.log(res)
if (res.data.res == 0) {
showToast({
message: '今日可预约人数已满,请重新选择日期预约!',
icon: 'fail',
duration: 2500,
onClose: () => {
disBtn.value = false
}
})
} else {
showToast({
message: '预约成功!',
icon: 'success',
duration: 1500,
onClose: () => {
router.replace({
path: '/preOrderSucceed',
query: {
id: packageId.value
}
})
}
})
}
}).catch(() => {
showToast({
message: '预约超时,请返回重新预约!',
icon: 'fail',
duration: 2000,
onClose: () => {
history.go(-1)
}
})
})
}
}
//
const subFormFail = (err: any) => {
console.log(err)
}
const cascaderClose = () => {
showTypePicker.value = false
result2.value = ''
}
//
const hospitalColumns = ref<any[]>([])
const typeColumns = ref<any[]>([
{ text: '心血管', value: 1 },
{ text: '肿瘤', value: 2 },
{ text: '综合', value: 3 }
])
//
const fetchActualHospital = () => {
getActualHospital({
token: localStorage.getItem('token')
}).then((res: any) => {
if (res.data.obj === 'isnull') {
showToast({
message: '请联系后台管理员添加医院!',
icon: 'fail',
duration: 1500
})
} else {
//
const newHospitalObj = res.data.obj.map((item: any) => {
return {
text: item['hospitalName'],
value: item['id'],
address: item['address'],
businessStart: item['businessStart'],
businessEnd: item['businessEnd'],
responsible: item['responsible'],
telPhone: item['telPhone']
}
})
hospitalColumns.value = newHospitalObj
}
}).catch((err: any) => {
console.log(err)
})
}
// popup
const onHospitalConfirm = (res: any) => {
selectedHospital.value = {}
result1.value = res.selectedOptions[0]?.text;
showHospitalPicker.value = false;
selectedHospital.value = res.selectedOptions[0]
hospitalName.value = res.selectedOptions[0]?.value
};
/* const onTypeConfirm = (res: any) => {
result2.value = res.selectedOptions[0]?.text;
examType.value = res.selectedOptions[0]?.value
showTypePicker.value = false
// dom
getPackageDetail({
checkId: JSON.stringify(res.selectedOptions[0].value),
token: localStorage.getItem('token'),
combType: 2
}).then((result: any) => {
console.log(result)
if (result.data.obj.tibean.length === 0) {
showToast({
message: '体检套餐为空,请联系后台管理员发布体检套餐!',
icon: 'warning-o'
})
personalPackageName.value = ''
result2.value = ''
} else {
console.log(result)
personalPackageName.value = result.data.obj.tibean[0].combName
packageId.value = result.data.obj.tibean[0].id
sonPackageDetails.value = result.data.obj.tibeanson
basePackageDetails.value = result.data.obj.basebean
console.log(packageId.value)
totalPrice.value = 0
//
for (let i = 0; i < sonPackageDetails.value.length; i++) {
totalPrice.value += Number(sonPackageDetails.value[i].combinPrice)
}
for (let j = 0; j < basePackageDetails.value.length; j++) {
totalPrice.value += Number(basePackageDetails.value[j].combinPrice)
}
packageDetailStatus.value = 1
}
}).catch((err: any) => {
console.log(err)
})
} */
//
const calendarChange = (res: any) => {
console.log(res, '日期改变')
selectedDate.value = res
}
//
const onChange = (res: any) => {
console.log(res)
result2.value = res.selectedOptions[0]?.text;
examType.value = res.selectedOptions[0]?.value
getPackageDetail({
checkId: JSON.stringify(res.selectedOptions[0].value),
token: localStorage.getItem('token'),
combType: 2
}).then((result: any) => {
console.log(result)
if (result.data.obj.tibean.length === 0) {
showToast({
message: '体检套餐为空,请联系后台管理员发布体检套餐!',
icon: 'fail',
duration: 2000
})
result2.value = ''
} else {
showTotalTc.value = true
personalPackageName.value = result.data.obj.tibean[0].combName
packageId.value = result.data.obj.tibean[0].id
sonPackageDetails.value = result.data.obj.tibeanson
basePackageDetails.value = result.data.obj.basebean
console.log(packageId.value)
totalPrice.value = 0
//
for (let i = 0; i < sonPackageDetails.value.length; i++) {
totalPrice.value += Number(sonPackageDetails.value[i].combinPrice)
}
for (let j = 0; j < basePackageDetails.value.length; j++) {
totalPrice.value += Number(basePackageDetails.value[j].combinPrice)
}
}
}).catch((err: any) => {
console.log(err)
})
}
//
const closePopup = () =>{
if (result2.value === '') {
showToast({
message: '未选择职工套餐!',
icon: 'fail',
duration: 1500
})
} else {
showTypePicker.value = false
}
}
//
const fetchDayWeek = (chosenDay: any) => {
let oneDayTime = 1000 * 60 * 60 * 24
let today = new Date(chosenDay)
// 7
let todayDay = today.getDay() || 7
let startDate = new Date(
today.getTime() - oneDayTime * (todayDay - 1)
)
let dateList = new Array()
//
for(let i = 0; i < 7; i++){
let temp = new Date(startDate.getTime() + i * oneDayTime)
let year = temp.getFullYear()
let month = temp.getMonth() + 1
let day = temp.getDate()
if (day < 10 && month < 10) {
dateList[i] = `${year}-0${month}-0${day}`
} else if (month >= 10 && day < 10) {
dateList[i] = `${year}-${month}-0${day}`
} else if (day >= 10 && month < 10) {
dateList[i] = `${year}-0${month}-${day}`
} else {
dateList[i] = `${year}-${month}-${day}`
}
}
return dateList
}
//
const disabledDate = (date: any) => {
const year = date.getFullYear();
// +1
const month = (date.getMonth()+1);
const day = date.getDate();
const currDate = ref<any>(``)
//
if (day < 10 && month < 10) {
currDate.value = `${year}-0${month}-0${day}`;
} else if (month >= 10 && day < 10) {
currDate.value = `${year}-${month}-0${day}`;
} else if (day >= 10 && month < 10) {
currDate.value = `${year}-0${month}-${day}`;
} else {
currDate.value = `${year}-${month}-${day}`;
}
//
const disabledDateArr = [];
//
let oneDayTime = 1000 * 60 * 60 * 24
let today = new Date() // selectedDate.value
// 7
let todayDay = today.getDay() || 7
let startDate = new Date(
today.getTime() - oneDayTime * (todayDay - 1)
)
let dateList = new Array()
/* let dayCount = new Date().getDay()
let todayTemp = new Date(startDate.getTime() + (dayCount - 1) * oneDayTime)
let tempYear = todayTemp.getFullYear()
let tempMonth = todayTemp.getMonth() + 1
let tempDay = todayTemp.getDate()
let trueToday = ref<any>('')
if (tempDay < 10 && tempMonth < 10) {
trueToday = `${tempYear}-0${tempMonth}-0${tempDay}`
} else if (tempMonth >= 10 && tempDay < 10) {
trueToday = `${tempYear}-${tempMonth}-0${tempDay}`
} else if (tempDay >= 10 && tempMonth < 10) {
trueToday = `${tempYear}-0${tempMonth}-${tempDay}`
} else {
trueToday = `${tempYear}-${tempMonth}-${tempDay}`
}
console.log(trueToday, 'sss') */
/* let trueToday = new Date()
let trueTodayYear = trueToday.getFullYear()
let trueTodayMonth = trueToday.getMonth() + 1
let trueTodayDay = trueToday.getDate()
let formatToady = ''
if (trueTodayDay < 10 && trueTodayMonth < 10) {
formatToady = `${trueTodayYear}-0${trueTodayMonth}-0${trueTodayDay}`
} else if (trueTodayMonth >= 10 && trueTodayDay < 10) {
formatToady = `${trueTodayYear}-${trueTodayMonth}-0${trueTodayDay}`
} else if (trueTodayDay >= 10 && trueTodayMonth < 10) {
formatToady = `${trueTodayYear}-0${trueTodayMonth}-${trueTodayDay}`
} else {
formatToady = `${trueTodayYear}-${trueTodayMonth}-${trueTodayDay}`
} */
//
for(let i = 0; i < 7; i++){
let temp = new Date(startDate.getTime() + i * oneDayTime)
let year = temp.getFullYear()
let month = temp.getMonth() + 1
let day = temp.getDate()
if (day < 10 && month < 10) {
dateList[i] = `${year}-0${month}-0${day}`
} else if (month >= 10 && day < 10) {
dateList[i] = `${year}-${month}-0${day}`
} else if (day >= 10 && month < 10) {
dateList[i] = `${year}-0${month}-${day}`
} else {
dateList[i] = `${year}-${month}-${day}`
}
disabledDateArr.push(dateList[i])
}
/* for (let j = 0; j < cancelWeekList.value.length; j++) {
disabledDateArr.push(cancelWeekList.value[j])
} */
if (disabledDateArr.includes(currDate.value)) {
return true;
}
return false;
}
onMounted(() => {
fetchActualHospital()
realToday.value = getJT(new Date())
console.log(route.query.cancelDate, '取消日时间戳')
console.log(fetchDayWeek(Number(route.query.cancelDate)), '取消日所处的星期')
cancelWeekList.value = fetchDayWeek(Number(route.query.cancelDate))
console.log(getNextWeekFirst('start', 1)) //
})
</script>
<style scoped lang="scss">
.form-area{
width: 100%;
margin: 0.2rem auto;
.upper-info{
width: 96%;
margin: 0 auto;
background-color: #f8f8f8;
box-sizing: border-box;
padding: 0.3rem;
border-radius: 0.1rem;
position: relative;
.inner-package{
width: 100%;
box-sizing: border-box;
padding: 0.2rem;
height: 10.5rem;
.inner-tit{
font-size: 20px;
font-weight: bold;
color: #2c97ef;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
padding: 0.2rem 0;
border-bottom: 1px solid #d3d3d3;
}
h1{
font-size: 20px;
color: #2c97ef;
margin-bottom: 0.4rem;
font-weight: bold;
}
h2{
margin-bottom: 0.4rem;
line-height: 26px;
}
.cfm-btn{
width: 100%;
position: fixed;
left: 10px;
bottom: 10px;
margin-top: 0.5rem;
}
}
}
.personal-area{
display: flex;
justify-content: space-between;
align-items: center;
}
}
.hospital-info-area{
width: 94%;
margin: 0.5rem auto;
background-color: #fff;
border-radius: 0.1rem;
box-sizing: border-box;
padding: 0.3rem;
.info{
width: 100%;
height: 80%;
display: flex;
flex-direction: column;
margin: 0.1rem auto;
h5{
font-size: 16px;
margin-bottom: 0.2rem;
line-height: 20px;
}
h5:nth-child(5){
margin-bottom: 0;
}
}
}
.btn{
width: 100%;
margin: 0.5rem auto;
display: flex;
justify-content: center;
}
.package-area{
.package-name{
font-size: 20px;
margin-bottom: 0.15rem;
font-weight: bold;
color: #2c97ef;
}
.package-price, .package-content{
font-size: 16px;
line-height: 26px;
}
.package-price{
margin-bottom: 0.5rem;
}
.package-price{
span{
color: red;
}
}
}
.total-price{
display: flex;
justify-content: right;
margin-top: 1rem;
font-size: 18px;
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<van-nav-bar
title="体检报告"
left-arrow
@click-left="onClickLeft"
/>
<van-field
v-model="value1"
left-icon="search"
placeholder="查找报告"
style="width: 95%; margin: 0.2rem auto;"
/>
<van-field
v-model="fieldValue"
is-link
readonly
label="年份"
placeholder="请选择年份"
@click="showPicker = true"
style="width: 95%; margin: 0.2rem auto;"
/>
<van-popup v-model:show="showPicker" round position="bottom">
<van-picker
:columns="columns"
@cancel="showPicker = false"
@confirm="onConfirm"
/>
</van-popup>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const value1 = ref<any>('')
const fieldValue = ref<any>('')
const showPicker = ref<boolean>(false)
const columns = ref<any[]>([
{ text: '2023年', value: 0 },
{ text: '2022年', value: 1 },
{ text: '2021年', value: 2 },
])
const onClickLeft = () => {
history.back()
}
const onConfirm = (res: any) => {
showPicker.value = false
fieldValue.value = res.selectedOptions[0].text
console.log(res.selectedOptions[0].value)
}
//
/* const iptChange = (res: any) => {
console.log(res)
} */
onMounted(() => {
})
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,403 @@
<template>
<van-nav-bar
title="重置密码"
/>
<div class="background">
<div class="block_3 flex-col">
<div class="section_1 flex-col"></div>
<div class="section_2 flex-col"></div>
<div class="section_3 flex-col"></div>
</div>
</div>
<van-form
@submit="subNewPwd"
class="forget-area"
>
<van-field
v-model="phoneNumber"
name="phoneNumber"
:placeholder="phoneNumPlaceHolder"
@focus="focusPhoneNum"
@blur="blurPhoneNum"
:rules="[{ required: true, message: '请填写手机号!' }]"
autocomplete="off"
clearable
style="border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px;"
/>
<van-field
v-model="newPwd"
name="newPwd"
:type="newPwdType"
:placeholder="pwdPlaceHolder"
@focus="focusPwd"
@blur="blurPwd"
:rules="[{
required: true,
message: '请输入新密码!',
validator: iptPwd
}]"
autocomplete="off"
clearable
style="margin-top: 0.5rem; border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px;"
>
<template #button>
<van-button
style="font-size: 16px; background-color: transparent; color: #1989fa; border: none;"
size="small"
type="primary"
>
<span v-if="newPwdStatus === 0" @click="showNewPwd">查看</span>
<span v-if="newPwdStatus === 1" @click="hideNewPwd">隐藏</span>
</van-button>
</template>
</van-field>
<van-field
v-model="confirmNewPwd"
name="confirmNewPwd"
type="password"
:placeholder="confirmPwdPlaceHolder"
@focus="focusConfirmPwd"
@blur="blurConfirmPwd"
:rules="[{
required: true,
message: '请确认新密码!' ,
validator: confirmPwd
}]"
autocomplete="off"
style="margin-top: 0.5rem; border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px;"
>
<!-- <template #button>
<van-button
style="font-size: 16px; background-color: transparent; color: #1989fa; border: none;"
size="small"
type="primary"
>
<span v-if="confirmPwdStatus === 0" @click="showConfirmPwd">查看</span>
<span v-if="confirmPwdStatus === 1" @click="hideConfirmPwd">隐藏</span>
</van-button>
</template> -->
</van-field>
<van-field
v-model="verifyNum"
name="verifyNum"
:placeholder="veriPlaceHolder"
@focus="focusVeri"
@blur="blurVeri"
:rules="[{ required: true }]"
autocomplete="off"
style="margin-top: 0.5rem; border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px; display: flex; align-items: center;"
>
<template #button>
<van-button
style="border-radius: 0.8rem;"
size="small"
type="primary"
@click="sendCode"
:disabled="veriBtnDisable"
>
<span v-if="countStatus === 0">{{ time }}</span>
<span v-if="countStatus === 1">
<span>{{ countSecond }}</span>
s
</span>
</van-button>
</template>
</van-field>
<div class="btn-area">
<van-button
type="primary"
native-type="submit"
style="width: 70%; border-radius: 0.5rem; font-size: 18px;"
>
确认修改
</van-button>
</div>
</van-form>
</template>
<script setup lang="ts">
import { showToast } from 'vant';
import { ref, onMounted } from 'vue'
import { editNewPwd, sendVeriCode } from '../../api/ForgetPassword'
import { useRouter, useRoute } from 'vue-router'
import './scss/index.scss'
const phoneNumPlaceHolder = ref<string>('请输入手机号')
const pwdPlaceHolder = ref<string>('请输入新密码')
const confirmPwdPlaceHolder = ref<string>('请确认新密码')
const veriPlaceHolder = ref<string>('验证码')
const router = useRouter()
const route = useRoute()
const phoneNumber = ref<any>('')
const newPwd = ref<any>('')
const confirmNewPwd = ref<any>('')
const verifyNum = ref<any>('')
const countStatus = ref<number>(0)
const countSecond = ref<number>(60)
const veriBtnDisable = ref<boolean>(false)
const sendData = ref<any>({})
const time = ref<any>('发送验证码')
const pwdPattern = /^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&*]+$)(?![\d!@#$%^&*]+$)[a-zA-Z\d!@#$%^&*]+$/
const newPwdType = ref<any>('password')
const newPwdStatus = ref<number>(0)
// const confirmPwdType = ref<any>('password')
// const confirmPwdStatus = ref<number>(0)
//
const showNewPwd = () => {
newPwdType.value = 'input'
newPwdStatus.value = 1
}
//
const hideNewPwd = () => {
newPwdType.value = 'password'
newPwdStatus.value = 0
}
//
/* const showConfirmPwd = () => {
confirmPwdType.value = 'input'
confirmPwdStatus.value = 1
} */
//
/* const hideConfirmPwd = () => {
confirmPwdType.value = 'password'
confirmPwdStatus.value = 0
} */
//
const focusPhoneNum = () => {
phoneNumPlaceHolder.value = ''
}
const focusPwd = () => {
pwdPlaceHolder.value = ''
}
const focusConfirmPwd = () => {
confirmPwdPlaceHolder.value = ''
}
const focusVeri = () => {
veriPlaceHolder.value = ''
}
//
const blurPhoneNum = () => {
phoneNumPlaceHolder.value = '请输入手机号'
}
const blurPwd = () => {
pwdPlaceHolder.value = '请输入新密码'
}
const blurConfirmPwd = () => {
confirmPwdPlaceHolder.value = '请确认新密码'
}
const blurVeri = () => {
veriPlaceHolder.value = '验证码'
}
/* const onClickLeft = () => {
history.back()
} */
//
const subNewPwd = (val: any) => {
if (Number(verifyNum.value) !== Number(localStorage.getItem('veriCode')) //
|| phoneNumber.value === null //
|| !localStorage.getItem('veriCode') //
|| newPwd.value !== confirmNewPwd.value //
|| phoneNumber.value.length !== 11 //
) {
showToast({
message: '手机号或验证码不正确!',
icon: 'fail',
duration: 1500,
onClose: () => {
verifyNum.value = ''
}
})
} else {
console.log('修改成功', val.newPwd)
sendData.password = val.newPwd
sendData.telephone = val.phoneNumber
console.log(sendData.password, sendData.telephone)
editNewPwd({
password: sendData.password,
telephone: sendData.telephone
}).then((res: any) => {
console.log(res)
if (res.data.obj.num === 1) {
showToast({
message: res.data.resMsg,
icon: 'success',
duration: 1500,
onClose: () => {
localStorage.removeItem('veriCode')
router.push('/accountLogin')
}
})
} else {
showToast({
message: '修改密码失败!',
icon: 'fail',
duration: 1500
})
}
}).catch((err: any) => {
console.log(err)
})
}
}
//
const iptPwd = (val: any) => {
if (!pwdPattern.test(val)) {
showToast({
message: '密码必须包含大小写字母、特殊字符和数字!',
icon: 'fail',
duration: 3000,
onClose: () => {
newPwd.value = ''
}
})
}
}
//
const confirmPwd = (val: any) => {
if (val !== newPwd.value) {
showToast({
message: '请确认密码保持一致!',
icon: 'fail',
duration: 1500,
onClose: () => {
confirmNewPwd.value = ''
}
})
}
}
//
const sendCode = () => {
console.log(phoneNumber.value.length)
if (phoneNumber.value.length !== 11) {
showToast({
message: '请输入正确格式的手机号!',
icon: 'fail',
duration: 1500,
onClose: () => {
phoneNumber.value = ''
}
})
} else {
sendVeriCode({
telephone: phoneNumber.value
}).then((res: any) => {
console.log(res)
// data
if (res.data === '') {
showToast({
message: '此人员不在系统中,请联系后台管理员添加账号!',
icon: 'fail',
duration: 3000,
onClose: () => {
phoneNumber.value = ''
}
})
} else {
// 60s
localStorage.setItem('veriCode', res.data)
countStatus.value = 1
veriBtnDisable.value = true
const timeOut = setTimeout(() => {
localStorage.removeItem('veriCode')
countStatus.value = 0
countSecond.value = 60
veriBtnDisable.value = false
clearInterval(interval)
clearTimeout(timeOut)
}, 60 * 1000)
const interval = setInterval(() => {
countSecond.value -= 1
}, 1000)
}
}).catch((err: any) => {
console.log(err)
})
}
}
//
/* const editPwd = (value: any) => {
} */
onMounted(() => {
console.log(route.query.phoneNum)
if (route.query) {
phoneNumber.value = route.query.phoneNum
} else {
phoneNumber.value = ''
}
})
/* onBeforeUnmount(() => {
localStorage.removeItem('veriCode')
}) */
</script>
<style scoped lang="scss">
.background {
width: 10rem;
height: 8rem;
background: url('../../static/bg.jpg')
100% no-repeat;
background-size: 100% 100%;
width: 100%;
position: absolute;
margin-bottom: 7rem;
left: 0;
top: 0;
.section_1 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
width: 4rem;
height: 4rem;
position: absolute;
}
.section_2 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
position: absolute;
left: 0.1rem;
top: 1.2rem;
width: 6rem;
height: 6rem;
}
.section_3 {
background-color: rgba(255, 255, 255, 0.0624);
border-radius: 50%;
position: absolute;
left: 6rem;
top: 0.5rem;
width: 4rem;
height: 4rem;
}
}
.forget-area{
width: 80%;
margin: 0 auto;
box-sizing: border-box;
padding: 7rem 0.5rem;
}
.btn-area{
width: 100%;
margin-top: 1rem;
display: flex;
justify-content: center;
}
</style>

View File

@ -0,0 +1,3 @@
:root:root{
--van-field-placeholder-text-color: #000;
}

349
src/views/Home/Home.vue Normal file
View File

@ -0,0 +1,349 @@
<template>
<div>
<div class="swipe-area">
<van-swipe :autoplay="3000">
<van-swipe-item>
<img src="../../static/post1.png" alt="">
</van-swipe-item>
<van-swipe-item>
<img src="../../static/post2.png" alt="">
</van-swipe-item>
<van-swipe-item>
<img src="../../static/post3.png" alt="">
</van-swipe-item>
</van-swipe>
</div>
<h2 class="tit">体检服务</h2>
<div class="services">
<div class="services-item" @click="judgePreOrdered()">
<img :src="preOrderImg" alt=""/>
<span>体检预约</span>
</div>
<div v-if="userStatus !== 0" class="services-item" @click="judgeCareerPre()">
<img :src="careerExamImg" alt=""/>
<span>职业体检</span>
</div>
<div class="services-item" @click="jumpReport()">
<img :src="reportImg" alt=""/>
<span>体检报告</span>
</div>
<div class="services-item" @click="jumpMyPre()">
<img :src="myPreImg" alt=""/>
<span>我的预约</span>
</div>
</div>
<TabBar/>
</div>
</template>
<script setup lang="ts" name="Home">
import TabBar from '../../components/TabBar.vue';
import { onMounted, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { getUserStatus, isPreOrdered } from '../../api/Home'
//
import preOrderImg from '../../static/preOrder.png'
import careerExamImg from '../../static/careerExam.png'
import reportImg from '../../static/report.png'
import myPreImg from '../../static/myPreOrder.png'
import { showToast } from 'vant';
const route = useRoute()
const router = useRouter()
const userStatus = ref<number>(0)
const appoint1 = ref<number>(3)
const appoint2 = ref<number>(2)
// const currentTime = ref<number>(new Date().getTime())
const originCancel = ref<any>()
const cancelTime = ref<any>()
const cancelWeekStart = ref<any>()
const cancelWeekEnd = ref<any>()
//
// typestartend
// dates0-112
// cancelDay
const getCancelWeek = (type: string, dates = 0, cancelDay: string | number | Date) => {
let now = new Date(cancelDay);
let nowTime = now.getTime();
let day = now.getDay();
if (day == 0) {
nowTime = nowTime - 7 * 24 * 60 * 60 * 1000
}
let longTime = 24 * 60 * 60 * 1000;
let n = longTime * 7 * (dates || 0);
let dd
if (type == "start") {
dd = nowTime - (day - 1) * longTime + n;
};
if (type == "end") {
if (day == 0) {
dd = nowTime + (7 - day) * longTime + n + longTime;
} else {
dd = nowTime + (7 - day) * longTime + n;
}
};
let trueDD = new Date(dd);
let y = trueDD.getFullYear();
let m = trueDD.getMonth() + 1;
let d = trueDD.getDate();
let trueM = m < 10 ? "0" + m : m;
let trueD = d < 10 ? "0" + d : d;
let trueDay = y + "-" + trueM + "-" + trueD;
return trueDay;
};
//
const fetchUserStatus = () => {
getUserStatus({
token: localStorage.getItem('token'),
telephone: localStorage.getItem('phoneNumber')
}).then((res: any) => {
console.log(res)
originCancel.value = res.data.obj.cancelTime
// console.log(originCancel.value)
userStatus.value = Number(res.data.obj.status)
cancelTime.value = Date.parse(res.data.obj.cancelTime)
/* console.log(getCancelWeek('start', 0, cancelTime.value), getCancelWeek('end', 0, cancelTime.value))
console.log(Date.parse(res.data.obj.cancelTime), '7.1')
console.log(Date.parse(getCancelWeek('end', 0, cancelTime.value)), '7.2') */
cancelWeekStart.value = Date.parse(getCancelWeek('start', 0, cancelTime.value))
cancelWeekEnd.value = Date.parse(getCancelWeek('end', 0, cancelTime.value))
/* console.log(cancelTime.value, '')
console.log(cancelWeekStart.value, '取消周首日时间戳')
console.log(cancelWeekEnd.value, '取消周最后一日时间戳') */
}).catch((err: any) => {
console.log(err)
})
}
//
const judgePreOrdered = () => {
isPreOrdered({
token: localStorage.getItem('token'),
appoint: appoint2.value
}).then((res: any) => {
console.log(res, '收到')
if (res.data.obj === 1) {
router.push({
path: '/examPreOrder',
query: {
cancelDate: cancelTime.value + 7 * 24 * 60 * 60 * 1000
}
})
} else {
showToast({
message: '您已经预约过,无法再次预约!',
icon: 'fail',
duration: 2000
})
}
}).catch((err: any) => {
console.log(err, '错误')
})
}
//
const judgeCareerPre = () => {
isPreOrdered({
token: localStorage.getItem('token'),
appoint: appoint1.value
}).then((res: any) => {
console.log(res, '收到')
if (res.data.obj === 1) {
router.push({
path: '/careerExam'
})
} else {
showToast({
message: '您已经预约过,无法再次预约!',
icon: 'fail',
duration: 2000
})
}
}).catch((err: any) => {
console.log(err, '错误')
})
}
//
/* const jumpExam = () => {
if (originCancel.value == null) {
judgePreOrdered()
} else if (cancelTime.value > cancelWeekStart.value && cancelTime.value < cancelWeekEnd.value) {
if (currentTime.value < Date.parse(getCancelWeek('start', 1, cancelTime.value))) {
showToast({
message: '本周已取消预约,请下周再次预约!',
icon: 'fail',
duration: 2000
})
} else {
judgePreOrdered()
}
} else {
console.log('日期异常')
}
} */
//
const jumpReport = () => {
router.push({
path: '/examReport'
})
}
//
const jumpMyPre = () => {
router.push({
path: '/myPreOrder'
})
}
//
/* const jumpCareer = () => {
if (originCancel.value == null) {
judgeCareerPre()
} else if (cancelTime.value > cancelWeekStart.value && cancelTime.value < cancelWeekEnd.value) {
if (currentTime.value < Date.parse(getCancelWeek('start', 1, cancelTime.value))) {
showToast({
message: '本周已取消预约,请下周再次预约!',
icon: 'fail',
duration: 2000
})
} else {
judgeCareerPre()
}
} else {
console.log('日期异常')
}
} */
onMounted(() => {
/* console.log(currentTime.value, '')
console.log(Date.parse(getCancelWeek('start', 1, currentTime.value)), '下周一时间戳') */
if (route.query.pwd === 'YNsbd@123456') {
showToast({
message: '首次登录,请您重置密码!',
icon: 'fail',
duration: 3000,
onClose: () => {
router.replace({
path: '/forgetPassword',
query: {
phoneNum: localStorage.getItem('phoneNumber')
}
})
}
})
}
// cookie
if (!document.cookie) {
showToast({
message: '登录状态已过期,请重新登录!',
icon: 'fail',
duration: 1500,
onClose: () => {
localStorage.removeItem('token')
localStorage.removeItem('phoneNumber')
localStorage.removeItem('phyName')
localStorage.removeItem('idcard')
localStorage.removeItem('sex')
localStorage.removeItem('age')
localStorage.removeItem('telepNumber')
localStorage.removeItem('departName')
history.go(0)
}
})
} else {
fetchUserStatus()
}
})
</script>
<style scoped lang="scss">
.background {
width: 10rem;
height: 8rem;
background: url('../../static/bg.jpg');
background-size: 100% 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
.section_1 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
width: 4rem;
height: 4rem;
position: absolute;
}
.section_2 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
position: absolute;
left: 0.1rem;
top: 1.2rem;
width: 6rem;
height: 6rem;
}
.section_3 {
background-color: rgba(255, 255, 255, 0.0624);
border-radius: 50%;
position: absolute;
left: 6rem;
top: 0.5rem;
width: 4rem;
height: 4rem;
}
}
.swipe-area{
width: 95%;
height: 70%;
margin: 0 auto;
padding-top: 0.8rem;
img{
width: 100%;
height: 100%;
}
}
.tit{
margin: 0.6rem 0 0 0;
padding-left: 0.2rem;
font-size: 20px;
font-weight: bold;
}
.services{
width: 95%;
margin: 0.3rem auto;
height: 7rem;
border-radius: 0.2rem;
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
padding: 1rem 0 0 1.2rem;
background-color: #fff;
.services-item{
width: 20%;
height: 30%;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
margin-right: 1rem;
margin-bottom: 0.1rem;
image{
width: 100%;
height: 100%;
margin-bottom: 0.2rem;
}
span{
text-align: center;
font-size: 16px;
padding-top: 0.3rem;
}
}
}
</style>

View File

@ -0,0 +1,289 @@
<template>
<div>
<div class="background">
<div class="block_3 flex-col">
<div class="section_1 flex-col"></div>
<div class="section_2 flex-col"></div>
<div class="section_3 flex-col"></div>
</div>
</div>
<h2 class="log-tit">云送体检预约</h2>
<van-form @submit="logPhoneSub" class="log-form">
<van-field
v-model="phoneNumber"
name="phoneNumber"
:placeholder="phoneNumPlaceHolder"
@focus="focusPhoneNum"
@blur="blurPhoneNum"
:rules="[{ required: true, message: '请填写手机号!' }]"
autocomplete="off"
clearable
style="border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px;"
/>
<van-field
v-model="verifyNum"
name="verifyNum"
:placeholder="veriPlaceHolder"
@focus="focusVeri"
@blur="blurVeri"
:rules="[{ required: true }]"
autocomplete="off"
style="margin-top: 0.5rem; border: 1px solid #62b0b0; background-color: #f3f9f9; font-size: 16px; display: flex; align-items: center;"
>
<template #button>
<van-button
style="border-radius: 0.8rem"
size="small"
type="primary"
@click="sendVeriCode"
:disabled="veriBtnDisable"
>
<span v-if="countStatus === 0">{{ time }}</span>
<span v-if="countStatus === 1">
<span>{{ countSecond }}</span>
s
</span>
</van-button>
</template>
</van-field>
<div class="user-taps">
<span @click="jumpForget()">忘记密码</span>
<span @click="jumpAccount()">账号密码登录</span>
</div>
<div class="btn-area">
<van-button
type="primary"
native-type="submit"
style="width: 70%; border-radius: 0.5rem; font-size: 18px;"
>
登录
</van-button>
</div>
</van-form>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { sendPhoneVeri, logWithMsg } from '../../api/MsgLogin'
import { showToast, showFailToast } from 'vant';
import './scss/index.scss'
const phoneNumPlaceHolder = ref<string>('手机号')
const veriPlaceHolder = ref<string>('验证码')
const phoneNumber = ref<any>('')
const verifyNum = ref<any>('')
const router = useRouter()
const time = ref<any>('发送验证码')
const countStatus = ref<number>(0)
const countSecond = ref<number>(60)
const veriBtnDisable = ref<boolean>(false)
const msgInfo = ref<any>({})
//
const focusPhoneNum = () => {
phoneNumPlaceHolder.value = ''
}
const focusVeri = () => {
veriPlaceHolder.value = ''
}
//
const blurPhoneNum = () => {
phoneNumPlaceHolder.value = '手机号'
}
const blurVeri = () => {
veriPlaceHolder.value = '验证码'
}
//
const jumpForget = () => {
router.push({
path: '/forgetPassword'
})
}
//
const jumpAccount = () => {
router.push({
path: '/accountLogin'
})
}
//
const sendVeriCode = () => {
if (phoneNumber.value.length !== 11) {
showToast({
message: '请输入正确格式的手机号!',
icon: 'fail',
duration: 1500,
onClose: () => {
phoneNumber.value = ''
}
})
} else {
sendPhoneVeri({
telephone: phoneNumber.value
}).then((res: any) => {
console.log(res)
if (res.data === '') {
showToast({
message: '此人员不在系统中,请联系后台管理员添加账号!',
icon: 'fail',
duration: 3000,
onClose: () => {
phoneNumber.value = ''
}
})
} else {
// 60s
localStorage.setItem('veriPhoneCode', res.data)
countStatus.value = 1
veriBtnDisable.value = true
const phoneTimeOut = setTimeout(() => {
localStorage.removeItem('veriPhoneCode')
countStatus.value = 0
countSecond.value = 60
veriBtnDisable.value = false
clearInterval(phoneInterval)
clearTimeout(phoneTimeOut)
}, 60 * 1000)
const phoneInterval = setInterval(() => {
countSecond.value -= 1
}, 1000)
}
}).catch((err: any) => {
console.log(err)
})
}
}
//
const logPhoneSub = (val: any) => {
//
if (Number(verifyNum.value) !== Number(localStorage.getItem('veriPhoneCode'))
|| phoneNumber.value === null //
|| !localStorage.getItem('veriPhoneCode') //
|| phoneNumber.value.length !== 11 //
) {
showToast({
message: '手机号或验证码不正确!',
icon: 'fail',
duration: 1500,
onClose: () => {
verifyNum.value = ''
}
})
} else {
console.log('修改成功!', val)
msgInfo.telephone = val.phoneNumber
//
logWithMsg({
telephone: msgInfo.telephone
}).then((res: any) => {
console.log(res)
if (res.data.resMsg === 'success') {
showToast({
message: '登录成功!',
icon: 'success',
duration: 1500,
onClose: () => {
localStorage.setItem('token', res.data.obj)
localStorage.setItem('avatarUrl', 'https://img.zcool.cn/community/0104c958b69c23a801219c77ba5da2.png?x-oss-process=image/auto-orient,1/resize,m_lfit,w_1280,limit_1/sharpen,100')
localStorage.setItem('phoneNumber', msgInfo.telephone)
localStorage.removeItem('veriPhoneCode')
// 3h
const overDate = new Date().getTime() - 8 * 60 * 60 * 1000 + 3 * 60 * 60 * 1000
document.cookie = `loginStatus=0;expires=${new Date(overDate)}`
router.replace({
path: '/home'
})
}
})
}
}).catch(() => {
showFailToast('登录失败!')
})
}
}
onMounted(() => {
})
</script>
<style scoped lang="scss">
.background {
width: 10rem;
height: 8rem;
background: url('../../static/bg.jpg')
100% no-repeat;
background-size: 100% 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
.section_1 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
width: 4rem;
height: 4rem;
position: absolute;
}
.section_2 {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
position: absolute;
left: 0.1rem;
top: 1.2rem;
width: 6rem;
height: 6rem;
}
.section_3 {
background-color: rgba(255, 255, 255, 0.0624);
border-radius: 50%;
position: absolute;
left: 6rem;
top: 0.5rem;
width: 4rem;
height: 4rem;
}
}
.log-tit{
width: 100%;
padding-top: 4rem;
text-align: center;
font-size: 30px;
font-weight: bold;
}
.log-form{
width: 80%;
height: 8rem;
margin: 3.5rem auto;
box-sizing: border-box;
padding: 0.5rem;
.user-taps{
width: 100%;
margin-top: 0.3rem;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding: 0 0.2rem;
span{
font-size: 14px;
color: #49b3f2;
}
}
.btn-area{
width: 100%;
margin-top: 0.6rem;
display: flex;
justify-content: center;
}
}
</style>

View File

@ -0,0 +1,3 @@
:root:root{
--van-field-placeholder-text-color: #000;
}

View File

@ -0,0 +1,80 @@
<template>
<van-nav-bar
title="消息通知"
left-arrow
@click-left="onClickLeft"
/>
<!-- <div class="msgs-block" v-for="(item, index) in reportList" :key="index">
<van-swipe-cell :before-close="onDelete" :name="item.name" @close="onClose">
<van-cell :border="false" :title="item.title" value="内容">
<van-badge dot position="left"></van-badge>
</van-cell>
<template #right>
<van-button square type="danger" @click="toggleDelete" text="删除" />
</template>
</van-swipe-cell>
</div> -->
</template>
<script setup lang="ts">
/* import { ref, onMounted } from 'vue'
import { showConfirmDialog } from 'vant'; */
//
/* const reportList = ref<any[]>([
{
name: 'report1',
title: '体检报告已更新',
},
{
name: 'report2',
title: '职业健康待体检',
},
{
name: 'report3',
title: '这条是多余的',
}
]) */
const onClickLeft = () => {
history.back()
}
/* const toggleDelete = () => {
} */
//
/* const onDelete = (e: any) => {
const { position } = e
// console.log(name)
if (position === 'right') {
showConfirmDialog({
title: '确认删除吗?'
}).then((res: any) => {
console.log(res)
}).catch((err: any) => {
console.log(err)
})
}
}
const onClose = (e: any) => {
console.log(e)
} */
/* onMounted(() => {
}) */
</script>
<style scoped lang="scss">
.msgs-block{
width: 100%;
margin: 0.05rem auto;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
</style>

View File

@ -0,0 +1,365 @@
<template>
<van-nav-bar
title="我的预约"
left-arrow
@click-left="onClickLeft"
/>
<van-form @submit="myPreForm">
<div class="my-form">
<van-field
v-model="examStatus"
name="examStatus"
is-link
readonly
placeholder="请选择体检状态"
@click="showPicker = true"
style="width: 80%;"
autocomplete="off"
/>
<van-popup v-model:show="showPicker" round position="bottom">
<van-picker
:columns="columns"
@cancel="showPicker = false"
@confirm="onConfirm"
/>
</van-popup>
<van-button
type="primary"
native-type="submit"
style="font-size: 16px;"
>
查询
</van-button>
</div>
</van-form>
<div class="tip">提示向左滑动取消预约</div>
<!-- 待体检模块 -->
<div
class="my-pre-area"
v-for="(item, index) in readyExamedList"
:key="index"
v-if="upperStatus === 4 || upperStatus === 2"
@click="seeReport(item.id, item.combName)"
>
<van-swipe-cell style="width: 100%; height: 100%">
<div class="swipe-container">
<div class="lef">
<img :src="readyExamImg" alt="">
</div>
<div class="rig">
<h1>{{ item.hospitalName }}</h1>
<h2>
{{ item.combName }}
<span v-if="readyExamedList[index].setMealPrice !== null">
{{ readyExamedList[index].setMealPrice }}
</span>
</h2>
<h3>预约时间{{ item.phyAppontTime }}</h3>
</div>
</div>
<template #right>
<van-button
style="height: 100%;"
square
type="danger"
text="取消"
@click="cancel"
/>
</template>
</van-swipe-cell>
</div>
<!-- 已取消模块 -->
<div
class="my-pre-area"
v-for="(item, index) in isCanceledList"
:key="index"
v-if="upperStatus === 4 || upperStatus === 1"
@click="seeReport(item.id, item.combName)"
>
<div class="swipe-container">
<div class="lef">
<img :src="isCanceledImg" alt="">
</div>
<div class="rig">
<h1>{{ item.hospitalName }}</h1>
<h2>
{{ item.combName }}
<span v-if="isCanceledList[index].setMealPrice !== null">
{{ isCanceledList[index].setMealPrice }}
</span>
</h2>
<h3>预约时间{{ item.phyAppontTime }}</h3>
</div>
</div>
</div>
<!-- 已体检模块 -->
<div
class="my-pre-area"
v-for="(item, index) in isExamedList"
:key="index"
v-if="upperStatus === 4 || upperStatus === 3"
@click="seeReport(item.id, item.combName)"
>
<van-swipe-cell style="width: 100%; height: 100%">
<div class="swipe-container">
<div class="lef">
<img :src="isExamedImg" alt="">
</div>
<div class="rig">
<h1>{{ item.hospitalName }}</h1>
<h2>
{{ item.combName }}
<span v-if="isExamedList[index].setMealPrice !== null">
{{ isExamedList[index].setMealPrice }}
</span>
</h2>
<h3>预约时间{{ item.phyAppontTime }}</h3>
</div>
</div>
</van-swipe-cell>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { getPreOrderInfo, cancelPort } from '../../api/MyPreOrder'
import { showConfirmDialog, showToast } from 'vant'
import { useRouter } from 'vue-router'
import isCanceledImg from '../../static/isCanceled.png'
import readyExamImg from '../../static/readyExam.png'
import isExamedImg from '../../static/isExamed.png'
const router = useRouter()
const examStatus = ref<any>('')
const showPicker = ref<boolean>(false)
const examStatusNum = ref<number>(0)
const orderList = ref<any[]>([])
//
const isExamedList = ref<any[]>([])
const readyExamedList = ref<any[]>([])
const isCanceledList = ref<any[]>([])
// id
const readyExamId = ref<any>('')
const isExamedId = ref<any>('')
const isCanceledId = ref<any>('')
//
const upperStatus = ref<number>(4)
//
const columns = ref<any[]>([
{ text: '全部', value: 4 },
{ text: '已取消', value: 1 },
{ text: '待体检', value: 2 },
{ text: '已体检', value: 3 },
])
//
const onClickLeft = () => {
history.back()
}
//
const myPreForm = (res: any) => {
res.examStatus = examStatusNum.value
if (res.examStatus === 1) {
upperStatus.value = 1
} else if (res.examStatus === 2) {
upperStatus.value = 2
} else if (res.examStatus === 3) {
upperStatus.value = 3
} else if (res.examStatus === 4) {
upperStatus.value = 4
}
}
//
// typestartend
// dates0-112
/* const getNextWeekFirst = (type: any, dates = 0) => {
let now = new Date();
let nowTime = now.getTime();
let day = now.getDay();
let longTime = 24 * 60 * 60 * 1000;
let n = longTime * 7 * (dates || 0);
let dd
if (type == "start") {
dd = nowTime - (day - 1) * longTime + n;
};
if (type == "end") {
dd = nowTime + (7 - day) * longTime + n;
};
let trueDD = new Date(dd);
let y = trueDD.getFullYear();
let m = trueDD.getMonth() + 1;
let d = trueDD.getDate();
let trueM = m < 10 ? "0" + m : m;
let trueD = d < 10 ? "0" + d : d;
let trueDay = y + "-" + trueM + "-" + trueD;
return trueDay;
}; */
//
const cancel = () => {
showConfirmDialog({
title: '确认取消体检吗?',
width: '7rem'
}).then(() => {
cancelPort({
token: localStorage.getItem('token'),
cancelId: readyExamId.value
}).then((res: any) => {
console.log(res, '取消预约')
showToast({
message: '取消成功!',
icon: 'success',
duration: 1500,
onClose: () => {
history.go(0)
}
})
}).catch((err: any) => {
console.log(err)
})
}).catch(() => {
//
})
}
//
const seeReport = (
packageId: any,
packageName: any
) => {
router.push({
path: '/preOrderReceipt',
query: {
id: packageId,
combName: packageName
}
})
}
//
const onConfirm = (res: any) => {
showPicker.value = false
examStatus.value = res.selectedOptions[0].text
examStatusNum.value = res.selectedOptions[0].value
}
// 1 2 3
const fetchPreOrderInfo = () => {
getPreOrderInfo({
token: localStorage.getItem('token')
}).then((res: any) => {
console.log(res)
if (res.data.obj === 'isnull') {
showToast({
message: '未找到预约记录!',
icon: 'fail',
duration: 1500
})
} else {
console.log(res)
orderList.value = res.data.obj
for (let i = 0; i < res.data.obj.length; i++) {
if (Number(res.data.obj[i].ifCancel) === 1) {
isCanceledList.value.push(res.data.obj[i])
isCanceledId.value = res.data.obj[i].id
} else if (Number(res.data.obj[i].ifCancel) === 2) {
readyExamedList.value.push(res.data.obj[i])
readyExamId.value = res.data.obj[i].id
} else if (Number(res.data.obj[i].ifCancel) === 3) {
isExamedList.value.push(res.data.obj[i])
isExamedId.value = res.data.obj[i].id
}
}
}
}).catch((err: any) => {
console.log(err)
})
}
onMounted(() => {
fetchPreOrderInfo()
})
</script>
<style scoped lang="scss">
.my-form{
width: 96%;
height: 1rem;
margin: 0.2rem auto;
margin-bottom: 0.5rem;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: nowrap;
}
.tip{
width: 92%;
font-size: 16px;
box-sizing: border-box;
padding: 0.1rem;
margin: 0.3rem auto;
color: #9c9898;
}
.my-pre-area{
width: 94%;
margin: 0.1rem auto;
border-radius: 0.1rem;
box-sizing: border-box;
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
.swipe-container{
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
.lef{
width: 24%;
height: 2.4rem;
img{
position: absolute;
top: -51%;
left: -43%;
width: 150%;
height: 150%;
}
}
.rig{
width: 76%;
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 0.3rem 0.3rem 0.3rem 0;
margin-right: 0;
h1{
font-size: 18px;
font-weight: bold;
margin-bottom: 0.3rem;
}
h2{
width: 100%;
display: flex;
font-size: 16px;
justify-content: space-between;
margin-bottom: 0.3rem;
span{
color: red;
}
}
h3{
font-size: 14px;
}
}
}
}
</style>

View File

@ -0,0 +1,3 @@
/* :root:root{
--van-dialog-width: 500px
} */

View File

@ -0,0 +1,111 @@
<template>
<van-nav-bar
title="个人信息"
left-arrow
@click-left="onClickLeft"
/>
<div class="info-area">
<div class="name">
姓名
<span>{{ phyName }}</span>
</div>
<div>
身份证号
<span>{{ idcard }}</span>
</div>
<div>
年龄
<span>{{ age }}</span>
</div>
<div>
性别
<span>{{ sex }}</span>
</div>
<div>
联系方式
<span>{{ telepNumber }}</span>
</div>
<div>
部门
<span>{{ departName }}</span>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
import './scss/index.scss'
//
const phyName = localStorage.getItem('phyName')
const idcard = localStorage.getItem('idcard')
const age = localStorage.getItem('age')
const sex = localStorage.getItem('sex')
const telepNumber = localStorage.getItem('telepNumber')
const departName = localStorage.getItem('departName')
const onClickLeft = () => {
history.back()
}
onMounted(() => {
})
</script>
<style scoped lang="scss">
.status-bar{
width: 100%;
height: 48px;
}
.info-area{
width: 96%;
display: flex;
flex-direction: column;
margin: 1.5rem auto;
font-size: 16px;
div{
width: 100%;
height: 2rem;
font-size: 20px;
background-color: #fff;
margin-bottom: 0.08rem;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
padding: 0.1rem 0.4rem;
}
/* .avatar{
height: 1.5rem;
margin-bottom: 0.05rem;
}
.rig-area{
width: 20%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 0;
div{
width: 80%;
height: 100%;
padding: 0;
image {
width: 100%;
height: 100%;
}
}
}
.rig-area2{
width: 18%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 0;
} */
}
</style>

View File

@ -0,0 +1,3 @@
:root:root{
--van-nav-bar-background: #f8f8f8;
}

View File

@ -0,0 +1,128 @@
<template>
<van-nav-bar
title="体检预约单"
left-arrow
@click-left="onClickLeft"
/>
<div class="warn" v-if="showStatus === 1">暂无体检的相关信息</div>
<div class="receipt-area" v-if="showStatus === 0">
<h1>体检单据</h1>
<h2>套餐名称</h2>
<span>{{ packageName }}</span>
<h2>体检项目</h2>
<span v-for="(item, index) in receiptInfo" :key="index">
{{ item.mealName + ' ' }}
</span>
<h2>体检内容</h2>
<div class="meal-content" v-for="(item, index) in receiptInfo" :key="index">
<!-- <span>{{ item.mealContent }}</span>
<span>{{ item.mealPrice }}</span> -->
<div class="content">{{ item.mealName }}{{ item.mealContent }}</div>
<div class="meal-price">{{ item.mealPrice }}</div>
</div>
<h2 style="color: red;">体检总价{{ totalPrice }}</h2>
</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
import { ref, onMounted } from 'vue'
import { seePackage } from '../../api/PreOrderReceipt'
const route = useRoute()
const packageId = ref<any>('')
const packageName = ref<any>('')
const receiptInfo = ref<any[]>([])
const totalPrice = ref<number>(0)
const showStatus = ref<number>(0)
//
const onClickLeft = () => {
history.back()
}
//
const checkPackage = () => {
seePackage({
cancelId: packageId.value,
token: localStorage.getItem('token')
}).then((res: any) => {
console.log(res)
if (res.data.obj.length === 0) {
showStatus.value === 1
} else {
receiptInfo.value = res.data.obj
for (let i = 0; i < res.data.obj.length; i++) {
totalPrice.value += Number(res.data.obj[i].mealPrice)
}
}
}).catch((err: any) => {
console.log(err)
})
}
onMounted(() => {
console.log(route.query.id, route.query.combName)
packageId.value = route.query.id
packageName.value = route.query.combName
checkPackage()
})
</script>
<style scoped lang="scss">
.warn{
width: 85%;
margin: 1rem auto;
background-color: #fff;
box-sizing: border-box;
padding: 0.4rem;
border-radius: 0.2rem;
font-size: 24px;
text-align: center;
}
.receipt-area{
width: 85%;
margin: 1.5rem auto;
background-color: #fff;
box-sizing: border-box;
padding: 0.4rem;
border-radius: 0.2rem;
.meal-content{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
border-bottom: 1px dashed black;
box-sizing: border-box;
padding-bottom: 0.5rem;
}
h1{
width: 100%;
text-align: center;
font-size: 26px;
font-weight: bold;
margin-bottom: 0.6rem;
}
h2{
font-size: 20px;
margin: 0.4rem 0;
font-weight: bold;
}
.content{
width: 80%;
font-size: 18px;
line-height: 26px;
}
span{
font-size: 18px;
line-height: 26px;
}
.meal-price{
font-size: 18px;
text-align: right;
color: red;
}
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<van-nav-bar
title="体检预约"
/>
<div class="succeedImg">
<img :src="succeedImg" alt="">
</div>
<h2 class="tit">恭喜您预约成功</h2>
<div class="btns-area">
<van-button
type="primary"
style="width: 45%; margin-bottom: 0.3rem; border-radius: 1rem; font-size: 18px; background-color: #fff; border-color: #1989fa; color: #1989fa;"
@click="jumpHome"
>返回首页
</van-button>
<van-button
type="primary"
style="width: 45%; border-radius: 1rem; font-size: 18px;"
@click="jumpReceipt"
>查看预约
</van-button>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import succeedImg from '../../static/preOrderSucceed.png'
const route = useRoute()
const router = useRouter()
const packageId = ref<any>('')
//
const jumpHome = () => {
router.replace({
path: '/home'
})
}
//
const jumpReceipt = () => {
router.push({
path: '/myPreOrder',
})
}
onMounted(() => {
console.log(route.query.id)
packageId.value = route.query.id
})
</script>
<style scoped lang="scss">
.succeedImg{
width: 80%;
margin: 5rem auto;
margin-bottom: 0.5rem;
img{
width: 100%;
height: 100%;
}
}
.tit{
width: 100%;
text-align: center;
font-size: 20px;
font-weight: bold;
}
.btns-area{
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 3rem auto;
}
</style>

215
src/views/User/User.vue Normal file
View File

@ -0,0 +1,215 @@
<template>
<div>
<div class="bg"></div>
<div class="avatar-area">
<!-- 选择头像 -->
<van-uploader
:after-read="afterRead"
:max-count="1"
v-model="fileList"
:reupload="true"
:deletable="false"
readonly
/>
</div>
<h2 class="user-name">{{ userInfo.phyName }}</h2>
<div class="user-tap">
<!-- <div class="warn-area">
<van-notice-bar
style="width: 100%; border-radius: 0.1rem;"
left-icon="volume-o"
scrollable
speed="100"
text="您好您在2023年5月1日的体检中有异常项具体请查看体检报告..."
/>
</div> -->
<div class="taps">
<div @click="jumpPersonInfo()">
<div>
<img src="../../static/perInfo.png" alt="">
</div>
<span>个人信息</span>
</div>
<div @click="jumpMsgNotice()">
<div>
<img src="../../static/notice.png" alt="">
</div>
<span>消息通知</span>
</div>
<div @click="exitLogin()">
<div>
<img src="../../static/exit.png" alt="">
</div>
<span>退出登录</span>
</div>
</div>
</div>
<TabBar/>
</div>
</template>
<script setup lang="ts">
import './scss/index.scss'
import TabBar from '../../components/TabBar.vue';
import { getUserInfo } from '../../api/user.js'
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { showConfirmDialog } from 'vant';
const router = useRouter()
const userInfo = ref<any>({})
//
const fileList = ref<any[]>([
{ url: localStorage.getItem('avatarUrl') }
])
const afterRead = (file: any) => {
console.log(file)
}
//
const jumpPersonInfo = () => {
router.push({
path: '/personalInfo'
})
}
//
const jumpMsgNotice = () => {
router.push({
path: '/msgNotice'
})
}
// 退
const exitLogin = () => {
showConfirmDialog({
title: '确认退出登录吗?',
width: '7rem'
}).then(() => {
// confirm
localStorage.removeItem('token')
// 退cookie
const delCookie = new Date().getTime() - 8 * 60 * 60 * 1000
document.cookie = `loginStatus=0;expires=${new Date(delCookie)}`
history.go(0)
}).catch(() => {
// cancel
})
}
onMounted(() => {
getUserInfo({
token: localStorage.getItem('token')
}).then((res: any) => {
userInfo.value = res.data.obj[0]
const data = res.data.obj[0]
localStorage.setItem('phyName', data.phyName)
localStorage.setItem('idcard', data.idcard)
localStorage.setItem('age', data.age)
localStorage.setItem('telepNumber', data.telepNumber)
localStorage.setItem('departName', data.departName)
if (Number(data.sex) === 1) {
localStorage.setItem('sex', '女')
} else if (Number(data.sex) === 0) {
localStorage.setItem('sex', '男')
}
console.log(userInfo.value)
}).catch((err: any) => {
console.log(err)
})
})
</script>
<style scoped lang="scss">
.bg{
width: 10rem;
height: 8rem;
background-color: #008080;
position: absolute;
left: 0;
top: 0;
}
.avatar-area{
width: 100%;
height: 6rem;
padding-top: 2rem;
display: flex;
justify-content: center;
margin-bottom: 0.6rem;
}
.user-name{
width: 100%;
margin-top: 0.6rem;
height: 0.5rem;
display: flex;
color: #fff;
justify-content: center;
font-size: 22px;
margin-bottom: 1.2rem;
}
.user-tap{
width: 96%;
background-color: #fff;
margin: 0.4rem auto;
box-sizing: border-box;
padding: 0.2rem;
border-radius: 0.1rem;
.warn-area{
width: 100%;
height: 1rem;
line-height: 100%;
display: flex;
align-items: center;
.img-area{
width: 12%;
height: 100%;
display: flex;
img{
margin: auto;
width: 90%;
height: 90%;
}
}
span{
padding-left: 0.15rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.taps{
width: 100%;
display: flex;
flex-direction: column;
margin-top: 0.1rem;
div{
width: 100%;
height: 1rem;
margin: 0.1rem;
border-bottom: 1px solid #f2f2f2;
display: flex;
justify-content: left;
align-items: center;
div{
width: 12%;
height: 100%;
display: flex;
border: none;
img{
margin: auto;
width: 50%;
height: 60%;
}
}
span{
font-size: 16px;
}
}
div:nth-child(3){
border: none;
}
}
}
</style>

View File

@ -0,0 +1,3 @@
:root:root{
--van-uploader-size: 4rem;
}

1
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

25
tsconfig.json Normal file
View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/plugins/mitt.js", "src/plugins/mitt.js", "src/plugins/mitt.js", "src/plugins/mitt.js"],
"references": [{ "path": "./tsconfig.node.json" }]
}

10
tsconfig.node.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

37
vite.config.ts Normal file
View File

@ -0,0 +1,37 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import postCssPxToRem from 'postcss-pxtorem'
import vueSetupExtend from 'vite-plugin-vue-setup-extend'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
base: './',
publicDir: 'assets',
plugins: [vue(), vueSetupExtend(), Components({
resolvers: [VantResolver()],
})],
css: {
postcss: {
plugins: [
postCssPxToRem({
rootValue: 40,
propList: ['*']
})
]
}
},
server: {
host: '0.0.0.0',
port: 1234,
open: true,
proxy: {
'/AppPeaManager': {
target: 'http://192.168.0.14:18087',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/AppPeaManager/, '/AppPeaManager')
}
}
}
})