docs(specs): 汇总铁律和前后端开发规范文档到MD目录

- 新增 MD/specs/IRON_RULES.md — 执行铁律汇总(v2.0, 8条铁律)
- 新增 MD/specs/BACKEND_DEVELOPMENT_STANDARD.md — 后端开发规范
- 新增 MD/specs/FRONTEND_DEVELOPMENT_STANDARD.md — 前端开发规范
- 新增 healthlink-his-ui/AGENTS.md — 前端铁律引用
- 更新 healthlink-his-server/AGENTS.md — 同步规范文档引用
- 修复10个文档缺失的元数据(文档类型标签)
- 全部30个文档通过命名规范和元数据检查
This commit is contained in:
2026-06-06 09:33:13 +08:00
parent 7a00f4db96
commit 3578a24254
15 changed files with 1217 additions and 0 deletions

View File

@@ -1,5 +1,9 @@
# HealthLink HIS 三甲医院达标详细设计方案
> **文档类型**: 架构设计
> **适用范围**: 三甲达标架构
> **版本**: v1.0
> **目标**: 完全符合三级甲等综合医院信息化评审标准
> **依据**: 国家卫健委三甲评审标准(2022)、电子病历评级≥4级、互联互通≥四级甲等
> **编制日期**: 2026-06-06

View File

@@ -1,5 +1,9 @@
# HIS项目Bug修复记录 v1.0
> **文档类型**: Bug修复
> **适用范围**: 全项目Bug记录
> **版本**: v1.0
> **编制人:** 陈琳
> **编制日期:** 2026-05-01
> **统计范围:** 2026-04-01 至 2026-05-01

View File

@@ -1,5 +1,9 @@
# HealthLink HIS 三甲医院达标开发计划
> **文档类型**: 开发计划
> **适用范围**: 三甲达标开发
> **版本**: v1.0
> **目标**: 完全符合三级甲等综合医院信息化评审标准
> **依据**: 《三级医院评审标准2022年版》、电子病历评级≥4级、互联互通≥四级甲等
> **编制日期**: 2026-06-06

View File

@@ -1,5 +1,9 @@
# Flyway 数据库迁移使用指南
> **文档类型**: 使用指南
> **适用范围**: 数据库迁移
> **版本**: v1.0
> **项目**: HealthLink-HIS 医院管理系统
> **数据库**: PostgreSQL 192.168.110.252:15432 (schema: hisdev)
> **Flyway 版本**: 8.5.x (Spring Boot 2.7 管理)

View File

@@ -1,5 +1,11 @@
# 后端发布前检查清单
> **文档类型**: 技术规范
> **适用范围**: 后端开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
## 📋 基础检查项
### Maven编译验证

View File

