| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- import { palette as C } from './data'
- const tipOpt = {
- backgroundColor: 'rgba(12,43,94,.94)',
- borderWidth: 0,
- textStyle: { color: '#fff', fontSize: 12 },
- padding: [8, 12],
- extraCssText: 'box-shadow:0 6px 18px rgba(12,43,94,.3);border-radius:6px;',
- }
- function axisStyle(opts = {}) {
- return {
- axisLine: { lineStyle: { color: '#E4E9F2' } },
- axisTick: { show: false },
- axisLabel: { color: C.mut, fontSize: 11 },
- splitLine: { lineStyle: { color: '#F2F5FA', type: 'dashed' } },
- ...opts,
- }
- }
- const sliceDate = (s) => s.map((x) => String(x[0]).slice(2, 7))
- const sliceDateFull = (s) => s.map((x) => String(x[0]).slice(0, 10))
- const upGrad = (color) => ({
- type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [{ offset: 0, color: '#3D7BE0' }, { offset: 1, color }],
- })
- const downGrad = (color) => ({
- type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [{ offset: 0, color: '#4FCB9A' }, { offset: 1, color }],
- })
- // ============== 月度累计值(柱图) ==============
- export function monthlyAccumulatedOption(series, { title = '累计值', color = C.brand, unit = '亿元' } = {}) {
- const cats = sliceDate(series)
- const values = series.map((x) => x[1])
- return {
- tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
- grid: { top: 18, left: 60, right: 24, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: unit, ...axisStyle() },
- series: [{
- name: title,
- type: 'bar',
- data: values,
- barWidth: 12,
- itemStyle: {
- color: (p) => (p.value >= 0 ? upGrad(color) : downGrad(C.down)),
- borderRadius: [3, 3, 0, 0],
- },
- label: { show: false },
- }],
- }
- }
- // ============== 月度累计同比(柱图,含 0 轴线) ==============
- export function monthlyYoYOption(series, { title = '累计同比', color = C.brand, unit = '%' } = {}) {
- const cats = sliceDate(series)
- const values = series.map((x) => x[1])
- return {
- tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
- grid: { top: 18, left: 50, right: 18, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: unit, ...axisStyle() },
- series: [{
- name: title,
- type: 'bar',
- data: values,
- barWidth: 12,
- itemStyle: {
- color: (p) => (p.value >= 0 ? upGrad(color) : downGrad(C.down)),
- borderRadius: [3, 3, 0, 0],
- },
- label: {
- show: true, position: 'top', fontSize: 10, color: C.mut,
- formatter: (p) => (typeof p.value === 'number' ? p.value.toFixed(2) : ''),
- },
- markLine: {
- symbol: ['none', 'none'],
- data: [{ yAxis: 0, lineStyle: { color: C.faint, type: 'dashed', width: 1 } }],
- label: { show: false },
- },
- }],
- }
- }
- // ============== 收入 vs 支出 双柱 ==============
- export function incomeVsExpenseOption(income, expense) {
- const cats = sliceDate(income)
- return {
- tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
- legend: {
- data: ['收入', '支出'],
- top: 4, textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8,
- },
- grid: { top: 32, left: 60, right: 24, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: '亿元', ...axisStyle() },
- series: [
- {
- name: '收入',
- type: 'bar',
- data: income.map((x) => x[1]),
- barWidth: 8,
- itemStyle: { color: upGrad(C.brand), borderRadius: [2, 2, 0, 0] },
- },
- {
- name: '支出',
- type: 'bar',
- data: expense.map((x) => x[1]),
- barWidth: 8,
- itemStyle: { color: upGrad(C.warn), borderRadius: [2, 2, 0, 0] },
- },
- ],
- }
- }
- // ============== 政府性基金 收入 vs 支出 双柱 ==============
- export function fundIncVsExpOption(income, expense) {
- const cats = sliceDate(income)
- return {
- tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
- legend: {
- data: ['基金收入', '基金支出'],
- top: 4, textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8,
- },
- grid: { top: 32, left: 60, right: 24, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: '亿元', ...axisStyle() },
- series: [
- {
- name: '基金收入',
- type: 'bar',
- data: income.map((x) => x[1]),
- barWidth: 8,
- itemStyle: { color: upGrad(C.purple), borderRadius: [2, 2, 0, 0] },
- },
- {
- name: '基金支出',
- type: 'bar',
- data: expense.map((x) => x[1]),
- barWidth: 8,
- itemStyle: { color: upGrad(C.brand), borderRadius: [2, 2, 0, 0] },
- },
- ],
- }
- }
- // ============== 赤字 / 专项债 年度(柱图) ==============
- export function yearlyBarOption(series, { title = '年度', color = C.warn, unit = '亿元' } = {}) {
- const cats = series.map((x) => String(x[0]).slice(0, 4))
- const values = series.map((x) => x[1])
- return {
- tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
- grid: { top: 18, left: 60, right: 24, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: unit, ...axisStyle() },
- series: [{
- name: title,
- type: 'bar',
- data: values,
- barWidth: 18,
- itemStyle: { color: upGrad(color), borderRadius: [3, 3, 0, 0] },
- label: {
- show: true, position: 'top', fontSize: 10, color: C.mut,
- formatter: (p) => (typeof p.value === 'number' ? p.value.toLocaleString() : ''),
- },
- }],
- }
- }
- // ============== 赤字率 折线 ==============
- export function yearlyLineOption(series, { title = '赤字率', color = C.up, unit = '%' } = {}) {
- const cats = series.map((x) => String(x[0]).slice(0, 4))
- const values = series.map((x) => x[1])
- return {
- tooltip: { ...tipOpt, trigger: 'axis' },
- grid: { top: 18, left: 50, right: 18, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: unit, ...axisStyle() },
- series: [{
- name: title,
- type: 'line',
- smooth: true,
- showSymbol: true,
- symbol: 'circle',
- symbolSize: 5,
- data: values,
- lineStyle: { color, width: 2.5 },
- itemStyle: { color },
- areaStyle: {
- type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [{ offset: 0, color: 'rgba(225,59,59,.16)' }, { offset: 1, color: 'rgba(225,59,59,0)' }],
- },
- label: {
- show: true, position: 'top', color: C.mut, fontSize: 10,
- formatter: (p) => (typeof p.value === 'number' ? p.value.toFixed(1) + '%' : ''),
- },
- }],
- }
- }
- // ============== 政府债余额 月度 折线 ==============
- export function monthlyLineOption(series, { title = '政府债余额', color = C.brand, unit = '万亿元' } = {}) {
- const cats = sliceDate(series)
- const values = series.map((x) => x[1])
- return {
- tooltip: { ...tipOpt, trigger: 'axis' },
- grid: { top: 18, left: 60, right: 24, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: unit, ...axisStyle() },
- series: [{
- name: title,
- type: 'line',
- smooth: true,
- showSymbol: false,
- symbol: 'circle',
- symbolSize: 4,
- data: values,
- lineStyle: { color, width: 2.5 },
- itemStyle: { color },
- areaStyle: {
- type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
- colorStops: [{ offset: 0, color: 'rgba(21,82,208,.16)' }, { offset: 1, color: 'rgba(21,82,208,0)' }],
- },
- label: { show: false },
- }],
- }
- }
- // ============== 收支差 ==============
- export function gapOption(income, expense, { title = '财政收支差', color = C.up, unit = '亿元' } = {}) {
- const cats = sliceDate(income)
- const inc = new Map(income)
- const exp = new Map(expense)
- const gap = cats.map((_, i) => {
- const d = String(income[i][0])
- const iv = inc.get(d)?.[1]
- const ev = exp.get(d)?.[1]
- if (typeof iv !== 'number' || typeof ev !== 'number') return null
- return iv - ev
- })
- return {
- tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
- grid: { top: 18, left: 60, right: 24, bottom: 28 },
- xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
- yAxis: { type: 'value', name: unit, ...axisStyle() },
- series: [{
- name: title,
- type: 'bar',
- data: gap,
- barWidth: 12,
- itemStyle: {
- color: (p) => (p.value >= 0 ? upGrad(color) : downGrad(C.down)),
- borderRadius: [3, 3, 0, 0],
- },
- label: { show: false },
- markLine: {
- symbol: ['none', 'none'],
- data: [{ yAxis: 0, lineStyle: { color: C.faint, type: 'dashed', width: 1 } }],
- label: { show: false },
- },
- }],
- }
- }
|