This commit is contained in:
程蕊 2024-10-22 13:20:35 +08:00
commit 80e2636082
37 changed files with 12058 additions and 0 deletions

33
.gitignore vendored Normal file
View File

@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

100
pom.xml Normal file
View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>IntelligentMedicalPlatform</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>IntelligentMedicalPlatform</name>
<description>IntelligentMedicalPlatform</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,11 @@
package edu.blm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootvueApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootvueApplication.class, args);
}
}

View File

@ -0,0 +1,19 @@
package edu.blm.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
// 使用 allowedOriginPatterns 代替 allowedOrigins
.allowedOriginPatterns("http://localhost:8080")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}

View File

@ -0,0 +1,36 @@
package edu.blm.controller;
import edu.blm.pojo.User;
import edu.blm.service.UserApprovalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user/approval")
@CrossOrigin(origins = "http://localhost:8080")
public class UserApprovalController {
// 通过字段注入的方式引入 UserApprovalService
@Autowired
private UserApprovalService userApprovalService;
//获取待审核用户列表接口
@RequestMapping("/pending")
public List<User> getPendingUsers() {
return userApprovalService.getPendingUsers();
}
//批准用户接口
@PostMapping("/approve/{username}")
public void approveUser(@PathVariable String username) {
userApprovalService.approveUser(username);
}
//拒绝用户接口
@PostMapping("/reject/{username}")
public void rejectUser(@PathVariable String username) {
userApprovalService.rejectUser(username);
}
}

View File

@ -0,0 +1,54 @@
package edu.blm.controller;
import edu.blm.pojo.Result;
import edu.blm.pojo.User;
import edu.blm.service.UserService;
import edu.blm.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
@CrossOrigin(origins = "http://localhost:8080")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public Result register(@RequestBody User user) {
String username = user.getUsername();
String password = user.getPassword();
//查询用户
User u = userService.findByUser(username);
if(u == null) {
//注册
userService.register(username, password);
return Result.success();
}
else {
return Result.error("用户名已占用");
}
}
@PostMapping("/login")
public Result login(@RequestBody User user) {
String username = user.getUsername();
String password = user.getPassword();
User u = userService.findByUser(username);
if(u == null) {
return Result.error("用户名错误");
}
if(Md5Util.getMD5String(password).equals(u.getPassword())){
return Result.success(u);
}else{
return Result.error("密码错误");
}
}
}

View File

@ -0,0 +1,33 @@
package edu.blm.mapper;
import edu.blm.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
@Mapper
public interface UserMapper {
// 查询
@Select("select * from user where username = #{username}")
User findByUser(String username);
// 新增并设置审核状态为 0
@Insert("insert into user(username, password, create_time, update_time, role,audit_status)" +
"values(#{username},#{password},now(),now(),0,0)")
void add(String username, String password);
// 获取待审核用户
@Select("SELECT * FROM user WHERE audit_status = 0 ")
List<User> getPendingUsers();
// 批准用户确保只有审核状态为 0 的用户能被批准
@Update("UPDATE user SET audit_status = 1 WHERE username = #{username}")
void approveUser(String username);
// 拒绝用户
@Update("UPDATE user SET audit_status = 2 WHERE username = #{username}")
void rejectUser(String username);
}

View File

@ -0,0 +1,28 @@
package edu.blm.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
private Integer code; //业务状态码 0-成功 1-失败
private String message; //提示信息
private T data; //响应数据
//快捷返回操作成功响应结果
public static <T> Result<T> success(T data) {
return new Result<T>(0, "success", data);
}
public static Result success() {
return new Result(0, "success", null);
}
public static Result error(String message) {
return new Result(1, message, null);
}
}

View File

@ -0,0 +1,17 @@
package edu.blm.pojo;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class User {
private Integer id;
private String username;
private String password;
private String email;
private Integer role;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private Integer auditStatus;
}

View File

@ -0,0 +1,10 @@
package edu.blm.service;
import edu.blm.pojo.User;
import java.util.List;
public interface UserApprovalService {
List<User> getPendingUsers();
void approveUser(String username);
void rejectUser(String username);
}

View File

@ -0,0 +1,11 @@
package edu.blm.service;
import edu.blm.pojo.User;
public interface UserService {
//根据用户名查询数据库
User findByUser(String username);
//注册 将用户名和密码添加到数据库中
void register(String username, String password);
}

View File

