# LookupEditor 查找编辑器

一个查找输入组件，提供只读文本字段和操作按钮，用于打开外部选择对话框或模态窗口。

## 特性

- **只读输入**: 将选中的值显示为文本，不可直接编辑
- **操作触发**: 内置操作按钮，用于打开查找对话框或模态窗口
- **多种样式**: 支持plain、outlined和filled样式
- **表单集成**: 与表单和验证无缝协作
- **键盘支持**: 处理键盘导航和事件
- **焦点事件**: 支持焦点获得和失去事件处理
- **可清除值**: 非必填字段的可选清除功能
- **显示模式**: 支持编辑和显示模式

## 安装

```bash
npm install @ticatec/uniface-element
```

## 使用方法

### 基本用法

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedValue = null;
  let displayText = '';
  
  function handleLookupAction() {
    // 在这里打开查找对话框/模态窗口
    console.log('打开查找对话框...');
    
    // 示例：模拟用户选择
    setTimeout(() => {
      selectedValue = { id: 1, name: '张三' };
      displayText = '张三';
    }, 1000);
  }
</script>

<LookupEditor 
  bind:value={selectedValue}
  text={displayText}
  onAction={handleLookupAction}
  placeholder="点击选择用户"
  variant="outlined"
  style="width: 300px;"
/>
```

### 员工查找

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  import EmployeeLookupDialog from './EmployeeLookupDialog.svelte';
  
  let selectedEmployee = null;
  let employeeName = '';
  let showLookupDialog = false;
  
  function openEmployeeLookup() {
    showLookupDialog = true;
  }
  
  function handleEmployeeSelected(employee) {
    selectedEmployee = employee;
    employeeName = `${employee.firstName} ${employee.lastName}`;
    showLookupDialog = false;
  }
  
  function handleValueChange(value) {
    console.log('员工值变化:', value);
  }
</script>

<LookupEditor 
  bind:value={selectedEmployee}
  text={employeeName}
  onAction={openEmployeeLookup}
  onchange={handleValueChange}
  placeholder="选择员工"
  variant="filled"
  mandatory
/>

{#if showLookupDialog}
  <EmployeeLookupDialog 
    on:select={handleEmployeeSelected}
    on:close={() => showLookupDialog = false}
  />
{/if}
```

### 带焦点事件的客户查找

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedCustomer = null;
  let customerDisplay = '';
  
  function handleCustomerLookup() {
    // 打开客户选择模态窗口
    openCustomerModal();
  }
  
  function handleFocus(event) {
    console.log('查找器获得焦点');
    // 可以高亮字段或显示提示
  }
  
  function handleBlur(event) {
    console.log('查找器失去焦点');
    // 可以验证或保存状态
  }
</script>

<LookupEditor 
  bind:value={selectedCustomer}
  text={customerDisplay}
  onAction={handleCustomerLookup}
  onfocus={handleFocus}
  onblur={handleBlur}
  placeholder="搜索客户..."
  variant="outlined"
/>
```

### 表单中的产品查找

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  import FormField from '@ticatec/uniface-element/form-field';
  
  let orderData = {
    product: null,
    quantity: 1,
    notes: ''
  };
  
  let productName = '';
  let errors = {};
  
  function openProductCatalog() {
    // 打开产品选择对话框
    console.log('打开产品目录...');
  }
  
  function validateForm() {
    errors = {};
    
    if (!orderData.product) {
      errors.product = '请选择产品';
    }
    
    if (!orderData.quantity || orderData.quantity < 1) {
      errors.quantity = '数量必须至少为1';
    }
    
    return Object.keys(errors).length === 0;
  }
</script>

<form on:submit|preventDefault={validateForm}>
  <FormField label="产品" required error={errors.product}>
    <LookupEditor 
      bind:value={orderData.product}
      text={productName}
      onAction={openProductCatalog}
      placeholder="选择产品"
      variant="outlined"
      mandatory
    />
  </FormField>
  
  <FormField label="数量" required error={errors.quantity}>
    <input 
      type="number" 
      bind:value={orderData.quantity}
      min="1"
      placeholder="输入数量"
    />
  </FormField>
  
  <button type="submit">下单</button>
</form>
```

## API 参考

### 属性

