尚医通是一个网上预约挂号系统,包含后台管理系统和前台用户系统,采用前后端分离开发模式。
尚医通是采用Vue3全家桶、TypeScript、Vite、Pinia、Element-plus等技术栈开发的在线医疗服务平台,集成了多家医院的挂号信息,提供全程跟踪服务,用户可以随时了解自己的挂号状态。
前端整体功能,已经学习完了,功能均已实现,在这里记录一下技术重点.....
一、接口
服务器地址:syt.atguigu.cn
医院接口:http://139.198.34.216:8201/swagger-ui.html
公共数据接口: http://139.198.34.216:8202/swagger-ui.html
会员接口:http://139.198.34.216:8203/swagger-ui.html
短信验证码接口:http://139.198.34.216:8204/swagger-ui.html
订单接口:http://139.198.34.216:8206/swagger-ui.html
文件上传接口:http://139.198.34.216:8205/swagger-ui.html
后台用户接口:http://139.198.34.216:8212/swagger-ui.html
二、项目其他配置
2.1 浏览器自动打开 找到 package.json 配置文件!
"scripts": {
"dev": "vite --open",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
2.2src 别名的配置
找到 vite.config.ts 配置文件。 如果红色语法提示请安装@types/node 是 TypeScript 的一个声明文件包,用于描述 Node.js 核心模块和常用的第三方库的类型信息
安装这份
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve(__dirname, 'src')
}
}
})
找到 tsconfig.json 配置文件,找到配置项 compilerOptions 添加配置,这一步的作用是让 IDE 可以对路径进行智能提示
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
//微信开放平台官网地址 open.weixin.qq.com
//查看微信扫码登录文档 mp.weixin.qq.com/
项目当中全部路由:、 用户未登录可以访问的路由 /home /hospital/register /hospital/detail /hospital/notice /hospital/close / hospital/search 剩下其余的路由未登录不能访问的,如果用户登录了全部的路由都是可以访问的
引入清除默认样式
三、顶部、底部静态页面搭建
页面展示
App.vue
<template>
<div class="container">
<!-- 顶部全局组件 -->
<HospitalTop />
<!-- 展示路由组件的区域 -->
<div class="content">展示路由组件的区域</div>
<!-- 底部全局组件 -->
<HospitalBottom />
</div>
</template>
<script setup lang="ts"></script>
<style scoped lang="scss">
.container {
display: flex;
/* 切换主轴方向 */
flex-direction: column;
/* justify-content: center; */
align-items: center;
.content {
margin-top: 70px;
width: 1200px;
min-height: 700px;
}
}
</style>
hospital_top.vue
<template>
<div class="top">
<div class="content">
<!-- 左侧 -->
<div class="left">
<img src="../../assets/images/logo.png" alt="" />
<p>尚医通 预约挂号统一平台</p>
</div>
<!-- 右侧 -->
<div class="right">
<div class="help">帮助中心</div>
<div class="login">登录/注册</div>
</div>
</div>
</div>
</template>
<script setup lang="ts"></script>
<style scoped lang="scss">
.top {
/* 固定到顶部 */
position: fixed;
/* 层级 */
z-index: 999;
width: 100%;
height: 70px;
background: #fff;
display: flex;
/* 主轴上居中 */
justify-content: center;
.content {
width: 1200px;
height: 70px;
background: white;
display: flex;
justify-content: space-between;
.left {
display: flex;
/* 主轴侧轴都居中 */
justify-content: center;
align-items: center;
img {
width: 50px;
height: 50px;
margin-right: 10px;
}
p {
font-size: 20px;
color: #55a6fe;
}
}
.right {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #bbb;
.help {
margin-right: 10px;
}
}
}
}
</style>
hospital_bottom.vue
<template>
<div class="bottom">
<div class="contont">
<div class="left">蜀ICP备2021007923号</div>
<div class="right">
<span> 联系我们 </span>
<span>合作伙伴</span>
<span>隐私协议</span>
<span>用户协议</span>
</div>
</div>
</div>
</template>
<script setup lang="ts"></script>
<style scoped lang="scss">
.bottom {
width: 100%;
height: 50px;
background-color: #f0f2f5;
display: flex;
justify-content: center;
.contont {
width: 1200px;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
.right {
span {
margin: 0px 5px;
}
}
}
}
</style>
四、路由配置
1.1目录
1.2路由index文件
import { createRouter, createWebHistory } from "vue-router";
// createApp方法,用于创建路由器实例,可以管理多个路由
export default createRouter({
// 路由模式的设置
history: createWebHistory(),
// 管理路由
routes: [
{
path: "/home",
// 路由懒加载模式
component: () => import("@/pages/home/index.vue"),
},
{
path: "/hospital",
component: () => import("@/pages/hospital/index.vue"),
},
{
path: "/",
// 路由重定向到home
redirect: "/home",
},
],
// 滚动行为:控制滚动条的位置
scrollBehavior() {
return {
left: 0,
top: 0,
};
},
});
1.3 路由出口
五、首页静态搭建banner
element-plus 的使用
搜索组件
效果图
六、首页等级与地区组件拆分与静态搭建
level/index.vue
<template>
<div class="level">
<h1>医院</h1>
<div class="content">
<div class="left">等级:</div>
<ul class="hospital">
<li class="active">全部</li>
<li>三级甲等</li>
<li>三级甲等</li>
<li>三级甲等</li>
<li>三级甲等</li>
<li>三级甲等</li>
<li>三级甲等</li>
<li>三级甲等</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts"></script>
<style scoped lang="scss">
.level {
color: #7f7f7f;
h1 {
font-weight: 900;
margin: 10px 0px;
}
.content {
display: flex;
.left {
margin-right: 10px;
}
.hospital {
display: flex;
li {
margin-right: 10px;
&.active {
color: #55a6fe;
}
}
/* 鼠标进经过时变色 */
li:hover {
color: #55a6fe;
/* 鼠标经过时出现小手 */
cursor: pointer;
}
}
}
}
</style>
region/index.vue
<template>
<div class="region">
<div class="content">
<div class="left">地区:</div>
<ul>
<li class="active">全部</li>
<li>昌平区</li>
<li>昌平区</li>
<li>昌平区</li>
<li v-for="item in 20" :key="item">昌平区</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts"></script>
<style scoped lang="scss">
.region {
color: #7f7f7f;
margin-top: 10px;
.content {
display: flex;
.left {
margin-right: 10px;
width: 50px;
}
ul {
display: flex;
flex-wrap: wrap;
li {
margin-right: 10px;
margin-bottom: 10px;
&.active {
color: #55a6fe;
}
}
li:hover {
color: #55a6fe;
/* 鼠标经过时出现小手 */
cursor: pointer;
}
}
}
}
</style>
七、分页搭建
八、网络axios二次封装
utils/request.ts
// 对于axios 函数库进行二次封装
// 你工作的时候是否axios进行二次封装?二次封装的目的是什么?
// 目的1:利用axios请求、响应拦截器功能
// 目的2:请求拦截器,一般可以在请求头中携带公共的参数:token
// 目的3:响应拦截器,可以简化服务器返回的数据,处理http网络错误
import axios from "axios";
import { ElMessage } from "element-plus";
// 利用axios.create方法创建一个axios实例:可以设置基础路径、超时的时间的设置
const request = axios.create({
baseURL: "/api", //请求的基础路径的设置
timeout: 5000, //超时时间的设置,超出5秒请求就失败
});
// 请求拦截器
request.interceptors.request.use((config) => {
// config :请求拦截器回调注入的对象(配置对象),p配置对象的身上最重要的一件事情headers属性
// k可以通过请求头携带公共参数-token
return config;
});
// 响应拦截器
request.interceptors.response.use(
(response) => {
// 响应拦截器成功地回调,一般会进行简化
return response;
},
(error) => {
// 处理http网络错误
let status = error.response.status;
switch (status) {
case 404:
// 错误提示信息
ElMessage({
type: "error",
// message: error.message,
message: "请求失败路径,出现问题",
});
break;
case 401:
// 错误提示信息
ElMessage({
type: "error",
// message: error.message,
message: "参数有误",
});
break;
case 500 | 501 | 502 | 503 | 504 | 505:
// 错误提示信息
ElMessage({
type: "error",
// message: error.message,
message: "服务器挂了",
});
break;
}
return Promise.reject(new Error(error.message));
}
);
// 务必对外暴露axios
export default request;
九、配置代理跨域
十、分页及获取数据的实现
10.1 获取数据接口配置
// 统一管理首页模块接口
import request from "@/utils/request";
// 通过枚举管理首页模块的接口地址
enum API {
// 获取已有的医院的是数据接口地址
HOSPITAL_URL = "/hosp/hospital/",
}
// 获取医院的数据
export const reqHospital = (page: number, limit: number) =>
request.get(API.HOSPITAL_URL + `${page}/${limit}`);
10.2 获取首页数据
10. 分页功能
十一、等级和区域展示
11.1等级及高亮展示
接口类型
11.2获取等级数据
11.3获取医院地区数据
高亮显示
11.4首页根据等级与地区筛选医院展示
给组件绑定事件
暂无数据
十二、首页根据关键字搜索医院及路由简单跳转
接口ts类型
数据接口
绑定事件
当用户搜索关键字时,会出现推荐数据项
因为官方文档中写的是需要返回value值,所以就弄了一个showData函数,让其返回一个对象(对象的话就会有吧value值)
路由跳转三步走
十三、首页常见科室搭建
十四、医院详情菜单与子路由
建五个文件
路由菜单
点击这些组件就会进行跳转
点击搜索框的推荐数据,也会进行跳转到详情页
十五、Pinia仓库存储医院详情数据
pnpm i pinia@2.1.3(注意不要安装最新版,否则会有冲突报错)
拿数据->取数据->存数据
十六、预约挂号业务1
base64码转图片
data:image/jpeg;base64,
<img :src="`data:image/jpeg;base64,`+hospitalStore.hospitalInfo.hospital?.logoData" alt=""/>
16.2、医院详情业务
<template>
<div class="detail">
<!-- 医院名字与等级 -->
<div class="top">
<div class="name">{{ hospitalStore.hospitalInfo.hospital?.hosname }}</div>
<div class="level">
<svg
t="1688813652495"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="9729"
width="16"
height="16"
>
<path
d="M939.358251 423.424662c-23.01825-37.252439-62.924121-60.779272-107.019409-63.209624-2.755764-0.38681-5.510504-0.579191-8.347109-0.579191l-152.202471-0.121773c6.649444-28.975938 10.015098-58.653865 10.015098-88.657202 0-28.223808-3.213181-57.139372-9.556657-85.952604-0.447185-2.043542-1.098008-4.006244-1.932002-5.866614-15.820314-57.302077-67.37755-96.841605-127.282918-96.841605-72.827679 0-132.081201 59.254545-132.081201 132.081201 0 3.334955 0.132006 6.66991 0.406253 10.015098-2.196015 57.211003-32.108279 109.947088-80.269162 141.363611-14.447037 9.42465-18.524912 28.773324-9.099239 43.220361 9.414417 14.437827 28.752858 18.535145 43.220361 9.099239 65.811892-42.925648 106.429984-115.325585 108.656699-193.684234 0.030699-1.332345-0.010233-2.663666-0.14224-3.996011-0.203638-2.012843-0.304945-4.016477-0.304945-6.019087 0-38.381146 31.233352-69.614497 69.614497-69.614497 32.57593 0 60.474326 22.204721 67.824735 53.997821 0.356111 1.534959 0.823761 3.019777 1.402953 4.453429 4.696975 22.814612 7.076162 45.579081 7.076162 67.743894 0 37.485753-6.222725 74.352405-18.494213 109.592001-3.324722 9.546424-1.819438 20.111037 4.02671 28.345582 5.856381 8.245801 15.332197 13.146415 25.448602 13.156648l193.226816 0.101307c1.423419 0.264013 2.857071 0.426719 4.300956 0.477884 24.116257 0.9967 45.935192 13.614066 58.603723 34.090423 7.838525 12.31242 11.438517 26.800389 10.431583 41.939181-0.080841 0.945535-0.121773 1.911536-0.11154 2.877537 0 0.854461 0.040932 1.697665 0.11154 2.53166 0.010233 0.335644-0.030699 0.661056-0.11154 0.976234-0.101307 0.376577-0.193405 0.772596-0.284479 1.159406l-74.972529 330.391802c-0.914836 1.281179-1.738597 2.6432-2.449795 4.046153-5.937223 11.762905-14.660908 21.48329-25.346271 28.172643-10.746762 6.812149-23.059182 10.614755-35.757388 11.06194-0.854461-0.061398-513.766226-0.224104-513.766226-0.224104-0.467651-0.020466-0.935302-0.030699-1.402953-0.030699 0 0-111.01542 0.172939-112.718201 0.457418-1.932002 0-3.446495-1.50426-3.446495-3.415796l0.299829-416.334173c0-1.901303 1.545192-3.446495 3.01466-3.456728l1.245364 0.121773c1.174756 0.132006 2.653433 0.284479 3.52836 0.193405l83.82822-0.222057 0 339.367221c0 17.253966 13.979386 31.233352 31.233352 31.233352s31.233352-13.979386 31.233352-31.233352L281.009092 435.350273c0-1.778506 0-8.631588 0-10.411117 0-17.253966-13.979386-30.928407-31.233352-30.928407-1.50426 0-117.547183 0.304945-119.402437 0.304945-36.34272 0-65.913199 29.566386-65.913199 65.893756l-0.299829 416.334173c0 36.337603 29.571503 65.902966 65.913199 65.902966 2.541893 0 111.406323-0.457418 111.406323-0.457418 0.457418 0.020466 0.925069 0.030699 1.382487 0.030699 0 0 511.458671 0.274246 512.505513 0.274246 25.469068 0 50.296523-7.197936 71.647807-20.73116 19.612687-12.281721 35.777855-29.881564 46.839795-50.967812 3.660366-5.622044 6.435573-11.875468 8.256034-18.615986 0.11154-0.416486 0.213871-0.823761 0.304945-1.240247l74.881454-330.340637c1.596358-6.212492 2.257413-12.586666 2.00261-18.992563C960.892707 473.366098 953.948551 446.331371 939.358251 423.424662z"
fill="#d81e06"
p-id="9730"
></path>
<path
d="M450.027553 518.650467c-17.253966 0-31.233352 13.979386-31.233352 31.233352l0 30.470989c0 17.253966 13.979386 31.233352 31.233352 31.233352 17.253966 0 31.233352-13.979386 31.233352-31.233352l0-30.470989C481.260905 532.629853 467.281519 518.650467 450.027553 518.650467z"
fill="#d81e06"
p-id="9731"
></path>
<path
d="M693.805696 518.650467c-17.253966 0-31.233352 13.979386-31.233352 31.233352l0 30.470989c0 17.253966 13.979386 31.233352 31.233352 31.233352 17.253966 0 31.233352-13.979386 31.233352-31.233352l0-30.470989C725.039048 532.629853 711.058638 518.650467 693.805696 518.650467z"
fill="#d81e06"
p-id="9732"
></path>
<path
d="M648.940882 660.09492c-14.304797-9.393951-33.592073-5.398964-43.159986 8.763594-0.132006 0.193405-13.614066 19.754926-34.171264 19.754926-19.98824 0-32.423457-18.09717-33.266661-19.368116-9.17087-14.427594-28.254507-18.809391-42.834574-9.770528-14.650675 9.109472-19.155269 28.366048-10.055007 43.016723 11.214413 18.047028 41.96988 48.588625 86.156242 48.588625 43.962258 0 75.104535-30.318516 86.572728-48.222281C667.404396 688.461991 663.216004 669.500127 648.940882 660.09492z"
fill="#d81e06"
p-id="9733"
></path>
</svg>
<span>{{
hospitalStore.hospitalInfo.hospital?.param.hostypeString
}}</span>
</div>
</div>
<!-- 医院logo与路线 -->
<div class="logo">
<div class="left">
<img
:src="
`data:image/jpeg;base64,` +
hospitalStore.hospitalInfo.hospital?.logoData
"
alt=""
/>
</div>
<div class="right">
<div class="address">
<svg
t="1688828004474"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="10870"
width="16"
height="16"
>
<path
d="M512 512a136.533333 136.533333 0 1 1 136.533333-136.533333 136.533333 136.533333 0 0 1-136.533333 136.533333z m0-219.272533a81.92 81.92 0 1 0 81.92 81.92 81.92 81.92 0 0 0-81.92-81.92z"
fill="#0073FF"
p-id="10871"
></path>
<path
d="M512 831.214933a27.306667 27.306667 0 0 1-19.2512-8.055466l-214.493867-214.357334a330.5472 330.5472 0 1 1 467.490134 0l-214.357334 214.357334a27.306667 27.306667 0 0 1-19.387733 8.055466z m0-732.091733a275.933867 275.933867 0 0 0-195.106133 471.04L512 765.269333l195.106133-195.106133A275.933867 275.933867 0 0 0 512 99.1232z"
fill="#0073FF"
p-id="10872"
></path>
<path
d="M514.321067 979.490133c-147.456 0-306.107733-37.000533-306.107734-118.3744 0-45.602133 51.746133-81.92 145.681067-102.4a27.306667 27.306667 0 1 1 11.605333 53.384534c-78.370133 17.066667-102.673067 41.915733-102.673066 49.015466 0 18.432 88.064 63.761067 251.4944 63.761067s251.4944-45.192533 251.4944-63.761067c0-7.3728-25.258667-32.768-106.496-49.834666a27.306667 27.306667 0 1 1 11.195733-53.384534c96.6656 20.343467 150.186667 56.9344 150.186667 103.2192-0.273067 80.964267-158.9248 118.3744-306.3808 118.3744z"
fill="#0073FF"
p-id="10873"
></path>
</svg>
<span
>具体位置:{{
hospitalStore.hospitalInfo.hospital?.param?.fullAddress
}}</span
>
</div>
<div class="route">
规划路线:{{ hospitalStore.hospitalInfo.hospital?.route }}
</div>
</div>
</div>
<!-- 医院的介绍 -->
<div class="footer">
<h1>医院介绍</h1>
<p>
{{ hospitalStore.hospitalInfo.hospital?.intro }}
</p>
</div>
</div>
</template>
<script setup lang="ts">
// 获取医院详情仓库数据进行展示
import useDetailStore from "@/store/modules/hospitalDetail";
let hospitalStore = useDetailStore();
</script>
<style scoped lang="scss">
.detail {
.top {
display: flex;
align-items: center;
.name {
font-size: 30px;
font-weight: 900;
}
.level {
color: #7f7f7f;
margin-left: 10px;
span {
margin-left: 5px;
}
}
}
.logo {
display: flex;
margin: 10px 0px;
.left {
img {
width: 80px;
height: 80px;
border-radius: 50px;
}
}
.right {
color: #7f7f7f;
margin-left: 10px;
div {
margin: 10px 0px;
}
}
}
.footer {
color: #7f7f7f;
p {
margin-top: 10px;
line-height: 30px;
}
}
}
</style>
16.3 小bug
第一次进去本来是能够显示的,而且带有编号,但是但切换菜单时,编号就消失了
16.4做科室时遇见的错误
错误原因:在箭头后面加对象符号{},但是却没有return 回去,导致打印出来的result是undefine。
解决办法:1、不加{},因为箭头函数如果只有一行表达式,可以不加括号,箭头函数自带return。 2、 或者在箭头后面加{return xxxxx},不要忘记return,不然会出现错误
16.5、医院科室业务
效果
左侧导航栏及高亮效果
右侧信息及点击哪个导航就定位到对应的科室
完整代码:
<template>
<div class="register">
<div class="top">
<div class="title">
{{ hospitalStore.hospitalInfo.hospital?.hosname }}
</div>
<div class="level">
<svg
t="1688813652495"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="9729"
width="16"
height="16"
>
<path
d="M939.358251 423.424662c-23.01825-37.252439-62.924121-60.779272-107.019409-63.209624-2.755764-0.38681-5.510504-0.579191-8.347109-0.579191l-152.202471-0.121773c6.649444-28.975938 10.015098-58.653865 10.015098-88.657202 0-28.223808-3.213181-57.139372-9.556657-85.952604-0.447185-2.043542-1.098008-4.006244-1.932002-5.866614-15.820314-57.302077-67.37755-96.841605-127.282918-96.841605-72.827679 0-132.081201 59.254545-132.081201 132.081201 0 3.334955 0.132006 6.66991 0.406253 10.015098-2.196015 57.211003-32.108279 109.947088-80.269162 141.363611-14.447037 9.42465-18.524912 28.773324-9.099239 43.220361 9.414417 14.437827 28.752858 18.535145 43.220361 9.099239 65.811892-42.925648 106.429984-115.325585 108.656699-193.684234 0.030699-1.332345-0.010233-2.663666-0.14224-3.996011-0.203638-2.012843-0.304945-4.016477-0.304945-6.019087 0-38.381146 31.233352-69.614497 69.614497-69.614497 32.57593 0 60.474326 22.204721 67.824735 53.997821 0.356111 1.534959 0.823761 3.019777 1.402953 4.453429 4.696975 22.814612 7.076162 45.579081 7.076162 67.743894 0 37.485753-6.222725 74.352405-18.494213 109.592001-3.324722 9.546424-1.819438 20.111037 4.02671 28.345582 5.856381 8.245801 15.332197 13.146415 25.448602 13.156648l193.226816 0.101307c1.423419 0.264013 2.857071 0.426719 4.300956 0.477884 24.116257 0.9967 45.935192 13.614066 58.603723 34.090423 7.838525 12.31242 11.438517 26.800389 10.431583 41.939181-0.080841 0.945535-0.121773 1.911536-0.11154 2.877537 0 0.854461 0.040932 1.697665 0.11154 2.53166 0.010233 0.335644-0.030699 0.661056-0.11154 0.976234-0.101307 0.376577-0.193405 0.772596-0.284479 1.159406l-74.972529 330.391802c-0.914836 1.281179-1.738597 2.6432-2.449795 4.046153-5.937223 11.762905-14.660908 21.48329-25.346271 28.172643-10.746762 6.812149-23.059182 10.614755-35.757388 11.06194-0.854461-0.061398-513.766226-0.224104-513.766226-0.224104-0.467651-0.020466-0.935302-0.030699-1.402953-0.030699 0 0-111.01542 0.172939-112.718201 0.457418-1.932002 0-3.446495-1.50426-3.446495-3.415796l0.299829-416.334173c0-1.901303 1.545192-3.446495 3.01466-3.456728l1.245364 0.121773c1.174756 0.132006 2.653433 0.284479 3.52836 0.193405l83.82822-0.222057 0 339.367221c0 17.253966 13.979386 31.233352 31.233352 31.233352s31.233352-13.979386 31.233352-31.233352L281.009092 435.350273c0-1.778506 0-8.631588 0-10.411117 0-17.253966-13.979386-30.928407-31.233352-30.928407-1.50426 0-117.547183 0.304945-119.402437 0.304945-36.34272 0-65.913199 29.566386-65.913199 65.893756l-0.299829 416.334173c0 36.337603 29.571503 65.902966 65.913199 65.902966 2.541893 0 111.406323-0.457418 111.406323-0.457418 0.457418 0.020466 0.925069 0.030699 1.382487 0.030699 0 0 511.458671 0.274246 512.505513 0.274246 25.469068 0 50.296523-7.197936 71.647807-20.73116 19.612687-12.281721 35.777855-29.881564 46.839795-50.967812 3.660366-5.622044 6.435573-11.875468 8.256034-18.615986 0.11154-0.416486 0.213871-0.823761 0.304945-1.240247l74.881454-330.340637c1.596358-6.212492 2.257413-12.586666 2.00261-18.992563C960.892707 473.366098 953.948551 446.331371 939.358251 423.424662z"
fill="#d81e06"
p-id="9730"
></path>
<path
d="M450.027553 518.650467c-17.253966 0-31.233352 13.979386-31.233352 31.233352l0 30.470989c0 17.253966 13.979386 31.233352 31.233352 31.233352 17.253966 0 31.233352-13.979386 31.233352-31.233352l0-30.470989C481.260905 532.629853 467.281519 518.650467 450.027553 518.650467z"
fill="#d81e06"
p-id="9731"
></path>
<path
d="M693.805696 518.650467c-17.253966 0-31.233352 13.979386-31.233352 31.233352l0 30.470989c0 17.253966 13.979386 31.233352 31.233352 31.233352 17.253966 0 31.233352-13.979386 31.233352-31.233352l0-30.470989C725.039048 532.629853 711.058638 518.650467 693.805696 518.650467z"
fill="#d81e06"
p-id="9732"
></path>
<path
d="M648.940882 660.09492c-14.304797-9.393951-33.592073-5.398964-43.159986 8.763594-0.132006 0.193405-13.614066 19.754926-34.171264 19.754926-19.98824 0-32.423457-18.09717-33.266661-19.368116-9.17087-14.427594-28.254507-18.809391-42.834574-9.770528-14.650675 9.109472-19.155269 28.366048-10.055007 43.016723 11.214413 18.047028 41.96988 48.588625 86.156242 48.588625 43.962258 0 75.104535-30.318516 86.572728-48.222281C667.404396 688.461991 663.216004 669.500127 648.940882 660.09492z"
fill="#d81e06"
p-id="9733"
></path>
</svg>
<span>{{
hospitalStore.hospitalInfo.hospital?.param.hostypeString
}}</span>
</div>
</div>
<!-- 展示内容的区域 -->
<div class="content">
<div class="left">
<img
:src="
`data:image/jpeg;base64,` +
hospitalStore.hospitalInfo.hospital?.logoData
"
alt=""
/>
</div>
<div class="right">
<div>挂号规则</div>
<div class="time">
预约周期:10天 放号时间:{{
hospitalStore.hospitalInfo.bookingRule?.releaseTime
}}
停挂时间:{{ hospitalStore.hospitalInfo.bookingRule?.stopTime }}
</div>
<div class="address">
具体位置:{{ hospitalStore.hospitalInfo.hospital?.param.fullAddress }}
</div>
<div class="route">
规划路线:{{ hospitalStore.hospitalInfo.hospital?.route }}
</div>
<div class="releasetime">
退号时间:就诊前一工作日{{
hospitalStore.hospitalInfo.bookingRule?.quitTime
}}前取消
</div>
<div class="rule">预约挂号规则</div>
<div
class="ruleInfo"
v-for="(item, index) in hospitalStore.hospitalInfo.bookingRule?.rule"
:key="index"
>
{{ item }}
</div>
</div>
</div>
<!-- 放置每一个医院的科室数据 -->
<div class="deparment">
<div class="leftNav">
<ul>
<li
v-for="(deparment, index) in hospitalStore.deparmentArr"
:class="{ active: index == currentIndex }"
@click="changeIndex(index)"
:key="deparment.depcode"
>
{{ deparment.depname }}
</li>
</ul>
</div>
<div class="deparmentInfo">
<!-- 用一个div代表:大科室与小科室 -->
<div
class="showDeparment"
v-for="deparment in hospitalStore.deparmentArr"
:key="deparment.depcode"
>
<h1 class="cur">{{ deparment.depname }}</h1>
<!-- 每一个大的科室下小科室 -->
<ul>
<li v-for="item in deparment.children" :key="item.depcode">
{{ item.depname }}
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
// 引入医院详情仓库的数据
import useDetailStore from "@/store/modules/hospitalDetail";
let hospitalStore = useDetailStore();
// 控制科室高亮的响应式数据
let currentIndex = ref<number>(0);
// 左侧大的科室点击的事件
const changeIndex = (index: number) => {
currentIndex.value = index;
// 点击导航获取右侧科室(大的科室好标题)
let allH1 = document.querySelectorAll(".cur");
// console.log(allH1);
// 滚动到对应科室的位置
allH1[currentIndex.value].scrollIntoView({
behavior: "smooth",//过渡动画效果
block:'start',//滚动到的位置,默认是起始位置
});
};
</script>
<style scoped lang="scss">
.register {
.top {
display: flex;
.title {
font-size: 30px;
font-weight: 900;
}
.level {
color: #7f7f7f;
margin-left: 10px;
/* 文字居中 */
height: 40px;
text-align: center;
line-height: 40px;
span {
margin-left: 5px;
}
}
}
.content {
display: flex;
margin-top: 20px;
.left {
width: 80px;
img {
width: 80px;
height: 80px;
boder-radius: 50%;
}
}
.right {
/* 左边占了80px,剩下的空间给右边 */
flex: 1;
font-size: 14px;
margin-left: 20px;
.time,
.route,
.address,
.releasetime,
.ruleInfo {
margin-top: 10px;
color: #7f7f7f;
}
.rule {
margin: 10px 0;
}
}
}
.deparment {
width: 100%;
height: 500px;
display: flex;
margin-top: 20px;
/* background: pink; */
.leftNav {
width: 80px;
height: 100%;
ul {
width: 100%;
height: 100%;
background: rgb(248, 248, 248);
display: flex;
flex-direction: column;
li {
flex: 1;
text-align: center;
color: #7f7f7f;
font-size: 14px;
line-height: 30px;
/* 高亮效果 */
&.active {
border-left: 1px solid red;
color: red;
background: white;
}
}
}
}
.deparmentInfo {
/* 除了 leftNav占了80px,其他都是deparmentInfo*/
flex: 1;
margin-left: 20px;
height: 100%;
overflow: auto;
/* 清除滚动条 */
&::-webkit-scrollbar {
display: none;
}
.showDeparment {
h1 {
background: rgb(248, 248, 248);
color: #7f7f7f;
}
ul {
display: flex;
flex-wrap: wrap;
li {
width: 33%;
color: #7f7f7f;
line-height: 30px;
}
}
}
}
}
}
</style>
16.6、登录静态搭建
注册为全局组件main.ts
完整代码
<template>
<div class="login-container">
<!-- title:对话框左上角的标题 v-model :控制对话框的显示与隐藏 -->
<el-dialog v-model="userStore.visiable" title="用户登录">
<!-- 对话框身体部分结构 -->
<div class="content">
<el-row>
<!-- 左侧结构:收集号码登录、微信扫一扫登录 -->
<el-col :span="12">
<div class="login">
<div v-show="scene == 0">
<el-form>
<el-form-item>
<el-input
placeholder="请你输入手机号码"
:prefix-icon="User"
></el-input>
</el-form-item>
<el-form-item>
<el-input
placeholder="请你输入手机验证码"
:prefix-icon="Lock"
></el-input>
</el-form-item>
<el-form-item>
<el-button>获取验证码</el-button>
</el-form-item>
</el-form>
<el-button type="primary" style="width: 100%"
>用户登陆</el-button
>
<div class="bottom" @click="changeScene">
<p>微信扫码登录</p>
<svg
t="1688921974790"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="15061"
width="32"
height="32"
>
<path
d="M1023.162182 641.303273c0-143.243636-143.243636-260.910545-306.944-260.910546-168.820364 0-306.944 117.666909-306.944 260.910546s133.003636 260.910545 306.944 260.910545c35.816727 0 71.633455-10.24 107.426909-20.456727l97.210182 56.273454-25.576728-92.090181c71.633455-56.273455 127.883636-127.906909 127.883637-204.637091z m-404.130909-46.056728c-20.456727 0-35.816727-15.36-35.816728-35.816727 0-15.336727 20.456727-35.816727 35.816728-35.816727 25.576727 0 46.056727 15.36 46.056727 35.816727-0.023273 15.36-20.48 35.816727-46.056727 35.816727z m194.397091 0c-15.336727 0-35.816727-15.36-35.816728-35.816727 0-15.336727 20.456727-35.816727 35.816728-35.816727 25.576727 0 46.056727 15.36 46.056727 35.816727 0 15.36-15.36 35.816727-46.056727 35.816727z m0 0"
fill="#04AE0F"
p-id="15062"
></path>
<path
d="M358.097455 104.122182c-199.517091 0-358.120727 133.026909-358.120728 306.967273 0 97.210182 56.273455 179.060364 143.243637 240.453818L107.426909 758.970182l127.906909-61.393455c46.033455 10.24 81.850182 20.456727 127.906909 20.456728h35.816728c-5.12-25.576727-10.216727-51.153455-10.216728-76.730182 0-158.580364 133.003636-286.510545 306.944-286.510546h35.816728C690.641455 211.549091 537.157818 104.122182 358.097455 104.122182z m-112.54691 240.453818c-25.576727 0-56.273455-15.36-56.273454-46.056727 0-25.6 25.6-46.056727 56.273454-46.056728 25.576727 0 46.056727 15.36 46.056728 46.056728-5.12 30.696727-20.456727 46.056727-46.056728 46.056727z m250.693819 0c-25.576727 0-56.273455-15.36-56.273455-46.056727 0-25.6 25.576727-46.056727 56.273455-46.056728 25.576727 0 46.056727 15.36 46.056727 46.056728-0.023273 30.696727-20.48 46.056727-46.056727 46.056727z m0 0"
fill="#04AE0F"
p-id="15063"
></path>
</svg>
</div>
</div>
<div class="webchat" v-show="scene == 1">微信扫码登录</div>
</div>
</el-col>
<el-col :span="12">
<div class="leftContent">
<div class="top">
<div class="item">
<img src="../../assets/images/code_app.png" alt="" />
<svg
t="1688921974790"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="15061"
width="16"
height="16"
>
<path
d="M1023.162182 641.303273c0-143.243636-143.243636-260.910545-306.944-260.910546-168.820364 0-306.944 117.666909-306.944 260.910546s133.003636 260.910545 306.944 260.910545c35.816727 0 71.633455-10.24 107.426909-20.456727l97.210182 56.273454-25.576728-92.090181c71.633455-56.273455 127.883636-127.906909 127.883637-204.637091z m-404.130909-46.056728c-20.456727 0-35.816727-15.36-35.816728-35.816727 0-15.336727 20.456727-35.816727 35.816728-35.816727 25.576727 0 46.056727 15.36 46.056727 35.816727-0.023273 15.36-20.48 35.816727-46.056727 35.816727z m194.397091 0c-15.336727 0-35.816727-15.36-35.816728-35.816727 0-15.336727 20.456727-35.816727 35.816728-35.816727 25.576727 0 46.056727 15.36 46.056727 35.816727 0 15.36-15.36 35.816727-46.056727 35.816727z m0 0"
fill="#515151"
p-id="15062"
></path>
<path
d="M358.097455 104.122182c-199.517091 0-358.120727 133.026909-358.120728 306.967273 0 97.210182 56.273455 179.060364 143.243637 240.453818L107.426909 758.970182l127.906909-61.393455c46.033455 10.24 81.850182 20.456727 127.906909 20.456728h35.816728c-5.12-25.576727-10.216727-51.153455-10.216728-76.730182 0-158.580364 133.003636-286.510545 306.944-286.510546h35.816728C690.641455 211.549091 537.157818 104.122182 358.097455 104.122182z m-112.54691 240.453818c-25.576727 0-56.273455-15.36-56.273454-46.056727 0-25.6 25.6-46.056727 56.273454-46.056728 25.576727 0 46.056727 15.36 46.056728 46.056728-5.12 30.696727-20.456727 46.056727-46.056728 46.056727z m250.693819 0c-25.576727 0-56.273455-15.36-56.273455-46.056727 0-25.6 25.576727-46.056727 56.273455-46.056728 25.576727 0 46.056727 15.36 46.056727 46.056728-0.023273 30.696727-20.48 46.056727-46.056727 46.056727z m0 0"
fill="#515151"
p-id="15063"
></path>
</svg>
<p>微信扫一扫关注</p>
<p>“快速预约挂号”</p>
</div>
<div class="item">
<img src="../../assets/images/code_login_wechat.png" alt="" />
<svg
t="1688923491762"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="16931"
width="16"
height="16"
>
<path
d="M766.003899 974.097466H282.947368a47.906433 47.906433 0 0 1-47.906432-47.906433V83.836257a47.906433 47.906433 0 0 1 47.906432-47.906432h483.056531a47.906433 47.906433 0 0 1 47.906432 47.906432v842.354776a47.906433 47.906433 0 0 1-47.906432 47.906433z m-241.528265-57.88694a61.879142 61.879142 0 1 0-61.879143-61.879142 61.879142 61.879142 0 0 0 61.879143 61.879142z m202.604288-791.454191H321.871345v598.83041h405.208577V124.756335z"
fill="#E61D15"
p-id="16932"
></path>
</svg>
<p>扫一扫下载</p>
<p>“预约挂号”APP</p>
</div>
</div>
</div>
<p class="tip">尚医通官方指定平台</p>
<p class="tip">快速挂号 安全放心</p>
</el-col>
</el-row>
</div>
<template #footer>
<el-button type="primary" size="default">关闭窗口</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { User, Lock } from "@element-plus/icons-vue";
// 获取user仓库的数据visiable,可以控制login组件的对话框显示与隐藏
// import useUserStore from '@/store/mod'
import useUserStore from "@/store/modules/user";
import { ref } from "vue";
let userStore = useUserStore();
let scene = ref<number>(0); //0代表手机号码登录,1代表微信扫码登录
// 点击微信扫码登录|微信小图标切换为微信扫码登录
const changeScene = () => {
scene.value = 1;
};
</script>
<script lang="ts">
// 用vue2写个别名,方便vue插件寻找数据
export default {
name: "Login",
};
</script>
<style scoped lang="scss">
.login-container {
/* 要修改组件内部的样式,就要用深度选择器 */
:deep(.el-dialog__body) {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.login {
padding: 20px;
border: 1px solid #ccc;
}
.bottom {
display: flex;
flex-direction: column;
align-items: center;
p {
margin: 10px 0px;
}
}
.leftContent {
.top {
display: flex;
justify-content: space-around;
.item {
display: flex;
flex-direction: column;
align-items: center;
img {
width: 130px;
height: 130px;
}
p {
margin: 5px 0px;
}
}
}
}
.tip {
text-align: center;
margin: 20px 0px;
font-size: 20px;
font-weight: 900;
}
}
</style>
16.7、登录组件获取验证码
接口设置
输入框验证规则
获取验证码的方法
放在仓库中
16.8获取验证码倒计时业务
将倒计时组件进行封装
用v-if v-else 判断展示哪个组件,当flag为真时,倒计时组件开启,否则关闭。
还有就是当你输入的手机号码不符合规定时或者当开启倒计时后,获取验证码的按钮将会被禁用
十七、登录业务功能
登录相关的ts类型
登录接口
登录请求
登录逻辑
发送登录请求
登录请求成功:顶部组件需要展示用户名字/对话框关闭
登录失败:弹出对应登录失败的错误信息
17.1、普通表单校验规则(一般不用)
17.2、自定义表单校验
17.3、关闭对话框时表单清空
方法二: 当对话框关闭时,直接销毁Login组件
APP.vuew
17.4、退出登录
清除本地存储和仓库存储的数据