@ -0,0 +1,34 @@
package edu.blm.service.impl;
import edu.blm.mapper.UserMapper;
import edu.blm.pojo.User;
import edu.blm.service.UserApprovalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserApprovalServiceImpl implements UserApprovalService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> getPendingUsers() {
return userMapper.getPendingUsers();
}
@Transactional
@Override
public void approveUser(String username) {
userMapper.approveUser(username);
}
@Transactional
@Override
public void rejectUser(String username) {
userMapper.rejectUser(username);
}
}

View File

@ -0,0 +1,29 @@
package edu.blm.service.impl;
import edu.blm.mapper.UserMapper;
import edu.blm.pojo.User;
import edu.blm.service.UserService;
import edu.blm.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByUser(String username) {
User u = userMapper.findByUser(username);
return u;
}
@Override
public void register(String username, String password) {
//加密
String md5String = Md5Util.getMD5String(password);
//添加
userMapper.add(username,md5String);
}
}

View File

@ -0,0 +1,72 @@
package edu.blm.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Util {
/**
* 默认的密码字符串组合用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
*/
protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
protected static MessageDigest messagedigest = null;
static {
try {
messagedigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsaex) {
System.err.println(Md5Util.class.getName() + "初始化失败MessageDigest不支持MD5Util。");
nsaex.printStackTrace();
}
}
/**
* 生成字符串的md5校验值
*
* @param s
* @return
*/
public static String getMD5String(String s) {
return getMD5String(s.getBytes());
}
/**
* 判断字符串的md5校验码是否与一个已知的md5码相匹配
*
* @param password 要校验的字符串
* @param md5PwdStr 已知的md5校验码
* @return
*/
public static boolean checkPassword(String password, String md5PwdStr) {
String s = getMD5String(password);
return s.equals(md5PwdStr);
}
public static String getMD5String(byte[] bytes) {
messagedigest.update(bytes);
return bufferToHex(messagedigest.digest());
}
private static String bufferToHex(byte bytes[]) {
return bufferToHex(bytes, 0, bytes.length);
}
private static String bufferToHex(byte bytes[], int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
appendHexPair(bytes[l], stringbuffer);
}
return stringbuffer.toString();
}
private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>>
// 为逻辑右移将符号位一起右移,此处未发现两种符号有何不同
char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换
stringbuffer.append(c0);
stringbuffer.append(c1);
}
}

View File

@ -0,0 +1,9 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/blm
username: root
password: 123456
server:
port: 8081

View File

@ -0,0 +1,13 @@
package org.example.intelligentmedicalplatform;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class IntelligentMedicalPlatformSpringbootvueApplicationTests {
@Test
void contextLoads() {
}
}

23
vue/.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

19
vue/README.md Normal file
View File

@ -0,0 +1,19 @@
# vue
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

5
vue/babel.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

19
vue/jsconfig.json Normal file
View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

10703
vue/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

30
vue/package.json Normal file
View File