| 属性 | 类型 | 默认值 | 描述 |
|------|------|---------|-------------|
| `value` | `any` | `null` | 选中的值/对象 |
| `text` | `string` | `''` | 输入字段中显示的文本 |
| `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | 视觉样式变体 |
| `placeholder` | `string` | `''` | 未选中值时的占位符文本 |
| `disabled` | `boolean` | `false` | 组件是否禁用 |
| `readonly` | `boolean` | `false` | 组件是否只读 |
| `mandatory` | `boolean` | `false` | 是否必填（影响清除按钮） |
| `compact` | `boolean` | `false` | 是否使用紧凑样式 |
| `style` | `string` | `''` | 自定义CSS样式 |
| `displayMode` | `DisplayMode` | `DisplayMode.Edit` | 显示模式（编辑或显示） |

### 事件

| 事件 | 类型 | 描述 |
|-------|------|-------------|
| `onAction` | `() => void` | 点击操作按钮时触发 |
| `onchange` | `(value: any) => void` | 值改变时触发 |
| `onfocus` | `(event: FocusEvent) => void` | 输入框获得焦点时触发 |
| `onblur` | `(event: FocusEvent) => void` | 输入框失去焦点时触发 |

### 键盘事件

组件还转发这些键盘事件：

- `on:keydown` - 键盘按键事件

## 高级用法

### 多步骤查找

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedLocation = null;
  let locationText = '';
  let currentStep = 'country'; // 'country' -> 'state' -> 'city'
  
  function handleLocationLookup() {
    switch (currentStep) {
      case 'country':
        openCountrySelector();
        break;
      case 'state':
        openStateSelector();
        break;
      case 'city':
        openCitySelector();
        break;
    }
  }
  
  function handleLocationChange(location) {
    selectedLocation = location;
    if (location) {
      locationText = `${location.city}, ${location.state}, ${location.country}`;
    } else {
      locationText = '';
      currentStep = 'country';
    }
  }
</script>

<LookupEditor 
  bind:value={selectedLocation}
  text={locationText}
  onAction={handleLocationLookup}
  onchange={handleLocationChange}
  placeholder="选择位置（国家 → 省份 → 城市）"
  variant="outlined"
/>
```

### 带验证的查找

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedItem = null;
  let itemText = '';
  let isValid = true;
  let validationMessage = '';
  
  function validateSelection(item) {
    if (!item) {
      isValid = false;
      validationMessage = '必须选择项目';
      return false;
    }
    
    if (item.status === 'inactive') {
      isValid = false;
      validationMessage = '选中的项目已停用';
      return false;
    }
    
    isValid = true;
    validationMessage = '';
    return true;
  }
  
  function handleSelectionChange(value) {
    validateSelection(value);
  }
</script>

