# 构建一个OA系统日程管理模块
本文将介绍如何使用Spring Boot和Vue.js构建一个OA系统日程管理模块,支持日程的添加、修改、删除、提醒和共享功能。
## 项目结构
项目结构如下:
```text
oa-schedule-management/
│ pom.xml
│
└───src/main/java/com/example/oaschedulemanagement/
│ │ OaScheduleManagementApplication.java
│ └───controller/
│ │ AuthController.java
│ │ ScheduleController.java
│ └───model/
│ │ Role.java
│ │ Schedule.java
│ │ User.java
│ └───repository/
│ │ RoleRepository.java
│ │ ScheduleRepository.java
│ │ UserRepository.java
│ └───service/
│ │ AuthService.java
│ │ NotificationService.java
│ │ ScheduleService.java
│ │ SharingService.java
└───src/main/resources/
│ application.properties
└───frontend/
│ package.json
└───src/
└───components/
│ ScheduleList.vue
│ ScheduleForm.vue
│ ScheduleDetail.vue
│ App.vue
│ main.js
```
## 后端部分
### 依赖配置(pom.xml)
```xml
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.twilio.sdk</groupId>
<artifactId>twilio</artifactId>
<version>8.29.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
```
### 应用配置(application.properties)
```properties
spring.datasource.url=jdbc:mysql://localhost:3306/oa_schedule_db
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
spring.mail.host=smtp.example.com
spring.mail.port=587
spring.mail.username=your-email@example.com
spring.mail.password=your-email-password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
twilio.account.sid=your_twilio_account_sid
twilio.auth.token=your_twilio_auth_token
twilio.phone.number=your_twilio_phone_number
spring.redis.host=localhost
spring.redis.port=6379
```
### 用户模型和角色模型
#### 用户模型(User.java)
```java
package com.example.oaschedulemanagement.model;
import javax.persistence.*;
import java.util.Set;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
// Getters and setters...
}
```
#### 角色模型(Role.java)
```java
package com.example.oaschedulemanagement.model;
import javax.persistence.*;
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and setters...
}
```
### 用户仓库接口和角色仓库接口
#### 用户仓库接口(UserRepository.java)
```java
package com.example.oaschedulemanagement.repository;
import com.example.oaschedulemanagement.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
```
#### 角色仓库接口(RoleRepository.java)
```java
package com.example.oaschedulemanagement.repository;
import com.example.oaschedulemanagement.model.Role;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RoleRepository extends JpaRepository<Role, Long> {
}
```
### 用户认证和授权服务
#### 认证服务类(AuthService.java)
```java
package com.example.oaschedulemanagement.service;
import com.example.oaschedulemanagement.model.Role;
import com.example.oaschedulemanagement.model.User;
import com.example.oaschedulemanagement.repository.RoleRepository;
import com.example.oaschedulemanagement.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.HashSet;
@Service
public class AuthService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
public void registerUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setRoles(new HashSet<>(roleRepository.findAll()));
userRepository.save(user);
}
}
```
### 认证控制器类
#### 认证控制器类(AuthController.java)
```java
package com.example.oaschedulemanagement.controller;
import com.example.oaschedulemanagement.model.User;
import com.example.oaschedulemanagement.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private AuthService authService;
@PostMapping("/register")
public String registerUser(@RequestBody User user) {
authService.registerUser(user);
return "User registered successfully";
}
}
```
### 通知服务类
```java
package com.example.oaschedulemanagement.service;
import com.twilio.Twilio;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.type.PhoneNumber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class NotificationService {
@Autowired
private JavaMailSender mailSender;
@Value("${twilio.account.sid}")
private String twilioAccountSid;
@Value("${twilio.auth.token}")
private String twilioAuthToken;
@Value("${twilio.phone.number}")
private String twilioPhoneNumber;
public void sendEmailReminder(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
mailSender.send(message);
}
public void sendSmsReminder(String to, String messageBody) {
Twilio.init(twilioAccountSid, twilioAuthToken);
Message message = Message.creator(
new PhoneNumber(to),
new PhoneNumber(twilioPhoneNumber),
messageBody
).create();
}
}
```
### 共享服务类
```java
package com.example.oaschedulemanagement.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class SharingService {
@Autowired
private JavaMailSender mailSender;
public void shareSchedule(Long scheduleId, String email) {
// 实现共享逻辑,如发送邮件通知等
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(email);
message.setSubject("Shared Schedule Notification");
message.setText("You have a new shared schedule with ID: " + scheduleId);
mailSender.send(message);
}
}
```
### 控制器类
```java
package com.example.oaschedulemanagement.controller;
import com.example.oaschedulemanagement.model.Schedule;
import com.example.oaschedulemanagement.service.NotificationService;
import com.example.oaschedulemanagement.service.ScheduleService;
import com.example.oaschedulemanagement.service.SharingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/schedules")
public class ScheduleController {
@Autowired
private ScheduleService scheduleService;
@Autowired
private NotificationService notificationService;
@Autowired
private SharingService sharingService;
@GetMapping
public List<Schedule> getAllSchedules() {
return scheduleService.getAllSchedules();
}
@GetMapping("/{id}")
public Schedule getScheduleById(@PathVariable Long id) {
return scheduleService.getScheduleById(id).orElseThrow();
}
@PostMapping
public Schedule createSchedule(@RequestBody Schedule schedule) {
Schedule newSchedule = scheduleService.addSchedule(schedule);
notificationService.sendEmailReminder(newSchedule.getEmailReminder(), "Schedule Reminder", "You have a new schedule: " + newSchedule.getTitle());
notificationService.sendSmsReminder(newSchedule.getSmsReminder(), "You have a new schedule: " + newSchedule.getTitle());
if (newSchedule.getSharedWith() != null) {
sharingService.shareSchedule(newSchedule.getId(), newSchedule.getSharedWith());
}
return newSchedule;
}
@PutMapping("/{id}")
public Schedule updateSchedule(@PathVariable Long id, @RequestBody Schedule scheduleDetails) {
return scheduleService.updateSchedule(id, scheduleDetails);
}
@DeleteMapping("/{id}")
public void deleteSchedule(@PathVariable Long id) {
scheduleService.deleteSchedule(id);
}
}
```
## 前端部分
### 使用Vue.js构建用户界面
首先,在`frontend`目录下创建一个Vue.js项目,并安装必要的依赖:
```bash
npm init vue@latest
cd frontend
npm install
```
### 配置API服务
在`frontend/src`目录下创建`api`文件夹,并在其中创建`apiService.js`文件,用于与后端进行通信:
```javascript
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'http://localhost:8080/api',
withCredentials: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
export default {
getSchedules() {
return apiClient.get('/schedules');
},
getSchedule(id) {
return apiClient.get(`/schedules/${id}`);
},
createSchedule(schedule) {
return apiClient.post('/schedules', schedule);
},
updateSchedule(id, schedule) {
return apiClient.put(`/schedules/${id}`, schedule);
},
deleteSchedule(id) {
return apiClient.delete(`/schedules/${id}`);
}
};
```
### 创建Vue组件
#### ScheduleList.vue
```html
<template>
<div>
<h1>Schedule List</h1>
<ul>
<li v-for="schedule in schedules" :key="schedule.id">
<router-link :to="{ name: 'ScheduleDetail', params: { id: schedule.id } }">
{{ schedule.title }}
</router-link>
</li>
</ul>
</div>
</template>
<script>
import apiService from '../api/apiService';
export default {
data() {
return {
schedules: []
};
},
created() {
apiService.getSchedules().then(response => {
this.schedules = response.data;
});
}
};
</script>
```
#### ScheduleForm.vue
```html
<template>
<div>
<h1>Create/Update Schedule</h1>
<form @submit.prevent="submitForm">
<div>
<label for="title">Title:</label>
<input type="text" v-model="schedule.title" />
</div>
<div>
<label for="description">Description:</label>
<input type="text" v-model="schedule.description" />
</div>
<div>
<label for="startTime">Start Time:</label>
<input type="datetime-local" v-model="schedule.startTime" />
</div>
<div>
<label for="endTime">End Time:</label>
<input type="datetime-local" v-model="schedule.endTime" />
</div>
<div>
<label for="emailReminder">Email Reminder:</label>
<input type="email" v-model="schedule.emailReminder" />
</div>
<div>
<label for="smsReminder">SMS Reminder:</label>
<input type="text" v-model="schedule.smsReminder" />
</div>
<div>
<label for="sharedWith">Shared With:</label>
<input type="email" v-model="schedule.sharedWith" />
</div>
<button type="submit">Submit</button>
</form>
</div>
</template>
<script>
import apiService from '../api/apiService';
export default {
data() {
return {
schedule: {
title: '',
description: '',
startTime: '',
endTime: '',
emailReminder: '',
smsReminder: '',
sharedWith: ''
}
};
},
methods: {
submitForm() {
if (this.schedule.id) {
apiService.updateSchedule(this.schedule.id, this.schedule).then(() => {
this.$router.push({ name: 'ScheduleList' });
});
} else {
apiService.createSchedule(this.schedule).then(() => {
this.$router.push({ name: 'ScheduleList' });
});
}
}
},
created() {
if (this.$route.params.id) {
apiService.getSchedule(this.$route.params.id).then(response => {
this.schedule = response.data;
});
}
}
};
</script>
```
#### ScheduleDetail.vue
```html
<template>
<div>
<h1>Schedule Detail</h1>
<p>{{ schedule.title }}</p>
<p>{{ schedule.description }}</p>
<p>{{ schedule.startTime }}</p>
<p>{{ schedule.endTime }}</p>
<button @click="deleteSchedule">Delete</button>
<router-link :to="{ name: 'ScheduleForm', params: { id: schedule.id } }">Edit</router-link>
</div>
</template>
<script>
import apiService from '../api/apiService';
export default {
data() {
return {
schedule: {}
};
},
created() {
apiService.getSchedule(this.$route.params.id).then(response => {
this.schedule = response.data;
});
},
methods: {
deleteSchedule() {
apiService.deleteSchedule(this.schedule.id).then(() => {
this.$router.push({ name: 'ScheduleList' });
});
}
}
};
</script>
```
### App.vue
```html
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
};
</script>
```
### main.js
```javascript
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import ScheduleList from './components/ScheduleList.vue';
import ScheduleForm from './components/ScheduleForm.vue';
import ScheduleDetail from './components/ScheduleDetail.vue';
Vue.config.productionTip = false;
Vue.use(VueRouter);
const routes = [
{ path: '/', component: ScheduleList, name: 'ScheduleList' },
{ path: '/schedule/:id', component: ScheduleDetail, name: 'ScheduleDetail' },
{ path: '/schedule-form/:id?', component: ScheduleForm, name: 'ScheduleForm' }
];
const router = new VueRouter({
routes
});
new Vue({
render: h => h(App),
router
}).$mount('#app');
```
## 总结
通过以上步骤,构建了一个功能丰富且用户友好的OA系统日程管理模块。这个模块支持用户登录、注册,提供了完善的日程管理功能,包括日程的添加、修改、删除、提醒、共享和分类管理等。前端部分使用Vue.js构建了一个简洁、直观的用户界面,提高了用户体验。