当前位置: 首页 > news >正文

开源预约挂号平台 - 从0到上线

文章目录

  • 开源预约挂号平台 - 从0到上线
    • 演示地址
    • 源码地址
    • 可以学到的技术
      • 前端技术
      • 后端技术
      • 部署上线
      • 开发工具
      • 其他技术
      • 业务功能
  • 项目讲解
    • 前端
      • 创建项目 - 安装`PNPM` - 使用`VSCODE `- 安装插件
      • 首页
        • 顶部与底部 - 封装组建 - 使用`scss`左右布局
        • 中间内容部分
          • 路由 -` vue-router`
          • `BANNER`- 走马灯效果 - 使用`elementplus`
          • 搜索区 - 自动填充组建 - 深度选择器
          • `AXIOS`发起请求
          • 筛选区
          • 表格部分与分页 - 使用`TypeScript`类型
          • 筛选区与首页表格父子组件传参
      • 医院部分
        • 使用 `Pinia`仓库
        • 科室滑动效果
      • 登录模块
          • 自定义表单验证
          • 验证码功能
          • `Token`功能
      • 挂号功能
          • 挂号列表动画功能
          • 卡片印章样式
      • 订单详情
      • 实名认证
          • 前端上传图片功能
      • 就诊人管理
        • 级联选择器
        • 路由鉴权与`Nprogress`加载进度条
    • 后端
      • 框架图
      • 创建表
        • 业务表
        • 字段表
      • 配置表
      • 数据初始化 -` BRP.COM.Init`
      • REST接口 - `BRP.COM.REST.Api`
      • 统一入口,统一错误处理 - `BRP.COM.SafeRun`
      • `ORM`映射的使用
      • `JWT`功能
      • 后端处理上传文件
    • 部署
      • 部署云
        • 华为云创建服务器流程
        • 阿里云创建服务器流程
      • 在安装`Linux`,`Centos`系统中安装数据库
      • 创建数据库
      • 创建命名空间
      • 创建Application
      • 三库分离
      • 创建灾备数据库
      • 备份数据库
      • 恢复数据库
      • 将数据库加入MIRROR
      • 部署`NGINX`
      • 打包前端文件
      • 跨越问题处理
      • 使用`Git`进行版本控制
      • 上传`Github`
  • **创造价值,分享学习,一起成长,相伴前行,欢迎大家提出意见,共同交流。**

开源预约挂号平台 - 从0到上线

  • 项目缩写名称:BRP - Booking Registration Platform

演示地址

  • 预约挂号平台

在这里插入图片描述

源码地址

  • 前端源码 - https://github.com/yaoxin521123/brp-app-web.git
  • 后端源码 - https://github.com/yaoxin521123/brp-iris.git

可以学到的技术

前端技术

  • Vue3ViteTypeScriptvue-routerPiniaelementplusAXIOSscss

后端技术

  • IRIS2023REST,统一入口,统一错误处理,ORMJWT,自研框架,后端处理上传文件

部署上线

  • 华为云,Centos7.9Ngnix,创建独立命名空间,创建独立数据库,创建独立Applicaion,三库分离,打包前端文件,跨域问题,创建灾备服务器,备份数据库,恢复数据库,将数据库加入MIRROR

开发工具

  • vscodeIRIS2023

其他技术

  • SVG矢量图使用,路由鉴权,封装全局组件,HTTP上传图片,使用Git进行版本控制,上传Github

业务功能

  • 手机登录,扫码二维码登录,微信支付,预约挂号,医院详情,预约通知,实名认证,挂号订单,就诊人管理

项目讲解

由于篇幅有限,以下为重点功能讲解,可参考项目源码对比观看。

前端

创建项目 - 安装PNPM - 使用VSCODE - 安装插件

  1. 先安装node.jsnpm
  • 下载地址:https://nodejs.cn/download/

在这里插入图片描述

下一步安装即可。

C:\Users\hp>node -v
v16.14.0C:\Users\hp>npm -v
8.3.1
  1. 打开cmd,安装pnpm
npm install -g pnpm

注:网络不好可以替换镜像地址。

获取当前配置的镜像地址
pnpm get registry设置新的镜像地址
pnpm set registry https://registry.npm.taobao.org
  1. 在任意路径下打开cmd,创建vue3项目。依次填写名称 - brp-app-webVueTypeScript

在这里插入图片描述

E:\vue>pnpm create vite
../.pnpm-store/v3/tmp/dlx-13224          |   +1 +
../.pnpm-store/v3/tmp/dlx-13224          | Progress: resolved 1, reused 0, downloaded 1, added 1, done
√ Project name: ... brp-app-web
Select a framework :  Vue
Seiect a variant : TypeScript
  1. 使用vscode打开项目,在terminl中输入pnpm run dev即可启动项目。

在这里插入图片描述

  1. vscode推荐使用v3插件如下:
  • Element UI Snippets - v0.7.2
  • Prettier - Code formatter - v10.1.0
  • TypeScript Vue Plugin (Volar) - v1.8.26
  • Wink Snippets - v1.0.5
  1. main.ts文件中引入必要的依赖包
import { createApp } from "vue";
import "@/style/reset.scss";
import App from "@/App.vue";
import router from "@/router";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
//@ts-ignore
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
import pinia from "@/store";
const app = createApp(App);
app.use(router);
app.use(ElementPlus, {locale: zhCn,
});
app.use(pinia);
app.mount("#app");

首页

首页分为顶部,底部,中间内容部分:BANNER区,搜索区,筛选区,表格,分页,右侧。

在这里插入图片描述

顶部与底部 - 封装组建 - 使用scss左右布局
  1. 将顶部与底部封装为全局组件。

在这里插入图片描述

  1. 将全局组件引入到main.ts
...
import HosptialTop from "@/components/hospital_top/index.vue";
import HosptialBottom from "@/components/hospital_bottom/index.vue";
...
const app = createApp(App);
app.component("HosptialTop", HosptialTop);
app.component("HosptialBottom", HosptialBottom);
app.mount("#app");

注:再使用ts中有代码提示报错,运行时没有报错,可以使用//@ts-ignore忽略。

  1. App.vue中引入全局组件,该文件为入口文件。
  • 布局分部为头部,中部,底部,中间部用于内容切换路由跳转等。
<template><div class="container"><HosptialTop /><div class="content"><router-view></router-view></div><HosptialBottom /><Login /></div>
</template>
  1. 实现头部与底部左右布局,以头部scss样式举例。

注:使用scss前需要先安装scss 在项目目录中使用cmd执行pnpm i scss命令即可。

  • 先让top浮动 display: flex;居中 justify-content: center;并在位置固定position: fix;层级在最上z-index: 999;
  • content中让leftright浮动起来,在左右两侧justify-content: space-between;
  • 其余为宽高大小,居中等属性。

注:后面的前端界面中有大量左右布局均为此方式,后面不再赘述。

在这里插入图片描述

<style scoped lang="scss">
.top {position: fix;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: 70px;height: 50px;margin-right: 10px;}p {font-size: 20px;color: #55a6fe;}}.right {display: flex;justify-content: center;align-items: center;font-size: 14px;color: #ccc;.help {margin-right: 10px;}}}
}
</style>
中间内容部分
路由 - vue-router
  1. 中间内容部分需要使用路由来切换页面,首先创建文件router/index.ts编写路由。

注:使用vue-router时需要在项目目录中打开cmd执行命令pnpm i vue-router安装路由。

  • createRouter为创建路由配置方法。
  • scrollBehavior()方法每次路由跳转滚动条自动回到顶部。
  • component: () => import("@/pages/home/index.vue"),懒加载路由,import中文件为路由的路径。
import { createRouter, createWebHistory } from "vue-router";
export default createRouter({history: createWebHistory(),routes: [{path: "/home",component: () => import("@/pages/home/index.vue"),meta: {title: "首页",},},],scrollBehavior() {return {left: 0,top: 0,};},
});
  1. main.ts中引入路由。
...
import router from "@/router";
...
app.use(router);
...
  1. 设置好路由后在地址栏就可以输入路由名称进行路由跳转。
  • http://119.3.235.244/home
  • http://119.3.235.244/hospital
BANNER- 走马灯效果 - 使用elementplus
  • 创建组件pages - carousel - index.vue

  • 使用组件el-carousel,循环4次,设置img图片即可。

  <el-carousel height="350px"><el-carousel-item v-for="item in 4" :key="item"><img src="@/assets/images/web-banner-1.png" alt="" /></el-carousel-item></el-carousel>

在这里插入图片描述

搜索区 - 自动填充组建 - 深度选择器

在这里插入图片描述

  1. 创建组件pages - search - index.vue

  2. 使用组件el-autocomplete

  • :fetch-suggestions="fetchData"为搜索时防抖的触发方法根据输入内容进行后台查询。
    <el-autocompleteclearableplaceholder="请输入医院名称"v-model="hosname":fetch-suggestions="fetchData":trigger-on-focus="false"@select="goDetail"/>
  1. 由于搜索组件的宽度为深层样式,所以这里使用 ::v-deep()修改组件内部的样式。

注:如果去掉scoped关键字,则样式为全局样式。

<style scoped lang="scss">
.search {width: 100%;height: 50px;display: flex;justify-content: center;align-items: center;margin: 10px 0px;::v-deep(.el-input__wrapper) {width: 600px;margin-right: 10px;}
}
</style>
AXIOS发起请求
  1. 创建文件utils - request.ts,编写代码如下。

注:需要安装axiospnpm i axios

  1. 利用axios.create方法创建一个axios实例:可以设置基础路径、超时的时间的设置。
  2. 利用axios请求、响应拦截器功能,请求拦截器,一般可以在请求头中携带公共的参数token,响应拦截器,可以简化服务器返回的数据,处理http网络错误。
  3. 对外暴露axios
