[TOC]
# DAY21(2025/07/04)Vue+Highchart
## 進度日誌
- 額外新增3張圖表
## 筆記區📘 Vue3
### 額外新增3張圖表
CityPieChart.vue
```html
<template>
<div>
<h2>註冊地分布</h2>
<highcharts :options="chartOptions" />
</div>
</template>
<script setup>
import { ref, onMounted, watch, inject } from 'vue'
const filters = inject('filters')
const chartOptions = ref({
chart: { type: 'pie', height: 400 },
title: { text: null },
series: []
})
let rawData = null
onMounted(async () => {
const res = await fetch('/persona_target_guid.json')
const json = await res.json()
rawData = json.guid_data.find(e => e.類型 === '註冊地')
updateChart()
})
function updateChart() {
if (!rawData) return
const allCities = Object.keys(rawData).filter(key => key !== '類型')
chartOptions.value.series = [{
name: '人數',
data: allCities.map(city => ({
name: city,
y: Number(rawData[city][0])
}))
}]
}
watch(
() => [filters.gender.slice(), filters.age.slice()],
updateChart,
{ deep: true }
)
</script>
```

PowerHistogram.vue
```html
<template>
<div>
<h2>消費力直方圖</h2>
<highcharts :options="chartOptions" />
</div>
</template>
<script setup>
import { ref, onMounted, watch, inject } from 'vue'
const filters = inject('filters')
const chartOptions = ref({
chart: { type: 'column', height: 400 },
title: { text: null },
xAxis: { categories: [], title: { text: '消費力' } },
series: []
})
let rawData = null
onMounted(async () => {
const res = await fetch('/persona_target_guid.json')
const json = await res.json()
rawData = json.guid_data.find(e => e.類型 === '消費力直方圖')
updateChart()
})
function updateChart() {
if (!rawData) return
const ranges = Object.keys(rawData).filter(k => k !== '類型')
chartOptions.value.xAxis.categories = ranges
chartOptions.value.series = [{
name: '人數',
data: ranges.map(range => Number(rawData[range][1]))
}]
}
watch(
() => [filters.gender.slice(), filters.age.slice()],
updateChart,
{ deep: true }
)
</script>
```

TendencyBar.vue
```html
<template>
<div>
<h2>消費傾向與習慣</h2>
<highcharts :options="chartOptions" />
</div>
</template>
<script setup>
import { ref, onMounted, watch, inject } from 'vue'
const filters = inject('filters')
const chartOptions = ref({
chart: { type: 'bar', height: 400 },
title: { text: null },
xAxis: { categories: [], title: { text: '傾向' } },
series: []
})
let rawData = null
onMounted(async () => {
const res = await fetch('/persona_target_guid.json')
const json = await res.json()
rawData = json.guid_data.find(e => e.類型 === '消費傾向與習慣')
updateChart()
})
function updateChart() {
if (!rawData) return
const items = Object.keys(rawData).filter(k => k !== '類型')
chartOptions.value.xAxis.categories = items
chartOptions.value.series = [{
name: '人數',
data: items.map(item => rawData[item]['1'].count)
}]
}
watch(
() => [filters.gender.slice(), filters.age.slice()],
updateChart,
{ deep: true }
)
</script>
```

---
App.vue
```html
<script setup>
import { provide } from 'vue'
import { filters, pendingFilters } from './filters'
import GenderAgeBar from './components/GenderAgeBar.vue'
import CityPieChart from './components/CityPieChart.vue'
import TendencyBar from './components/TendencyBar.vue'
import PowerHistogram from './components/PowerHistogram.vue'
provide('filters', filters)
provide('pendingFilters', pendingFilters)
function toggleGender(gender) {
const idx = pendingFilters.gender.indexOf(gender)
if (idx >= 0) pendingFilters.gender.splice(idx, 1)
else pendingFilters.gender.push(gender)
}
function applyFilters() {
filters.gender = pendingFilters.gender.slice()
filters.age = pendingFilters.age.slice()
}
function resetFilters() {
pendingFilters.gender = []
pendingFilters.age = []
filters.gender = []
filters.age = []
}
</script>
<template>
<div>
<div>
<button @click="toggleGender('男')">男</button>
<button @click="toggleGender('女')">女</button>
<button @click="toggleGender('未填寫')">未填寫</button>
<button @click="applyFilters">篩選</button>
<button @click="resetFilters">重置</button>
<div>
<span v-for="g in pendingFilters.gender" :key="g">{{ g }} ×</span>
<span v-for="a in pendingFilters.age" :key="a">{{ a }} ×</span>
</div>
</div>
<GenderAgeBar />
<CityPieChart />
<TendencyBar />
<PowerHistogram />
</div>
</template>
```