294 lines
8.3 KiB
Markdown
294 lines
8.3 KiB
Markdown
# Service Package Multi-Select Implementation (服务套餐多选实现)
|
||
|
||
## Changes Made
|
||
|
||
Updated the service package field from a simple text input to a multi-select dropdown with data loaded from the dictionary API.
|
||
|
||
### 1. Added Dictionary API Import
|
||
**File**: `admin/src/views/consumer/prescription/order_list.vue`
|
||
|
||
```typescript
|
||
import { getDictData } from '@/api/app'
|
||
```
|
||
|
||
### 2. Added Service Package Options State
|
||
```typescript
|
||
// 服务套餐选项
|
||
const servicePackageOptions = ref<Array<{ name: string; value: string }>>([])
|
||
```
|
||
|
||
### 3. Added Loading Function
|
||
```typescript
|
||
// 加载服务套餐选项
|
||
const loadServicePackageOptions = async () => {
|
||
try {
|
||
const data = await getDictData({ type: 'server_order' })
|
||
servicePackageOptions.value = (data?.server_order || []).filter((item: any) => item.status !== 0)
|
||
console.log('服务套餐选项已加载:', servicePackageOptions.value.length)
|
||
} catch (error) {
|
||
console.error('加载服务套餐选项失败:', error)
|
||
servicePackageOptions.value = []
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. Updated onMounted Hook
|
||
```typescript
|
||
onMounted(async () => {
|
||
await loadRegionData()
|
||
await loadServicePackageOptions() // Added
|
||
getLists()
|
||
})
|
||
```
|
||
|
||
### 5. Changed Form Field Type
|
||
Changed `editForm.service_package` from string to array:
|
||
```typescript
|
||
// Before:
|
||
service_package: '',
|
||
|
||
// After:
|
||
service_package: [] as string[],
|
||
```
|
||
|
||
### 6. Updated Edit Form UI
|
||
Changed from text input to multi-select:
|
||
|
||
**Before:**
|
||
```vue
|
||
<el-input v-model="editForm.service_package" maxlength="100" />
|
||
```
|
||
|
||
**After:**
|
||
```vue
|
||
<el-select
|
||
v-model="editForm.service_package"
|
||
multiple
|
||
collapse-tags
|
||
collapse-tags-tooltip
|
||
placeholder="请选择服务套餐"
|
||
clearable
|
||
class="w-full"
|
||
>
|
||
<el-option
|
||
v-for="item in servicePackageOptions"
|
||
:key="item.value"
|
||
:label="item.name"
|
||
:value="item.value"
|
||
/>
|
||
</el-select>
|
||
```
|
||
|
||
### 7. Updated Data Loading Logic
|
||
Added logic to handle both array and string formats when loading data:
|
||
|
||
```typescript
|
||
// 处理服务套餐:如果是字符串,转换为数组
|
||
if (d.service_package) {
|
||
if (Array.isArray(d.service_package)) {
|
||
editForm.service_package = d.service_package
|
||
} else if (typeof d.service_package === 'string') {
|
||
editForm.service_package = d.service_package.split(',').filter(v => v.trim() !== '')
|
||
} else {
|
||
editForm.service_package = []
|
||
}
|
||
} else {
|
||
editForm.service_package = []
|
||
}
|
||
```
|
||
|
||
### 8. Updated Form Submission
|
||
Convert array back to comma-separated string for backend:
|
||
|
||
```typescript
|
||
service_package: Array.isArray(editForm.service_package) ? editForm.service_package.join(',') : '',
|
||
```
|
||
|
||
### 9. Added Display Formatter
|
||
Added `formatServicePackage()` function to display service packages in detail view:
|
||
|
||
```typescript
|
||
// 格式化服务套餐显示
|
||
function formatServicePackage(value: any): string {
|
||
if (!value) return '—'
|
||
|
||
let packages: string[] = []
|
||
if (Array.isArray(value)) {
|
||
packages = value
|
||
} else if (typeof value === 'string') {
|
||
packages = value.split(',').filter(v => v.trim() !== '')
|
||
}
|
||
|
||
if (packages.length === 0) return '—'
|
||
|
||
// 将值转换为名称
|
||
const names = packages.map(val => {
|
||
const option = servicePackageOptions.value.find(opt => opt.value === val)
|
||
return option ? option.name : val
|
||
})
|
||
|
||
return names.join('、')
|
||
}
|
||
```
|
||
|
||
### 10. Updated Detail Display
|
||
```vue
|
||
<el-descriptions-item label="服务套餐">
|
||
{{ formatServicePackage(detailData.service_package) }}
|
||
</el-descriptions-item>
|
||
```
|
||
|
||
## Data Flow
|
||
|
||
### Loading Options:
|
||
1. Component mounts
|
||
2. `loadServicePackageOptions()` calls API: `/adminapi/config/dict?type=server_order`
|
||
3. Filters out disabled options (status !== 0)
|
||
4. Stores in `servicePackageOptions`
|
||
|
||
### Editing Order:
|
||
1. User opens edit dialog
|
||
2. Backend returns `service_package` as string: `"package1,package2,package3"`
|
||
3. Frontend splits string into array: `['package1', 'package2', 'package3']`
|
||
4. Multi-select displays selected options
|
||
5. User can add/remove selections
|
||
6. On save, array is joined back to string: `"package1,package2,package3"`
|
||
7. Backend receives comma-separated string
|
||
|
||
### Displaying in Detail:
|
||
1. Backend returns `service_package` as string
|
||
2. `formatServicePackage()` splits string into array
|
||
3. Maps values to display names using `servicePackageOptions`
|
||
4. Joins names with Chinese comma: `"套餐A、套餐B、套餐C"`
|
||
|
||
## UI Features
|
||
|
||
### Multi-Select Features:
|
||
- **Multiple Selection**: Users can select multiple service packages
|
||
- **Collapse Tags**: Selected items are collapsed with a count badge when many are selected
|
||
- **Collapse Tags Tooltip**: Hover over collapsed tags to see all selections
|
||
- **Clearable**: Users can clear all selections with one click
|
||
- **Searchable**: Built-in search functionality (default for el-select)
|
||
|
||
### Display Format:
|
||
- Detail view: `套餐A、套餐B、套餐C` (Chinese comma separator)
|
||
- Edit form: Tag-style display with collapse for many items
|
||
- Empty state: Shows `—` when no packages selected
|
||
|
||
## Backend Compatibility
|
||
|
||
### Database Storage:
|
||
The backend stores service packages as a comma-separated string in the database:
|
||
```
|
||
service_package: "package1,package2,package3"
|
||
```
|
||
|
||
### API Response:
|
||
The backend returns the string as-is, and the frontend handles the conversion.
|
||
|
||
### API Request:
|
||
The frontend sends the string format, maintaining backward compatibility.
|
||
|
||
## Testing Steps
|
||
|
||
### 1. Test Options Loading
|
||
1. Open order list page
|
||
2. Check browser console for: `服务套餐选项已加载: X`
|
||
3. Open edit dialog
|
||
4. Click on service package dropdown
|
||
5. Verify options are displayed
|
||
|
||
### 2. Test Multi-Selection
|
||
1. Edit an order
|
||
2. Click service package dropdown
|
||
3. Select multiple packages
|
||
4. Verify tags appear below the dropdown
|
||
5. Select many packages to test collapse behavior
|
||
6. Hover over collapsed tags to see tooltip
|
||
|
||
### 3. Test Saving
|
||
1. Select multiple service packages
|
||
2. Save the order
|
||
3. Check browser Network tab
|
||
4. Verify payload contains: `service_package: "value1,value2,value3"`
|
||
5. Verify database is updated
|
||
|
||
### 4. Test Display
|
||
1. Open order detail view
|
||
2. Check "服务套餐" field
|
||
3. Verify it shows: `套餐A、套餐B、套餐C`
|
||
4. Test with orders that have:
|
||
- Multiple packages
|
||
- Single package
|
||
- No packages (should show `—`)
|
||
|
||
### 5. Test Backward Compatibility
|
||
1. Edit an old order that has service_package as string
|
||
2. Verify it loads correctly into the multi-select
|
||
3. Verify you can modify and save
|
||
|
||
### 6. Test Clear Functionality
|
||
1. Edit an order with service packages selected
|
||
2. Click the clear button (×) on the select
|
||
3. Verify all selections are cleared
|
||
4. Save and verify database is updated to empty string
|
||
|
||
## Dictionary API Format
|
||
|
||
The API endpoint `/adminapi/config/dict?type=server_order` should return:
|
||
|
||
```json
|
||
{
|
||
"server_order": [
|
||
{
|
||
"name": "套餐A",
|
||
"value": "package_a",
|
||
"status": 1
|
||
},
|
||
{
|
||
"name": "套餐B",
|
||
"value": "package_b",
|
||
"status": 1
|
||
},
|
||
{
|
||
"name": "套餐C (已停用)",
|
||
"value": "package_c",
|
||
"status": 0
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Note**: Options with `status: 0` are filtered out and not displayed.
|
||
|
||
## Related Files
|
||
|
||
### Frontend:
|
||
- `admin/src/views/consumer/prescription/order_list.vue`
|
||
- Added `getDictData` import
|
||
- Added `servicePackageOptions` state
|
||
- Added `loadServicePackageOptions()` function
|
||
- Updated `editForm.service_package` to array type
|
||
- Updated edit form UI to multi-select
|
||
- Added data loading/saving conversion logic
|
||
- Added `formatServicePackage()` display function
|
||
- Updated detail display
|
||
|
||
### Backend:
|
||
- `/adminapi/config/dict` endpoint (should already exist)
|
||
- Dictionary data for `type=server_order`
|
||
|
||
## Summary
|
||
|
||
✅ Changed from text input to multi-select dropdown
|
||
✅ Loads options from dictionary API
|
||
✅ Supports multiple selection with tag display
|
||
✅ Collapse tags for better UI when many items selected
|
||
✅ Converts between array (frontend) and string (backend)
|
||
✅ Displays formatted names in detail view
|
||
✅ Backward compatible with existing string data
|
||
✅ Filters out disabled options
|
||
✅ Clearable and searchable
|
||
|
||
The service package field now provides a better user experience with predefined options and multi-selection capability!
|