@ -0,0 +1,30 @@
{
"name": "vue",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.7.7",
"core-js": "^3.8.3",
"element-plus": "^2.8.4",
"vue": "^3.2.13",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

BIN
vue/public/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

17
vue/public/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="./image.png">
<title>智能医疗平台</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

7
vue/src/App.vue Normal file
View File

@ -0,0 +1,7 @@
<template>
<router-view/>
</template>
<style>
</style>

BIN
vue/src/assets/b.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
vue/src/assets/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

16
vue/src/main.js Normal file
View File

@ -0,0 +1,16 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 引入element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(router)
app.use(ElementPlus)
app.mount('#app')

60
vue/src/router/index.js Normal file
View File

@ -0,0 +1,60 @@
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue')
},
{
path: '/register',
name: 'Register',
component: () => import('@/views/Register.vue')
},
{
path: '/menu',
name: 'Menu',
component: () => import('@/views/Menu.vue'),
redirect: '/home',
children: [
{
path: '/home',
name: 'Home',
component: () => import('@/views/Home.vue'),
},
{
path:'/adminmanage',
name: 'AdminManage',
component: () => import('@/views/AdminManage.vue'),
},
]
},
{
path: '/manage',
name: 'Manage',
component: () => import('@/views/Manage.vue'),
children: [
{
path: '/userapproval',
name: 'UserApproval',
component: () => import('@/views/UserApproval.vue')
},
]
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
router.beforeEach((to, from, next) => {
console.log(`Navigating from ${from.path} to ${to.path}`);
next();
});
export default router;

View File

@ -0,0 +1,15 @@
<template>
<div>
<p>
This is the AdminManage page.
</p>
</div>
</template>
<script>
export default {
name: 'AdminManage',
};
</script>

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

@ -0,0 +1,14 @@
<template>
<div>
<p>欢迎来到智能医疗平台的首页</p>
</div>
</template>
<script>
export default {
};
</script>
<style scoped>
</style>

165
vue/src/views/Login.vue Normal file
View File

@ -0,0 +1,165 @@
<template>
<div id="login">
<div id="left-side">
<img src="@/assets/b.jpg" class="img"/>
</div>
<div id="right-side">
<el-form :model="form" :rules="rules" ref="form" id="subForm">
<h1 class="titile">欢迎登录</h1>
<el-form-item label="用户名" prop="username">
<el-input class="input-field" v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input class="input-field" type="password" v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" class="submit-button" @click="login">登录</el-button>
</el-form-item>
<el-form-item>
<a href="/register" class="register-link">没有账号去注册</a>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "Login",
data() {
return {
form: {
username: '',
password: '',
},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 11, message: '长度在 6 到 11 个字符', trigger: 'blur' }
],
},
};
},
methods: {
login() {
this.$refs['form'].validate((valid) => {
if (valid) {
//
axios.post('http://localhost:8081/user/login', {
username: this.form.username,
password: this.form.password
})
.then(response => {
if (response.data.code == 0) {
this.$message({
type: "success",
message: response.data.data.username+" 欢迎登录!"
});
if(response.data.data.role == 1){
this.$router.push('/manager');
}else{
this.$router.push("/menu");
}
} else {
this.$message.error(response.data.message || "登录失败");
}
})
.catch(error => {
console.error(error);
this.$message.error("登录请求出错");
});
}
});
},
},
};
</script>
<style scoped>
#login {
background: linear-gradient(to bottom right, #4caf50, #2196f3);
height: 100vh;
display: flex;
}
#left-side {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding-left: 20px;
}
#right-side {
flex: 1;
display: flex;
justify-content: flex-end;
padding-right: 50px;
align-items: center;
}
#subForm {
background-color: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(15px);
border-radius: 10px;
padding: 50px 40px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
width: 420px;
height: 500px;
display: grid;
place-items: center;
}
.img {
height: 600px;
width: auto;
}
.titile {
text-align: center;
color: #fff0fd;
font-weight: bold;
font-size: 30px;
margin: 20px auto;
}
.input-field {
color: #fff;
font-size: 18px;
height: 30px;
width:320px;
margin-left: 20px;
}
.submit-button {
background-color: #ff5722;
color: #fff;
width: 300px;
height: auto;
border-radius: 30px;
font-size: 25px;
transition: background-color 0.3s ease;
margin: 10px auto;
}
.submit-button:hover {
background-color: #e64a19;
}
.register-link {
color: #fff;
font-size: 18px;
text-decoration: underline;
text-align: right;
}
.register-link:hover {
color: #181688;
}
</style>

104
vue/src/views/Manage.vue Normal file
View File

@ -0,0 +1,104 @@
<template>
<el-row class="container">
<el-col :span="4">
<el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2" text-color="#fff">
<div class="logo-title-container">
<img src="@/assets/image.png" class="logo" />
<p class="mb-2">后台管理菜单</p>
</div>
<el-sub-menu>
<template #title>
<el-icon><location /></el-icon>
<span>用户管理</span>
</template>
<el-menu-item-group title="用户操作">
<el-menu-item @click="userApprovalClick" index="/userapproval">审核用户注册</el-menu-item>
<el-menu-item index="/userInfoManagement">管理用户信息</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="hospitalManagement">
<template #title>
<el-icon><hospital /></el-icon>
<span>医院管理</span>
</template>
<el-menu-item-group title="医院操作">
<el-menu-item index="hospitalInfoManagement">管理医院信息</el-menu-item>
<el-menu-item index="departmentSettingManagement">管理科室设置</el-menu-item>
<el-menu-item index="doctorInfoManagement">管理医生信息</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="orderManagement">
<template #title>
<el-icon><shopping-cart /></el-icon>
<span>订单管理</span>
</template>
<el-menu-item-group title="订单操作">
<el-menu-item index="appointmentOrderManagement">管理预约挂号订单</el-menu-item>
<el-menu-item index="purchaseOrderManagement">管理在线购药订单</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="dataStatistics">
<template #title>
<el-icon><bar-chart /></el-icon>
<span>数据统计</span>
</template>
<el-menu-item-group title="统计操作">
<el-menu-item index="userDataStatistics">统计用户数据</el-menu-item>
<el-menu-item index="businessDataStatistics">统计业务数据</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</el-col>
<el-col :span="20">
<div v-if="$route.path === '/manage'">
<h2 class="text-center">欢迎来到后台管理系统</h2>
<img src="@/assets/b.jpg" class="img"/>
</div>
<router-view/>
</el-col>
</el-row>
</template>
<script>
export default {
name: 'Manage',
methods: {
userApprovalClick() {
this.$router.push('/userapproval');
}
}
}
</script>
<style scoped>
.container{
height: 100vh;
}
.el-menu-vertical-demo{
height: 100%;
}
.logo-title-container {
display: flex;
align-items: center;
}
.logo {
width: 50px;
height: 50px;
margin-left: 10px;
}
.mb-2 {
color: white;
font-size: 26px;
margin-left: 20px;
}
.text-center {
margin-top: 50px;
font-size: 30px;
text-align: center;
}
.img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>

