Compare commits

...

7 Commits

Author SHA1 Message Date
jsh
6495f56e25 修改jar包名 2025-10-12 12:11:57 +08:00
jsh
d0d9d6d18b 修复tgy周一没有门诊的bug 2025-10-12 12:06:02 +08:00
jsh
2949a48e63 使用swing 可视化 2025-10-12 12:05:23 +08:00
jsh
b5a118994a 日期格式为MM月dd日 2025-10-12 10:50:42 +08:00
jsh
043c1b71a1 输出Excel 2025-10-11 21:51:46 +08:00
jsh
cc687b9536 优化代码:rest方法 2025-10-11 21:02:00 +08:00
jsh
5d9a5dda10 修复bug,完成基本逻辑 2025-10-11 20:45:59 +08:00
6 changed files with 278 additions and 48 deletions

1
.idea/encodings.xml generated
View File

@@ -2,5 +2,6 @@
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

2
.idea/misc.xml generated
View File

@@ -8,5 +8,5 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" project-jdk-name="21" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" project-jdk-name="19" project-jdk-type="JavaSDK" />
</project>

47
pom.xml
View File

@@ -9,9 +9,52 @@
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version> </dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
</dependencies>
<build>
<finalName>schedule</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.dota.App</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,59 @@
package com.dota;
import javax.swing.*;
import java.awt.*;
public class App {
public static void main(String[] args) {
SwingUtilities.invokeLater(App::lanuch);
}
static String[] doctors = new String[]{"顾磊", "章亮", "唐婷婷", "杨祖怡", "李宁", "周晖"};
static void lanuch() {
JFrame jframe = new JFrame("排班系统");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(600,400);
jframe.setLayout(new BorderLayout(10, 10));
var dateField = new JTextField("2025-10-13");
var weekNumField = new JTextField("2");
var filePathField = new JTextField("C:\\Users\\yangz\\Documents\\医生排班.xlsx");
var doctorField = new JComboBox<>(doctors);
doctorField.setSelectedIndex(0);
var resText = new JTextArea("点击确定按钮,输出执行结果");
var btn = new JButton("确定");
// 输入区域
JPanel inputPanel = new JPanel(new GridLayout(4,2,10,5));
jframe.add(inputPanel, BorderLayout.NORTH);
inputPanel.add(new JLabel("排班日期"));
inputPanel.add(dateField);
inputPanel.add(new JLabel("排班周数"));
inputPanel.add(weekNumField);
inputPanel.add(new JLabel("第一个值班的医生"));
inputPanel.add(doctorField);
inputPanel.add(new JLabel("输出文件位置"));
inputPanel.add(filePathField);
//结果区域
JPanel resPanel = new JPanel();
jframe.add(resPanel, BorderLayout.CENTER);
resPanel.add(resText);
// 按钮区域
var btnPanel = new JPanel();
jframe.add(btnPanel, BorderLayout.SOUTH);
btnPanel.add(btn);
btn.addActionListener(e->{
resText.setText("运行中,请稍等");
Main.run(dateField.getText(), Integer.parseInt(weekNumField.getText()), (String) doctorField.getSelectedItem(), filePathField.getText());
resText.setText("运行结束,请查看排班文件");
});
jframe.setLocationRelativeTo(null);
jframe.setVisible(true);
}
}

View File

