Files
zyt/SERVICE_PACKAGE_MULTI_SELECT.md
T
2026-04-16 11:13:26 +08:00

8.3 KiB
Raw Blame History

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

import { getDictData } from '@/api/app'

2. Added Service Package Options State

// 服务套餐选项
const servicePackageOptions = ref<Array<{ name: string; value: string }>>([])

3. Added Loading Function

// 加载服务套餐选项
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

onMounted(async () => {
    await loadRegionData()
    await loadServicePackageOptions()  // Added
    getLists()
})

5. Changed Form Field Type

Changed editForm.service_package from string to array:

// Before:
service_package: '',

// After:
service_package: [] as string[],

6. Updated Edit Form UI

Changed from text input to multi-select:

Before:

<el-input v-model="editForm.service_package" maxlength="100" />

After:

<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:

// 处理服务套餐:如果是字符串,转换为数组
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:

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:

// 格式化服务套餐显示
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

<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:

{
    "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.

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!