feat:移植工程
This commit is contained in:
40
src/components/Home/Budget/BudgetChart.vue
Normal file
40
src/components/Home/Budget/BudgetChart.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="budget-chart">
|
||||
<div class="budget-rank-chart card-item" ref="budgetRankChartRef"/>
|
||||
<div class="budget-project-chart card-item" ref="budgetProjectChartRef"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
import { barChartOptions, pieChartOptions } from 'vue3-common/utils/eChartsUtil'
|
||||
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
const budgetRankChartRef = ref<HTMLElement>()
|
||||
const budgetProjectChartRef = ref<HTMLElement>()
|
||||
|
||||
let budgetRankChart: echarts.ECharts
|
||||
let budgetProjectChart: echarts.ECharts
|
||||
|
||||
watch(() => budgetStore.isRefresh, () => {
|
||||
updateChart()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
budgetRankChart = echarts.init(budgetRankChartRef.value as HTMLElement)
|
||||
budgetProjectChart = echarts.init(budgetProjectChartRef.value as HTMLElement)
|
||||
})
|
||||
|
||||
const updateChart = () => {
|
||||
// 预算排行统计图
|
||||
const rankNameList = budgetStore.budgetRankStatsList.map((item) => item.name)
|
||||
const rankValueList = budgetStore.budgetRankStatsList.map((item) => item.value)
|
||||
budgetRankChart.setOption(barChartOptions('📊预算排行', '项目', rankNameList, '金额', rankValueList))
|
||||
|
||||
// 预算项目统计图
|
||||
budgetProjectChart.setOption(pieChartOptions('📊预算项目', '项目', '', budgetStore.budgetProjectStatsList))
|
||||
}
|
||||
</script>
|
||||
114
src/components/Home/Budget/BudgetDialog.vue
Normal file
114
src/components/Home/Budget/BudgetDialog.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<el-dialog v-model="budgetStore.budgetDialog.visible"
|
||||
:title="budgetStore.budgetDialog.title"
|
||||
center @open="openDialogEvent"
|
||||
width="50%" class="budget-dialog">
|
||||
<el-form ref="formRef" :model="budgetStore.budgetDialog.data"
|
||||
:rules="rules" label-width="100px">
|
||||
<el-form-item label="预算类别" prop="category">
|
||||
<el-select
|
||||
v-model="budgetStore.budgetDialog.data.category"
|
||||
allow-create filterable placeholder="请输入或选择预算类别">
|
||||
<el-option
|
||||
v-for="(item, index) in budgetStore.budgetCategoryList"
|
||||
:key="index" :label="item" :value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="预算项目" prop="project">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.project" autocomplete="off"
|
||||
placeholder="请输入预算项目" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="预算内容" prop="content">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.content" autocomplete="off"
|
||||
placeholder="请输入预算内容" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="供应商" prop="vendor">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.vendor" autocomplete="off"
|
||||
placeholder="请输入预算供应商" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="预算支出" prop="budget">
|
||||
<el-input
|
||||
v-model="budgetStore.budgetDialog.data.budget"
|
||||
placeholder="请输入预算支出" clearable
|
||||
:formatter="(value: string) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
|
||||
:parser="(value: string) => value.replace(/\$\s?|(,*)/g, '')"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="实际支出" prop="actual">
|
||||
<el-input
|
||||
v-model="budgetStore.budgetDialog.data.actual"
|
||||
placeholder="请输入实际支出" clearable
|
||||
:formatter="(value: string) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
|
||||
:parser="(value: string) => value.replace(/\$\s?|(,*)/g, '')"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="支付时间">
|
||||
<el-date-picker
|
||||
v-model="budgetStore.budgetDialog.data.payTime"
|
||||
type="datetime" placeholder="请选择支付时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remake">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.remake" autocomplete="off"
|
||||
placeholder="请输入备注" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
import { FormRules } from 'element-plus'
|
||||
import { budgetRules } from '@/utils/element/elRules'
|
||||
import { nextTick, reactive, ref } from 'vue'
|
||||
|
||||
const formRef = ref()
|
||||
const rules = reactive<FormRules>(budgetRules)
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
/**
|
||||
* 打开对话框事件
|
||||
*/
|
||||
const openDialogEvent = async () => {
|
||||
await nextTick(() => {
|
||||
formRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
formRef.value.validate().then(async () => {
|
||||
await budgetStore.handleBlogApi(budgetStore.budgetDialog.data.id)
|
||||
budgetStore.queryInfo.category = budgetStore.budgetDialog.data.category
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
budgetStore.budgetDialog.visible = false
|
||||
}
|
||||
</script>
|
||||
54
src/components/Home/Budget/BudgetQuery.vue
Normal file
54
src/components/Home/Budget/BudgetQuery.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="budget-query common-query">
|
||||
<el-switch
|
||||
v-model="budgetStore.showDataType"
|
||||
inline-prompt
|
||||
style="--el-switch-on-color: #CA6C65; --el-switch-off-color: #009FA8"
|
||||
active-value="CHART" inactive-value="DATA"
|
||||
active-text="图表统计" inactive-text="数据显示"
|
||||
@change="changeShowDataTypeEvent"
|
||||
/>
|
||||
|
||||
<el-select
|
||||
v-model="budgetStore.queryInfo.category"
|
||||
placeholder="请选择类别" style="width: 120px"
|
||||
@focus="focusCategoryEvent" @change="changeCategoryEvent">
|
||||
<el-option
|
||||
v-for="(item, index) in budgetStore.budgetCategoryList"
|
||||
:key="index" :label="item" :value="item"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-button v-if="budgetStore.showDataType === 'DATA'"
|
||||
type="primary" @click="addBudgeClick">新增预算
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
const focusCategoryEvent = async () => {
|
||||
await budgetStore.queryBudgetCategory()
|
||||
}
|
||||
|
||||
const changeCategoryEvent = async () => {
|
||||
await budgetStore.refreshInfo()
|
||||
}
|
||||
|
||||
const addBudgeClick = () => {
|
||||
budgetStore.budgetApiType = 'ADD'
|
||||
budgetStore.budgetDialog = {
|
||||
title: '新增预算',
|
||||
visible: true,
|
||||
data: budgetStore.getEmptyBudget()
|
||||
}
|
||||
budgetStore.budgetDialog.data.category = budgetStore.queryInfo.category
|
||||
}
|
||||
|
||||
const changeShowDataTypeEvent = async () => {
|
||||
await budgetStore.refreshInfo()
|
||||
}
|
||||
</script>
|
||||
98
src/components/Home/Budget/BudgetTable.vue
Normal file
98
src/components/Home/Budget/BudgetTable.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<el-table :data="budgetStore.budgetList"
|
||||
border stripe show-summary
|
||||
:span-method="spanMethod" :summary-method="summaryMethod"
|
||||
:header-cell-style="tableHeaderStyle()"
|
||||
:row-style="tableRowStyle()" :cell-style="tableCellStyle()"
|
||||
class="budget-table card-item">
|
||||
<el-table-column type="index" align="center" width="80"/>
|
||||
<el-table-column prop="project" label="项目" align="center" min-width="5%"/>
|
||||
<el-table-column prop="content" label="内容" align="center" min-width="10%"/>
|
||||
<el-table-column prop="vendor" label="供应商" align="center" min-width="10%"/>
|
||||
<el-table-column prop="budget" label="预算支出(元)" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ formatAmount(scope.row.budget) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="actual" label="实际支出(元)" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ formatAmount(scope.row.actual) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="save" label="节省预算(元)" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ formatAmount(scope.row.budget - scope.row.actual) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="percent" label="支出占比" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ `${((scope.row.actual / totalActual) * 100).toFixed(2)}%` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remake" label="备注" align="center" min-width="10%"/>
|
||||
<el-table-column fixed="right" label="操作" align="center" width="250">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" @click="editBudget(scope.row)">编辑</el-button>
|
||||
<el-button type="primary" @click="editBudget(scope.row)">账单</el-button>
|
||||
<el-button type="danger" @click="deleteBudget(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
import { IBudgetInfo } from '@/types/budget.ts'
|
||||
import { computed } from 'vue'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { formatAmount } from 'vue3-common/utils/numberUtil'
|
||||
import { getRowspan, getSummaryData } from 'vue3-common/utils/elUtil'
|
||||
import { commonElMessageBox, tableHeaderStyle, tableCellStyle, tableRowStyle } from 'vue3-common/utils/elUtil'
|
||||
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
const spanIndex = 1
|
||||
const summaryColumnList = ['budget', 'actual', 'save']
|
||||
|
||||
const totalActual = computed(() => {
|
||||
return budgetStore.budgetList.reduce((sum, item: IBudgetInfo) => {
|
||||
return sum + Number(item.actual || 0)
|
||||
}, 0)
|
||||
})
|
||||
|
||||
const spanMethod = (data: { row: any; column: any; rowIndex: number; columnIndex: number }) => {
|
||||
// 需要合并的列索引
|
||||
if (data.columnIndex === spanIndex) {
|
||||
return getRowspan(budgetStore.budgetList, data.column.property, data.rowIndex, data.row)
|
||||
}
|
||||
}
|
||||
|
||||
const summaryMethod = (data: { columns: any[]; data: any[] }) => {
|
||||
const sums = getSummaryData(data.columns, data.data, summaryColumnList)
|
||||
// 格式化输出
|
||||
sums[6] = formatAmount(parseFloat(sums[4] as string) - parseFloat(sums[5] as string))
|
||||
sums[4] = formatAmount(parseFloat(sums[4] as string))
|
||||
sums[5] = formatAmount(parseFloat(sums[5] as string))
|
||||
sums[7] = '100%'
|
||||
return sums
|
||||
}
|
||||
|
||||
const editBudget = (budget: IBudgetInfo) => {
|
||||
budgetStore.budgetApiType = 'UPDATE'
|
||||
budgetStore.budgetDialog = {
|
||||
title: '编辑预算',
|
||||
visible: true,
|
||||
data: deepCopyObject(budget)
|
||||
}
|
||||
}
|
||||
|
||||
const deleteBudget = (budget: IBudgetInfo) => {
|
||||
budgetStore.budgetApiType = 'DELETE'
|
||||
commonElMessageBox('是否删除该预算?').then(() => {
|
||||
budgetStore.handleBlogApi(budget.id as number)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user