@@ -3,10 +3,16 @@ package com.dota;
import com.dota.domain.Doctor;
import com.dota.domain.Week;
import com.dota.domain.WorkEnum;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.util.Arrays;
import java.io.FileOutputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class Main {
static String filePath = "C:\\Users\\yangz\\Documents\\医生排班.xlsx";
static Doctor gl;
static Doctor zl;
static Doctor ttt;
@@ -15,7 +21,19 @@ public class Main {
static Doctor zh;
static Doctor tgy;
// 日期
static int days = 0;
// 医生下标
static int idx = 0;
//开始日期
static LocalDate day;
public static void main(String[] args) {
run("2025-10-13", 2, "周晖", "C:\\Users\\yangz\\Documents\\医生排班.xlsx");
}
static void run(String date, int weekNum, String name, String file){
init();
var doctorOrder = new Doctor[]{
gl, zl, ttt, zy, ln, zh
@@ -24,8 +42,87 @@ public class Main {
ln, zy, ttt, zl, zh, gl, tgy
};
for (int i = 0; i < 2; i++) {
schedule(doctorOrder, outputOrder);
filePath = file;
write(date, weekNum, name, doctorOrder, outputOrder);
}
/**
* @param startDay 开始第一天
* @param weekNum 输出周数
* @param name 第一周第一天值班的医生名字
*/
static void write(String startDay, int weekNum, String name, Doctor[] doctors, Doctor[] outputDoctors) {
day = LocalDate.parse(startDay);
for (int i = 0; i < doctors.length; i++) {
if (doctors[i].name.equals(name)) {
idx = i;
break;
}
}
var list = new ArrayList<Doctor>();
for (int i = 0; i < weekNum; i++) {
list.addAll(schedule(doctors, outputDoctors));
}
try(var workbook = new XSSFWorkbook()) {
var sheet = workbook.createSheet();
int rowNum = 0;
for (int i = 0; i < weekNum; i++) {
writeHead(sheet, rowNum, day);
day = day.plusDays(7);
rowNum += 2;
writeSchedult(sheet, rowNum, list.subList(i * 7, (i+1) * 7));
rowNum += 8;
}
for (int i = 0; i < 8; i++) {
sheet.autoSizeColumn(i);
}
try(var output = new FileOutputStream(filePath)) {
workbook.write(output);
}
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 写入表头,周几和日期
*/
static void writeHead(Sheet sheet, int rowNum, LocalDate day){
DateTimeFormatter mmdd = DateTimeFormatter.ofPattern("MM月dd日");
int i = 1;
var row = sheet.createRow(rowNum++);
var r2 = sheet.createRow(rowNum);
for (Week w:Week.values()) {
var cell = row.createCell(i);
cell.setCellValue(w.getValue());
cell = r2.createCell(i++);
cell.setCellValue(day.format(mmdd));
day = day.plusDays(1);
}
}
/**
* 写入医生排班
*/
static void writeSchedult(Sheet sheet, int rowNum, List<Doctor> doctors){
for (Doctor doctor : doctors) {
var row = sheet.createRow(rowNum++);
int colNum = 0;
var cell = row.createCell(colNum++);
cell.setCellValue(doctor.name);
for (WorkEnum work : doctor.works) {
cell = row.createCell(colNum++);
cell.setCellValue(work.getName());
}
}
}
@@ -55,16 +152,11 @@ public class Main {
ttt.swap = zl;
}
static void schedule(Doctor[] doctors, Doctor[] outputOrder) {
// 日期
int days = 0;
// 医生下标
int idx = 0;
for (int k = 0; k < 2; k++) {
//生成一周的排班
static List<Doctor> schedule(Doctor[] doctors, Doctor[] outputOrder) {
var res = new ArrayList<Doctor>();
for (int i = 0; i < 7; i++) {
var d = doctors[idx];
if (d.firstRest) {
d.firstRest = false;
d.works[0] = WorkEnum.HOLIDAY;
@@ -92,40 +184,63 @@ public class Main {
}
days = (days + 1) % 7;
idx = (idx + 1) % doctors.length;
idx = (idx + 1) % 6;
}
fix(doctors);
rest(doctors);
print(outputOrder);
for (Doctor d : doctors) {
for (Doctor d : outputOrder) {
res.add(d.clone());
d.reset();
}
return res;
}
static class Rest {
int day;
int cnt;
public Rest(int day, int cnt){
this.day = day;
this.cnt = cnt;
}
}
// 给有调休的安排休息
// 保证同一组必须有一个在
static void rest(Doctor[] doctors) {
var list = new Rest[5];
for (int i = 0; i < 5; i++) {
list[i] = new Rest(i, 0);
}
for (Doctor doctor : doctors) {
if (doctor.lastRestCount == 0) {
for (int i = 0; i < 5; i++) {
if (doctor.works[i] == WorkEnum.DUTY || doctor.works[i] == WorkEnum.WORK) {
list[i].cnt++;
}
}
}
var queue = new PriorityQueue<Rest>((a,b)->b.cnt-a.cnt);
for (Rest rest : list) {
queue.offer(rest);
}
for (Doctor doctor : doctors) {
if (doctor.restCount == 0) {
continue;
}
int count = 0;
for (int j = 0; j < 5; j++) {
if (checkRest(j, doctor, doctors)) {
doctor.works[j] = WorkEnum.REST;
count++;
int i = 0;
var temp = new ArrayList<Rest>();
while (i < doctor.restCount) {
Rest r = queue.poll();
if (checkRest(r.day, doctor, doctors)) {
doctor.works[r.day] = WorkEnum.REST;
i++;
}
if (count==doctor.lastRestCount) {
break;
temp.add(r);
}
}
}
for (Doctor doctor : doctors) {
doctor.lastRestCount = doctor.restCount;
queue.addAll(temp);
}
}
@@ -261,14 +376,18 @@ public class Main {
return false;
}
static void print(Doctor[] outputOrder) {
static void print(List<Doctor> outputOrder) {
var size = outputOrder.size() / 7;
int idx = 0;
for (int i = 0; i < size; i++) {
System.out.printf("%10s", " ");
for (Week value : Week.values()) {
System.out.printf("%10s", value.getValue());
}
System.out.println(" ");
for (Doctor doctor : outputOrder) {
for (int j = 0;j<7;j++) {
var doctor = outputOrder.get(idx++);
System.out.printf("%10s", doctor.name);
for (WorkEnum work : doctor.works) {
System.out.printf("%10s", work.getName());
@@ -278,3 +397,4 @@ public class Main {
System.out.println(" ");
}
}
}

View File

@@ -2,9 +2,7 @@ package com.dota.domain;
public class Doctor {
public String name;
// 周的调休
public int lastRestCount;
// 下周的调休
// 周五六日值班的调休
public int restCount = 0;
// 门诊时间
@@ -33,7 +31,15 @@ public class Doctor {
this.name = name;
}
@Override
public Doctor clone() {
var d = new Doctor(this.name);
System.arraycopy(this.works, 0, d.works, 0, this.works.length);
return d;
}
public void reset() {
this.restCount = 0;
for (int i = 0; i < 5; i++) {
works[i] = WorkEnum.WORK;
}
@@ -42,10 +48,11 @@ public class Doctor {
}
switch (name) {
case "田国燕" -> works[0] = WorkEnum.OPD;
case "周晖" -> works[1] = WorkEnum.OPD;
case "唐婷婷" -> works[2] = WorkEnum.OPD;
case "李宁" -> works[3] = WorkEnum.OPD;
case "章亮" -> works[4] = WorkEnum.OPD;
case "李宁" -> works[4] = WorkEnum.OPD;
case "章亮" -> works[3] = WorkEnum.OPD;
}
}