# HChart 组件使用文档

## 目录

- [组件介绍](#组件介绍)
- [基本用法](#基本用法)
- [Props API](#props-api)
- [Events API](#events-api)
- [Methods API](#methods-api)
- [配置结构](#配置结构)
- [数据格式](#数据格式)
- [从 ECharts 配置转换](#从-echarts-配置转换)
- [完整示例](#完整示例)
- [样式属性](#样式属性)
- [注意事项](#注意事项)

---

## 组件介绍

`HChart` 是一个基于 ECharts 的可配置图表组件，支持柱状图、折线图、饼图三种常用图表类型。组件提供了预设的样式配置，支持静态数据、动态数据（Logic）和配置化使用方式。

### 特性

- ✅ 支持三种图表类型：柱状图（bar）、折线图（line）、饼图（pie）
- ✅ 支持静态数据（dataset）和动态数据（logicName）
- ✅ 自动数据格式转换和字段映射
- ✅ 预设样式，支持自定义覆盖
- ✅ 响应式布局，自动适配窗口大小
- ✅ 支持从后端配置中心获取配置

---

## 基本用法

### 方式1：直接传入配置（推荐）

<template>
  <HChart :config="chartConfig" />
</template>

<script setup>
import { ref } from 'vue'
import HChart from '@/base-client/components/his/HChart/HChart.vue'

const chartConfig = ref({
  type: 'pie',
  xtitle: '访问来源',
  dataset: [
    { label: '直接访问', value: 335 },
    { label: '邮件营销', value: 310 },
    { label: '联盟广告', value: 234 }
  ]
})
</script>### 方式2：通过配置名称查询

<template>
  <HChart
    query-params-name="chart-patient-stats"
    :fixed-query-form="{ condition: '1=1', dateRange: '2024-01' }"
    service-name="af-his"
  />
</template>

<script setup>
import HChart from '@/base-client/components/his/HChart/HChart.vue'
</script>### 方式3：使用 Logic 获取数据

<template>
  <HChart
    :config="chartConfig"
    :fixed-query-form="queryForm"
  />
</template>

<script setup>
import { ref, reactive } from 'vue'
import HChart from '@/base-client/components/his/HChart/HChart.vue'

const queryForm = reactive({
  condition: '1=1',
  startDate: '2024-01-01',
  endDate: '2024-01-31'
})

const chartConfig = ref({
  type: 'bar',
  xtitle: '患者统计',
  data: 'getPatientStatistics', // logicName
  dataMapping: {
    labelField: 'month',
    valueField: 'count'
  }
})
</script>---

## Props API

| 参数 | 说明 | 类型 | 默认值 | 必填 |
|------|------|------|--------|------|
| `queryParamsName` | 配置名称（用于从后端查询配置） | `String` | `''` | 否 |
| `serviceName` | 服务名 | `String` | `'af-his'` | 否 |
| `fixedQueryForm` | 固定查询参数（传递给 logic） | `Object` | `{ condition: '1=1' }` | 否 |
| `config` | 图表配置对象 | `Object` | `null` | 否 |

**注意**：`queryParamsName` 和 `config` 必须提供一个。

---

## Events API

| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| `init` | 图表初始化完成 | `(config: Object)` - 配置对象 |
| `dataLoaded` | 数据加载完成 | `(data: Array)` - 转换后的数据数组 |
| `error` | 发生错误 | `(error: Error)` - 错误对象 |

### 使用示例

<template>
  <HChart
    :config="chartConfig"
    @init="handleInit"
    @dataLoaded="handleDataLoaded"
    @error="handleError"
  />
</template>

<script setup>
const handleInit = (config) => {
  console.log('图表初始化:', config)
}

const handleDataLoaded = (data) => {
  console.log('数据加载完成:', data)
}

const handleError = (error) => {
  console.error('发生错误:', error)
}
</script>---

## Methods API

通过 `ref` 调用组件方法：

| 方法名 | 说明 | 参数 |
|--------|------|------|
| `refresh()` | 刷新图表（重新获取配置和数据） | - |
| `reload(newQueryForm)` | 重新加载图表（可更新查询参数） | `newQueryForm?: Object` |
| `chartInstance` | 获取 ECharts 实例（用于高级操作） | - |

### 使用示例
e
<template>
<HChart ref="chartRef" :config="chartConfig" />
<a-button @click="handleRefresh">刷新</a-button>
<a-button @click="handleReload">重新加载</a-button>
</template>

<script setup>
import { ref } from 'vue'

const chartRef = ref(null)

const handleRefresh = () => {
  chartRef.value?.refresh()
}

const handleReload = () => {
  chartRef.value?.reload({ condition: '1=1', dateRange: '2024-02' })
}
</script>---

## 配置结构

### 完整配置对象
ript
interface HChartConfig {
// 图表类型
type: 'bar' | 'line' | 'pie'

// 图表标题（显示在组件顶部）
xtitle?: string

// 静态数据（与 data 二选一）
dataset?: Array<{ label: string, value: number }>

// Logic 名称（与 dataset 二选一）
data?: string

// 数据映射配置（当后端返回的字段名不是 label/value 时使用）
dataMapping?: {
labelField?: string  // 默认: 'label'
valueField?: string  // 默认: 'value'
}

// Legend 配置（ECharts legend 配置）
legend?: Object

// Grid 配置（ECharts grid 配置）
grid?: Object

// 自定义 ECharts 配置（会与预设配置合并）
options?: Object
}### 配置字段说明

#### `type` - 图表类型

- `'bar'`：柱状图
- `'line'`：折线图
- `'pie'`：饼图

#### `xtitle` - 图表标题

显示在组件顶部的标题文本。

#### `dataset` - 静态数据

数组格式，每个元素包含 `label` 和 `value`：
t
dataset: [
{ label: '1月', value: 120 },
{ label: '2月', value: 200 }
]#### `data` - Logic 名称

后端 Logic 的名称，组件会通过 `runLogic` 获取数据。

#### `dataMapping` - 数据映射

当后端返回的字段名不是标准格式时，使用此配置映射：
ipt
dataMapping: {
labelField: 'month',    // 后端字段名 → label
valueField: 'count'     // 后端字段名 → value
}#### `legend` - 图例配置

ECharts legend 配置对象：
script
legend: {
orient: 'vertical',
left: 'left'
}#### `grid` - 网格配置

ECharts grid 配置对象：
cript
grid: {
left: 48,
right: 24,
bottom: 24,
top: 36
}#### `options` - 自定义配置

可以覆盖或扩展预设配置，支持所有 ECharts 配置项：
vascript
options: {
title: {
text: '自定义标题',
subtext: '副标题'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
series: [
{
radius: '50%',
emphasis: {
itemStyle: {
shadowBlur: 10
}
}
}
]
}**注意**：`options.series` 会与预设配置深度合并，但 `data` 字段会保留预设值（从 logic 获取的数据）。

---

## 数据格式

### Logic 返回值格式

`accountsReceivableChartLogic` 或其他 Logic 应该返回一个对象数组。

#### 标准格式（推荐）
avascript
// 使用 label 和 value（无需配置 dataMapping）
[
{ label: '直接访问', value: 335 },
{ label: '邮件营销', value: 310 },
{ label: '联盟广告', value: 234 }
]#### 自动识别格式

组件会自动识别以下字段：

// 方式1：使用 name/value
[
{ name: '直接访问', value: 335 },
{ name: '邮件营销', value: 310 }
]

// 方式2：使用 text/value
[
{ text: 'Q1', value: 320 },
{ text: 'Q2', value: 280 }
]

// 方式3：使用 x/y
[
{ x: 'Mon', y: 120 },
{ x: 'Tue', y: 200 }
]

// 方式4：使用 count
[
{ name: '内科', count: 120 },
{ name: '外科', count: 96 }
]#### 自定义字段格式

如果后端返回的字段名不是上述标准字段，需要配置 `dataMapping`：

// 后端返回
[
{ category: '直接访问', amount: 335 },
{ category: '邮件营销', amount: 310 }
]

// HChart 配置
{
type: 'pie',
data: 'accountsReceivableChartLogic',
dataMapping: {
labelField: 'category',
valueField: 'amount'
}
}### 数据转换规则

根据 `transformData` 函数的逻辑：

**有 `dataMapping` 配置时**：
- 使用指定的 `labelField` 和 `valueField`
- 如果字段不存在，label 回退到 `name` 或 `label`，value 回退到 `value` 或 `0`

**无 `dataMapping` 配置时**（自动识别）：
- Label 字段优先级：`label` → `name` → `text` → `x` → 对象第一个键
- Value 字段优先级：`value` → `count` → `y` → 对象第二个键 → `0`

---

## 从 ECharts 配置转换

### 转换对照表

| ECharts 配置 | HChart 配置 | 说明 |
|-------------|------------|------|
| `series[0].type` | `type` | 提取图表类型 |
| `title.text` | `xtitle` | 图表标题 |
| `series[0].data` | `dataset` 或 `data` | 数据源 |
| `legend` | `legend` | 图例配置 |
| `grid` | `grid` | 网格配置 |
| 其他配置 | `options` | 自定义配置 |

### 转换示例

#### 示例1：饼图转换

**原始 ECharts 配置**：ascript
const echartsOption = {
title: {
text: 'Referer of a Website',
subtext: 'Fake Data',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '50%',
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}**转换为 HChart 配置**：ript
const hChartConfig = {
type: 'pie',
xtitle: 'Referer of a Website',
// 方式1：静态数据
dataset: [
{ label: 'Search Engine', value: 1048 },
{ label: 'Direct', value: 735 },
{ label: 'Email', value: 580 }
],
// 方式2：动态数据
// data: 'accountsReceivableChartLogic',
legend: {
orient: 'vertical',
left: 'left'
},
options: {
title: {
text: 'Referer of a Website',
subtext: 'Fake Data',
left: 'center'
},
tooltip: {
trigger: 'item'
},
series: [
{
name: 'Access From',
radius: '50%',
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
}#### 示例2：柱状图转换

**原始 ECharts 配置**：ascript
const echartsOption = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
},
yAxis: {
type: 'value'
},
series: [
{
type: 'bar',
data: [120, 200, 150, 80, 70]
}
]
}**转换为 HChart 配置**：
const hChartConfig = {
type: 'bar',
dataset: [
{ label: 'Mon', value: 120 },
{ label: 'Tue', value: 200 },
{ label: 'Wed', value: 150 },
{ label: 'Thu', value: 80 },
{ label: 'Fri', value: 70 }
]
}#### 示例3：折线图转换

**原始 ECharts 配置**：ascript
const echartsOption = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
},
yAxis: {
type: 'value'
},
series: [
{
type: 'line',
smooth: true,
data: [120, 200, 150, 80, 70]
}
]
}**转换为 HChart 配置**：
const hChartConfig = {
type: 'line',
dataset: [
{ label: 'Mon', value: 120 },
{ label: 'Tue', value: 200 },
{ label: 'Wed', value: 150 },
{ label: 'Thu', value: 80 },
{ label: 'Fri', value: 70 }
]
}---

## 完整示例

### 示例1：静态数据饼图

<template>
  <HChart :config="pieConfig" />
</template>

<script setup>
import { ref } from 'vue'
import HChart from '@/base-client/components/his/HChart/HChart.vue'

const pieConfig = ref({
  type: 'pie',
  xtitle: '访问来源',
  dataset: [
    { label: '直接访问', value: 335 },
    { label: '邮件营销', value: 310 },
    { label: '联盟广告', value: 234 },
    { label: '视频广告', value: 135 },
    { label: '搜索引擎', value: 1548 }
  ],
  legend: {
    orient: 'vertical',
    left: 'left'
  },
  options: {
    tooltip: {
      trigger: 'item',
      formatter: '{a} <br/>{b}: {c} ({d}%)'
    }
  }
})
</script>### 示例2：动态数据柱状图

<template>
  <HChart
    :config="barConfig"
    :fixed-query-form="queryForm"
    @dataLoaded="handleDataLoaded"
  />
</template>

<script setup>
import { ref, reactive } from 'vue'
import HChart from '@/base-client/components/his/HChart/HChart.vue'

const queryForm = reactive({
  condition: '1=1',
  startDate: '2024-01-01',
  endDate: '2024-01-31'
})

const barConfig = ref({
  type: 'bar',
  xtitle: '患者统计',
  data: 'getPatientStatistics',
  dataMapping: {
    labelField: 'month',
    valueField: 'count'
  },
  options: {
    grid: {
      left: 48,
      right: 24,
      bottom: 24,
      top: 36
    }
  }
})

const handleDataLoaded = (data) => {
  console.log('数据加载完成:', data)
}
</script>### 示例3：多个图表展示

<template>
  <div class="charts-container">
    <HChart
      v-for="chart in charts"
      :key="chart.id"
      :config="chart"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import HChart from '@/base-client/components/his/HChart/HChart.vue'

const charts = ref([
  {
    id: 'chart-1',
    type: 'line',
    xtitle: '平均住院日趋势',
    dataset: [
      { label: '1月', value: 6.1 },
      { label: '2月', value: 5.8 },
      { label: '3月', value: 5.6 }
    ]
  },
  {
    id: 'chart-2',
    type: 'pie',
    xtitle: '科室占比',
    dataset: [
      { label: '内科', value: 120 },
      { label: '外科', value: 96 },
      { label: '儿科', value: 82 }
    ]
  },
  {
    id: 'chart-3',
    type: 'bar',
    xtitle: '工作量对比',
    dataset: [
      { label: 'A组', value: 320 },
      { label: 'B组', value: 280 },
      { label: 'C组', value: 260 }
    ]
  }
])
</script>

<style scoped>
.charts-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  gap: 24px;
}
</style>### 示例4：动态更新数据

<template>
  <div>
    <HChart ref="chartRef" :config="chartConfig" />
    <a-button @click="updateData">更新数据</a-button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import HChart from '@/base-client/components/his/HChart/HChart.vue'

const chartRef = ref(null)
const chartConfig = ref({
  type: 'line',
  xtitle: '动态数据图表',
  dataset: [
    { label: '1', value: Math.random() * 100 },
    { label: '2', value: Math.random() * 100 },
    { label: '3', value: Math.random() * 100 }
  ]
})

const updateData = () => {
  chartConfig.value.dataset = chartConfig.value.dataset.map(item => ({
    ...item,
    value: Math.random() * 100
  }))
}
</script>### 示例5：使用配置中心

<template>
  <HChart
    query-params-name="chart-patient-stats"
    :fixed-query-form="queryForm"
    service-name="af-his"
    @init="handleInit"
    @error="handleError"
  />
</template>

<script setup>
import { reactive } from 'vue'
import HChart from '@/base-client/components/his/HChart/HChart.vue'
import { message } from 'ant-design-vue'

const queryForm = reactive({
  condition: '1=1',
  dateRange: '2024-01'
})

const handleInit = (config) => {
  console.log('配置加载完成:', config)
  message.success('图表初始化成功')
}

const handleError = (error) => {
  console.error('错误:', error)
  message.error('图表加载失败')
}
</script>---

## 样式属性

### 布尔样式开关

通过属性控制样式：

| 属性 | 说明 | 类型 |
|------|------|------|
| `show-border` | 显示边框 | `Boolean` 或 `String` |

### 使用示例

<template>
  <!-- 显示边框 -->
  <HChart :config="config" show-border />

  <!-- 或者使用字符串 -->
  <HChart :config="config" show-border="true" />
</template>---

## 预设配置说明

HChart 为每种图表类型提供了预设样式：

### 柱状图（Bar）

- 颜色：`#3362DA`（主色）、`#4C7CFF`（hover）
- 圆角：顶部 4px
- 动画：420ms，延迟 60ms/项
- 阴影：hover 时显示

### 折线图（Line）

- 颜色：`#28C8B5`（主色）、`#4BE1CD`（hover）
- 平滑曲线：`smooth: true`
- 面积填充：透明度 0.1
- 动画：420ms，延迟 50ms/项

### 饼图（Pie）

- 半径：55%
- 边框：白色，2px
- 动画：420ms
- Hover：放大 6px，显示阴影

可以通过 `options` 覆盖这些预设配置。

---

## 注意事项

1. **数据格式**：Logic 必须返回数组，即使只有一条数据也要返回 `[{...}]`
2. **字段映射**：如果后端字段名不是标准格式，必须配置 `dataMapping`
3. **配置优先级**：`options` 中的配置会覆盖预设配置，但 `data` 字段会保留预设值
4. **响应式**：组件会自动监听窗口大小变化并调整图表尺寸
5. **内存管理**：组件卸载时会自动销毁 ECharts 实例
6. **数据更新**：修改 `config` 或 `fixedQueryForm` 会自动重新加载数据
7. **错误处理**：建议监听 `error` 事件处理错误情况
8. **配置来源**：`queryParamsName` 和 `config` 必须提供一个

---

## 常见问题

### Q1: 如何自定义图表颜色？

A: 在 `options.series[0]` 中配置 `itemStyle.color`：

{
type: 'bar',
dataset: [...],
options: {
series: [{
itemStyle: {
color: '#FF6B6B'
}
}]
}
}### Q2: 如何显示多个系列？

A: 目前 HChart 只支持单系列图表。如需多系列，建议直接使用 ECharts 或扩展组件。

### Q3: Logic 返回的数据格式不对怎么办？

A: 配置 `dataMapping` 指定字段映射：

{
data: 'yourLogic',
dataMapping: {
labelField: 'yourLabelField',
valueField: 'yourValueField'
}
}### Q4: 如何获取 ECharts 实例进行高级操作？

A: 通过 `ref` 获取 `chartInstance`：

const chartRef = ref(null)
// 获取实例
const instance = chartRef.value?.chartInstance
// 调用 ECharts API
instance?.setOption({...})---

## 更新日志

- **v1.0.0**：初始版本，支持 bar、line、pie 三种图表类型

---

**文档版本**：1.0.0
**最后更新**：2024-01-XX
