“编译修改”

This commit is contained in:
weizhong committed 2025-10-14 16:41:19 +08:00
1 parent 69e4b08946
commit e79bf5a26c
224 files changed
+66161 -6

No files matched your search

@@ -0,0 +1,500 @@
# 出国行程变更 - 申请行程情况字段调整
## 📋 修改时间
2025-10-13
## 🎯 需求说明
调整"二、申请行程情况"和"三、实际行程情况"部分的字段显示:
### 原字段布局
- 申请出行时间
- 地点
- 在外停留时间
### 新字段布局
- **前往国家** - 对应数据库字段 `original_destination`
- **出境事由** - 对应数据库字段 `original_exit_reason`
- **行程安排** - 对应数据库字段 `original_itinerary`
## ✅ 确认事项
### 数据库表结构
数据库表 `rs_overseas_itinerary_change` 已有所需字段,**无需修改**:
```sql
-- 原记录信息(从出国记录表冗余存储)
`original_destination` varchar(100) DEFAULT NULL COMMENT '原目的地国家',
`original_destination_city` varchar(100) DEFAULT NULL COMMENT '原目的地城市',
`original_exit_reason` varchar(100) DEFAULT NULL COMMENT '原出境事由',
`original_start_date` date DEFAULT NULL COMMENT '原出发日期',
`original_end_date` date DEFAULT NULL COMMENT '原返回日期',
`original_duration` int(11) DEFAULT NULL COMMENT '原出国天数',
`original_itinerary` text COMMENT '原行程安排',
-- 变更信息
`new_destination` varchar(100) DEFAULT NULL COMMENT '新目的地国家',
`new_destination_city` varchar(100) DEFAULT NULL COMMENT '新目的地城市',
`new_exit_reason` varchar(100) DEFAULT NULL COMMENT '新出境事由',
`new_start_date` date DEFAULT NULL COMMENT '新出发日期',
`new_end_date` date DEFAULT NULL COMMENT '新返回日期',
`new_duration` int(11) DEFAULT NULL COMMENT '新出国天数',
`new_itinerary` text COMMENT '新行程安排',
```
### 后端代码
后端实体类、VO类、Bo类已有相应字段,**无需修改**。
### 前端API类型
前端API接口类型定义已有相应字段,**无需修改**:
```typescript
export interface ItineraryChangeVO {
// ... 其他字段
originalDestination: string;
originalExitReason: string;
originalItinerary: string;
newDestination?: string;
newExitReason?: string;
newItinerary?: string;
}
```
## 📝 修改内容
### 一、前端表单UI修改
**文件**: `web/src/views/rs/overseas/itinerary-change.vue`
#### 1. 二、申请行程情况(只读显示)
**修改前**:
```vue
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="申请出行时间">
<el-input :value="formatDate(form.originalStartDate)" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="地点">
<el-input v-model="form.originalDestination" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="在外停留时间">
<el-input :value="`${formatDate(form.originalStartDate)} 至 ${formatDate(form.originalEndDate)} (${form.originalDuration || 0}天)`" disabled />
</el-form-item>
</el-col>
</el-row>
```
**修改后**:
```vue
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="前往国家">
<el-input v-model="form.originalDestination" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="出境事由">
<el-input v-model="form.originalExitReason" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="申请出行时间">
<el-input :value="`${formatDate(form.originalStartDate)} 至 ${formatDate(form.originalEndDate)}`" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="在外停留天数">
<el-input :value="`${form.originalDuration || 0}天`" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="行程安排">
<el-input
v-model="form.originalItinerary"
type="textarea"
:rows="3"
disabled
placeholder="原行程安排"
/>
</el-form-item>
</el-col>
</el-row>
```
#### 2. 三、实际行程情况(用户填写)
**修改前**:
```vue
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="实际出行时间" prop="newStartDate">
<el-date-picker v-model="form.newStartDate" ... />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="地点" prop="newDestination">
<el-input v-model="form.newDestination" ... />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="在外停留时间">
<!-- 日期范围选择器 -->
</el-form-item>
</el-col>
</el-row>
```
**修改后**:
```vue
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="前往国家" prop="newDestination">
<el-input v-model="form.newDestination" placeholder="请输入实际前往国家" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="出境事由" prop="newExitReason">
<el-input v-model="form.newExitReason" placeholder="请输入实际出境事由" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="实际出行时间" prop="newStartDate">
<el-date-picker
v-model="newDateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="在外停留天数">
<el-input :value="`${form.newDuration || 0}天`" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="行程安排" prop="newItinerary">
<el-input
v-model="form.newItinerary"
type="textarea"
:rows="3"
placeholder="请输入实际行程安排"
maxlength="1000"
show-word-limit
/>
</el-form-item>
</el-col>
</el-row>
```
### 二、数据自动填充逻辑修改
**文件**: `web/src/views/rs/overseas/itinerary-change.vue`
**修改前**:
```typescript
// 填充申请行程情况
state.form.originalDestination = selectedApplication.destination;
state.form.originalDestinationCity = selectedApplication.destinationCity;
state.form.originalExitReason = selectedApplication.exitReason || selectedApplication.purposeDetail;
state.form.originalStartDate = selectedApplication.startDate;
state.form.originalEndDate = selectedApplication.endDate;
state.form.originalDuration = selectedApplication.duration;
state.form.originalItinerary = selectedApplication.itinerary;
```
**修改后**:
```typescript
// 填充申请行程情况
// 前往国家:优先使用destinationCountry,其次使用destination
state.form.originalDestination = selectedApplication.destinationCountry || selectedApplication.destination;
state.form.originalDestinationCity = selectedApplication.destinationCity;
// 出境事由:优先使用exitReason,其次使用purpose
state.form.originalExitReason = selectedApplication.exitReason || selectedApplication.purpose;
// 行程安排
state.form.originalItinerary = selectedApplication.itinerary;
state.form.originalStartDate = selectedApplication.startDate;
state.form.originalEndDate = selectedApplication.endDate;
state.form.originalDuration = selectedApplication.duration;
// 默认将原信息复制到新信息
state.form.newDestination = selectedApplication.destinationCountry || selectedApplication.destination;
state.form.newDestinationCity = selectedApplication.destinationCity;
state.form.newExitReason = selectedApplication.exitReason || selectedApplication.purpose;
state.form.newItinerary = selectedApplication.itinerary;
state.form.newStartDate = selectedApplication.startDate;
state.form.newEndDate = selectedApplication.endDate;
state.form.newDuration = selectedApplication.duration;
```
### 三、日期范围计算属性(新增)
**文件**: `web/src/views/rs/overseas/itinerary-change.vue`
**新增计算属性**(用于日期范围选择器的双向绑定):
```typescript
// 新出行时间日期范围(用于日期选择器的双向绑定)
const newDateRange = computed({
get() {
if (state.form.newStartDate && state.form.newEndDate) {
return [state.form.newStartDate, state.form.newEndDate];
}
return null;
},
set(value: any) {
if (value && value.length === 2) {
state.form.newStartDate = value[0];
state.form.newEndDate = value[1];
} else {
state.form.newStartDate = '';
state.form.newEndDate = '';
}
}
});
```
**说明**:
- 日期选择器需要绑定一个数组 `[startDate, endDate]`
- 计算属性的 `get` 方法将两个独立的日期字段组合成数组
- 计算属性的 `set` 方法将数组拆分成两个独立的日期字段
- 现有的 `watch` 监听 `newStartDate` 和 `newEndDate` 自动计算天数
### 四、变更类型自动识别逻辑增强
**文件**: `web/src/views/rs/overseas/itinerary-change.vue`
**修改前**:
```typescript
// 自动识别变更类型
const changeTypeList: string[] = [];
if (state.form.newDestination !== state.form.originalDestination) {
changeTypeList.push('目的地变更');
}
if (state.form.newStartDate !== state.form.originalStartDate ||
state.form.newEndDate !== state.form.originalEndDate) {
changeTypeList.push('时间变更');
}
if (state.form.newItinerary && state.form.newItinerary !== state.form.originalItinerary) {
changeTypeList.push('行程变更');
}
```
**修改后**:
```typescript
// 自动识别变更类型
const changeTypeList: string[] = [];
if (state.form.newDestination !== state.form.originalDestination) {
changeTypeList.push('目的地变更');
}
if (state.form.newExitReason !== state.form.originalExitReason) {
changeTypeList.push('出境事由变更'); // 新增
}
if (state.form.newStartDate !== state.form.originalStartDate ||
state.form.newEndDate !== state.form.originalEndDate) {
changeTypeList.push('时间变更');
}
if (state.form.newItinerary && state.form.newItinerary !== state.form.originalItinerary) {
changeTypeList.push('行程变更');
}
```
### 四、表单验证规则调整
**文件**: `web/src/views/rs/overseas/itinerary-change.vue`
**修改前**:
```typescript
rules: {
applicationId: [{ required: true, message: '请选择原出国申请', trigger: 'change' }],
newDestination: [{ required: true, message: '请输入实际目的地', trigger: 'blur' }],
newStartDate: [{ required: true, message: '请选择实际出行日期', trigger: 'change' }],
changeReason: [{ required: true, message: '请输入变更原因', trigger: 'blur' }]
}
```
**修改后**:
```typescript
rules: {
applicationId: [{ required: true, message: '请选择原出国申请', trigger: 'change' }],
newDestination: [{ required: true, message: '请输入实际前往国家', trigger: 'blur' }],
newExitReason: [{ required: true, message: '请输入实际出境事由', trigger: 'blur' }], // 新增
newItinerary: [{ required: true, message: '请输入实际行程安排', trigger: 'blur' }], // 新增
changeReason: [{ required: true, message: '请输入变更原因', trigger: 'blur' }]
}
```
## 📦 涉及文件清单
### 前端代码(1个文件)
1. `web/src/views/rs/overseas/itinerary-change.vue` - 表单页面
### 数据库和后端
- **无需修改** - 字段已存在
## 🎨 新字段展示效果
### 二、申请行程情况(只读)
```
┌─────────────────────────────────────────────────────────────┐
│ 二、申请行程情况 │
├─────────────────────────────────────────────────────────────┤
│ 前往国家: [只读] 出境事由: [只读] │
│ 申请出行时间: [只读] 在外停留天数: [只读] │
│ 行程安排: [只读-多行文本框] │
└─────────────────────────────────────────────────────────────┘
```
### 三、实际行程情况(可编辑)
```
┌─────────────────────────────────────────────────────────────┐
│ 三、实际行程情况 │
├─────────────────────────────────────────────────────────────┤
│ 前往国家: [输入框] 出境事由: [输入框] │
│ 实际出行时间: [日期范围选择器] 在外停留天数: [自动计算] │
│ 行程安排: [多行文本框,1000字限制] │
└─────────────────────────────────────────────────────────────┘
```
## 🔄 数据流程
```
1. 用户选择原出国申请
↓
2. 调用 getOverseasApplication(applicationId) 获取申请详情
↓
3. handleApplicationChange 函数自动填充
- 前往国家:destinationCountry 或 destination
- 出境事由:exitReason 或 purpose
- 行程安排:itinerary
↓
4. 用户填写实际情况
- 前往国家(必填)
- 出境事由(必填)
- 行程安排(必填,最多1000字)
↓
5. 系统自动识别变更类型
- 目的地变更
- 出境事由变更 ← 新增
- 时间变更
- 行程变更
↓
6. 提交保存
```
## 📊 字段映射关系
### 出国申请表 → 行程变更表(原信息)
| 出国申请表字段 | 行程变更表字段 | 显示标签 | 说明 |
|---------------|---------------|---------|------|
| destinationCountry / destination | original_destination | 前往国家 | 优先使用destinationCountry |
| exitReason / purpose | original_exit_reason | 出境事由 | 优先使用exitReason |
| itinerary | original_itinerary | 行程安排 | 多行文本 |
### 用户填写 → 行程变更表(新信息)
| 用户输入 | 行程变更表字段 | 显示标签 | 验证规则 |
|---------|---------------|---------|---------|
| 前往国家 | new_destination | 前往国家 | 必填 |
| 出境事由 | new_exit_reason | 出境事由 | 必填 |
| 行程安排 | new_itinerary | 行程安排 | 必填,最多1000字 |
## 🆚 修改对比
### 修改前后对比表
| 项目 | 修改前 | 修改后 |
|-----|-------|-------|
| **二、申请行程情况** | | |
| 第一行 | 申请出行时间、地点 | 前往国家、出境事由 |
| 第二行 | 在外停留时间 | 申请出行时间、在外停留天数 |
| 第三行 | - | 行程安排(多行) |
| **三、实际行程情况** | | |
| 第一行 | 实际出行时间、地点 | 前往国家、出境事由 |
| 第二行 | 在外停留时间 | 实际出行时间(日期选择器)、在外停留天数(自动计算) |
| 第三行 | - | 行程安排(多行) |
| **验证规则** | | |
| 必填字段 | 原申请、新目的地、新出行时间、变更原因 | 原申请、新国家、新事由、新行程、变更原因 |
| **变更类型识别** | | |
| 识别项目 | 目的地、时间、行程 | 目的地、出境事由(新增)、时间、行程 |
## ✅ 优化亮点
1. **字段展示完整** - 保留了出行时间和停留天数,同时增加了前往国家、出境事由、行程安排
2. **布局更合理** - 行程安排使用全宽多行文本框,便于显示完整内容
3. **验证更完善** - 三个核心字段均为必填,确保信息完整性
4. **变更识别增强** - 增加了"出境事由变更"的自动识别
5. **字段映射灵活** - 兼容新旧两种API字段命名(destinationCountry/destination、exitReason/purpose)
6. **用户体验优化** - 多行文本框带字数限制和计数器
## 🧪 测试要点
### 1. 数据自动填充测试
- [ ] 选择原出国申请后,"前往国家"正确填充(二、三部分)
- [ ] 选择原出国申请后,"出境事由"正确填充(二、三部分)
- [ ] 选择原出国申请后,"申请出行时间"正确填充(二部分,只读)
- [ ] 选择原出国申请后,"实际出行时间"正确填充(三部分,可编辑)
- [ ] 选择原出国申请后,"在外停留天数"正确填充(二、三部分)
- [ ] 选择原出国申请后,"行程安排"正确填充(二、三部分)
- [ ] 字段以只读方式显示
### 2. 用户输入测试
- [ ] "前往国家"输入框正常工作
- [ ] "出境事由"输入框正常工作
- [ ] "实际出行时间"日期范围选择器正常工作
- [ ] 修改日期后,"在外停留天数"自动更新
- [ ] 选择跨度天数计算正确(含起止日)
- [ ] "行程安排"多行文本框正常工作
- [ ] 字数限制(1000字)正常工作
- [ ] 字数计数器正常显示
### 3. 表单验证测试
- [ ] 未填写"前往国家"时显示错误提示
- [ ] 未填写"出境事由"时显示错误提示
- [ ] 未填写"行程安排"时显示错误提示
### 4. 变更类型识别测试
- [ ] 修改"前往国家"后,识别为"目的地变更"
- [ ] 修改"出境事由"后,识别为"出境事由变更"
- [ ] 修改"行程安排"后,识别为"行程变更"
- [ ] 同时修改多项时,正确组合变更类型
### 5. 数据保存测试
- [ ] 提交后,新信息正确保存到数据库
- [ ] 查看详情时,字段正确显示
- [ ] 编辑已有变更时,字段正确回显
## 📝 完成状态
✅ 前端表单UI修改完成
✅ 数据自动填充逻辑更新完成
✅ 变更类型识别逻辑增强完成
✅ 表单验证规则调整完成
✅ 无编译错误和警告
---
**修改完成时间**:2025-10-13
**涉及文件数量**:1个
**测试状态**:待测试