117
vue/src/views/Menu.vue Normal file
View File

@ -0,0 +1,117 @@
<template>
<el-menu class="el-menu-demo" mode="horizontal" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
<img src="@/assets/image.png" class="logo"/>
<p class="h5">智能医疗平台</p>
<el-menu-item @click="homeClick" index="/home" style="margin-left:10px;">首页</el-menu-item>
<el-sub-menu index="1">
<template #title>医院服务</template>
<el-menu-item index="1-1">科室查询</el-menu-item>
<el-menu-item index="1-2">医生查询</el-menu-item>
<el-menu-item index="1-3">预约挂号</el-menu-item>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>在线问诊</template>
<el-menu-item index="2-1">图文问诊</el-menu-item>
<el-menu-item index="2-2">视频问诊</el-menu-item>
</el-sub-menu>
<el-sub-menu index="3">
<template #title>药品服务</template>
<el-menu-item index="3-1">药品查询</el-menu-item>
<el-menu-item index="3-2">在线购药</el-menu-item>
<el-menu-item index="3-3">药品库存查询</el-menu-item>
</el-sub-menu>
<el-sub-menu index="4">
<template #title>健康管理</template>
<el-menu-item index="4-1">健康监测</el-menu-item>
<el-menu-item index="4-2">健康建议</el-menu-item>
</el-sub-menu>
<el-sub-menu index="5">
<template #title>医疗资源共享</template>
<el-menu-item index="5-1">医院信息共享</el-menu-item>
<el-menu-item index="5-2">医疗设备共享</el-menu-item>
<el-menu-item index="5-3">学术交流</el-menu-item>
</el-sub-menu>
<el-sub-menu index="6">
<template #title>安全与技术</template>
<el-menu-item index="6-1">区块链保障</el-menu-item>
<el-menu-item index="6-2">人工智能服务</el-menu-item>
</el-sub-menu>
<div class="avatar">
<el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"/>
</div>
<el-sub-menu index="7" class="admin">
<template #title>Admin</template>
<el-menu-item @click="adminManageClick" index="/adminmanage">个人信息管理</el-menu-item>
<el-menu-item index="7-2">我的预约</el-menu-item>
<el-menu-item index="7-3">问诊记录</el-menu-item>
<el-menu-item index="7-4">我的病历</el-menu-item>
<el-menu-item index="7-5">我的健康档案</el-menu-item>
<el-menu-item index="7-6">我的订单</el-menu-item>
</el-sub-menu>
</el-menu>
<router-view/>
</template>
<script >
export default {
name: 'Menu',
methods: {
adminManageClick() {
this.$router.push('/adminmanage');
},
homeClick() {
this.$router.push('/home');
},
},
};
</script>
<style scoped>
.el-menu-demo {
width: 100%;
height: 60px;
display: flex;
}
.logo {
width: auto;
height: auto;
margin-left: 20px;
}
.h5{
margin-left: 20px;
color: #063b7f;
font: optional;
font-size: 20px;
margin-top: 15px;
}
.avatar {
position: absolute;
right: 150px;
margin-top: 10px;
}
.el-sub-menu {
margin-left: 10px;
}
.admin {
position: absolute;
right: 20px;
}
</style>

161
vue/src/views/Register.vue Normal file
View File