@@ -0,0 +1,367 @@
# HealthLink-HIS 后端开发规范
> **文档类型**: 技术规范
> **适用范围**: 后端 Java 开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、技术栈
| 组件 | 版本 | 说明 |
|------|------|------|
| JDK | 25 | OpenJDK 25 (LTS) |
| Spring Boot | 4.0.6 | 框架核心 |
| MyBatis-Plus | 3.5.16 | ORM框架 |
| PostgreSQL | 15+ | 主数据库 |
| Redis | 7.x | 缓存/会话 |
| Maven | 3.9+ | 构建工具 |
---
## 二、项目结构
```
healthlink-his-server/
├── healthlink-his-common/ # 公共模块(枚举、常量、工具类)
├── healthlink-his-domain/ # 领域层实体、Mapper、Flyway迁移
├── healthlink-his-application/ # 应用层Controller、Service、业务逻辑
├── core-common/ # 若依公共核心
├── core-system/ # 若依系统模块
├── core-framework/ # 若依框架核心
├── core-quartz/ # 定时任务
├── core-generator/ # 代码生成
├── core-flowable/ # 工作流
└── core-admin/ # 管理后台
```
---
## 三、分层架构规范
### 3.1 Controller 层
- 路径:`com.healthlink.his.web.{module}.controller`
- 职责接收请求、参数校验、调用AppService、返回统一结果
- 禁止:直接操作数据库、编写业务逻辑
```java
@RestController
@RequestMapping("/api/v1/registration")
@Api(tags = "挂号管理")
public class RegistrationController {
@Autowired
private IRegistrationAppService registrationAppService;
@GetMapping("/list")
@PreAuthorize("@ss.hasPermi('registration:list')")
public TableDataInfo list(RegistrationQueryDto query) {
startPage();
List<RegistrationDto> list = registrationAppService.selectList(query);
return getDataTable(list);
}
}
```
### 3.2 AppService 层(应用服务)
- 路径:`com.healthlink.his.web.{module}.appservice`
- 职责编排业务流程、协调多个Service、事务管理
- 命名:`XxxAppService`(接口)+ `XxxAppServiceImpl`(实现)
### 3.3 Service 层
- 路径:`com.healthlink.his.web.{module}.service`
- 职责单表CRUD、基础业务逻辑
- 命名:`IXxxService`(接口)+ `XxxServiceImpl`(实现)
### 3.4 Mapper 层
- 路径:`com.healthlink.his.web.{module}.mapper`
- 职责数据访问、SQL映射
- 命名:`XxxMapper`(接口)+ `XxxMapper.xml`XML映射
### 3.5 Entity/Domain 层
- 路径:`com.healthlink.his.domain.{module}`
- 职责:实体定义、数据库表映射
- 命名:`Xxx`(实体类)
### 3.6 DTO 层
- 路径:`com.healthlink.his.web.{module}.dto`
- 职责:数据传输对象、查询参数、返回结果
---
## 四、命名规范
### 4.1 包命名
```
com.healthlink.his.web.{模块名}.{层级}
```
### 4.2 类命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| Controller | `XxxController` | `RegistrationController` |
| AppService接口 | `IXxxAppService` | `IRegistrationAppService` |
| AppService实现 | `XxxAppServiceImpl` | `RegistrationAppServiceImpl` |
| Service接口 | `IXxxService` | `IRegistrationService` |
| Service实现 | `XxxServiceImpl` | `RegistrationServiceImpl` |
| Mapper | `XxxMapper` | `RegistrationMapper` |
| Entity | `Xxx` | `Registration` |
| DTO | `XxxDto` / `XxxQueryDto` | `RegistrationDto` |
| Enum | `XxxEnum` / `XxxType` | `ItemType` |
### 4.3 方法命名
| 场景 | 命名规则 | 示例 |
|------|---------|------|
| 查询列表 | `selectList` / `queryList` | `selectList(query)` |
| 查询详情 | `selectById` / `getById` | `selectById(id)` |
| 新增 | `insert` / `save` / `add` | `insert(dto)` |
| 修改 | `update` / `modify` | `update(dto)` |
| 删除 | `delete` / `remove` | `deleteById(id)` |
| 批量操作 | `batchXxx` | `batchInsert(list)` |
### 4.4 数据库命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| 表名 | `{模块}_{功能}` 小写下划线 | `reg_registration` |
| 字段名 | 小写下划线 | `patient_id`, `create_time` |
| 主键 | `id``{表名}_id` | `registration_id` |
| 外键 | `{关联表}_id` | `patient_id` |
| 时间字段 | `create_time`, `update_time` | — |
| 软删除 | `del_flag` | — |
| 租户 | `tenant_id` | — |
---
## 五、编码规范
### 5.1 Controller 规范
```java
// ✅ 正确
@RestController
@RequestMapping("/api/v1/patient")
@Api(tags = "患者管理")
@Slf4j
public class PatientController {
@Autowired
private IPatientAppService patientAppService;
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('patient:query')")
public AjaxResult getInfo(@PathVariable Long id) {
return success(patientAppService.selectById(id));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('patient:add')")
public AjaxResult add(@Validated @RequestBody PatientDto dto) {
return toAjax(patientAppService.insert(dto));
}
}
// ❌ 错误 - Controller里写业务逻辑
public AjaxResult add(@RequestBody PatientDto dto) {
// 不应该在这里写验证逻辑
if (dto.getName() == null) {
return error("名称不能为空");
}
// 不应该在这里写数据库操作
patientMapper.insert(patient);
return success();
}
```
### 5.2 Service 规范
```java
// ✅ 正确 - 事务注解
@Transactional(rollbackFor = Exception.class)
public int insert(PatientDto dto) {
Patient patient = BeanUtils.copyProperties(dto, Patient.class);
patient.setCreateTime(new Date());
patient.setCreateBy(SecurityUtils.getUsername());
return patientMapper.insert(patient);
}
// ❌ 错误 - 自调用导致事务失效
public void batchProcess(List<PatientDto> list) {
for (PatientDto dto : list) {
this.insert(dto); // 自调用,事务不生效!
}
}
```
### 5.3 Mapper 规范
```java
// ✅ 正确 - 使用LambdaQueryWrapper
public List<Patient> selectList(PatientQueryDto query) {
LambdaQueryWrapper<Patient> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(query.getName()), Patient::getName, query.getName())
.eq(Patient::getDelFlag, "0")
.orderByDesc(Patient::getCreateTime);
return patientMapper.selectList(wrapper);
}
// ❌ 错误 - 字符串拼接SQL
public List<Patient> selectList(String name) {
String sql = "SELECT * FROM patient WHERE name = '" + name + "'";
return jdbcTemplate.queryForList(sql, Patient.class);
}
```
### 5.4 统一返回格式
```java
// 成功
return AjaxResult.success(data);
return AjaxResult.success("操作成功", data);
// 失败
return AjaxResult.error("患者不存在");
return AjaxResult.error(MessageUtils.message("patient.not.found"));
// 列表
TableDataInfo dataPage = getDataTable(list);
```
---
## 六、异常处理规范
### 6.1 业务异常
```java
throw new ServiceException("患者编号不能为空");
throw new ServiceException(MessageUtils.message("patient.id.required"));
```
### 6.2 全局异常处理
- 使用 `@RestControllerAdvice` + `@ExceptionHandler`
- 不在 Controller 中 try-catch 后返回错误
- 所有异常最终返回统一格式 `{code, msg, data}`
### 6.3 日志规范
```java
// ✅ 正确
log.info("患者挂号成功: patientId={}, registrationId={}", patientId, regId);
log.error("挂号失败: patientId={}", patientId, e);
// ❌ 错误
log.info("患者身份证号: " + idCard); // 敏感信息泄露
System.out.println("debug"); // 不使用System.out
```
---
## 七、安全规范
### 7.1 数据脱敏
- 患者身份证号:`***` 掩码
- 患者手机号前3后4中间 `****`
- 密码BCrypt 加密,不可逆
### 7.2 SQL注入防护
- 所有查询使用参数化查询
- 禁止字符串拼接 SQL
- 使用 MyBatis-Plus 的 `QueryWrapper` / `LambdaQueryWrapper`
### 7.3 权限控制
- 所有接口标注 `@PreAuthorize`
- 数据级权限校验(医生只能访问本科室患者)
- 敏感操作需二次确认
---
## 八、测试规范
### 8.1 测试类型
| 类型 | 工具 | 覆盖范围 |
|------|------|---------|
| 单元测试 | JUnit 5 + Mockito | Service/工具类 |
| 接口测试 | MockMvc + SpringBootTest | Controller接口 |
| 白盒测试 | Maven编译 | 全量代码 |
| 黑盒测试 | 手动/自动化 | 核心业务流程 |
### 8.2 接口测试规范
```java
@SpringBootTest
@AutoConfigureMockMvc
public class PatientApiTest {
@Test
public void testGetPatientInfo() throws Exception {
mockMvc.perform(get("/healthlink-his/api/v1/patient/{id}", 1L)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty())
.andExpect(jsonPath("$.data.name").isNotEmpty());
}
}
```
### 8.3 测试数据要求
- 测试数据必须基于业务逻辑设计
- 验证业务返回内容非仅HTTP状态码
- 覆盖正常流程和异常流程
- 包含边界条件测试
---
## 九、性能规范
### 9.1 数据库查询
- 无N+1查询问题使用 `JOIN` 或批量查询)
- 大表查询必须有分页限制
- 慢查询已优化(执行时间 < 500ms
- 索引已覆盖高频查询条件
### 9.2 接口性能
- 核心接口响应时间 < 1秒
- 列表接口支持分页无全量返回
- 大文件下载使用流式传输
### 9.3 缓存使用
- 频繁查询的字典数据使用Redis缓存
- 缓存必须设置过期时间
- 数据变更时主动清除相关缓存
---
## 十、Git提交规范
### Commit Message 格式
```
<type>(<scope>): <subject>
<body>
<footer>
```
### Type 类型
| Type | 说明 |
|------|------|
| feat | 新功能 |
| fix | Bug修复 |
| docs | 文档变更 |
| style | 代码格式不影响功能 |
| refactor | 重构 |
| test | 测试相关 |
| chore | 构建/工具变更 |
### 示例
```
feat(registration): 新增患者过敏史管理功能
- 新增 PatientAllergy 实体和 Mapper
- 新增 IRegistrationAppService.getPatientAllergy()
- 新增 /api/v1/registration/allergy 接口
- Flyway迁移脚本: V2.0.1__add_patient_allergy.sql
Co-authored-by: zhangsan <zhangsan@healthlink.com>
```
---
> **文档版本**: v1.0
> **最后更新**: 2026-06-06

View File

@@ -0,0 +1,523 @@
# HealthLink-HIS 前端开发规范
> **文档类型**: 技术规范
> **适用范围**: 前端 Vue3 开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、技术栈
| 组件 | 版本 | 说明 |
|------|------|------|
| Vue | 3.x | 前端框架 |
| Vite | 5.x | 构建工具 |
| Element Plus | 2.x | UI组件库 |
| Pinia | 2.x | 状态管理 |
| Vue Router | 4.x | 路由管理 |
| Axios | 1.x | HTTP客户端 |
| RuoYi-Vue3 | 3.9.2+ | 基础框架 |
---
## 二、项目结构
```
healthlink-his-ui/
├── src/
│ ├── api/ # API接口定义
│ │ ├── module_name/ # 按模块分组
│ │ │ ├── index.js # 接口入口
│ │ │ └── *.js # 各接口文件
│ │ └── system/ # 系统管理接口
│ ├── views/ # 页面视图
│ │ └── module_name/ # 按模块分组
│ │ └── index.vue # 页面组件
│ ├── components/ # 公共组件
│ ├── store/ # Pinia状态管理
│ │ ├── modules/ # 模块store
│ │ └── store.js # store入口
│ ├── router/ # 路由配置
│ ├── utils/ # 工具函数
│ ├── directive/ # 自定义指令
│ ├── plugins/ # 插件
│ ├── layout/ # 布局组件
│ └── assets/ # 静态资源
├── vite.config.js # Vite配置
├── package.json # 依赖配置
└── .env.dev # 开发环境变量
```
---
## 三、命名规范
### 3.1 文件命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| 页面组件 | `index.vue` | `views/registration/index.vue` |
| 弹窗组件 | `XxxDialog.vue` | `PatientDialog.vue` |
| 子组件 | `XxxDetail.vue` | `RegistrationDetail.vue` |
| API文件 | `index.js``xxx.js` | `api/registration/index.js` |
| Store模块 | `xxx.js` | `store/modules/user.js` |
| 工具函数 | `xxx.js` | `utils/validate.js` |
### 3.2 组件命名
```vue
<!-- 正确 - PascalCase -->
<template>
<PatientDialog ref="dialogRef" @success="getList" />
</template>
<!-- 错误 -->
<template>
<patient-dialog ref="dialogRef" />
</template>
```
### 3.3 变量命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| 响应式变量 | `camelCase` | `const patientList = ref([])` |
| 常量 | `UPPER_SNAKE_CASE` | `const MAX_RETRY = 3` |
| 事件处理函数 | `handle` 前缀 | `const handleClick = () => {}` |
| 获取数据函数 | `getList` / `getData` | `const getList = async () => {}` |
| 表单引用 | `xxxForm` / `ruleForm` | `const ruleForm = ref(null)` |
| 表格引用 | `xxxTable` / `tableRef` | `const tableRef = ref(null)` |
---
## 四、API 接口规范
### 4.1 API文件结构
```javascript
// api/registration/index.js
import request from '@/utils/request'
// 查询挂号列表
export function listRegistration(query) {
return request({
url: '/healthlink-his/api/v1/registration/list',
method: 'get',
params: query
})
}
// 查询挂号详情
export function getRegistration(id) {
return request({
url: '/healthlink-his/api/v1/registration/' + id,
method: 'get'
})
}
// 新增挂号
export function addRegistration(data) {
return request({
url: '/healthlink-his/api/v1/registration',
method: 'post',
data: data
})
}
// 修改挂号
export function updateRegistration(data) {
return request({
url: '/healthlink-his/api/v1/registration',
method: 'put',
data: data
})
}
// 删除挂号
export function delRegistration(ids) {
return request({
url: '/healthlink-his/api/v1/registration/' + ids,
method: 'delete'
})
}
```
### 4.2 API 路径规范
- 统一前缀:`/healthlink-his/api/v1/`
- 使用 kebab-case`/patient-allergy` 而非 `/patientAllergy`
- 列表接口:`/list`
- 详情接口:`/{id}`
- 新增:`POST /`
- 修改:`PUT /`
- 删除:`DELETE /{id}`
- 批量删除:`DELETE /{ids}`(逗号分隔)
---
## 五、页面组件规范
### 5.1 标准页面模板
```vue
<template>
<div class="app-container">
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
<el-form-item label="患者姓名" prop="patientName">
<el-input v-model="queryParams.patientName" placeholder="请输入患者姓名" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['registration:add']">新增</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="患者姓名" prop="patientName" />
<el-table-column label="操作" width="180" align="center">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['registration:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['registration:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 新增/修改弹窗 -->
<XxxDialog ref="dialogRef" @success="getList" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { listXxx, delXxx } from '@/api/xxx'
import XxxDialog from './XxxDialog.vue'
const { proxy } = getCurrentInstance()
const dataList = ref([])
const loading = ref(true)
const showSearch = ref(true)
const total = ref(0)
const ids = ref([])
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
patientName: undefined
})
const dialogRef = ref(null)
/** 查询列表 */
const getList = async () => {
loading.value = true
const res = await listXxx(queryParams)
dataList.value = res.rows
total.value = res.total
loading.value = false
}
/** 搜索 */
const handleQuery = () => {
queryParams.pageNum = 1
getList()
}
/** 重置 */
const resetQuery = () => {
proxy.resetForm('queryForm')
handleQuery()
}
/** 多选 */
const handleSelectionChange = (selection) => {
ids.value = selection.map(item => item.id)
}
/** 新增 */
const handleAdd = () => {
dialogRef.value.open()
}
/** 修改 */
const handleUpdate = (row) => {
dialogRef.value.open(row.id)
}
/** 删除 */
const handleDelete = async (row) => {
await proxy.$modal.confirm('确认删除该记录?')
await delXxx(row.id)
proxy.$modal.msgSuccess('删除成功')
getList()
}
onMounted(() => {
getList()
})
</script>
```
### 5.2 弹窗组件模板
```vue
<template>
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="患者姓名" prop="patientName">
<el-input v-model="form.patientName" placeholder="请输入患者姓名" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="cancel"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { getXxx, addXxx, updateXxx } from '@/api/xxx'
const { proxy } = getCurrentInstance()
const title = ref('')
const open = ref(false)
const formRef = ref(null)
const form = reactive({ id: undefined, patientName: '' })
const rules = {
patientName: [{ required: true, message: '患者姓名不能为空', trigger: 'blur' }]
}
/** 打开弹窗 */
const openDialog = async (id) => {
reset()
if (id) {
const res = await getXxx(id)
Object.assign(form, res.data)
title.value = '修改'
} else {
title.value = '新增'
}
open.value = true
}
/** 提交 */
const submitForm = async () => {
await proxy.$refs.formRef.validate()
if (form.id) {
await updateXxx(form)
proxy.$modal.msgSuccess('修改成功')
} else {
await addXxx(form)
proxy.$modal.msgSuccess('新增成功')
}
open.value = false
emit('success')
}
/** 取消 */
const cancel = () => {
open.value = false
reset()
}
const reset = () => {
form.id = undefined
form.patientName = ''
}
const emit = defineEmits(['success'])
defineExpose({ open: openDialog })
</script>
```
---
## 六、状态管理规范 (Pinia)
```javascript
// store/modules/user.js
import { defineStore } from 'pinia'
import { login, logout, getInfo } from '@/api/login'
const useUserStore = defineStore('user', {
state: () => ({
token: getToken(),
name: '',
roles: [],
permissions: []
}),
actions: {
async loginAction(userInfo) {
const res = await login(userInfo)
setToken(res.token)
this.token = res.token
},
async getInfoAction() {
const res = await getInfo()
this.name = res.user.nickName
this.roles = res.roles
this.permissions = res.permissions
},
logoutAction() {
this.token = ''
this.name = ''
this.roles = []
removeToken()
}
}
})
export default useUserStore
```
---
## 七、路由配置规范
```javascript
// router/index.js
const routes = [
{
path: '/registration',
component: Layout,
children: [
{
path: '',
name: 'Registration',
component: () => import('@/views/registration/index.vue'),
meta: { title: '挂号管理', icon: 'ticket' }
}
]
}
]
```
### 路由命名规则
- 路径使用 kebab-case`/patient-allergy`
- name 使用 PascalCase`PatientAllergy`
- meta.title 使用中文:`患者过敏史`
---
## 八、样式规范
### 8.1 使用 scoped
```vue
<style scoped>
.app-container {
padding: 20px;
}
</style>
```
### 8.2 使用 Element Plus 变量
```css
:deep(.el-button--primary) {
--el-button-bg-color: #1890ff;
}
```
### 8.3 禁止事项
- ❌ 使用内联样式(除动态绑定外)
- ❌ 使用 `!important`
- ❌ 全局样式污染其他组件
---
## 九、安全规范
### 9.1 XSS 防护
- 用户输入使用 `v-text` 而非 `v-html`
- 必须使用 `v-html` 时需做转义处理
### 9.2 敏感信息
- 不在前端硬编码密码、密钥
- API请求通过 `request.js` 统一拦截添加Token
- Token 存储在 `localStorage`,设置过期时间
### 9.3 权限控制
- 使用 `v-hasPermi` 指令控制按钮权限
- 使用路由 `meta.roles` 控制页面权限
- 接口请求在 `request.js` 中统一处理 401/403
---
## 十、性能优化
### 10.1 路由懒加载
```javascript
component: () => import('@/views/registration/index.vue')
```
### 10.2 组件按需导入
```javascript
import { ElButton, ElTable } from 'element-plus'
```
### 10.3 大列表优化
- 超过100行使用虚拟滚动
- 列表接口必须支持分页
- 图片使用懒加载 `v-lazy`
### 10.4 内存泄漏防护
- `onMounted` 中注册的事件在 `onUnmounted` 中移除
- 定时器在组件销毁时清除
- 避免在 `watch` 中创建新对象
---
## 十一、测试规范
### 11.1 单元测试 (Vitest)
```javascript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import PatientDialog from './PatientDialog.vue'
describe('PatientDialog', () => {
it('renders correctly', () => {
const wrapper = mount(PatientDialog)
expect(wrapper.find('.el-dialog').exists()).toBe(true)
})
})
```
### 11.2 E2E测试 (Playwright)
```javascript
import { test, expect } from '@playwright/test'
test('registration flow', async ({ page }) => {
await page.goto('/login')
await page.fill('#username', 'admin')
await page.fill('#password', 'admin123')
await page.click('.login-button')
await expect(page).toHaveURL('/')
await page.goto('/registration')
await expect(page.locator('.el-table')).toBeVisible()
})
```
---
## 十二、Git提交规范
同后端规范(`MD/specs/IRON_RULES.md`),额外要求:
- 提交前执行 `npm run lint` 确保无报错
- 提交前执行 `npm run build:dev` 确保构建成功
---
> **文档版本**: v1.0
> **最后更新**: 2026-06-06

247
MD/specs/IRON_RULES.md Normal file
View File

@@ -0,0 +1,247 @@
# HealthLink-HIS 执行铁律
> **文档类型**: 技术规范
> **适用范围**: 全项目开发流程
> **版本**: v2.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、铁律总览
| 编号 | 铁律名称 | 优先级 | 适用范围 |
|------|---------|--------|---------|
| #1 | 修改完必须测试 | P0 | 全量代码 |
| #2 | Flyway 数据库迁移 | P0 | 数据库变更 |
| #3 | 先分解再行动 | P1 | 非平凡任务 |
| #4 | 验证后信 | P1 | 编译/构建 |
| #5 | 文档统一管理 | P1 | 文档产出 |
| #6 | 测试通过后才提交 | P0 | 代码提交 |
| #7 | 前后端API路径对齐 | P0 | 接口开发 |
| #8 | 铁律和规范文档放MD目录 | P1 | 规范文档 |
---
## 二、铁律详细说明
### 铁律 #1: 修改完必须测试
**任何代码修改后,必须完成以下测试才能提交:**
#### 白盒测试
- `mvn clean compile` 编译通过无ERROR
- 单元测试全部通过(如有)
- 代码无新增编译警告(或有书面说明可忽略)
#### 黑盒测试
- 启动应用,验证无启动报错
- 测试关键接口(登录、核心业务接口)
- 验证请求响应结构正确(`{code, msg, data}`
- 验证业务逻辑正确性非仅HTTP状态码
#### 冒烟测试
- 应用正常启动(端口监听)
- 健康检查接口返回正常
- 基础 CRUD 操作正常
- 登录→获取菜单→核心业务流程通畅
#### 前端测试
- `npm run build:dev` 构建成功
- ESLint 无错误
- 页面无控制台报错
- 核心业务页面功能正常
---
### 铁律 #2: Flyway 数据库迁移
**但凡遇到有新建表和字段的,必须通过 Flyway 框架去实现。**
#### 操作规范
1.`healthlink-his-domain/src/main/resources/db/migration/` 下创建迁移脚本
2. 命名格式:`V{版本号}__{描述}.sql`(双下划线分隔)
3. 示例:`V2.0.1__add_patient_allergy_table.sql`
4. 迁移脚本必须包含完整的 DDLCREATE TABLE / ALTER TABLE
5. 必须提供回滚方案(文档记录,非自动回滚)
#### 禁止事项
- ❌ 直接在数据库执行 SQL 不走 Flyway
- ❌ 修改已执行的迁移脚本
- ❌ 迁移脚本中使用 `DROP TABLE`(除非明确需要)
- ❌ 跳过版本号
---
### 铁律 #3: 先分解再行动
**任何非平凡任务先出 plan 再执行。**
#### 触发条件
- 修改超过 3 个文件的任务
- 涉及多个模块的变更
- 数据库结构变更
- 新功能开发
#### 执行步骤
1. 分析现有代码和架构
2. 制定分步计划(使用 `update_plan`
3. 确认测试方案
4. 逐步执行并验证
---
### 铁律 #4: 验证后信
**每次修改后必须验证编译通过,不信记忆。**
#### 验证命令
```bash
# 后端编译
export JAVA_HOME=/opt/jdk-25
mvn clean compile -DskipTests
# 完整构建
mvn install -DskipTests
# 前端构建
cd healthlink-his-ui && npm run build:dev
```
---
### 铁律 #5: 文档统一管理
**所有文档必须存储在 `MD/` 目录中,遵循文档规范。**
#### 目录结构
```
MD/
├── DOCUMENTATION_STANDARD.md # 文档管理规范
├── architecture/ # 架构设计
├── development/ # 开发计划与记录
├── standards/ # 国家/行业标准
├── specs/ # 技术规范与流程
├── bugs/ # Bug分析与修复记录
├── guides/ # 使用指南
└── upgrade/ # 升级记录
```
#### 命名规范
- 文件名使用 **大写英文+下划线**(如 `GRADE3A_DETAILED_DESIGN.md`
- 不使用中文作文件名
- 不使用空格分隔单词
- 版本号标注在文件名末尾(如 `_V2`
#### 格式要求
- 文档头部必须包含元数据块(文档类型、版本、日期)
- 代码块必须标注语言类型
- 表格使用标准Markdown格式
#### 详细规范
参见 `MD/DOCUMENTATION_STANDARD.md`
---
### 铁律 #6: 测试通过后才提交
**代码修改必须通过完整测试后才能提交到远程仓库。**
#### 提交前检查
1. `mvn clean compile` 编译通过
2. 接口测试全部通过88/88
3. 前端构建成功
4. 无新增编译警告
5. 代码变更范围已确认(`git status`
#### 提交规范
- 使用标准 Commit Message 格式
- 参见 `MD/specs/COMMIT_TEMPLATE.md`
- 不提交未完成的功能
- 不提交调试代码和临时文件
---
### 铁律 #7: 前后端API路径对齐
**前后端API路径必须保持一致。**
#### 规范要求
1. 后端接口路径统一前缀:`/healthlink-his/`
2. 前端 `request.js` 中配置的 `baseURL` 必须与后端匹配
3. 接口变更必须同步更新前后端代码
4. 新增接口必须在 Swagger 文档中注册
5. 接口路径命名使用小写字母和连字符kebab-case
---
### 铁律 #8: 铁律和规范文档放MD目录
**所有铁律和规范文档统一存放在 `MD/specs/` 目录中。**
#### 已有规范文档
| 文档 | 路径 | 说明 |
|------|------|------|
| 执行铁律 | `MD/specs/IRON_RULES.md` | 本文档 |
| 后端开发规范 | `MD/specs/BACKEND_DEVELOPMENT_STANDARD.md` | 后端编码规范 |
| 前端开发规范 | `MD/specs/FRONTEND_DEVELOPMENT_STANDARD.md` | 前端编码规范 |
| 后端检查清单 | `MD/specs/BACKEND_CHECKLIST.md` | 发布前检查 |
| 前端检查清单 | `MD/specs/FRONTEND_CHECKLIST.md` | 发布前检查 |
| CI/CD门禁 | `MD/specs/CICD_GATEKEEPER.md` | 构建门禁 |
| 提交模板 | `MD/specs/COMMIT_TEMPLATE.md` | Commit规范 |
| 发布清单 | `MD/specs/RELEASE_CHECKLIST.md` | 发布流程 |
| E2E测试计划 | `MD/specs/PLAYWRIGHT_TESTING_PLAN.md` | Playwright测试 |
#### AGENTS.md 同步
- 后端 `healthlink-his-server/AGENTS.md` 必须引用本文档
- 新增铁律必须同步更新本文档和 AGENTS.md
---
## 三、违规处理
| 级别 | 描述 | 处理方式 |
|------|------|---------|
| P0 违规 | 跳过测试直接提交 | 必须回滚并重新测试 |
| P0 违规 | 数据库变更不走Flyway | 回滚数据库变更重新用Flyway执行 |
| P1 违规 | 未分解就行动 | 补充分析和计划文档 |
| P1 违规 | 文档不规范 | 补充元数据和格式 |
---
## 四、快速参考
### 后端开发速查
```bash
# 编译
export JAVA_HOME=/opt/jdk-25 && mvn clean compile -DskipTests
# 完整构建
mvn install -DskipTests
# 运行测试
mvn test -pl healthlink-his-application -Dtest="ClassName" -Dsurefire.failIfNoSpecifiedTests=false
# 启动应用
java -jar healthlink-his-application/target/*.jar --spring.profiles.active=dev
```
### 前端开发速查
```bash
# 开发模式
npm run dev
# 构建
npm run build:dev
# 测试
npm run test:run
# Lint
npm run lint
```
---
> **文档版本**: v2.0
> **最后更新**: 2026-06-06

View File

@@ -1,5 +1,8 @@
# 三甲医院 HIS 系统标准规范汇编
> **文档类型**: 国家标准
> **版本**: v1.0
> **编制目的**: 为 HealthLink HIS 系统重新设计提供国家级/行业级标准依据
> **适用范围**: 广西壮族自治区三级甲等综合医院
> **编制日期**: 2026-06-05

View File

@@ -1,5 +1,9 @@
# HealthLink-HIS 后端组件升级方案
> **文档类型**: 升级记录
> **适用范围**: 后端组件
> **版本**: v1.0
> **编制日期**: 2026-06-04
> **基线**: Spring Boot 2.5.15 + MyBatis Plus 3.5.5
> **目标**: 升级安全漏洞组件 + 小版本迭代,不做大版本迁移

View File

@@ -1,5 +1,9 @@
# MyBatis Plus 升级方案
> **文档类型**: 升级记录
> **适用范围**: MyBatis-Plus组件
> **版本**: v1.0
> **编制日期**: 2026-06-04
> **当前版本**: 3.5.5
> **目标版本**: 3.5.16 (最新稳定版, 2026-01-11)

View File

@@ -1,5 +1,9 @@
# RuoYi 3.9.2 前端合入清单
> **文档类型**: 升级记录
> **适用范围**: 前端组件
> **版本**: v1.0
> **编制日期**: 2026-06-04
> **基线**: RuoYi-Vue3 v3.9.2 (2026-03-26)
> **目标**: 从 RuoYi 3.9.2 合入高价值前端组件,不破坏现有业务

View File

@@ -1,5 +1,9 @@
# HealthLink-HIS 二次开发版本 — 组件升级计划
> **文档类型**: 升级记录
> **适用范围**: 组件升级
> **版本**: v2.0
> **编制日期**: 2026-06-03
> **对比基线**: Gitee `tntlinking-opensource/healthlink-his` 2.0 分支
> **目标**: 在不破坏现有业务的前提下,逐步引入高价值组件升级

View File

@@ -57,3 +57,17 @@ MD/
## 铁律 #6: 测试通过后才提交
**代码修改必须通过完整测试后才能提交到远程仓库。**
## 铁律 #7: 前后端API路径对齐
**前后端API路径必须保持一致。**
- 后端接口路径统一前缀:`/healthlink-his/`
- 接口变更必须同步更新前后端代码
- 新增接口必须在 Swagger 文档中注册
## 铁律 #8: 规范文档统一管理
**所有铁律和规范文档存放在 `MD/specs/` 目录中:**
- `MD/specs/IRON_RULES.md` — 执行铁律(完整版)
- `MD/specs/BACKEND_DEVELOPMENT_STANDARD.md` — 后端开发规范
- `MD/specs/FRONTEND_DEVELOPMENT_STANDARD.md` — 前端开发规范
- `MD/specs/BACKEND_CHECKLIST.md` — 后端发布检查清单
- `MD/specs/FRONTEND_CHECKLIST.md` — 前端发布检查清单

View File

@@ -0,0 +1,25 @@
# HealthLink-HIS 前端开发规范
## 铁律 #1: 修改完必须测试
- `npm run build:dev` 构建成功
- ESLint 无错误
- 页面无控制台报错
- 核心业务页面功能正常
## 铁律 #2: 前后端API路径对齐
- API路径统一前缀`/healthlink-his/api/v1/`
- 接口变更必须同步更新前后端代码
## 铁律 #3: 文档统一管理
- 所有文档存储在 `MD/` 目录中
- 命名规范:大写英文+下划线
## 铁律 #4: 测试通过后才提交
- `npm run build:dev` 构建成功
- `npm run lint` 无错误
- 功能测试通过
## 详细规范
- 前端开发规范: `MD/specs/FRONTEND_DEVELOPMENT_STANDARD.md`
- 前端检查清单: `MD/specs/FRONTEND_CHECKLIST.md`
- 执行铁律: `MD/specs/IRON_RULES.md`