4 changed files with 442 additions and 180 deletions
@ -1,23 +1,36 @@ |
|||
import http from 'apis/axios'; |
|||
|
|||
const apiUrl = import.meta.env.VITE_API_URL; |
|||
const ptccsens = `${apiUrl}/ptccsens/v1.0`; |
|||
const finance = `${ptccsens}/finance`; |
|||
|
|||
// 发起申请
|
|||
export const apply = params => http.post(`${finance}/apply`, params); |
|||
|
|||
// 审批
|
|||
export const audit = params => http.post(`${finance}/audit`, params); |
|||
|
|||
// 查询申请详情
|
|||
export const getApplyDetail = params => http.post(`${finance}/getApplyDetail`, params); |
|||
|
|||
// 通过任务id查看任务关联的财务信息
|
|||
export const getByTask = params => http.post(`${finance}/getByTask`, params); |
|||
|
|||
// 查看当前用户的费用申请历史信息(奖金)
|
|||
export const personalHistory = params => http.post(`${finance}/personalHistory`, params); |
|||
|
|||
// 查询费用申请类型
|
|||
export const queryType = params => http.post(`${finance}/queryType`, params); |
|||
import http from 'apis/axios'; |
|||
|
|||
const apiUrl = import.meta.env.VITE_API_URL; |
|||
const ptccsens = `${apiUrl}/ptccsens/v1.0`; |
|||
const finance = `${ptccsens}/finance`; |
|||
|
|||
// 发起申请
|
|||
export const apply = params => http.post(`${finance}/apply`, params); |
|||
|
|||
// 审批
|
|||
export const audit = params => http.post(`${finance}/audit`, params); |
|||
|
|||
// 查询申请详情
|
|||
export const getApplyDetail = params => |
|||
http.post(`${finance}/getApplyDetail`, params); |
|||
|
|||
// 通过任务id查看任务关联的财务信息
|
|||
export const getByTask = params => http.post(`${finance}/getByTask`, params); |
|||
|
|||
// 查看当前用户的费用申请历史信息(奖金)
|
|||
export const personalHistory = params => |
|||
http.post(`${finance}/personalHistory`, params); |
|||
|
|||
// 查询费用申请类型
|
|||
export const queryType = params => http.post(`${finance}/queryType`, params); |
|||
|
|||
// 任务支出统计
|
|||
export const taskExpense = params => |
|||
http.post(`${finance}/taskExpense`, params); |
|||
|
|||
// 名目支出统计
|
|||
export const rowExpense = params => http.post(`${finance}/rowExpense`, params); |
|||
|
|||
// 成员财务统计
|
|||
export const memberFinance = params => |
|||
http.post(`${finance}/memberFinance`, params); |
|||
|
@ -0,0 +1,168 @@ |
|||
<template> |
|||
<div v-if="data.info.length"> |
|||
<div class="w-full overflow-x-scroll"> |
|||
<table class="text-gray-500 mt-4 text-xs" v-if="props.id === 'taskTable'"> |
|||
<tr class="bg-gray-100"> |
|||
<td width="20%">任务名称</td> |
|||
<td width="16%">支出</td> |
|||
<td width="16%">占比</td> |
|||
<td width="16%">追加</td> |
|||
<td width="16%">操作</td> |
|||
</tr> |
|||
<tr v-for="item in data.info"> |
|||
<td>{{ item.taskName }}</td> |
|||
<td>{{ item.money }}</td> |
|||
<td>{{ item.percentage }}%</td> |
|||
<td> |
|||
<div v-if="!item.showField" @click="item.showField = true"> |
|||
{{ item.budget - 0 }} |
|||
</div> |
|||
<van-field |
|||
v-else |
|||
v-model="item.budget" |
|||
type="number" |
|||
class="input-box" |
|||
@change="handleUpdateBudget(item)" |
|||
@blur="item.showField = false" |
|||
/> |
|||
</td> |
|||
<td> |
|||
<van-icon name="plus" @click="toApplication" /> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
<table class="text-gray-500 mt-4 text-xs" v-if="props.id === 'nameTable'"> |
|||
<tr class="bg-gray-100"> |
|||
<td width="15%">任务名称</td> |
|||
<td width="16%">预算(元)</td> |
|||
<td width="16%">占比(元)</td> |
|||
</tr> |
|||
<tr v-for="item in data.info"> |
|||
<td>{{ item.rowName }}</td> |
|||
<td>{{ item.percentage }}</td> |
|||
<td>{{ item.money }}</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
<div class="w-1/2 mt-4 ml-48"> |
|||
<van-pagination |
|||
v-model="data.pageNum" |
|||
:items-per-page="data.pageSize" |
|||
:page-count="data.pages" |
|||
mode="simple" |
|||
/> |
|||
</div> |
|||
</div> |
|||
<van-empty v-else description="暂无数据" /> |
|||
<van-dialog |
|||
v-model:show="data.show" |
|||
title="追加预算" |
|||
show-cancel-button |
|||
@confirm="handleAdd" |
|||
> |
|||
<van-field |
|||
:border="data.border" |
|||
v-model="data.appendBudget" |
|||
type="textarea" |
|||
class="appendBudget" |
|||
placeholder="追加预算" |
|||
/> |
|||
</van-dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, reactive, onMounted, nextTick } from 'vue'; |
|||
import { taskExpense, rowExpense } from 'apis/finance'; |
|||
import { addBudget } from 'apis/projectFinance'; |
|||
|
|||
const projectId = useProjectId(); |
|||
const router = useRouter(); |
|||
|
|||
const props = defineProps({ |
|||
id: { type: Object, default: () => {} }, |
|||
}); |
|||
console.log('props.id: ', props.id); |
|||
const data = reactive({ |
|||
info: [], |
|||
pageNum: 1, |
|||
pageSize: 10, |
|||
pages: 0, |
|||
show: false, |
|||
appendBudget: '', |
|||
auditInfo: {}, |
|||
border: true, |
|||
}); |
|||
|
|||
// 追加预算确认 |
|||
async function handleUpdateBudget(item) { |
|||
try { |
|||
const params = { |
|||
param: { |
|||
appendBudget: item.budget - 0, |
|||
financeId: item.financeId, |
|||
projectId: projectId.value, |
|||
}, |
|||
}; |
|||
await addBudget(params); |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
} |
|||
} |
|||
|
|||
// 操作,跳转到发起申请界面 |
|||
function toApplication() { |
|||
const routeValue = router.currentRoute.value; |
|||
const query = routeValue.query; |
|||
router.push({ path: '/Initiate-application', query }); |
|||
} |
|||
|
|||
// 获取echarts图表数据(任务支出) |
|||
async function getTaskExpense() { |
|||
const params = { param: { projectId: projectId.value } }; |
|||
const res = await taskExpense(params); |
|||
for (let i = 0; i < res.length; i++) { |
|||
res.showField = false; |
|||
} |
|||
data.info = res; |
|||
} |
|||
// 获取echarts图表数据(名目支出) |
|||
async function getRowExpense() { |
|||
const params = { param: { projectId: projectId.value } }; |
|||
const res = await rowExpense(params); |
|||
data.info = res; |
|||
} |
|||
function setData() { |
|||
if (props.id === 'taskTable') { |
|||
getTaskExpense(); |
|||
} else if (props.id === 'nameTable') { |
|||
getRowExpense(); |
|||
} |
|||
} |
|||
onMounted(() => { |
|||
nextTick(() => { |
|||
// handleFinanceOfProject(); |
|||
setData(); |
|||
}); |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped lang="less"> |
|||
table { |
|||
width: 120%; |
|||
td { |
|||
border: 0.5px solid #ccc; |
|||
padding: 0.5rem; |
|||
} |
|||
} |
|||
.input-box { |
|||
padding: 0 !important; |
|||
border-bottom: 1px solid #ccc; |
|||
} |
|||
|
|||
.appendBudget { |
|||
border: 1px solid #ccc; |
|||
border-radius: 4px; |
|||
margin: 5%; |
|||
width: 90%; |
|||
} |
|||
</style> |
@ -1,148 +1,201 @@ |
|||
<template> |
|||
<!-- <div id="yield-chart"></div> --> |
|||
<div :id="props.id" style="width:400px;height:260px"></div> |
|||
<div :id="props.id" style="width: 400px; height: 260px"></div> |
|||
</template> |
|||
|
|||
|
|||
<script setup> |
|||
import { onMounted} from 'vue'; |
|||
const props = defineProps({ id: { type: Object, default: () => {} } }); |
|||
import { onMounted } from 'vue'; |
|||
import { taskExpense, rowExpense, memberFinance } from 'apis/finance'; |
|||
import { list } from 'postcss'; |
|||
const projectId = useProjectId(); |
|||
|
|||
onMounted(()=>{ |
|||
if(props.id){ |
|||
var myChart = echarts.init(document.getElementById(props.id)); |
|||
const props = defineProps({ |
|||
id: { type: Object, default: () => {} }, |
|||
}); |
|||
let oData = [ |
|||
{ |
|||
name: '办公费', |
|||
value: 36, |
|||
rate: 12, |
|||
}, |
|||
{ |
|||
name: '车辆费用', |
|||
value: 20, |
|||
rate: 20, |
|||
}, |
|||
{ |
|||
name: '差旅费33', |
|||
value: 15, |
|||
rate: -40, |
|||
}, |
|||
{ |
|||
name: '租赁费', |
|||
value: 10, |
|||
rate: -15, |
|||
}, |
|||
{ |
|||
name: '其他', |
|||
value: 9, |
|||
rate: 12, |
|||
}, |
|||
]; |
|||
// 获取echarts图表数据(任务支出) |
|||
async function getTaskExpense() { |
|||
const params = { param: { projectId: projectId.value } }; |
|||
const res = await taskExpense(params); |
|||
return changeData(res, 'taskName'); |
|||
} |
|||
// 获取echarts图表数据(名目支出) |
|||
async function getRowExpense() { |
|||
const params = { param: { projectId: projectId.value } }; |
|||
const res = await rowExpense(params); |
|||
return changeData(res, 'rowName'); |
|||
} |
|||
// 获取echarts图表数据(成员财务) |
|||
async function getMemberFinance() { |
|||
const params = { param: { projectId: projectId.value } }; |
|||
const res = await memberFinance(params); |
|||
return changeData(res, 'memberName'); |
|||
} |
|||
// 修改数据为optionData |
|||
function changeData(list, name) { |
|||
let optionsData = []; |
|||
for (let i = 0; i < list.length; i++) { |
|||
const data = { |
|||
name: list[i][name], |
|||
value: list[i].money - 0, |
|||
percentage: list[i].percentage, |
|||
}; |
|||
optionsData.push(data); |
|||
} |
|||
return optionsData; |
|||
} |
|||
function setData() { |
|||
if (props.id === 'taskEcharts') { |
|||
return getTaskExpense(); |
|||
} else if (props.id === 'nameEcharts') { |
|||
return getRowExpense(); |
|||
} else if (props.id === 'memberEcharts') { |
|||
return getMemberFinance(); |
|||
} else { |
|||
return oData; |
|||
} |
|||
} |
|||
|
|||
// |
|||
const data = [ |
|||
{ |
|||
name: '办公费', |
|||
value: 36, |
|||
rate: 12 |
|||
}, |
|||
{ |
|||
name: '车辆费用', |
|||
value: 20, |
|||
rate: 20 |
|||
}, |
|||
{ |
|||
name: '差旅费', |
|||
value: 15, |
|||
rate: -40 |
|||
}, |
|||
{ |
|||
name: '租赁费', |
|||
value: 10, |
|||
rate: -15 |
|||
}, |
|||
{ |
|||
name: '其他', |
|||
value: 9, |
|||
rate: 12 |
|||
}, |
|||
]; |
|||
function getTitleNum(list) { |
|||
let num = 0; |
|||
for (let i = 0; i < list.length; i++) { |
|||
num += list[i].value; |
|||
} |
|||
return num; |
|||
} |
|||
onMounted(async () => { |
|||
if (props.id) { |
|||
var myChart = echarts.init(document.getElementById(props.id)); |
|||
} |
|||
const data = await setData(); |
|||
const title = getTitleNum(data); |
|||
const option = { |
|||
title: { |
|||
text: 100, |
|||
textStyle:{ |
|||
fontSize:17, |
|||
color:"black" |
|||
}, |
|||
textAlign:"center", |
|||
x: '24%', |
|||
y: '35%', |
|||
text: title, |
|||
textStyle: { |
|||
fontSize: 17, |
|||
color: 'black', |
|||
}, |
|||
textAlign: 'center', |
|||
x: '24%', |
|||
y: '35%', |
|||
}, |
|||
legend: { |
|||
type: 'plain', |
|||
icon: 'circle', |
|||
orient: 'vertical', |
|||
left: '55%', |
|||
top: '15%', |
|||
align: 'left', |
|||
itemGap: 15, |
|||
itemWidth: 10, // 设置宽度 |
|||
itemHeight: 10, // 设置高度 |
|||
symbolKeepAspect: false, |
|||
textStyle: { |
|||
color: '#000', |
|||
rich: { |
|||
name: { |
|||
verticalAlign: 'right', |
|||
align: 'left', |
|||
width: 50, |
|||
fontSize: 12 |
|||
}, |
|||
value: { |
|||
align: 'left', |
|||
width: 40, |
|||
fontSize: 12 |
|||
}, |
|||
count: { |
|||
align: 'left', |
|||
width: 80, |
|||
fontSize: 12 |
|||
}, |
|||
} |
|||
type: 'plain', |
|||
icon: 'circle', |
|||
orient: 'vertical', |
|||
left: '55%', |
|||
top: '15%', |
|||
align: 'left', |
|||
itemGap: 15, |
|||
itemWidth: 10, // 设置宽度 |
|||
itemHeight: 10, // 设置高度 |
|||
symbolKeepAspect: false, |
|||
textStyle: { |
|||
color: '#000', |
|||
rich: { |
|||
name: { |
|||
verticalAlign: 'right', |
|||
align: 'left', |
|||
width: 50, |
|||
fontSize: 12, |
|||
}, |
|||
value: { |
|||
align: 'left', |
|||
width: 40, |
|||
fontSize: 12, |
|||
}, |
|||
count: { |
|||
align: 'left', |
|||
width: 80, |
|||
fontSize: 12, |
|||
}, |
|||
}, |
|||
data: data.map(item => item.name), |
|||
formatter: function(name) { |
|||
if (data && data.length) { |
|||
for (var i = 0; i < data.length; i++) { |
|||
if (name === data[i].name) { |
|||
return ( |
|||
'{name| ' + |
|||
name + |
|||
'} | ' + |
|||
'{value| ' + |
|||
data[i].value + |
|||
'%}' + |
|||
'{count| ' + |
|||
data[i].value + |
|||
'} ' |
|||
) |
|||
} |
|||
} |
|||
}, |
|||
data: data.map(item => item.name), |
|||
formatter: function (name) { |
|||
if (data && data.length) { |
|||
for (var i = 0; i < data.length; i++) { |
|||
if (name === data[i].name) { |
|||
return ( |
|||
'{name| ' + |
|||
name + |
|||
'} | ' + |
|||
'{value| ' + |
|||
data[i].percentage + |
|||
'%}' + |
|||
'{count| ' + |
|||
data[i].value + |
|||
'} ' |
|||
); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
series: [{ |
|||
series: [ |
|||
{ |
|||
name: '数量', |
|||
type: 'pie', |
|||
radius: ['40%', '55%'], |
|||
center: ['25%', '40%'], |
|||
data: data, |
|||
label: { |
|||
normal: { |
|||
show: false, |
|||
position: 'center', |
|||
formatter: '{text|{c}}\n{b}', |
|||
rich: { |
|||
text: { |
|||
align: 'center', |
|||
verticalAlign: 'middle', |
|||
padding: 8, |
|||
fontSize: 30 |
|||
}, |
|||
value: { |
|||
align: 'center', |
|||
verticalAlign: 'middle', |
|||
fontSize: 20 |
|||
} |
|||
} |
|||
normal: { |
|||
show: false, |
|||
position: 'center', |
|||
formatter: '{text|{c}}\n{b}', |
|||
rich: { |
|||
text: { |
|||
align: 'center', |
|||
verticalAlign: 'middle', |
|||
padding: 8, |
|||
fontSize: 30, |
|||
}, |
|||
value: { |
|||
align: 'center', |
|||
verticalAlign: 'middle', |
|||
fontSize: 20, |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
labelLine: { |
|||
normal: { |
|||
show: true |
|||
} |
|||
} |
|||
}] |
|||
}; |
|||
myChart.setOption(option); |
|||
|
|||
}) |
|||
normal: { |
|||
show: true, |
|||
}, |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
myChart.setOption(option); |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
|
|||
</style> |
|||
<style scoped></style> |
|||
|
Loading…
Reference in new issue