<div class="lookup-container">
  <LookupEditor 
    bind:value={selectedItem}
    text={itemText}
    onAction={openLookupDialog}
    onchange={handleSelectionChange}
    placeholder="选择项目"
    variant="outlined"
    style={isValid ? '' : 'border-color: #f44336;'}
  />
  
  {#if !isValid}
    <div class="error-message">{validationMessage}</div>
  {/if}
</div>

<style>
  .lookup-container {
    position: relative;
  }
  
  .error-message {
    color: #f44336;
    font-size: 0.875rem;
    margin-top: 4px;
  }
</style>
```

### 带最近选择的查找

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedUser = null;
  let userDisplayName = '';
  let recentSelections = [];
  let showRecentMenu = false;
  
  function handleUserLookup() {
    // 首先显示最近选择，然后是完整查找
    if (recentSelections.length > 0) {
      showRecentMenu = true;
    } else {
      openFullUserLookup();
    }
  }
  
  function handleUserSelected(user) {
    selectedUser = user;
    userDisplayName = user.displayName;
    
    // 添加到最近选择
    recentSelections = [
      user,
      ...recentSelections.filter(u => u.id !== user.id)
    ].slice(0, 5); // 只保留5个最近项目
    
    showRecentMenu = false;
  }
  
  function handleFocus() {
    // 获得焦点时可以显示最近选择
    if (recentSelections.length > 0 && !selectedUser) {
      showRecentMenu = true;
    }
  }
  
  function handleBlur() {
    // 失去焦点时隐藏最近菜单
    setTimeout(() => {
      showRecentMenu = false;
    }, 200); // 延迟以允许点击菜单项
  }
</script>

<div class="lookup-with-recent">
  <LookupEditor 
    bind:value={selectedUser}
    text={userDisplayName}
    onAction={handleUserLookup}
    onfocus={handleFocus}
    onblur={handleBlur}
    placeholder="选择用户"
    variant="outlined"
  />
  
  {#if showRecentMenu}
    <div class="recent-menu">
      <div class="recent-header">最近选择</div>
      {#each recentSelections as user}
        <button 
          class="recent-item"
          on:click={() => handleUserSelected(user)}
        >
          {user.displayName}
        </button>
      {/each}
      <button 
        class="recent-item show-all"
        on:click={openFullUserLookup}
      >
        显示所有用户...
      </button>
    </div>
  {/if}
</div>

<style>
  .lookup-with-recent {
    position: relative;
  }
  
  .recent-menu {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: white;
    border: 1px solid #ddd;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    z-index: 1000;
    max-height: 200px;
    overflow-y: auto;
  }
  
  .recent-header {
    padding: 8px 12px;
    font-size: 0.875rem;
    font-weight: 600;
    color: #666;
    border-bottom: 1px solid #eee;
  }
  
  .recent-item {
    display: block;
    width: 100%;
    padding: 8px 12px;
    border: none;
    background: white;
    text-align: left;
    cursor: pointer;
    transition: background-color 0.2s;
  }
  
  .recent-item:hover {
    background-color: #f5f5f5;
  }
  
  .recent-item.show-all {
    font-style: italic;
    color: #666;
    border-top: 1px solid #eee;
  }
</style>
```

## 样式

### CSS 变量

LookupEditor组件继承CommonPicker组件的样式，支持这些CSS变量：

```css
:root {
  --uniface-picker-border-color: #d1d5db;
  --uniface-picker-focus-border-color: #3b82f6;
  --uniface-picker-background: white;
  --uniface-picker-text-color: #374151;
  --uniface-picker-placeholder-color: #9ca3af;
}
```

### 自定义样式

```css
.custom-lookup {
  --uniface-picker-border-color: #e2e8f0;
  --uniface-picker-focus-border-color: #2563eb;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.custom-lookup input {
  font-weight: 500;
}

.custom-lookup .action-button {
  color: #2563eb;
}
```

### 样式变体

```svelte
<!-- Outlined 样式 -->
<LookupEditor variant="outlined" />

<!-- Filled 样式 -->
<LookupEditor variant="filled" />

<!-- Plain 样式 -->
<LookupEditor variant="plain" />
```

## 集成模式

### 与模态对话框集成

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  import Modal from '@ticatec/uniface-element/modal';
  
  let showModal = false;
  let selectedItem = null;
  let itemDisplay = '';
  
  function openLookup() {
    showModal = true;
  }
  
  function handleItemSelected(item) {
    selectedItem = item;
    itemDisplay = item.name;
    showModal = false;
  }
</script>

<LookupEditor 
  bind:value={selectedItem}
  text={itemDisplay}
  onAction={openLookup}
  placeholder="选择项目"
  variant="outlined"
/>

<Modal bind:show={showModal} title="选择项目">
  <!-- 在这里放置查找/选择内容 -->
  <ItemSelectionList on:select={handleItemSelected} />
</Modal>
```

### 与外部API集成

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedRecord = null;
  let recordDisplay = '';
  let isLoading = false;
  
  async function handleLookup() {
    isLoading = true;
    
    try {
      // 打开外部查找系统
      const result = await openExternalLookup();
      
      if (result) {
        selectedRecord = result;
        recordDisplay = result.displayName;
      }
    } catch (error) {
      console.error('查找失败:', error);
    } finally {
      isLoading = false;
    }
  }
</script>

<LookupEditor 
  bind:value={selectedRecord}
  text={recordDisplay}
  onAction={handleLookup}
  disabled={isLoading}
  placeholder={isLoading ? '加载中...' : '选择记录'}
  variant="outlined"
/>
```

## 最佳实践

### 1. 清晰的值显示

始终提供有意义的显示文本：

```svelte
<script>
  // 好的做法：清晰、描述性的显示
  $: displayText = selectedCustomer ? 
    `${selectedCustomer.name} (${selectedCustomer.code})` : '';
  
  // 避免：只显示ID或不清楚的文本
  // $: displayText = selectedCustomer?.id;
</script>
```

### 2. 处理加载状态

在查找操作期间显示适当的反馈：

```svelte
<script>
  let isLookupOpen = false;
  
  function handleLookup() {
    isLookupOpen = true;
    // 打开查找对话框
  }
</script>

<LookupEditor 
  disabled={isLookupOpen}
  placeholder={isLookupOpen ? '查找进行中...' : '选择项目'}
  onAction={handleLookup}
/>
```

### 3. 验证选择

始终验证查找选择：

```svelte
<script>
  function handleSelectionChange(value) {
    if (value && !value.isActive) {
      // 清除无效选择
      selectedItem = null;
      displayText = '';
      showError('选中的项目未激活');
    }
  }
</script>
```

### 4. 提供上下文

帮助用户理解他们正在选择什么：

```svelte
<LookupEditor 
  placeholder="选择员工（使用员工搜索）"
  text={selectedEmployee ? 
    `${selectedEmployee.name} - ${selectedEmployee.department}` : 
    ''
  }
/>
```

## 无障碍功能

- **键盘导航**: 支持Tab键和回车键的完整键盘支持
- **屏幕阅读器支持**: 适当的标签和通知
- **焦点管理**: 清晰的焦点指示器和逻辑tab顺序
- **ARIA属性**: 为辅助技术提供适当的角色和属性

## 浏览器支持

- **现代浏览器**: Chrome、Firefox、Safari、Edge（最新版本）
- **移动浏览器**: iOS Safari、Chrome Mobile、Firefox Mobile
- **键盘导航**: 所有平台的完整支持

## 相关组件

- **CommonPicker**: 内部使用的基础选择器组件
- **FormField**: 用于标签和验证的表单字段包装器
- **Modal**: 用于查找界面的模态对话框
- **ListBox**: 用于查找对话框的列表选择组件

## 许可证

MIT许可证 - 详情请参阅LICENSE文件。