@ -0,0 +1,161 @@
<template>
<div id="register">
<div id="left-side">
<img src="@/assets/b.jpg" class="img"/>
</div>
<div id="right-side">
<el-form :model="form" :rules="rules" ref="form">
<h1 class="titile">注册</h1>
<el-form-item label="账号" prop="username" >
<el-input class="input-field" v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input class="input-field" type="password" v-model="form.password"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="confirm">
<el-input class="input-field" type="password" v-model="form.confirm"></el-input>
</el-form-item>
<el-button type="danger" class="submit-button" @click="register">点击注册</el-button>
<a href="/login" class="login-link">已有账号去登录</a>
</el-form>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "Register",
data() {
return {
form: {},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
// { min: 2, max: 11, message: ' 3 5 ', trigger: 'blur'}
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 11, message: '长度在 6 到 11 个字符', trigger: 'blur'}
],
confirm: [
{ required: true, message: '请再次输入密码', trigger: 'blur'}
]
}
}
},
methods: {
register() {
if (this.form.password!== this.form.confirm) {
this.$message({
type: "error",
message: "两次输入密码不一致"
});
return;
}
axios.post('http://localhost:8081/user/register', {
username: this.form.username,
password: this.form.password
}).then(response => {
if (response.data.code === 0) {
this.$message({
type: "success",
message: "注册成功"
});
this.$router.push("/login");
} else {
this.$message({
type: "error",
message: "注册失败," + response.data.message
});
}
}).catch(error => {
this.$message({
type: "error",
message: "注册失败,请稍后重试"
});
});
}
}
}
</script>
<style scoped>
#register {
background: linear-gradient(to bottom right, #4caf50, #2196f3);
height: 100vh;
display: flex;
}
#left-side {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding-left: 20px;
}
#right-side {
flex: 1;
display: flex;
justify-content: flex-end;
padding-right: 50px;
align-items: center;
}
.el-form {
background-color: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(15px);
border-radius: 10px;
padding: 50px 40px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
width: 420px;
height: 500px;
display: grid;
place-items: center;
}
.img{
height: 600px;
width: auto;
}
.titile {
text-align: center;
color: #fff;
font-weight: bold;
font-size: 30px;
margin: 20px auto;
}
.input-field{
color: #fff;
font-size: 18px;
height: 30px;
width: 100%;
margin-left: 20px;
}
.submit-button {
background-color: #4caf50;
border: none;
width: 300px;
height: auto;
font-size: 20px;
border-radius: 30px;
font-size: 20px;
}
.submit-button:hover {
background-color: #388e3c;
}
.login-link {
color: #fff;
font-size: 18px;
text-decoration: underline;
}
.login-link:hover {
color: #181688;
}
</style>

View File

@ -0,0 +1,55 @@
<template>
<div>
<p class="title">用户审批页面</p>
<el-table :data="pendingUsers">
<el-table-column prop="username" label="用户名" />
<el-table-column prop="email" label="邮箱" />
<el-table-column label="操作">
<template #default="scope">
<el-button @click="approveUser(scope.row.username)">批准</el-button>
<el-button @click="rejectUser(scope.row.username)">拒绝</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
pendingUsers: [],
};
},
created() {
this.fetchPendingUsers();
},
methods: {
fetchPendingUsers() {
axios.get('http://localhost:8081/user/approval/pending').then(response => {
this.pendingUsers = response.data;
});
},
approveUser(username) {
axios.post(`http://localhost:8081/user/approval/approve/${username}`).then(() => {
this.fetchPendingUsers();
});
},
rejectUser(username) {
axios.post(`http://localhost:8081/user/approval/reject/${username}`).then(() => {
this.fetchPendingUsers();
});
},
},
};
</script>
<style scoped>
.title {
font-size: 24px;
font-weight: bold;
text-align: center;
}
</style>

19
vue/vue.config.js Normal file
View File

@ -0,0 +1,19 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false,
devServer: {
proxy: {
'/api': { // 匹配以 '/api' 开头的请求路径
target: 'http://localhost:8081', // 后端服务器地址
changeOrigin: true, // 允许跨域
pathRewrite: {
'^/api': '' // 将 '/api' 替换为空字符串,保持后端接口路径不变
}
// 可根据需要添加其他选项,如:
// ws: true, // 如果需要代理 WebSocket
// onProxyReq: (proxyReq, req, res) => {}, // 自定义代理请求处理逻辑
}
}
}
})