import axios from "axios";
import { ElMessage } from "element-plus";
import userUserStore from "@/store/modules/user";const request = axios.create({//baseURL: import.meta.env.VITE_API_BASE_URL,baseURL: "/api",timeout: 5000,
});request.interceptors.request.use((config) => {let userStore = userUserStore();if (userStore.userInfo.token) {config.headers.token = userStore.userInfo.token;}return config;
});request.interceptors.response.use((response) => {return response.data;},(error) => {let status = error.response.status;console.log(status);switch (status) {case 404:ElMessage({type: "error",message: error.message,});break;case 500 | 501 | 502 | 503 | 504 | 505:ElMessage({type: "error",message: "服务器挂了",});break;case 401:ElMessage({type: "error",message: "参数有误",});break;}return Promise.reject(new Error(error.message));}
);export default request;
筛选区

pages - home - level - index.vuepages - home - region- index.vue

在这里插入图片描述

  1. 筛选静态 代码为ul>li,样式浮动,使用flex按照比例划分区域。等级:占0.5份,其他占9份,并增加鼠标滑过样式。
  2. 将筛选区封装为组件使用。
  .content {display: flex;.left {margin-right: 10px;flex: 0.5;}.hospital {flex: 9;display: flex;li {margin-right: 10px;&.active {color: #55a6fe;}}li:hover {color: #55a6fe;cursor: pointer;}}}
表格部分与分页 - 使用TypeScript类型

在这里插入图片描述

  1. 表格显示内容为后端接口返回的数据。首先定义接口返回数据类型。api - home - type.ts

注:表格的样式与绑定数据不再赘述,参考elementUI官方即可。

  • ResponseData - 定义首页模块ts数据类型
  • Hospital - 代表已有的医院数据的ts类型
  • Content - 存储全部已有医院的数组类型
  • HospitalResponseData - 获取已有医院接口返回的数据ts类型
export interface ResponseData {code: number;message: string;ok: boolean;
}
export interface Hospital {id: string;createTime: string;updateTime: string;isDeleted: number;params: {hostypeString: string;fullAddress: string;};hoscode: string;hosname: string;hostype: string;provinceCode: string;cityCode: string;districtCode: string;address: string;logoData: string;intro: string;route: string;status: number;bookingRule: {cycle: number;releaseTime: string;stopTime: string;quitDay: number;quitTime: string;rule: string[];};
}
export type Content = Hospital[];export interface HospitalResponseData extends ResponseData {data: {content: Content;pageable: {sort: {sorted: boolean;unsorted: boolean;empty: boolean;};pageNumber: number;pageSize: number;offset: number;paged: boolean;unpaged: boolean;};totalPages: number;totalElements: number;last: boolean;first: boolean;sort: {sorted: boolean;unsorted: boolean;empty: boolean;};numberOfElements: number;size: number;number: number;empty: boolean;};
}
  1. 引入数据类型定义接口方法并暴露reqHospitalapi - home - index.ts
  • 通过枚举管理首页模块的接口地址
import request from "@/utils/request";
import type {HospitalResponseData,
} from "./type";
enum API {HOSPITAL_URL = "/hosp/hospital/",
}
export const reqHospital = (page: number,limit: number,hostype = "",districtCode = ""
) =>request.get<any, HospitalResponseData>(API.HOSPITAL_URL +`${page}/${limit}?hostype=${hostype}&districtCode=${districtCode}`);
  1. 在首页中发起请求获取数据。page.index.vue
  • onMounted - 页面加载完毕时回调的钩子。
  • getHospitalInfo - 获取已有的医院的数据
<script setup lang="ts">
...
onMounted(() => {getHospitalInfo();
});
const getHospitalInfo = async () => {let result: HospitalResponseData = await reqHospital(pageNo.value,pageSize.value,hosType.value,districtCode.value);if (result.code == 200) {hasHospitalArr.value = result.data.content;total.value = result.data.totalElements;}
};
...
</script>
  1. 点击分页时需要触发对应的回调方法
        <el-paginationclass="pagination"v-model:current-page="pageNo"v-model:page-size="pageSize":page-sizes="[10, 20, 30, 40]":background="true"layout="prev, pager, next, jumper,->,sizes,total":total="total"@current-change="currentChange"@size-change="sizeChange"/>
  • sizeChange - 分页器下拉菜单发生变化的时候会触发
  • currentChange - 分页器页码发生变化时候回调
const currentChange = () => {getHospitalInfo();
};const sizeChange = () => {pageNo.value = 1;getHospitalInfo();
};
筛选区与首页表格父子组件传参
  1. 给筛选区组件添加自定义回调方法。
        <!-- 等级子组件 --><Level @getLevel="getLevel" /><!--地区 --><Region @getRegion="getRegion" />
  1. 在父组件编写回调方法
  • 组件自定义事件:获取儿子给父组件传递过来的等级参数
  • 子组件自定义事件:获取子组件传递过来的地区参数
const getLevel = (level: string) => {hosType.value = level;getHospitalInfo();
};
const getRegion = (region: string) => {districtCode.value = region;getHospitalInfo();
};
  1. 在子组件接受参数并触发回调方法,通知父组件,父组件拿到参数可以根据参数做后台筛选。
  • 点击不同区域按钮回调
  • 给父组件传递区域的参数
const changeLevel = (level: string) => {regionFlag.value = level;$emit("getRegion", level);
};let $emit = defineEmits(["getRegion"]);

医院部分

在这里插入图片描述

使用 Pinia仓库
  1. 由于hospital路由的多个二级路由,需要获取点击医院的信息。所以使用Pinia仓库进行数据缓存。把获得信息提供给多个二级路由使用,这样就可以不用每个页面再次获取医院信息。
  2. 创建 Pinia仓库。store - modules - hospitalDetail.ts

注:使用pinia前需要先安装pnpm i pinia

  • useDetailStore为定义的全局数据。
  • state - 表示返回的数据。
  • actions - 触发的回调方法给state中数据赋值。
import { defineStore } from "pinia";
import { reqHospitalDetail, reqHospitalDeparment } from "@/api/hospital";
import type {HospitalDetailData,HospitalDetail,
} from "@/api/hospital/type";
import { DetailState } from "@/store/modules/interface";
const useDetailStore = defineStore("Detail", {state: (): DetailState => {return {hospitalInfo: {} as HospitalDetail,};},actions: {async getHospital(hoscode: string) {let result: HospitalDetailData = await reqHospitalDetail(hoscode);if (result.code == 200) {this.hospitalInfo = result.data;}},},getters: {},
});export default useDetailStore;
  1. hospital - index.vue中使用 pinia
  • 组件挂载完毕,通知pinia仓库发请求获取医院详情的数据,存储仓库当中。
...
import { useRouter, useRoute } from "vue-router";
import { onMounted } from "vue";
import useDetailStore from "@/store/modules/hospitalDetail";
let detailStore = useDetailStore();
let $router = useRouter();
let $route = useRoute();onMounted(() => {detailStore.getHospital($route.query.hoscode as string);
});
  1. 其他hospital二级路由拿到数据后获取展示即可。\pages\hospital\detail\index.vue

在这里插入图片描述

  • 引入医院详情仓库的数据
<script setup lang="ts">
import useDetailStore from "@/store/modules/hospitalDetail";
let hospitalStore = useDetailStore();
</script>
科室滑动效果

在这里插入图片描述

  1. 展示为左右两个部分,左侧为科室总称,右侧为改科室的子科室。
  • deparment - 放置每一个医院的科室的数据
  • deparmentInfo - 用一个div代表:大科室与小科室
  • 每一个大的科室下小科室
  <div class="deparment"><div class="leftNav"><ul><li@click="chaneIndex(index)":class="{ active: index == currentIndex }"v-for="(deparment, index) in hospitalStore.deparmentArr":key="deparment.depcode">{{ deparment.depname }}</li></ul></div><div class="deparmentInfo"><divclass="showDeparment"v-for="deparment in hospitalStore.deparmentArr":key="deparment.depcode"><h1 class="cur" style="padding: 10px;">{{ deparment.depname }}</h1><ul><li@click="showLogin(item)"v-for="item in deparment.children":key="item.depcode">{{ item.depname }}</li></ul></div></div></div>
  1. 左侧大的科室点击的事件
  • 点击导航获取右侧科室(大的科室H1标题)
  • 滚动到对应科室的位置
  • behavior: "smooth", 过渡动画效果
  • block: "start", 滚动到位置 默认起始位置
let currentIndex = ref<number>(0);
const chaneIndex = (index: number) => {currentIndex.value = index;let allH1 = document.querySelectorAll(".cur");allH1[currentIndex.value].scrollIntoView({behavior: "smooth",block: "start",});
};
  1. 滑动样式
  • &::-webkit-scrollbar { display: none;}隐藏滚动条
  • flex-direction: column;浮动布局为列布局
  .deparment {width: 100%;height: 500px;display: flex;margin-top: 20px;.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: 40px;&.active {border-left: 1px solid red;color: red;background: white;}}}}.deparmentInfo {flex: 1;margin-left: 20px;height: 100%;overflow: auto;&::-webkit-scrollbar {display: none;}.showDeparment {h1 {background-color: rgb(248, 248, 248);color: #7f7f7f;}ul {display: flex;flex-wrap: wrap;li {color: #7f7f7f;width: 33%;line-height: 30px;}}}}}

登录模块

在这里插入图片描述

登录为全局组件,包含手机号登录,微信扫码登录表单验证等功能。

自定义表单验证
  • 自定义校验规则:手机号码自定义校验规则
  • 验证码自定义校验规则
const validatorPhone = (_: any, value: any, callback: any) => {const reg = /^1[3-9]\d{9}$/;if (reg.test(value)) {callback();} else {callback(new Error("请输入正确的号码格式"));}
};
const validatorCode = (_: any, value: any, callback: any) => {if (/^\d{6}$/.test(value)) {callback();} else {callback(new Error("请输入正确的验证码格式"));}
};
const rules = {phone: [{ trigger: "blur", validator: validatorPhone }],code: [{ trigger: "blur", validator: validatorCode }],
};
验证码功能

在这里插入图片描述

  1. 将验证码功能封装为组件\components\countdown\index.vue
  • time - 倒计时的事件
  • watch - 监听父组件传递过来props数据变化
  • timer - 开启定时器
  • $emit('getFlag',false);通知父组件倒计时模式结束
  • let $emit = defineEmits(["getFlag"]);接受父组件传递过来的props->flag:用于控制计数器组件显示与隐藏的
<template><div><span>获取验证码({{ time }}s)</span></div>
</template><script setup lang="ts">
import { ref, watch } from "vue";
let props = defineProps(["flag"]);
let time = ref<number>(5);
watch(() => props.flag,() => {let timer = setInterval(() => {time.value--;if (time.value == 0) {$emit("getFlag", false);clearInterval(timer);}}, 1000);},{immediate: true,}
);
let $emit = defineEmits(["getFlag"]);
</script>
  1. 登录组件中引入验证码组件
 <Countdown v-if="flag" :flag="flag" @getFlag="getFlag" />
  1. 点击验证码按钮时触发事件
  • getFlag - 计数器子组件绑定的自定义事件。当倒计时为零的时候,通知父组件倒计时组件隐藏
  • getCode - 获取验证码按钮的回调
const getCode = async () => {flag.value = true;try {await userStore.getCode(loginParams.phone);loginParams.code = userStore.code;} catch (error) {ElMessage({type: "error",message: (error as Error).message,});}
};const getFlag = (val: boolean) => {flag.value = val;
};
Token功能
  1. 登录成功后将token存户到pinia
  • await userStore.userLogin(loginParams);调用userStore方法
const login = async () => {await form.value.validate();console.log(form.value.validate());try {await userStore.userLogin(loginParams);userStore.visiable = false;let redirect = $route.query.redirect;if (redirect) {$router.push(redirect as string);} else {$router.push("/home");}} catch (error) {ElMessage({type: "error",message: (error as Error).message,});}
};
  1. SET_TOKEN(JSON.stringify(this.userInfo));本地存储localStorage持久化存储用户信息。
        async userLogin(loginData: LoginData) {let result: UserLoginResponseData = await reqUserLogin(loginData);if (result.code == 200) {this.userInfo = result.data;SET_TOKEN(JSON.stringify(this.userInfo));return 'ok';} else {return Promise.reject(new Error(result.message));}},
export const SET_TOKEN = (userInfo:string)=>{localStorage.setItem('USERINFO',userInfo);
}
  1. axios中进行拦截请求头每次携带localStorage中的token信息
  • config:请求拦截器回调注入的对象(配置对象),配置对象的身上最终要的一件事情headers属性
request.interceptors.request.use((config) => {let userStore = useUserStore();if (userStore.userInfo.token) {config.headers.token = userStore.userInfo.token;}return config;
});

在这里插入图片描述

挂号功能

在这里插入图片描述

注:这里显示了为什么要将登录注册为全局组件,因为项目分为两个部分,一个部分是不用登录可展示的部分,另一部分是登录之后的功能。挂号就是必须要登录之后才展示的功能。

挂号列表动画功能

在这里插入图片描述

  1. \pages\hospital\register\register_step1.vue文件中样式
  • cur: item.workDate == workTime.workDate,根据条件添加cur属性,有cur属性代表当前点击元素,从而进行放大。
        <divclass="item"@click="changeTime(item)":class="{active: item.status == -1 || item.availableNumber == -1,cur: item.workDate == workTime.workDate,}"v-for="item in workData.bookingScheduleList":key="item">
  • transform: scale(1.1);动画放大了1.1倍
    .container {width: 100%;display: flex;margin: 30px 0px;.item {flex: 1;width: 100%;border: 1px solid skyblue;margin: 0px 5px;color: #7f7f7f;transition: all 0.5s;&.active {border: 1px solid #ccc;.top1 {background: #ccc;}}&.cur {transform: scale(1.1);}.top1 {background: #e8f2ff;height: 30px;width: 100%;text-align: center;line-height: 30px;}.bottom {width: 100%;height: 60px;text-align: center;line-height: 60px;}}}
卡片印章样式

在这里插入图片描述

  1. 将就诊人封装为单独的组件。components\visitor\visitor.vue
  • 给印章添加transition标签并声明名称为confirm
<template><div class="visitor">
...<div class="bottom"><p>证件类型:{{ user.param?.certificatesTypeString }}</p><p>证件号码:{{ user.certificatesNo }}</p><p>用户性别:{{ user.sex == 0 ? "女生" : "男士" }}</p><p>出生日期:{{ user.birthdate }}</p><p>手机号码:{{ user.phone }}</p><p>婚姻状况:{{ user.isMarry == 0 ? "未婚" : "已婚" }}</p><p>详细地址:{{ user.address }}</p><transition name="confirm"><div class="confirm" v-if="index == currentIndex">已选择</div></transition></div></div>
</template>
  1. 编写样式
  • position: absolute;绝对定位
  • border-radius: 50%;圆角50%
  • opacity: 0.5;透明度0.5
  • transform: rotate(35deg); 印章旋转角度
  • .confirm-enter-from,.confirm.enter-active, .confirm-enter-to 出入动画,持续动画时间。
  .bottom {position: relative;padding: 0px 10px;p {line-height: 40px;}.confirm {position: absolute;width: 200px;height: 200px;color: red;border-radius: 50%;border: 1px dashed red;text-align: center;line-height: 200px;left: 15%;top: 15%;opacity: 0.5;transform: rotate(35deg);font-weight: 900;}.confirm-enter-from {transform: scale(1);}.confirm.enter-active {transform: all 0.3s;}.confirm-enter-to {transform: scale(1.2);}}

订单详情

在这里插入图片描述

  • 订单详情根据路由是否带参数决定显示详细界面,还是列表界面。
  • pages\user\order\allOrder\index.vue
  • pages\user\order\detail\index.vue

实名认证

在这里插入图片描述

  • 业务逻辑,在第一次登录时需要先实名认证,认证后该界面显示认证结果。
前端上传图片功能
  1. pages\user\certification\index.vue中使用el-upload控件
  • :action=“/api/oss/file/fileUpload?fileHost=userAuah&userId=${userInfo.id}” 该属性表示选择图片后上传的后端服务器地址。
          <el-uploadref="upload"list-type="picture-card":limit="1":on-exceed="exceedhandler":on-success="successhandler":on-preview="handlePictureCardPreview":on-remove="handleRemove":action="`/api/oss/file/fileUpload?fileHost=userAuah&userId=${userInfo.id}`"><imgstyle="width: 100%; height: 100%"src="@\assets\images\auth_example.png"alt=""/></el-upload>
  1. 编写ts方法
  • exceedhandler - 超出数量的钩子
  • successhandler - 图品上传成功的钩子
  • handlePictureCardPreview - 照片墙预览的钩子
  • handleRemove - 删除图片的钩子

注:预览图片的地址为后端上传成功后返回的地址。

const exceedhandler = () => {ElMessage({type: "error",message: "图片只能上传一张图片",});
};
const successhandler = (response: any) => {form.value.clearValidate("certificatesUrl");params.certificatesUrl = response.data;console.log(params.certificatesUrl);
};
const handlePictureCardPreview = () => {//触发预览的钩子的时候,对话框显示dialogVisible.value = true;
};
const handleRemove = () => {params.certificatesUrl = "";
};

就诊人管理

在这里插入图片描述

  • 就诊人管理主要是针对患者的增删改查功能。
级联选择器

在这里插入图片描述

  1. 使用el-cascader级联选择器
  <el-cascader :props="props" v-model="userParams.addressSelected"   style="width: 100%" />
  1. ts中引入级联选择器配置
  • lazyLoad(node: any, resolve: any) - 加载级联选择器数据方法
  • resolve(showData); - 注入组件需要展示的数据
  • id: item.value, - 每次回传id查询下一级的选择列表。
import type { CascaderProps } from "element-plus";const props: CascaderProps = {lazy: true,async lazyLoad(node: any, resolve: any) {let result: any = await reqCity(node.data.id || "86");let showData = result.data.map((item: any) => {return {id: item.value,label: item.name,value: item.value,leaf: !item.hasChildren,};});resolve(showData);},
};
路由鉴权与Nprogress加载进度条

在这里插入图片描述

  • 路由鉴权:就是路由能不能被访问到权限设置->全局守卫完成
  • let whiteList - 存储用户未登录可以访问路由得路径
  • router.beforeEach((to, from, next) - 前置守卫
  • Nprogress.start();访问路由组件的之前,进度条开始动
  • document.title = 大姚挂号平台-${to.meta.title}; 动态设置网页左上角的标题
  • let token = userStore.userInfo.token;判断是否有token
  • router.afterEach((to, from) - 后置路由
  • Nprogress.done(); - 访问路由组件成功,进度条消息
import router from "./router";
import Nprogress from 'nprogress';
import useUserStore from '@/store/modules/user';
import pinia from '@/store'
let userStore = useUserStore(pinia);
import "nprogress/nprogress.css"
let whiteList = ["/home", '/hospital/register', '/hospital/detail', '/hospital/notice', '/hospital/close', '/hospital/search'];
router.beforeEach((to, from, next) => {Nprogress.start();document.title = `大姚挂号平台-${to.meta.title}`;let token = userStore.userInfo.token;if (token) {next();} else {if (whiteList.includes(to.path)) {next();} else {userStore.visiable = true;next({ path: '/home', query: { redirect: to.fullPath } })}}});router.afterEach((to, from) => {Nprogress.done();
})

后端

框架图

注:后端架构在《浅谈一下个人基于IRIS后端业务开发框架的理解》此博文中详细阐述,所以不再赘述。

在这里插入图片描述

创建表

业务表
  • 用户表 - BRP.BS.Account
  • 预约表 - BRP.BS.BookingSchedule
  • 医生表 - BRP.BS.Doctor
  • 挂号表 - BRP.BS.Doctor
  • 就诊人表 - BRP.BS.Patient
字段表
  • 区域表 - BRP.CT.Region
  • 订单状态表 - BRP.CT.OrderStatus
  • 医院级别表 - BRP.CT.Level
  • 医院表 - BRP.CT.Hospital
  • 科室表 - BRP.CT.Department
  • 城市表 - BRP.CT.City
  • 证件类型表 - BRP.CT.CertificatesType

配置表

  • 配置表 - BRP.CT.Config

所有表的关键字和父类如下:

  • %JSON.Adaptor - 用于导入导出json数据
  • BRP.COM.Map - ORM映射类
Class BRP.CT.Hospital Extends (%Persistent, %JSON.Adaptor, BRP.COM.Map) [ ClassType = persistent, Inheritance = left, ProcedureBlock, SqlRowIdName = id ]

注:字段就不一一列举了,可下源代码自行导入。

数据初始化 - BRP.COM.Init

  • 所有表创建完后进行初始化数据。
  • 将文件放入数据文件指定目录。

在这里插入图片描述

  • 执行方法w ##class(BRP.COM.Init).InitRegion("/brp/")即可。
Class BRP.COM.Init Extends %RegisteredObject
{/// w ##class(BRP.COM.Init).InitRegion("/brp/")
ClassMethod Init(path)
{tsd ..InitRegion(path _ "region.txt")d ..InitLevel(path _ "level.txt")d ..InitHospital(path _ "hospital.txt")d ..InitDepartment(path _ "department.txt")d ..InitBookingSchedule()d ..InitDocotr(path _ "doctor.txt")d ..InitPatient(path _ "patient.txt")d ..InitOrderStatus()d ..InitCertificatesType(path _ "certificatesType.txt")d ..InitCity(path _ "city.txt")d ..InitCitySecond()b ;alltcq $$$OK
}/// 初始化区域数据
/// w ##class(BRP.COM.Init).InitRegion("/brp/region.txt")
ClassMethod InitRegion(path)
{tss json = {}.%FromJSONFile(path)s iter = json.%GetIterator()while (iter.%GetNext(.key, .val)){s id = ##class(Util.GenerateClassUtils).SaveJson2Entity(val, "BRP.CT.Region")w "生成id:" _ id,!}b ;22tcq $$$OK
}
...
}

REST接口 - BRP.COM.REST.Api

  • CONTENTTYPE - 接口返回数据格式
  • CHARSET - 编码类型
  • REST接口有GET,POST,PUT,DELETE请求方法。
  • $g(%request.Data("districtCode", 1)) - 为路径中的Query参数。
  • s content = %request.Content - 为获取POST请求参数内容。
Class BRP.COM.REST.Api Extends %CSP.REST
{Parameter CONTENTTYPE = "application/json";Parameter CHARSET = "utf-8";/// http://119.3.235.244:52773/api/hosp/hospital/1/10
/// w ##class(BRP.COM.REST.Api).QueryHospitalByPage(1,10)
ClassMethod QueryHospitalByPage(page, limit) As %Status
{s pDistrictCode = $g(%request.Data("districtCode", 1))s pHostype = $g(%request.Data("hostype",1 )) s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.Hospital", "Query", pHostype, pDistrictCode)s json = ##class(BRP.COM.SafeRun).ReturnResultPage(json, page, limit)w jsonq $$$OK
}/// http://119.3.235.244:52773/api/cmn/dict/findByDictCode/HosType
/// w ##class(BRP.COM.REST.Api).QueryRegion("HosType")
ClassMethod QueryRegion(dictCode) As %Status
{if (dictCode = "HosType") {s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.Level", "Query")} elseif (dictCode = "CertificatesType") {s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.CertificatesType", "Query")} else {s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.Region", "Query")}w jsonq $$$OK
}.../// Url顺序区别参数多的放到下方,否则执行不到对应的路径
XData UrlMap
{
<Routes>
<Route Url="/cmn/dict/findByDictCode/:dictCode" Method="GET" Call="QueryRegion"/>
<Route Url="/hosp/hospital/department/:hoscode" Method="GET" Call="QueryDepartment"/>
<Route Url="/hosp/hospital/getSchedule/:scheduleId" Method="GET" Call="GetDoctorDataById"/>
<Route Url="/hosp/hospital/findByHosname/:hosname" Method="GET" Call="QueryHospital"/>
<Route Url="/hosp/hospital/:page/:limit" Method="GET" Call="QueryHospitalByPage"/>
<Route Url="/hosp/hospital/:hoscode" Method="GET" Call="GetHospitalData"/>
<Route Url="/sms/send/:phone" Method="GET" Call="GetCaptcha"/>
<Route Url="/user/login" Method="POST" Call="Login"/>
<Route Url="/hosp/hospital/auth/getBookingScheduleRule/:page/:limit/:hoscode/:depcode" Method="GET" Call="QueryBookingSchedule"/>
<Route Url="/hosp/hospital/auth/findScheduleList/:hoscode/:depcode/:workDate" Method="GET" Call="QueryDoctor"/>
<Route Url="/user/patient/auth/findAll" Method="GET" Call="QueryPatient"/>
<Route Url="/order/orderInfo/auth/submitOrder/:hoscode/:scheduleId/:patientId" Method="POST" Call="SubmitOrder"/>
<Route Url="/order/orderInfo/auth/getOrderInfo/:id" Method="GET" Call="GetOrderDataById"/>
<Route Url="/order/orderInfo/auth/cancelOrder/:id" Method="GET" Call="CancelOrder"/>
<Route Url="/order/orderInfo/auth/:page/:limit" Method="GET" Call="QueryOrder"/>
<Route Url="/order/orderInfo/auth/getStatusList" Method="GET" Call="QueryOrderStatus"/>
<Route Url="/user/patient/auth/save" Method="POST" Call="SavePatient"/>
<Route Url="/user/patient/auth/update" Method="PUT" Call="SavePatient"/>
<Route Url="/user/patient/auth/remove/:id" Method="DELETE" Call="DeletePatient"/>
<Route Url="/cmn/dict/findByParentId/:parentId" Method="GET" Call="QueryCity"/>
<Route Url="/user/auth/getUserInfo" Method="GET" Call="GetUserInfo"/>
<Route Url="/oss/file/fileUpload" Method="POST" Call="UploadFile"/>
<Route Url="/user/auth/userAuah" Method="POST" Call="UserAuah"/></Routes>
}}

统一入口,统一错误处理 - BRP.COM.SafeRun

注:统一入口,统一错误处理在《通用的异常处理程序机制与处理返回值方案》此博文中详细阐述,所以不再赘述。

Class BRP.COM.SafeRun Extends (%RegisteredObject, BRP.COM.Base)
{/// desc:统一入口网关,方便统一操作日志,错误等。
ClassMethod Gateway()
{s pClassName = $g(%request.Data("ClassName", 1))s pMethodName = $g(%request.Data("MethodName",1 )) s params = ..GetMethodParams(pClassName, pMethodName)	s ^yx("Gateway") = $lb(pClassName,pMethodName,params)q ..Execute(pClassName, pMethodName, params)
}/// desc:所有程序中错误军抛出异常,统一处理
/// w ##class(IMP.Common.SafeRun).Execute("IMP.Perms.Biz", "QueryRole")
ClassMethod Execute(pClassName, pMethodName, pParams...)
{s $ecode = ""try{d ..GetInfo()#; 判断方法是否有参数,没有参数不用串pParams,否则报错。if (##class(BRP.UTIL.Class).GetParamsList(pClassName, pMethodName) = ""){s result = $classmethod(pClassName, pMethodName)} else {s result = $classmethod(pClassName, pMethodName, pParams...)}} catch e {locktro:($tl > 0)if (e.%IsA("BRP.COM.Exception.SessionException")){ret ..Session2Json()} s data = e.Datas:$lv(data) data = $$Format^%qcr(data, 1)s msg = e.Name _ e.Location _ " *" _ data _ $zes ret = $$LOG^%ETN(msg)#; SQL异常if (e.%IsA("BRP.COM.Exception.SqlException")){s msg = e.AsSystemError()ret ..Failure2Json(msg)} elseif (e.%IsA("%Exception.SystemException")){	// 系统异常ret ..Failure2Json($ze )} elseif (e.%IsA("BRP.COM.Exception.ErrorException")){		// 通用错误异常ret ..Failure2Json(msg)} elseif (e.%IsA("%Exception.StatusException")){	// Status错误异常s msg = e.DisplayString()ret ..Failure2Json(msg)} elseif (e.%IsA("BRP.COM.Exception.WarningException")){	// 警告信息s msg = e.AsSystemError()ret ..Warning2Json(msg)} else {	// 其他兜底异常if (msg = ""){s msg = $ze} ret ..Failure2Json(msg)}}ret ..ReturnResult(result)
}ClassMethod HandleToken(token)
{throw:(token = "") $$$WarningException("token异常:", "请先登录")s ret = ##class(Util.Jwt).VerifyJwt(token)q ret
}}

ORM映射的使用

注:ORM映射的使用在《只需要改造一下实体类,以后再也不用写SQL了》此博文中详细阐述,所以不再赘述。

以查询区域Rest接口演示后端框架与ORM的使用

  1. BRP.BL.QUERY.Region中编写查询区域数组的方法。
  • BRP.CT.Region - 为区域实体表。
  • Query方法为封装的ORM映射返回的列表方法可直接返回数组。
Class BRP.BL.QUERY.Region Extends %RegisteredObject
{ClassMethod Query()
{q ##class(BRP.CT.Region).Query()
}}
BRP>zw ##class(BRP.BL.QUERY.Region).Query()
[{"id":17,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"东城区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110101"},{"id":18,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"西城区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110102"},{"id":19,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"朝阳区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110105"},{"id":20,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"丰台区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110106"},{"id":21,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"石景山区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110107"},{"id":22,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"海淀区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110108"},{"id":23,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"门头沟区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110109"},{"id":24,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"房山区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110111"},{"id":25,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"通州区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110112"},{"id":26,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"顺义区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110113"},{"id":27,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"昌平区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110114"},{"id":28,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"大兴区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110115"},{"id":29,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"怀柔区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110116"},{"id":30,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"平谷区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110117"},{"id":31,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"密云区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110118"},{"id":32,"createTime":"2020-06-23 15:48:57","dictCode":null,"hasChildren":false,"isDeleted":0,"name":"延庆区","param":null,"parentId":110100,"updateTime":"2020-06-23 15:52:57","value":"110119"}]  ; <DYNAMIC ARRAY>
  1. BRP.API.Region继承BRP.BL.QUERY.Region并重写Query()并返回。
  • ##super() - 调用父同名方法
Class BRP.API.Region Extends BRP.BL.QUERY.Region
{/// zw ##class(BRP.API.Region).Query()
ClassMethod Query()
{q ##super()
}}
  1. 使用统一入口调用接口方法如下:
s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.Level", "Query")
  1. Rest中定义方法
ClassMethod QueryRegion(dictCode) As %Status
{s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.Region", "Query")w jsonq $$$OK
}
  1. XData路由中定义路径与方法,请求方式。
XData UrlMap
{
<Routes>
<Route Url="/cmn/dict/findByDictCode/:dictCode" Method="GET" Call="QueryRegion"/>
</Routes>
}
  1. 在浏览器中输入接口路径
http://119.3.235.244:52773/api/cmn/dict/findByDictCode/1

在这里插入图片描述

JWT功能

注:JWT功能在《基于M实现的JWT解决方案》此博文中详细阐述,所以不再赘述。

  1. 登录成功后,生成JWT并将JWT保存到用户表或临时Global,用于后续对比。
ClassMethod Login(phone = "", pCaptcha = "")
{s captchaData = ^BRP("Login", "GetCaptcha", phone)s captcha = $lg(captchaData, 1)throw:(captcha '= pCaptcha) $$$LoginException("验证码错误")s id = $o(^BRP.BS.AccountI("Phone", phone, ""))if id = "" {s obj = ##class(BRP.BS.Account).%New()} else {s obj = ##class(BRP.BS.Account).%OpenId(id)}	s jwt = ##class(Util.Jwt).GenerateJwt()s obj.name = phones obj.phone = phones obj.token = jwts sc = obj.%Save()throw:($$$ISERR(sc)) $$$LoginException($system.Status.GetErrorText(sc))s obj = {}s obj.name = phones obj.token = jwtq obj
}
  1. 前端携带登录成功后生成的TOKEN,后端在必要的接口中进行判断。
  • s token = $g(%request.CgiEnvs("HTTP_TOKEN"))获取头信息中的TOKEN
  • HandleToken为验证token是否合法。

在这里插入图片描述

ClassMethod QueryDoctor(hoscode, depcode, workDate) As %Status
{s token = $g(%request.CgiEnvs("HTTP_TOKEN"))s json = ##class(BRP.COM.SafeRun).Execute("BRP.COM.SafeRun", "HandleToken", token)if ({}.%FromJSON(json).code = 0) {w json} else{s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.Doctor", "Query", hoscode, depcode, workDate)w json}q $$$OK
}
  1. 如果未携带TOKEN会提示请先登录。

在这里插入图片描述

  1. 携带TOKEN并成功数据返回正常数据。

在这里插入图片描述

后端处理上传文件

  • 后端处理上传文件功能对应前端HTTP上传图片功能。
  1. 定义后端REST上传文件接口与路由。
  • s binaryStream = $g(%request.MimeData("file", 1))获取前端上传的文件流

在这里插入图片描述

<Route Url="/oss/file/fileUpload" Method="POST" Call="UploadFile"/>
ClassMethod UploadFile() As %Status
{s binaryStream = $g(%request.MimeData("file", 1))s userId = $g(%request.Data("userId",1 )) s json = ##class(BRP.COM.SafeRun).Execute("BRP.API.Amount", "UploadFile", userId , binaryStream)w jsonq $$$OK
}
  1. 实现将文件保存到本地并返回可显示的http图片路径。

在这里插入图片描述

ClassMethod UploadFile(userId, binaryStream)
{s del = "\"s path = "C:\InterSystems\IRISHealth2023\CSP\brp\pic"if $$$isUNIX {s del = "/"s path = "/isc/iris/csp/brp/pic"}s bool = ##class(%File).CreateDirectoryChain(path, .return)s fileName = $zstrip($zdt($now(), 8, , 3), "*E'N") _ ".png"s fullFileName = path _ del _ fileName#dim fileBinaryStream as %Stream.FileBinary = ##class(%Stream.FileBinary).%New()s sc = fileBinaryStream.LinkToFile(fullFileName)$$$ThrowOnError(sc)s sc =  fileBinaryStream.CopyFromAndSave(binaryStream)$$$ThrowOnError(sc)s obj = ##class(BRP.BS.Account).%OpenId(userId)s obj.certificatesPhysicalUrl = fullFileNames sc = obj.%Save()$$$ThrowOnError(sc)q "http://119.3.235.244:52773/csp/brp/pic/" _ fileName
}

在这里插入图片描述

  1. 前端进行预览即可。

在这里插入图片描述

部署

部署云

  • 云服务器选择使用华为云与阿里云。
华为云创建服务器流程
  1. 首先注册华为云帐号,并登录
  • 华为云地址:https://activity.huaweicloud.com/

在这里插入图片描述

  1. 如果提示已注册过,则选择直接开通华为云。

在这里插入图片描述

  1. 选择服务器,24G1个月免费体验,点击立即体验

在这里插入图片描述

  1. 如果没有实名认证,先扫码实名认证

在这里插入图片描述

  1. 选择合适的服务器区域与操作系统,这里选择了CentOS7.9,点击立即购买

在这里插入图片描述

  1. 去支付即可。

在这里插入图片描述

  1. 点击返回HECS云服务器。

在这里插入图片描述

  1. 点击重置密码,该密码为登录云服务器密码。之后就可以通过配置Xshell访问云服务器了。

在这里插入图片描述

阿里云创建服务器流程
  1. 首先注册登录阿里云,选择云服务器。
  • 地址:https://www.aliyun.com/

在这里插入图片描述

  1. 点击免费试用。

在这里插入图片描述

  1. 选择产品配置,与操作系统。点击立即试用。

在这里插入图片描述

  1. 之后会提示创建成功。点击前往控制台。

在这里插入图片描述

  1. 创建成功,点击远程连接。

在这里插入图片描述

  1. 点击重置密码会后,就可以试用Xshell登录了。

在这里插入图片描述

在安装LinuxCentos系统中安装数据库

  1. ISC官网点击下载连接,此时会让你登录帐号,如果没有请先注册。

在这里插入图片描述

  1. 选择社区版。

在这里插入图片描述

3.选择IRIS,并选择操作系统与版本,最后点击下载。

在这里插入图片描述

在这里插入图片描述

  1. 下载完成后将文件上传到云服务器。在跟目录新建文件夹/isc

在这里插入图片描述

  1. 执行如下命令,解压安装包
cd /isc
tar -zxvf IRISHealth-2021.1.3.389.0.22951-lnxrhx64.tar.gz 
  1. cd到解压的目录
cd /isc/IRISHealth-2021.1.3.389.0.22951-lnxrhx64
  1. 执行命令 ./irisinstall,最后会提示安装完成即可。

在这里插入图片描述

  1. 安装完数据库后,需要修改云服务器安全组,开放端口。

在这里插入图片描述

  1. 安全组,点击配置规则

在这里插入图片描述

  1. 添加规则,添加如下端口 51773,52773,1972,80,8088,2188

在这里插入图片描述

  1. 配置完后端口就可以通过studio访问云库与云portal了。

在这里插入图片描述

创建数据库

  1. 打开portal >系统 > 配置 > 本地数据库,点击创建数据库

在这里插入图片描述

  1. 创建BRP-DATA数据库用于保存GlobalBRP-SRC数据库用于保存例程。下一步到完成即可。

在这里插入图片描述

  1. 创建完城后如下:

在这里插入图片描述

创建命名空间

  1. 在 系统 > 配置 > 命名空间 中点击新建命名空间。填写如下:
  • 命名空间为:BRP
  • Global数据库为:BRP-DATA
  • Routine数据库为:BRP-SRC

在这里插入图片描述

  1. 点击保存后,该命名空间创建成功

在这里插入图片描述

创建Application

  1. 系统 > 安全管理 > Web 应用程序,点击新建应用程序填写如下:
  • 名称:/api
  • 描述:预约挂号接口
  • 命名空间:BRP
  • 启用:REST
  • 分派类:BRP.COM.REST.Api

在这里插入图片描述

  1. 保存成功后rest接口可通过http访问。

在这里插入图片描述

  1. Application中的/api路径会自动追加到定义的路由路径中。

在这里插入图片描述

  1. 如果HTTP接口返回403,是因为UnknownUser权限不足,重新分配权限。

在这里插入图片描述

三库分离

  1. 根据创建数据库操作,分别创建BRP-CFBRP-BSBRP-CT数据库。
  • BRP-CF:配置数据库
  • BRP-CT:字典数据库
  • BRP-BS:业务数据库

在这里插入图片描述

  1. 在系统 > 配置 > 命名空间,选在BRP命名空间,选择Global映射。增加如下映射。
  • BRP.BS*开头的Global映射到BRP-BS库中
  • BRP.CF*开头的Global映射到BRP-BS库中
  • BRP.CT*开头的Global映射到BRP-BS库中

在这里插入图片描述

  1. 在系统 > Global中,验证三库分离是否成功。
  • 选择Databse查看对应的Global数据是否值,并且Global节点是否映射正确。

在这里插入图片描述

在这里插入图片描述

创建灾备数据库

  1. 分别为华为云服务器与阿里云服务器启用ISCAgent服务。
  • systemctl start ISCAgent
  • systemctl status ISCAgent
  • systemctl enable ISCAgent
[root@hecs-210841 ~]# systemctl start ISCAgent
[root@hecs-210841 ~]# systemctl status ISCAgentISCAgent.service - InterSystems AgentLoaded: loaded (/etc/systemd/system/ISCAgent.service; enabled; vendor preset: disabled)Active: active (running) since Mon 2023-12-25 20:40:46 CST; 13h agoMain PID: 18214 (ISCAgent)CGroup: /system.slice/ISCAgent.service├─18214 /usr/local/etc/irissys/ISCAgent├─18215 /usr/local/etc/irissys/ISCAgent├─20695 /usr/local/etc/irissys/ISCAgent└─20697 /usr/local/etc/irissys/ISCAgent
[root@hecs-210841 ~]# systemctl enable ISCAgent
  1. 启用后,进入portal,配置 - 镜像设置- 创建镜像才菜单可以使用了,在DB华为云上创建镜像。

在这里插入图片描述

  1. 填写如下信息:
  • 镜像名称:244DB
  • 不要使用SSL/TLS
  • 使用仲裁程序填写地址:XXX.XXX.XXX.XXX
  • 端口号默认:2188
  • 填写超级服务器地址:XXX.XXX.XXX.XXX

在这里插入图片描述

  1. 成功后,系统 - 镜像监视器显示如下图:

在这里插入图片描述

  1. 在阿里云MIRROR上,点击 系统 > 配置 > 将镜像加入为故障转移。
  • 镜像名称 :244DB
  • 代理地址为:华为云地址
  • 端口默认
  • 实例名称:IRIS

在这里插入图片描述

  1. 下一步 - 保存

在这里插入图片描述

  1. 回到华为云DB上查看镜像监视器,发现镜像成功

在这里插入图片描述

  1. 回到阿里云上查看镜像监视器,发现已同步成功

在这里插入图片描述

备份数据库

  1. DB上执行如下命令进行数据库备份,然后在MIRROR上进行数据恢复。
%SYS>d ^BACKUP1) Backup
2) Restore ALL
3) Restore Selected or Renamed Directories
4) Edit/Display List of Directories for Backups
5) Abort Backup
6) Display Backup volume information
7) Monitor progress of backup or restoreOption? 1*** The time is: 2023-12-26 10:14:36 ***InterSystems IRIS Backup Utility--------------------------
What kind of backup:1. Full backup of all in-use blocks2. Incremental since last backup3. Cumulative incremental since last full backup4. Exit the backup program
1 => y?? Type the number of the function you wantWhat kind of backup:1. Full backup of all in-use blocks2. Incremental since last backup3. Cumulative incremental since last full backup4. Exit the backup program
1 => 1
Specify output device (type STOP to exit)
Device: /isc/FullDBList_user.cbk => /isc/setmirror.cbk =>  
Backing up to device: /isc/FullDBList_user.cbk => /isc/setmirror.cbk
Description: backupdbBacking up the following directories:/isc/iris/mgr//isc/iris/mgr/HSCUSTOM//isc/iris/mgr/brpbs//isc/iris/mgr/brpcf//isc/iris/mgr/brpct//isc/iris/mgr/brpdata//isc/iris/mgr/brpsrc//isc/iris/mgr/hslib//isc/iris/mgr/hssys//isc/iris/mgr/irisaudit//isc/iris/mgr/user/Start the Backup (y/n)? => y

在这里插入图片描述

在这里插入图片描述

  1. 备份成功后,将备份文件发送到MIRROR服务器上。
  • scp 本地cbk路径,要发送的服务器地址。
  • 输入MIRROR服务器密码,等待传送数据即可。
scp /isc/setmirror.cbk root@123.57.246.161:/isc
Enter passphrase for key '/root/.ssh/id_rsa':
root@123.57.246.161's password:
setmirror.cbk   

恢复数据库

  1. 在阿里云MIRROR服务器上执行如下命令进行数据库恢复。

%SYS>do ^DBREST         Cache DBREST UtilityRestore database directories from a backup archiveRestore: 1. All directories2. Selected and/or renamed directories3. Display backup volume information4. Exit the restore program1 => 2Do you want to set switch 10 so that other processes will be
prevented from running during the restore? Yes => yesSpecify input file for volume 1 of backup 1(Type STOP to exit)
Device: /isc/setmirror.cbkThis backup volume was created by:IRIS for UNIX (Red Hat Enterprise Linux for x86-64) 2021.1.3The volume label contains:Volume number      1Volume backup      DEC 25 2023 09:43PM FullPrevious backup      Last FULL backup    Description        /isc/setmirror.cbkBuffer Count       0Mirror name        244DBFailover Member    HECS-210841/IRIS
Is this the backup you want to start restoring? Yes => yes
This backup was made on the other mirror member.
Limit restore to mirrored databases? noFor each database included in the backup file, you can:-- press RETURN to restore it to its original directory;-- type X, then press RETURN to skip it and not restore it at all.-- type a different directory name.  It will be restored to the directoryyou specify.  (If you specify a directory that already contains a database, the data it contains will be lost)./isc/iris/mgr/ => 
/isc/iris/mgr/HSCUSTOM/ => 
/isc/iris/mgr/brpbs/ => 
/isc/iris/mgr/brpcf/ => 
/isc/iris/mgr/brpct/ => 
/isc/iris/mgr/brpdata/ => 
/isc/iris/mgr/brpsrc/ => 
/isc/iris/mgr/hslib/ => 
/isc/iris/mgr/hssys/ => 
/isc/iris/mgr/irisaudit/ => 
/isc/iris/mgr/user/ => Do you want to change this list of directories? No => Restore will overwrite the data in the old database. Confirm Restore? No => yes***Restoring /isc/iris/mgr/ at 09:36:09
13107 blocks restored in 0.4 seconds for this pass, 13107 total restored.***Restoring /isc/iris/mgr/HSCUSTOM/ at 09:36:10
1397 blocks restored in 0.1 seconds for this pass, 1397 total restored....***Restoring /isc/iris/mgr/user/ at 09:36:45
1 blocks restored in 0.0 seconds for this pass, 79 total restored.Specify input file for volume 1 of backup following DEC 25 2023  09:43PM(Type STOP to exit)
Device: Do you have any more backups to restore? Yes => no
Mounting /isc/iris/mgr//isc/iris/mgr/        ... (Mounted)Mounting /isc/iris/mgr/HSCUSTOM//isc/iris/mgr/HSCUSTOM/  ... (Mounted)
...Mounting /isc/iris/mgr/user//isc/iris/mgr/user/   ... (Mounted)Restoring a directory restores the globals in it only up to the
date of the backup.  If you have been journaling, you can apply  
journal entries to restore any changes that have been made in the
globals since the backup was made.What journal entries do you wish to apply?1. All entries for the directories that you restored2. All entries for all directories3. Selected directories and globals4. No entriesApply: 1 => 1We know something about where journaling was at the time of the backup:
0: offset 198000 in /isc/iris/mgr/journal/MIRROR-244DB-20231225.003Are journal files created by this IRIS instance and located in their original
paths? (Uses journal.log to locate journals)?   enter Yes or No, please
Are journal files created by this IRIS instance and located in their original
paths? (Uses journal.log to locate journals)? yes
The earliest journal entry since the backup was made is at
offset 198000 in /isc/iris/mgr/journal/MIRROR-244DB-20231225.003Do you want to start from that location? Yes => Yes
/isc/iris/mgr/journal/MIRROR-244DB-20231225.003 is NOT in journal history log /isc/iris/mgr/journal.log
You might have specified a wrong journal history log[Not restored]%SYS>
  1. 恢复成功后查看MIRROR 数据Global恢复成功。

在这里插入图片描述

将数据库加入MIRROR

  1. 在系统 - 配置 - 本地数据库,点击添加到镜像,选择MIRROR的数据库,添加即可。

在这里插入图片描述

部署NGINX

  1. 在官网下载nginx

在这里插入图片描述

  1. 下载完成后,上传到云服务器。运行命令解压。
tar -zxvf nginx-1.24.0.tar.gz

在这里插入图片描述

  1. 解压后执行./configurem配置命令,发现有很多not found

img

  1. 安装依赖。
yum install gcc-c++
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y openssl openssl-devel
make && make install
  1. 安装成功进入/usr/local/nginx查看文件是否存在confsbinhtml文件夹,若存在则安装成功

在这里插入图片描述

打包前端文件

  1. brp-web-app项目的termina中执行打包命令pnpm run build。会生成的打包文件dist

在这里插入图片描述

  1. dist文件放入到云服务器nginxhtml目录中

在这里插入图片描述

  1. 执行命令./nginx启动。若/usr/local/nginx/logs中error.log无报错则表示启动成功。

跨越问题处理

  • 启动nginx后发现无法访问后台接口提示404CORS跨越错误。需要做出如下修改:
  1. 在前端文件vite.config.ts中增加如下配置:
  • 表示前端需要代理的跨域后端的接口。
  • /api表示路径中包含此路径代表是需要代理的请求。
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({...server: {proxy: {"/api": {target: "http://119.3.235.244:52773/",changeOrigin: true,},},},
});
  1. \utils\request.ts中增加如下配置:
  • 此配置代表会为后端请求自动增加/api路径。
const request = axios.create({baseURL: "/api",timeout: 5000,
});
  1. ngnixconf路径下nginx.conf做出如下修改:
  • location /api 表示在ngnix中为此路径字段替换为http://119.3.235.244:52773进行转发。

注:此处的/apihttp://119.3.235.244:52773后边均不带/,写成/api/http://119.3.235.244:52773/则代理失败。需要与前端文件的vite配置路径一一对应。

    server {listen       80;server_name  localhost;client_header_buffer_size 1M;large_client_header_buffers 4 1M;#charset koi8-r;#access_log  logs/host.access.log  main;location / {root   html;try_files $uri $uri/ /index.html last;index  index.html index.htm;client_max_body_size 100M;}location /api {proxy_pass http://119.3.235.244:52773;break;}}
  1. 重新启用./nginx -s quit && ./nginx*,查看跨越问题是否解决。

在这里插入图片描述

使用Git进行版本控制

注:Git详细使用可以查看《Git使用大全》

  1. 在项目目录创建Git仓库

在这里插入图片描述

  1. 添加并提交。

在这里插入图片描述

上传Github

  1. git上生成token

在这里插入图片描述

  1. Github上创建仓库brp-app-web,选择公开仓库。

在这里插入图片描述

  1. 用小乌龟PushGitHub远程仓库。
  • 输入账号密码
  • 再次输入帐号,密码使用刚生成的Token

在这里插入图片描述

  1. 查看文件是否推送成功

在这里插入图片描述

创造价值,分享学习,一起成长,相伴前行,欢迎大家提出意见,共同交流。

相关文章:

开源预约挂号平台 - 从0到上线

文章目录 开源预约挂号平台 - 从0到上线演示地址源码地址可以学到的技术前端技术后端技术部署上线开发工具其他技术业务功能 项目讲解前端创建项目 - 安装PNPM - 使用VSCODE - 安装插件首页顶部与底部 - 封装组建 - 使用scss左右布局中间内容部分路由 - vue-routerBANNER- 走马…...

Vue3的proxy

vue3.0中,使用proxy替换了原来遍历对象使用Object.defineProperty方法给属性添加set/get    vue的核心能力之一是监听用户定义的状态变化并响应式刷新DOM   vue2是通过替换状态对象属性的getter和setter来实现的,vue3则通过proxy进行   改为proxy后,可以突破vue当前的…...

Vue Router的介绍与引入

在这里是记录我引入Vue Router的全过程&#xff0c;引入方面也最好先看官方文档 一.介绍 Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成&#xff0c;让用 Vue.js 构建单页应用变得轻而易举。功能包括&#xff1a; 嵌套路由映射动态路由选择模块化、基于组件的…...

StratifiedKFold解释和代码实现

StratifiedKFold解释和代码实现 文章目录 一、StratifiedKFold是什么&#xff1f;二、 实验数据设置2.1 实验数据生成代码2.2 代码结果 三、实验代码3.1 实验代码3.2 实验结果3.3 结果解释3.4 数据打乱对这种交叉验证的影响。 四、总结 一、StratifiedKFold是什么&#xff1f; …...

四十八----react实战

一、项目中css模块化管理 1、css-loader 以下可以使用styles.xxx方式使用class是因为使用css-loader配置了module。 import styles from ./index.less export const App(){return <div className={styles.xxx}>hello word</div> }//webpack配置 {test:/\.css$/,u…...

三步实现Java的SM2前端加密后端解密

秦医如毒&#xff0c;无药可解。 话不多说&#xff0c;先上需要用到的js文件下载链接 和 jsp前端代码。 第一步&#xff1a;下载两个必备的js文件—— crypto-js.js、sm2.js 。 它们的下载链接如下↓&#xff08;该网页不魔法上网的话会很卡&#xff0c;毕竟github&#x…...

1分钟带你了解golang(go语言)

Golang&#xff1a;也被称为Go语言&#xff0c;是一种开源的编程语言。由Google的Robert Griesemer、Rob Pike和Ken Thompson于2007年开始设计&#xff0c;2009年11月正式对外发布。&#xff08;被誉为21世纪的C语言&#xff09; 像python一样的优雅&#xff0c;有c一样的性能…...

CSS-4

平面转换 整体认识 div {margin: 100px 0;width: 100px;height: 100px;background-color: pink;/* 过渡效果 */transition: all 1s;}/* 当鼠标悬停到div时&#xff0c;进行平面转换 */div:hover {transform: translate(800px) rotate(360deg) scale(2) skew(180deg);}作用&…...

Python为何适合开发AI项目?

Python在人工智能&#xff08;AI&#xff09;项目中的流行和广泛应用归因于多个因素&#xff0c;其中一些主要原因包括&#xff1a; 1、易学易用&#xff1a; Python语法简洁清晰&#xff0c;易于学习和理解。这使得新手能够更容易上手&#xff0c;并且对于处理复杂的AI算法和…...

总结心得:各设计模式使用场景

单例模式&#xff1a;创建单个对象 工厂模式&#xff1a;创建对象交给工厂完成&#xff0c;当需要创建的对象是一系列相互关联或相互依赖的产品族时 原型模式&#xff1a;克隆对象&#xff0c;避免创建初始化开销 建造者模式&#xff1a;创建一个复杂对象&#xff0c;该对象…...

详解Vue3中的事件监听方式

本文主要介绍Vue3中的事件监听方式。 目录 一、v-on指令二、使用符号简写三、事件修饰符四、动态事件名五、常见的监听事件六、自定义事件 在Vue3中&#xff0c;事件监听的方式与Vue2有一些不同。 下面是Vue3中事件监听方式的详细介绍&#xff1a; 一、v-on指令 Vue3中仍然使…...

Unity关于easySave2 easySave3保存数据的操作;包含EasySave3运行报错的解决

关于easySave2 easySave3保存数据的操作&#xff1b;包含EasySave3运行报错的解决 /// 数据存储路径&#xff08;Easy Save的默认储存位置为&#xff1a;Application.persistentDataPath&#xff0c;为了方便我们可以给它指定储存路径&#xff09; #region 存储数据/*/// /// 存…...

2022年全球软件质量效能大会(QECon上海站)-核心PPT资料下载

一、峰会简介 近年来&#xff0c;以云计算、移动互联网、物联网、工业互联网、人工智能、大数据及区块链等新一代信息技术构建的智能化应用和产品出现爆发式增长&#xff0c;突破了对于软件形态的传统认知&#xff0c;正以各种展现方式诠释着对新型智能软件的定义。这也使得对…...

【python报错】UserWarning: train_labels has been renamed targets

UserWarning: train_labels has been renamed targetswarnings.warn(“train_labels has been renamed targets”) 这是一条 Python 警告信息&#xff0c;它表示 train_labels 这个变量已经被重命名为 targets&#xff0c;在将来的版本中可能会移除 train_labels。因此&#x…...

算法专题四:前缀和

前缀和 一.一维前缀和(模板)&#xff1a;1.思路一&#xff1a;暴力解法2.思路二&#xff1a;前缀和思路 二. 二维前缀和(模板)&#xff1a;1.思路一&#xff1a;构造前缀和数组 三.寻找数组的中心下标&#xff1a;1.思路一&#xff1a;前缀和 四.除自身以外数组的乘积&#xff…...

STM32学习笔记十五:WS2812制作像素游戏屏-飞行射击游戏(5)探索动画之帧动画

本章又是个重要的章节——动画。 动画&#xff0c;本质上时一系列静态的画面连续播放&#xff0c;欺骗人眼产生动画效果。这个原理自打十九世纪电影诞生开始&#xff0c;就从来没变过。 我们的游戏中也需要一些动画效果&#xff0c;比如&#xff0c;被击中时的受伤效果&#…...

期末复习(程序设计)

根据字符出现频率排序 【问题描述】 给定一个字符串 s &#xff0c;根据字符出现的 频率 对其进行降序排序。一个字符出现的频率是它出现在字符串中的次数。 返回已排序的字符串。 频率相同的的字符按ascii值降序排序。 s不包含空格、制表符、换行符等特殊字符。 【输入格…...

html-css-js移动端导航栏底部固定+i18n国际化全局

需求&#xff1a;要做一个移动端的仿照小程序的导航栏页面操作&#xff0c;但是这边加上了i18n国家化&#xff0c;由于页面切换的时候会导致国际化失效&#xff0c;所以写了这篇文章 1.效果 切换页面的时候中英文也会跟着改变&#xff0c;不会导致切换后回到默认的语言 2.实现…...

Ubuntu Linux 入门指南:面向初学者

目录 1. Ubuntu Linux 简介 Ubuntu 的由来 Ubuntu 与其他 Linux 发行版的比较 Debian&#xff1a; Fedora&#xff1a; openSUSE&#xff1a; Arch Linux&#xff1a; Linux Mint&#xff1a; 第二部分&#xff1a;安装 Ubuntu 1. 准备安装 系统需求 创建 Ubuntu 启…...

常见算法面试题目

前言 总结一些常见的算法题目&#xff0c;每一个题目写一行思路&#xff0c;方便大家复习。具体题目的来源是下面的网站。 剑指offer 剑指offe2 leetcode200题 leetcode 100题 leetcode150题 leetcode 75题 文章目录 前言二叉树非递归遍历牛客JZ31 栈的压入、弹出序列 (…...

PiflowX组件-JDBCWrite

JDBCWrite组件 组件说明 使用JDBC驱动向任意类型的关系型数据库写入数据。 计算引擎 flink 有界性 Sink: Batch Sink: Streaming Append & Upsert Mode 组件分组 Jdbc 端口 Inport&#xff1a;默认端口 outport&#xff1a;默认端口 组件属性 名称展示名称默…...

算法导论复习题目

这题需要考虑什么呢&#xff1f; 一换元&#xff0c;二要使用主方法猜出结果&#xff0c;三是证明的时候添加一个低阶项来消除 LC检索 C&#xff08;x&#xff09;是从上帝视角来看的成本 对C(x)的一个估计&#xff1a; 由两个部分组成&#xff0c;就相当于由以往的经验对未来…...

HTTPS协议详解

目录 前言 一、HTTPS协议 1、加密是什么 2、为什么要加密 二、常见加密方式 1、对称加密 2、非对称加密 三、数据摘要与数据指纹 1、数据摘要 2、数据指纹 四、HTTPS加密策略探究 1、只使用对称加密 2、只使用非对称加密 3、双方都使用非对称加密 4、对称加密非…...

菜鸟学习vue3笔记-vue3 router回顾

1、路由router pnpm i vue-router2、创建使用环境 1.src下创建 router文件夹、里面创建index.ts文件 //创建一个路由暴露出去//1.引入createRouter import { createRouter, createWebHistory } from "vue-router";// import Home from ../components/Home.vue//…...

Mybatis枚举类型处理和类型处理器

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…...

2023 NCTF writeup

CRYPTO Sign 直接给了fx,gx&#xff0c;等于私钥给了&#xff0c;直接套代码&#xff0c;具体可以参考&#xff1a; https://0xffff.one/d/1424 fx [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…...

golang的大杀器协程goroutine

在Golang中&#xff0c;协程&#xff08;Goroutine&#xff09;是轻量级的执行单元&#xff0c;用于实现并发编程。它是Golang语言的重要组成部分&#xff0c;提供了简洁、高效的方式来处理并发任务。 特点&#xff1a; 1&#xff09;轻量级&#xff1a;Go语言的协程是轻量级…...

[Angular] 笔记 9:list/detail 页面以及@Output

1. Output input 好比重力&#xff0c;向下传递数据&#xff0c;list 传给 detail&#xff0c;smart 组件传给 dumb 组件&#xff0c;父组件传给子组件。input 顾名思义&#xff0c;输入数据给组件。 output 与之相反&#xff0c;好比火箭&#xff0c;向上传递数据或事件。ou…...

Linux学习笔记(一)

如果有自己的物理服务器请先查看这篇文章 文章目录 网卡配置Linux基础指令ls:列出目录内容cd(mkdir.rmkdir): 切换文件夹(创建,删除操作)cp:复制文件或目录mv:文件/文件夹移动cat:查看文件vi:文件查看编辑man:查看命令手册more: 查看文件内容less : 查看文件内容 ps: 显示当前进…...

Python 爬虫 教程

python爬虫框架&#xff1a;Scrapyd&#xff0c;Feapder&#xff0c;Gerapy 参考文章&#xff1a; python爬虫工程师&#xff0c;如何从零开始部署ScrapydFeapderGerapy&#xff1f; - 知乎 神器&#xff01;五分钟完成大型爬虫项目 - 知乎 爬虫框架-feapder - 知乎 scrap…...

uniapp原生插件 - android原生插件打包流程 ( 避坑指南一)

【彩带- 避坑知识点】: 当时开发中安卓插件打包成功后&#xff0c;uniapp引用插件aar&#xff0c;用云打包 &#xff0c;总是提示不包含插件。原因是因为module的androidManifest.xml文件没有注册activity。 这一步 很重要&#xff0c;一定要注册。 --------------------------…...

搭建maven私服

maven maven简介 什么是maven&#xff1f; Maven这个单词来自于意第绪语&#xff08;犹太语&#xff09;&#xff0c;意为知识的积累。 Maven项目对象模型(POM)&#xff0c;可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 Maven 除了以…...

EST-100身份证社保卡签批屏按捺终端PC版web版本http协议接口文档,支持web网页开发对接使用

<!DOCTYPE html><html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,initial-scale1.0"><title>演示DEMO</title><script type"text/…...

基于SpringBoot的毕业论文管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的毕业论文管理系统,java…...

iToF人脸识别

iToF(间接飞行时间)是一种测量光飞行时间的技术,主要应用于人脸识别。 iToF人脸识别技术在哪些场景下会用到 iToF人脸识别技术可以应用于许多场景,以下是一些常见的应用场景: 平安城市:在城市监控系统中,iToF人脸识别技术可以用于实时监控、目标检测和识别,以及异常行为…...

Django开发3

Django开发3 Django开发编辑用户9.靓号管理9.1 表结构9.2 靓号列表9.3 新建靓号9.4 编辑靓号9.5 搜索手机号9.6 分页 10.时间插件11.ModelForm和BootStrap操作 各位小伙伴想要博客相关资料的话关注公众号&#xff1a;chuanyeTry即可领取相关资料&#xff01; Django开发 部门管…...

MS2358:96KHz、24bit 音频 ADC

产品简述 MS2358 是带有采样速率 8kHz-96kHz 的立体声音频模数 转换器&#xff0c;适合于面向消费者的专业音频系统。 MS2358 通过使用增强型双位 Δ - ∑ 技术来实现其高精度 的特点。 MS2358 支持单端的模拟输入&#xff0c;所以不需要外部器 件&#xff0c;非常适…...

【Android12】Android Framework系列---tombstone墓碑生成机制

tombstone墓碑生成机制 Android中程序在运行时会遇到各种各样的问题&#xff0c;相应的就会产生各种异常信号&#xff0c;比如常见的异常信号 Singal 11&#xff1a;Segmentation fault表示无效的地址进行了操作&#xff0c;比如内存越界、空指针调用等。 Android中在进程(主要…...

中间件系列 - Redis入门到实战(原理篇)

前言 学习视频&#xff1a; 黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目 中间件系列 - Redis入门到实战 本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删除 学习目标 Redis数据结构Redis网…...

P2249 【深基13.例1】查找

P2249 【深基13.例1】查找 P2249 【深基13.例1】查找 题意 输入n 个不超过10的9次方的单调不减的&#xff08;就是后面的数字不小于前面的数字&#xff09;非负整数a1&#xff0c;a2&#xff0c;a3…然后进行 m 次询问。对于每次询问&#xff0c;给出一个整数q&#xff0c;要…...

linux常用shell脚本

查看系统当前进程连接数 netstat -an | grep ESTABLISHED | wc -l 如何在/usr目录下找出大小超过10MB的文件? find /usr -type f -size 10240k 添加一条到192.168.3.0/24的路由&#xff0c;网关为192.168.1.254&#xff1f; route add -net 192.168.3.0/24 netmask 255.2…...

Rust学习笔记005:结构体 struct

在 Rust 中&#xff0c;struct 是一种用于创建自定义数据类型的关键字&#xff0c;它允许你定义和组织数据的结构。struct 可以包含多个不同类型的字段&#xff08;fields&#xff09;&#xff0c;每个字段都有一个名称和一个类型。 定义结构体 下面是一个简单的例子&#xff…...

maven中dependencyManagement标签

简介 dependencyManagement正如其名&#xff0c;用于项目依赖的统一管理。 在父项目中的pom.xml文件中加入dependencyManagement标签即可完成依赖版本的声明。在声明完成后&#xff0c;子项目&#xff08;module&#xff09;中引用相同的依赖时可以不指定version标签自动引入…...

SparkStreaming与Kafka整合

1.3 SparkStreaming与Kafka整合 1.3.1 整合简述 kafka是做消息的缓存&#xff0c;数据和业务隔离操作的消息队列&#xff0c;而sparkstreaming是一款准实时流式计算框架&#xff0c;所以二者的整合&#xff0c;是大势所趋。 ​ 二者的整合&#xff0c;有主要的两大版本。 kaf…...

openwrt源码编译

下载openwrt源码 git clone https://github.com/openwrt/chaos_calmer.git // 官方下载地址 当前我们基于15.05版本开发&#xff0c;如果开发者想用最新的OpenWRT系统&#xff0c;可以下载 https://github.com/openwrt/openwrt.git git clone https://github.com/Ying-Yun/o…...

【Leetcode Sheet】Weekly Practice 22

Leetcode Test 1349 参加考试的最大学生数(12.26) 给你一个 m * n 的矩阵 seats 表示教室中的座位分布。如果座位是坏的&#xff08;不可用&#xff09;&#xff0c;就用 # 表示&#xff1b;否则&#xff0c;用 . 表示。 学生可以看到左侧、右侧、左上、右上这四个方向上紧邻…...

ROS TF坐标变换 - 静态坐标变换

目录 一、静态坐标变换&#xff08;C实现&#xff09;二、静态坐标变换&#xff08;Python实现&#xff09; 如前文所属&#xff0c;ROS通过广播的形式告知各模块的位姿关系&#xff0c;接下来详述这一机制的代码实现。 模块间的位置关系有两种类型&#xff0c;一种是相对固定…...

香橙派5plus从ssd启动Ubuntu

官方接口图 我实际会用到的就几个接口&#xff0c;背面的话就一个M.2固态的位置&#xff1a; 其中WIFI模块的接口应该也可以插2230的固态&#xff0c;不过是pcie2.0的速度&#xff0c;背面的接口则是pcie3.0*4的速度&#xff0c;差距还是挺大的。 开始安装系统 准备工作 一张…...

JWT+Redis 实现接口 Token 校验

1、业务逻辑 有一些接口&#xff0c;需要用户登录以后才能访问&#xff0c;用户没有登录则无法访问。 因此&#xff0c;对于一些限制用户访问的接口&#xff0c;可以在请求头中增加一个校验参数&#xff0c;用于判断接口对应的用户是否登录。 而对于一些不需要登录即可访问的接…...

C语言 linux文件操作(二)

文章目录 一、获取文件长度二、追加写入三、覆盖写入四、文件创建函数creat 一、获取文件长度 通过lseek函数&#xff0c;除了操作定位文件指针&#xff0c;还可以获取到文件大小&#xff0c;注意这里是文件大小&#xff0c;单位是字节。例如在file1文件中事先写入"你好世…...