Compare commits
43 Commits
Author | SHA1 | Date |
---|---|---|
|
db889ca3f9 | 4 years ago |
|
0bd7dc8f21 | 4 years ago |
|
6b819e6e34 | 4 years ago |
|
3ecb206451 | 4 years ago |
|
d1a77ea0dc | 4 years ago |
|
6c64449f41 | 4 years ago |
|
c51474ac2f | 4 years ago |
|
fabb3662de | 4 years ago |
|
4485da585c | 4 years ago |
|
6a05e2f8b5 | 4 years ago |
|
b2373db78b | 4 years ago |
|
da5dccc24c | 4 years ago |
|
1255bd667f | 4 years ago |
|
5b4043ba09 | 4 years ago |
|
b3a6c5cb40 | 4 years ago |
|
081f0729f4 | 4 years ago |
|
0cf0257cb9 | 4 years ago |
|
b7c71b087e | 4 years ago |
|
68ab2c908b | 4 years ago |
|
63935d892e | 4 years ago |
|
3428a00d9e | 4 years ago |
|
b6f2d4006e | 4 years ago |
|
3869ff242e | 4 years ago |
|
7bc5def9b3 | 4 years ago |
|
baede98c02 | 4 years ago |
|
dfb457d11d | 4 years ago |
|
984b0bc112 | 4 years ago |
|
9a3097ba22 | 4 years ago |
|
ea7b92e5d7 | 4 years ago |
|
f27dd3c0cb | 4 years ago |
|
1ec9334d34 | 4 years ago |
|
804ca96528 | 4 years ago |
|
ea051d3577 | 4 years ago |
|
35c73910f1 | 4 years ago |
|
7f5c5ba8d7 | 4 years ago |
|
7a0113348d | 4 years ago |
|
d05d4d95d1 | 4 years ago |
|
0434a23750 | 4 years ago |
|
7d03221bfa | 4 years ago |
|
095c043407 | 4 years ago |
|
8f0bc2dca9 | 4 years ago |
|
6ef8384880 | 4 years ago |
|
0cdb35e9d0 | 4 years ago |
38 changed files with 3273 additions and 169 deletions
@ -0,0 +1 @@ |
|||||
|
VITE_API_URL=https://test.tall.wiki |
@ -0,0 +1 @@ |
|||||
|
VITE_API_URL=http://www.tall.wiki |
@ -0,0 +1 @@ |
|||||
|
VITE_API_URL=https://test.tall.wiki |
@ -0,0 +1,56 @@ |
|||||
|
import Axios from 'axios'; |
||||
|
import { ElMessage } from 'element-plus' |
||||
|
import { useToken } from '../composables/state' |
||||
|
|
||||
|
const baseUrl = '/gateway'; |
||||
|
|
||||
|
const instance = Axios.create({ |
||||
|
baseUrl, |
||||
|
timeout: 20000, |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
// request
|
||||
|
instance.interceptors.request.use( |
||||
|
config => { |
||||
|
const token = useToken() |
||||
|
if (token.value) { |
||||
|
config.headers.Authorization = `Bearer ${token.value}`; |
||||
|
} |
||||
|
// config.headers.deviceId = store.state.systemInfo.deviceId;
|
||||
|
config.headers.deviceId = '1'; |
||||
|
config.headers.appType = 0; |
||||
|
return config; |
||||
|
}, |
||||
|
error => { |
||||
|
return Promise.reject(error); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
// response
|
||||
|
instance.interceptors.response.use( |
||||
|
response => { |
||||
|
if (response.status !== 200 || !response.data) { |
||||
|
return Promise.reject(response.statusText); |
||||
|
} |
||||
|
const { code, data, msg } = response.data; |
||||
|
if (code === 200) { |
||||
|
return data; |
||||
|
} |
||||
|
return Promise.reject(msg); |
||||
|
}, |
||||
|
error => { |
||||
|
if (error.response && error.response.data) { |
||||
|
const code = error.response.status; |
||||
|
const msg = error.response.data.message; |
||||
|
ElMessage.error(`Code: ${code}, Message: ${msg}`); |
||||
|
|
||||
|
console.error(`[Axios Error]`, error.response); |
||||
|
} else { |
||||
|
// ElMessage.error(`${error}`);
|
||||
|
} |
||||
|
return Promise.reject(error); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
export default instance; |
@ -0,0 +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); |
||||
|
|
||||
|
// 任务支出统计
|
||||
|
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,11 @@ |
|||||
|
import http from 'apis/axios'; |
||||
|
|
||||
|
const apiUrl = import.meta.env.VITE_API_URL; |
||||
|
const ptccsens = `${apiUrl}/gateway/tall3/v3.0`; |
||||
|
const users = `${ptccsens}/users`; |
||||
|
|
||||
|
// 根据userId 获取token
|
||||
|
export const getToken = userId => http.get(`${users}/userId`, { params: { userId } }); |
||||
|
|
||||
|
// 登录
|
||||
|
export const signIn = params => http.post(`${users}/signin`, params); |
@ -0,0 +1,8 @@ |
|||||
|
import http from 'apis/axios'; |
||||
|
|
||||
|
const apiUrl = import.meta.env.VITE_API_URL; |
||||
|
const ptccsens = `${apiUrl}/ptccsens/v1.0`; |
||||
|
const member = `${ptccsens}/member`; |
||||
|
|
||||
|
// 查询所有成员
|
||||
|
export const queryChecker = params => http.post(`${member}/queryChecker`, params); |
@ -0,0 +1,8 @@ |
|||||
|
import http from 'apis/axios'; |
||||
|
|
||||
|
const apiUrl = import.meta.env.VITE_API_URL; |
||||
|
const ptccsens = `${apiUrl}/ptccsens/v1.0`; |
||||
|
const ocr = `${ptccsens}/ocr`; |
||||
|
|
||||
|
// 发起申请
|
||||
|
export const bill = `${ocr}/bill`; |
@ -0,0 +1,33 @@ |
|||||
|
import http from 'apis/axios'; |
||||
|
|
||||
|
const apiUrl = import.meta.env.VITE_API_URL; |
||||
|
const ptccsens = `${apiUrl}/ptccsens/v1.0`; |
||||
|
const projectFinance = `${ptccsens}/projectFinance`; |
||||
|
|
||||
|
// 追加预算
|
||||
|
export const addBudget = params => |
||||
|
http.post(`${projectFinance}/addBudget`, params); |
||||
|
|
||||
|
// 查看所有的费用申请
|
||||
|
export const queryAllMoneyApply = params => |
||||
|
http.post(`${projectFinance}/queryAllMoneyApply`, params); |
||||
|
|
||||
|
// 查看项目下的财务信息
|
||||
|
export const queryFinanceOfProject = params => |
||||
|
http.post(`${projectFinance}/queryFinanceOfProject`, params); |
||||
|
|
||||
|
// 查看自己需要审批的申请
|
||||
|
export const queryNeedCheckByMe = params => |
||||
|
http.post(`${projectFinance}/queryNeedCheckByMe`, params); |
||||
|
|
||||
|
// 查看项目下的所有任务对应的财务信息
|
||||
|
export const queryProjectFinance = params => |
||||
|
http.post(`${projectFinance}/queryProjectFinance`, params); |
||||
|
|
||||
|
// 修改任务或项目的预算和奖金信息
|
||||
|
export const updateFinance = params => |
||||
|
http.post(`${projectFinance}/updateFinance`, params); |
||||
|
|
||||
|
// 时间财务图统计
|
||||
|
export const timeFinancialChart = params => |
||||
|
http.post(`${projectFinance}/timeFinancialChart`, params); |
@ -1,3 +1,29 @@ |
|||||
<template> |
<template> |
||||
<NuxtPage /> |
<NuxtPage /> |
||||
</template> |
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { reactive } from 'vue'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const token = useToken() |
||||
|
const user = useUser() |
||||
|
const userId = useUserId() |
||||
|
const projectId = useProjectId() |
||||
|
const taskId = useTaskId() |
||||
|
const projectName = useProjectName() |
||||
|
const taskName = useTaskName() |
||||
|
|
||||
|
// 获取路径上的参数 |
||||
|
const routeValue = router.currentRoute.value; |
||||
|
console.log('routeValue: ', routeValue); |
||||
|
token.value = routeValue && routeValue.query && routeValue.query.token ? routeValue.query.token : ''; |
||||
|
userId.value = routeValue && routeValue.query && routeValue.query.userId ? routeValue.query.userId : ''; |
||||
|
projectId.value = routeValue && routeValue.query && routeValue.query.projectId ? routeValue.query.projectId : ''; |
||||
|
taskId.value = routeValue && routeValue.query && routeValue.query.id ? routeValue.query.id : ''; |
||||
|
projectName.value = routeValue && routeValue.query && routeValue.query.pn ? routeValue.query.pn : ''; |
||||
|
taskName.value = routeValue && routeValue.query && routeValue.query.tn ? routeValue.query.tn : ''; |
||||
|
|
||||
|
</script> |
||||
|
@ -0,0 +1,144 @@ |
|||||
|
<template> |
||||
|
<div id="barEcharts" style="width: 380px; height: 350px"></div> |
||||
|
</template> |
||||
|
<script setup> |
||||
|
import { onMounted } from 'vue'; |
||||
|
import { timeFinancialChart } from 'apis/projectFinance'; |
||||
|
|
||||
|
const projectId = useProjectId(); |
||||
|
|
||||
|
const data = reactive({ |
||||
|
timeList: [], |
||||
|
taskNameList: [], |
||||
|
}); |
||||
|
|
||||
|
async function getChartData() { |
||||
|
try { |
||||
|
const params = { param: { projectId: projectId.value } }; |
||||
|
const res = await timeFinancialChart(params); |
||||
|
console.log('res:', res); |
||||
|
return processing(res); |
||||
|
} catch (error) { |
||||
|
console.error(error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function processing(list) { |
||||
|
let timeList = [ |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
]; |
||||
|
for (let i = 0; i < list.length; i++) { |
||||
|
for (let j = 0; j < list[i].data.length; j++) { |
||||
|
const m = list[i].data[j].time - 0; |
||||
|
timeList[m - 1] = m + '月'; |
||||
|
} |
||||
|
} |
||||
|
for (let i = 0; i < timeList.length; i++) { |
||||
|
if (!timeList[i]) { |
||||
|
timeList.splice(i, 1); |
||||
|
i -= 1; |
||||
|
} |
||||
|
} |
||||
|
let series = []; |
||||
|
let taskNameList = []; |
||||
|
for (let i = 0; i < list.length; i++) { |
||||
|
let data = []; |
||||
|
taskNameList.push(list[i].name); |
||||
|
for (let k = 0; k < timeList.length; k++) { |
||||
|
data.push(null); |
||||
|
} |
||||
|
for (let k = 0; k < list[i].data.length; k++) { |
||||
|
for (let m = 0; m < timeList.length; m++) { |
||||
|
if (list[i].data[k].time - 0 + '月' === timeList[m]) { |
||||
|
data[m] = list[i].data[k].expend - 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
let obj = { |
||||
|
name: list[i].name, |
||||
|
type: 'bar', |
||||
|
stack: 'total', |
||||
|
label: { |
||||
|
show: false, |
||||
|
color: '#FFFFFF', |
||||
|
}, |
||||
|
barWidth: 12, |
||||
|
data: data, |
||||
|
}; |
||||
|
series.push(obj); |
||||
|
} |
||||
|
data.timeList = timeList; |
||||
|
data.taskNameList = taskNameList; |
||||
|
console.log('series: ', series); |
||||
|
return series; |
||||
|
} |
||||
|
|
||||
|
onMounted(async () => { |
||||
|
const myChart = echarts.init(document.getElementById('barEcharts')); |
||||
|
const series = await getChartData(); |
||||
|
const option = { |
||||
|
tooltip: { |
||||
|
trigger: 'axis', |
||||
|
axisPointer: { |
||||
|
type: 'shadow', |
||||
|
}, |
||||
|
}, |
||||
|
legend: { |
||||
|
top: 10, |
||||
|
right: 0, |
||||
|
icon: 'circle', |
||||
|
orient: 'horizontal', |
||||
|
itemGap: 10, |
||||
|
itemWidth: 10, |
||||
|
itemHeight: 14, |
||||
|
textStyle: { |
||||
|
fontSize: 14, |
||||
|
color: '#858585', |
||||
|
fontWeight: 400, |
||||
|
}, |
||||
|
}, |
||||
|
data: data.taskNameList, |
||||
|
color: ['#7E84A3', '#FF914C', '#5189F8', '#3FC7BB'], |
||||
|
grid: { |
||||
|
left: '15%', |
||||
|
right: '0', |
||||
|
bottom: '5%', |
||||
|
containLabel: false, |
||||
|
}, |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
data: data.timeList, |
||||
|
axisTick: { |
||||
|
show: false, |
||||
|
}, |
||||
|
axisLabel: { |
||||
|
show: true, |
||||
|
}, |
||||
|
axisLine: { |
||||
|
show: false, |
||||
|
}, |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
splitLine: { |
||||
|
lineStyle: { |
||||
|
color: '#F3F4F5', |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
series: series, |
||||
|
}; |
||||
|
myChart.setOption(option); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,122 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div |
||||
|
v-if="data.info.list && data.info.list.length" |
||||
|
class="w-full overflow-x-scroll" |
||||
|
> |
||||
|
<table class="text-gray-500 mt-4 text-ms"> |
||||
|
<tr class="bg-gray-100 text-gray-400"> |
||||
|
<td class="name">申请人</td> |
||||
|
<td class="money">金额(元)</td> |
||||
|
<td class="time">时间</td> |
||||
|
<td class="remark">备注</td> |
||||
|
</tr> |
||||
|
<tr v-for="item in data.info.list" class="text-gray-500"> |
||||
|
<td>{{ item.submitName }}</td> |
||||
|
<td> |
||||
|
{{ (+item.money / 100).toFixed(2) }} |
||||
|
</td> |
||||
|
<td> |
||||
|
{{ dayjs(item.submitTime - 0).format('YYYY/MM/DD') }} |
||||
|
</td> |
||||
|
<td> |
||||
|
{{ item.remark }} |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<div class="w-1/2 mt-4 ml-48"> |
||||
|
<el-pagination |
||||
|
v-model="data.pageNum" |
||||
|
:items-per-page="data.pageSize" |
||||
|
:page-count="data.pages" |
||||
|
mode="simple" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-empty v-else description="暂无数据" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import dayjs from 'dayjs'; |
||||
|
import { personalHistory } from 'apis/finance'; |
||||
|
import { ref, reactive, onMounted, nextTick } from 'vue'; |
||||
|
|
||||
|
const data = reactive({ |
||||
|
info: {}, |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
pages: 0, |
||||
|
}); |
||||
|
|
||||
|
const projectId = useProjectId(); |
||||
|
const taskDetailId = useTaskId(); |
||||
|
const taskName = useTaskName(); |
||||
|
|
||||
|
/** |
||||
|
* 查看当前用户的费用申请历史信息(奖金) |
||||
|
* @param { Number } pageNum |
||||
|
* @param { Number } pageSize |
||||
|
* @param { String } projectId |
||||
|
* @param { String } name |
||||
|
*/ |
||||
|
async function handlePersonalHistory() { |
||||
|
try { |
||||
|
const params = { |
||||
|
param: { |
||||
|
pageNum: data.pageNum, |
||||
|
pageSize: data.pageSize, |
||||
|
projectId: projectId.value, |
||||
|
taskDetailId: taskDetailId.value, |
||||
|
taskName: taskName.value, |
||||
|
type: 1, |
||||
|
}, |
||||
|
}; |
||||
|
const res = await personalHistory(params); |
||||
|
data.info = res; |
||||
|
data.pageNum = res.pageNum ? +res.pageNum : 1; |
||||
|
data.pageSize = res.pageSize ? +res.pageSize : 10; |
||||
|
data.pages = res.pages ? +res.pages : 0; |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function confirm() { |
||||
|
alert('确认放款'); |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
nextTick(() => { |
||||
|
handlePersonalHistory(); |
||||
|
}); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
table { |
||||
|
width: 500px; |
||||
|
td { |
||||
|
border: 0.5px solid #ccc; |
||||
|
padding: 0.85rem; |
||||
|
width: 5.9375rem; |
||||
|
} |
||||
|
.name { |
||||
|
width: 100px; |
||||
|
} |
||||
|
.money { |
||||
|
width: 100px; |
||||
|
} |
||||
|
.time { |
||||
|
width: 170px; |
||||
|
} |
||||
|
.remark { |
||||
|
width: 120px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.input-box { |
||||
|
padding: 0 !important; |
||||
|
border-bottom: 1px solid #ccc; |
||||
|
} |
||||
|
</style> |
@ -1,13 +0,0 @@ |
|||||
<template> |
|
||||
<h1> |
|
||||
Common Hello.vue <br /><small>{{ modalDisplay }}</small> |
|
||||
<van-button type="primary" @click="modalDisplay = !modalDisplay"> |
|
||||
主要按钮 |
|
||||
</van-button> |
|
||||
</h1> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
const modalDisplay = useModal(); |
|
||||
console.log(modalDisplay.value); |
|
||||
</script> |
|
@ -0,0 +1,170 @@ |
|||||
|
<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> |
||||
|
<el-field |
||||
|
v-else-if="financeId - 0 !== 0 && item.showField" |
||||
|
v-model="item.budget" |
||||
|
type="number" |
||||
|
class="input-box" |
||||
|
@change="handleUpdateBudget(item)" |
||||
|
@blur="item.showField = false" |
||||
|
/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<el-icon name="plus" @click="toApplication(item)" /> |
||||
|
</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"> |
||||
|
<el-pagination |
||||
|
v-model="data.pageNum" |
||||
|
:items-per-page="data.pageSize" |
||||
|
:page-count="data.pages" |
||||
|
mode="simple" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-empty v-else description="暂无数据" /> |
||||
|
<el-dialog |
||||
|
v-model:show="data.show" |
||||
|
title="追加预算" |
||||
|
show-cancel-button |
||||
|
@confirm="handleAdd" |
||||
|
> |
||||
|
<el-field |
||||
|
:border="data.border" |
||||
|
v-model="data.appendBudget" |
||||
|
type="textarea" |
||||
|
class="appendBudget" |
||||
|
placeholder="追加预算" |
||||
|
/> |
||||
|
</el-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(item) { |
||||
|
const routeValue = router.currentRoute.value; |
||||
|
const query = routeValue.query; |
||||
|
query.tn = item.taskName; |
||||
|
// console.log('query: ', 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> |
@ -0,0 +1,151 @@ |
|||||
|
<template> |
||||
|
<div v-if="data.info.list && data.info.list.length"> |
||||
|
<div class="w-full overflow-x-scroll"> |
||||
|
<table class="text-gray-500 mt-4"> |
||||
|
<tr class="bg-gray-100"> |
||||
|
<td width="20%">申请人</td> |
||||
|
<td width="25%">金额(元)</td> |
||||
|
<td width="30%">时间</td> |
||||
|
<td width="25%">操作</td> |
||||
|
</tr> |
||||
|
<tr v-for="item in data.info.list"> |
||||
|
<td @click="openDetails(item.applyId)">{{item.submitName}}</td> |
||||
|
<td @click="openDetails(item.applyId)">{{item.money}}</td> |
||||
|
<td @click="openDetails(item.applyId)">{{dayjs(item.submitTime - 0).format('YYYY-MM-DD')}}</td> |
||||
|
<td> |
||||
|
<div v-if="!item.applyType" class="flex flex-row justify-around"> |
||||
|
|
||||
|
<el-button type="success" size="mini" class="rounded" @click="showRemark(item.financeCheckId, 1)">通过</el-button> |
||||
|
<el-button type="danger" size="mini" class="rounded" @click="showRemark(item.financeCheckId, 2)">驳回</el-button> |
||||
|
</div> |
||||
|
<div class="text-center" v-else :class="item.applyType === 1 ? 'text-blue-500' : 'text-red-500'">{{ item.applyType === 1 ? '已完成' : '已驳回' }}</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</div> |
||||
|
<div class="w-1/2 mt-4 ml-48"> |
||||
|
<el-pagination v-model="data.pageNum" :items-per-page="data.pageSize" :page-count="data.pages" mode="simple" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-empty v-else description="暂无数据" /> |
||||
|
|
||||
|
<el-dialog v-model:show="data.show" title="备注" show-cancel-button @confirm="handleAudit"> |
||||
|
<!-- <el-field :border="data.border" v-model="data.remark" type="textarea" class="remark" placeholder="请输入备注" /> --> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import dayjs from "dayjs"; |
||||
|
import {ref, reactive, onMounted, nextTick} from'vue'; |
||||
|
import { audit } from 'apis/finance'; |
||||
|
import { queryNeedCheckByMe } from 'apis/projectFinance'; |
||||
|
import { ElMessage } from 'element-plus' |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
|
||||
|
const router = useRouter() |
||||
|
|
||||
|
const data = reactive({ |
||||
|
info: {}, |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
pages: 0, |
||||
|
show: false, |
||||
|
remark: '', |
||||
|
auditInfo: {}, |
||||
|
border: true |
||||
|
}) |
||||
|
|
||||
|
const taskId = useTaskId() |
||||
|
|
||||
|
/** |
||||
|
* 查看项目下的所有任务对应的财务信息 |
||||
|
* @param { Number } pageNum |
||||
|
* @param { Number } pageSize |
||||
|
* @param { String } taskDetailId 任务详情id |
||||
|
*/ |
||||
|
async function handleFinanceOfProject(){ |
||||
|
try { |
||||
|
const params = { |
||||
|
param:{ |
||||
|
pageNum: data.pageNum, |
||||
|
pageSize: data.pageSize, |
||||
|
taskDetailId: taskId.value |
||||
|
} |
||||
|
} |
||||
|
const res = await queryNeedCheckByMe(params) |
||||
|
data.info = res |
||||
|
data.pageNum = res && res.pageNum ? +res.pageNum : 1 |
||||
|
data.pageSize = res && res.pageSize ? +res.pageSize : 10 |
||||
|
data.pages = res && res.pages ? +res.pages : 0 |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
nextTick(() => { |
||||
|
handleFinanceOfProject() |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
// 填写备注 |
||||
|
function showRemark(financeCheckId, checkStatus){ |
||||
|
data.show = true |
||||
|
data.auditInfo = { financeCheckId, checkStatus } |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 审批 |
||||
|
* @param { Number } checkStatus 审核状态 1已通过 2驳回 |
||||
|
* @param { String } financeCheckId 审核id |
||||
|
* @param { String } remark 备注 |
||||
|
*/ |
||||
|
async function handleAudit(financeCheckId, checkStatus){ |
||||
|
try { |
||||
|
const { auditInfo, remark } = data |
||||
|
const { financeCheckId, checkStatus } = data.auditInfo |
||||
|
const params = { |
||||
|
param:{ |
||||
|
financeCheckId, |
||||
|
checkStatus, |
||||
|
remark: data.remark |
||||
|
} |
||||
|
} |
||||
|
await audit(params) |
||||
|
ElMessage.success('审批成功') |
||||
|
handleFinanceOfProject() |
||||
|
data.remark = '' |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 详情 |
||||
|
function openDetails(applyId){ |
||||
|
const routeValue = router.currentRoute.value; |
||||
|
const query = routeValue.query; |
||||
|
query.applyId = applyId; |
||||
|
router.push({ path: '/financial-approval-details', query }); |
||||
|
} |
||||
|
</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 |
||||
|
} |
||||
|
|
||||
|
.remark{ |
||||
|
border: 1px solid #ccc; |
||||
|
border-radius: 4px; |
||||
|
margin: 5%; |
||||
|
width: 90%; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,151 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div v-if="data.info.taskFinanceList && data.info.taskFinanceList.list && data.info.taskFinanceList.list.length"> |
||||
|
<table class="w-full text-gray-500 mt-4 text-ms"> |
||||
|
<tr class="bg-gray-100"> |
||||
|
<td class="name">任务名称</td> |
||||
|
<td>预算(元)</td> |
||||
|
<td>奖金(元)</td> |
||||
|
</tr> |
||||
|
<tr v-for="item in data.info.taskFinanceList.list"> |
||||
|
<td>{{item.name}}</td> |
||||
|
<td> |
||||
|
<div v-if="!item.showBudgetEdit" @click="editBudge(item)">{{ item.budget }}</div> |
||||
|
<el-field v-else v-model="item.budget" type="number" class="input-box" @change="handleUpdateFinance(item, 'budget')" @blur="item.showBudgetEdit = false" /> |
||||
|
</td> |
||||
|
<td> |
||||
|
<div v-if="!item.showBonusEdit" @click="editBonus(item)">{{ item.bonus }}</div> |
||||
|
<el-field v-else v-model="item.bonus" type="number" class="input-box" @change="handleUpdateFinance(item, 'bonus')" @blur="item.showBonusEdit = false" /> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td>合计</td> |
||||
|
<td>{{ num.except(+data.info.budget,100) || 0 }}</td> |
||||
|
<td>{{ num.except(+data.info.bonus,100) || 0 }}</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<div class="w-1/2 mt-4 ml-48"> |
||||
|
<el-pagination v-model="data.pageNum" :items-per-page="data.pageSize" :page-count="data.pages" mode="simple" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-empty v-else description="暂无数据" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { queryProjectFinance, updateFinance } from 'apis/projectFinance' |
||||
|
import {ref, reactive, onMounted, nextTick} from'vue' |
||||
|
import num from 'utils/num'; |
||||
|
|
||||
|
const data = reactive({ |
||||
|
info: {}, |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
pages: 0, |
||||
|
budget: 0, |
||||
|
bonus: 0, |
||||
|
}) |
||||
|
|
||||
|
const projectId = useProjectId() |
||||
|
|
||||
|
// 显示修改预算框 |
||||
|
function editBudge(item){ |
||||
|
data.budget = num.except(+item.budget,100) |
||||
|
data.info.taskFinanceList.list.forEach((list) => { |
||||
|
if(item.taskFinanceId === list.taskFinanceId){ |
||||
|
list.showBudgetEdit = true |
||||
|
}else{ |
||||
|
list.showBudgetEdit = false |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 显示修改预算框 |
||||
|
function editBonus(item){ |
||||
|
data.bonus = num.except(+item.bonus,100) |
||||
|
data.info.taskFinanceList.list.forEach((list) => { |
||||
|
if(item.taskFinanceId === list.taskFinanceId){ |
||||
|
list.showBonusEdit = true |
||||
|
}else{ |
||||
|
list.showBonusEdit = false |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查看项目下的所有任务对应的财务信息 |
||||
|
* @param { Number } pageNum |
||||
|
* @param { Number } pageSize |
||||
|
* @param { String } projectId |
||||
|
* @param { String } name |
||||
|
*/ |
||||
|
async function handleProjectFinance(){ |
||||
|
try { |
||||
|
const params = { |
||||
|
param:{ |
||||
|
pageNum: data.pageNum, |
||||
|
pageSize: data.pageSize, |
||||
|
projectId: projectId.value |
||||
|
} |
||||
|
} |
||||
|
const res = await queryProjectFinance(params) |
||||
|
data.info = res |
||||
|
data.pageNum = res.taskFinanceList && res.taskFinanceList.pageNum ? +res.taskFinanceList.pageNum : 1 |
||||
|
data.pageSize = res.taskFinanceList && res.taskFinanceList.pageSize ? +res.taskFinanceList.pageSize : 10 |
||||
|
data.pages = res.taskFinanceList && res.taskFinanceList.pages ? +res.taskFinanceList.pages : 0 |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改任务或项目的预算和奖金信息 |
||||
|
* @param { Number } bonus 奖金 |
||||
|
* @param { Number } budget 预算 |
||||
|
* @param { String } taskDetailId 任务详情id |
||||
|
* @param { String } taskFinanceId 任务财务信息id |
||||
|
*/ |
||||
|
async function handleUpdateFinance(item, type){ |
||||
|
try { |
||||
|
console.log('item, type: ', item, type, data[type], item[type]); |
||||
|
item[type] = data[type] |
||||
|
console.log('item: ', item.bonus); |
||||
|
const params = { |
||||
|
param:{ |
||||
|
// bonus: num.ride(+item.bonus,100), |
||||
|
// budget: num.ride(+item.budget,100), |
||||
|
taskDetailId: item.taskDetailId, |
||||
|
taskFinanceId: item.taskFinanceId, |
||||
|
} |
||||
|
} |
||||
|
const res = await updateFinance(params) |
||||
|
handleProjectFinance() |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
nextTick(() => { |
||||
|
handleProjectFinance() |
||||
|
}) |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
table { |
||||
|
td { |
||||
|
border: 0.5px solid #ccc; |
||||
|
padding: 0.85rem; |
||||
|
width: 5.9375rem; |
||||
|
} |
||||
|
.name{ |
||||
|
width:50% |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.input-box{ |
||||
|
padding: 0!important; |
||||
|
border-bottom: 1px solid #ccc |
||||
|
} |
||||
|
</style> |
@ -1,10 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
Hello |
|
||||
<h2>{{ modalDisplay }}</h2> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
const modalDisplay = useModal(); |
|
||||
</script> |
|
@ -0,0 +1,159 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div |
||||
|
v-if="data.info.list && data.info.list.length" |
||||
|
class="w-full overflow-x-scroll" |
||||
|
> |
||||
|
<table class="text-gray-500 mt-4 text-ms"> |
||||
|
<tr class="bg-gray-100 text-gray-400"> |
||||
|
<td class="name">申请人</td> |
||||
|
<td class="money">金额(元)</td> |
||||
|
<td class="time">时间</td> |
||||
|
<td class="status">状态</td> |
||||
|
</tr> |
||||
|
<tr v-for="item in data.info.list" class="text-gray-500"> |
||||
|
<td @click="openDetails(item.applyId)">{{ item.submitName }}</td> |
||||
|
<td @click="openDetails(item.applyId)"> |
||||
|
{{ num.except(+item.money, 100) }} |
||||
|
</td> |
||||
|
<td @click="openDetails(item.applyId)"> |
||||
|
{{ dayjs(item.submitTime - 0).format('YYYY/MM/DD') }} |
||||
|
</td> |
||||
|
<td> |
||||
|
<!-- <div v-if="!item.showBonusEdit" @click="item.showBonusEdit = true"> --> |
||||
|
<span v-if="item.applyType - 0 === 0" class="text-gray-500"> |
||||
|
待审核 |
||||
|
</span> |
||||
|
<span v-else-if="item.applyType - 0 === 1" class="text-gray-500"> |
||||
|
已通过 |
||||
|
</span> |
||||
|
<span v-else-if="item.applyType - 0 === 2" class="text-red-500"> |
||||
|
已驳回 |
||||
|
</span> |
||||
|
<span v-else-if="item.applyType - 0 === 3" class="text-gray-500"> |
||||
|
待放款 |
||||
|
</span> |
||||
|
<el-button |
||||
|
v-else-if="item.applyType - 0 === 4" |
||||
|
type="success" |
||||
|
size="mini" |
||||
|
class="rounded" |
||||
|
@click="confirm" |
||||
|
> |
||||
|
确认 |
||||
|
</el-button> |
||||
|
<span v-else-if="item.applyType - 0 === 5" class="text-green-500"> |
||||
|
已确认 |
||||
|
</span> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<div class="w-1/2 mt-4 ml-48"> |
||||
|
<el-pagination |
||||
|
v-model="data.pageNum" |
||||
|
:items-per-page="data.pageSize" |
||||
|
:page-count="data.pages" |
||||
|
mode="simple" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-empty v-else description="暂无数据" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import dayjs from 'dayjs'; |
||||
|
import { personalHistory } from 'apis/finance'; |
||||
|
import { ref, reactive, onMounted, nextTick } from 'vue'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import num from 'utils/num'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const data = reactive({ |
||||
|
info: {}, |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
pages: 0, |
||||
|
}); |
||||
|
|
||||
|
const projectId = useProjectId(); |
||||
|
const taskDetailId = useTaskId(); |
||||
|
const taskName = useTaskName(); |
||||
|
|
||||
|
/** |
||||
|
* 查看当前用户的费用申请历史信息(奖金) |
||||
|
* @param { Number } pageNum |
||||
|
* @param { Number } pageSize |
||||
|
* @param { String } projectId |
||||
|
* @param { String } name |
||||
|
*/ |
||||
|
async function handlePersonalHistory() { |
||||
|
try { |
||||
|
const params = { |
||||
|
param: { |
||||
|
pageNum: data.pageNum, |
||||
|
pageSize: data.pageSize, |
||||
|
projectId: projectId.value, |
||||
|
taskDetailId: taskDetailId.value, |
||||
|
taskName: taskName.value, |
||||
|
type: 0, |
||||
|
}, |
||||
|
}; |
||||
|
const res = await personalHistory(params); |
||||
|
data.info = res; |
||||
|
data.pageNum = res.pageNum ? +res.pageNum : 1; |
||||
|
data.pageSize = res.pageSize ? +res.pageSize : 10; |
||||
|
data.pages = res.pages ? +res.pages : 0; |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function confirm() { |
||||
|
alert('确认放款'); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
onMounted(() => { |
||||
|
nextTick(() => { |
||||
|
handlePersonalHistory(); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
// 详情 |
||||
|
function openDetails(applyId){ |
||||
|
const routeValue = router.currentRoute.value; |
||||
|
const query = routeValue.query; |
||||
|
query.applyId = applyId; |
||||
|
router.push({ path: '/application-details', query }); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
table { |
||||
|
width: 500px; |
||||
|
td { |
||||
|
border: 0.5px solid #ccc; |
||||
|
padding: 0.85rem; |
||||
|
width: 5.9375rem; |
||||
|
} |
||||
|
.name { |
||||
|
width: 100px; |
||||
|
} |
||||
|
.money { |
||||
|
width: 100px; |
||||
|
} |
||||
|
.time { |
||||
|
width: 120px; |
||||
|
} |
||||
|
.status { |
||||
|
width: 120px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.input-box { |
||||
|
padding: 0 !important; |
||||
|
border-bottom: 1px solid #ccc; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,198 @@ |
|||||
|
<template> |
||||
|
<!-- <div id="yield-chart"></div> --> |
||||
|
<div :id="props.id" style="width: 400px; height: 260px"></div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { onMounted } from 'vue'; |
||||
|
import { taskExpense, rowExpense, memberFinance } from 'apis/finance'; |
||||
|
const projectId = useProjectId(); |
||||
|
const props = defineProps({ id: { type: String, 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; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
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: 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, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
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: [ |
||||
|
{ |
||||
|
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, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
labelLine: { |
||||
|
normal: { |
||||
|
show: true, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
myChart.setOption(option); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped></style> |
@ -0,0 +1,36 @@ |
|||||
|
<template> |
||||
|
<div class="pt-4"> |
||||
|
<el-input |
||||
|
v-model="searchRef" |
||||
|
placeholder="搜索" |
||||
|
:prefix-icon="Search" |
||||
|
></el-input> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
|
||||
|
import {ref} from 'vue' |
||||
|
const searchRef = ref('') |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<style lang="less"> |
||||
|
|
||||
|
.el-search{ |
||||
|
padding: 0; |
||||
|
} |
||||
|
.el-search__content{ |
||||
|
border: 1px solid #ccc; |
||||
|
background-color: #fff; |
||||
|
height:1.85rem; |
||||
|
border-radius:0.2rem |
||||
|
} |
||||
|
.el-field__left-icon{ |
||||
|
margin-right: var(--el-padding-base); |
||||
|
width: 45%; |
||||
|
padding-left: 40%; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
</style> |
@ -0,0 +1,29 @@ |
|||||
|
import { useState } from '#app'; |
||||
|
|
||||
|
export const useToken = () => { |
||||
|
return useState('token', () => ''); |
||||
|
}; |
||||
|
|
||||
|
export const useUserId = () => { |
||||
|
return useState('userId', () => ''); |
||||
|
}; |
||||
|
|
||||
|
export const useProjectId = () => { |
||||
|
return useState('projectId', () => ''); |
||||
|
}; |
||||
|
|
||||
|
export const useUser = () => { |
||||
|
return useState('user', () => null); |
||||
|
}; |
||||
|
|
||||
|
export const useTaskId = () => { |
||||
|
return useState('taskId', () => null); |
||||
|
}; |
||||
|
|
||||
|
export const useProjectName = () => { |
||||
|
return useState('projectName', () => null); |
||||
|
}; |
||||
|
|
||||
|
export const useTaskName = () => { |
||||
|
return useState('taskName', () => null); |
||||
|
}; |
@ -1,5 +1,14 @@ |
|||||
<template> |
<template> |
||||
<div> |
<div class="container"> |
||||
<slot /> |
<slot /> |
||||
</div> |
</div> |
||||
</template> |
</template> |
||||
|
|
||||
|
<style lang="less"> |
||||
|
.container{ |
||||
|
background:#eee; |
||||
|
height:100%; |
||||
|
width:100%; |
||||
|
overflow:hidden; |
||||
|
} |
||||
|
</style> |
||||
|
@ -0,0 +1,585 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<!-- 导航返回上一页 --> |
||||
|
<div title="发起申请" left-arrow @click="router.go(-1)" ></div> |
||||
|
<!-- 申请发票需要输入的数据 --> |
||||
|
<div class="bg-white pb-3"> |
||||
|
<div class="text-gray-500 px-4 py-3 font-semibold">发票信息</div> |
||||
|
<!-- 是否上传票据 --> |
||||
|
<div v-show="data.isInvoice"> |
||||
|
<div class="mx-4 pb-3 border-b"> |
||||
|
<div class="flex pt-3 pb-2 justify-between" v-show="data.titleHidden"> |
||||
|
<div> |
||||
|
<span class="text-red-500">*</span> |
||||
|
<span class="text-gray-500">上传票据凭证 </span> |
||||
|
<span class="text-gray-400 text-xs">(仅支持ipg格式)</span> |
||||
|
</div> |
||||
|
<el-button |
||||
|
plain |
||||
|
type="primary" |
||||
|
size="mini" |
||||
|
@click="data.isInvoice = false" |
||||
|
>手动输入</el-button |
||||
|
> |
||||
|
</div> |
||||
|
<!-- <el-overlay :show="data.showUploading"> --> |
||||
|
<div |
||||
|
class="text-center border-b w-52 h-24 border-dashed border-2 upload-box" |
||||
|
v-show="!data.isSuccess" |
||||
|
> |
||||
|
<el-uploader v-model="data.fileList" multiple :max-count="1" :after-read="afterRead" class="z-50 opacity-0" /> |
||||
|
<div class="upload-txt"> |
||||
|
<p class="text-gray-400 text-xl pt-3">+</p> |
||||
|
<p class="text-gray-400 text-xs">上传并识别凭证</p> |
||||
|
</div> |
||||
|
<!-- <el-loading type="spinner" v-if="data.showUploading" class="upload-txt z-50" /> --> |
||||
|
</div> |
||||
|
<!-- </el-overlay> --> |
||||
|
|
||||
|
<!-- 上传票据成功后显示发票信息 --> |
||||
|
<div v-show="data.isSuccess"> |
||||
|
<el-field |
||||
|
v-for="item in data.invoiceInfo" |
||||
|
required |
||||
|
v-model="item.value" |
||||
|
:label="item.name" |
||||
|
@change="cahngeInvoiceList($event, item)" |
||||
|
input-align="right" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 手动输入信息 --> |
||||
|
<div v-show="!data.isInvoice"> |
||||
|
<el-field |
||||
|
required |
||||
|
v-model="data.money" |
||||
|
label="申请金额" |
||||
|
placeholder="输入申请金额" |
||||
|
input-align="right" |
||||
|
/> |
||||
|
</div> |
||||
|
<!-- 备注信息 --> |
||||
|
<div class="text-gray-500 py-4 pl-5">备注</div> |
||||
|
<el-cell-group> |
||||
|
<el-field |
||||
|
v-model="data.remark" |
||||
|
rows="2" |
||||
|
autosize |
||||
|
type="textarea" |
||||
|
maxlength="40" |
||||
|
placeholder="请输入备注" |
||||
|
show-word-limit |
||||
|
class="border rounded" |
||||
|
/> |
||||
|
</el-cell-group> |
||||
|
</div> |
||||
|
<!-- 选择审核人 --> |
||||
|
<div class="mt-3"> |
||||
|
<div class="flex bg-white p-4"> |
||||
|
<div class="text-red-500">*</div> |
||||
|
<div class="text-gray-500 pl-1 font-semibold">审核人</div> |
||||
|
</div> |
||||
|
<div class="px-3 bg-white"> |
||||
|
<div> |
||||
|
<el-button |
||||
|
class="button" |
||||
|
size="mini" |
||||
|
v-for="item in data.reviewerList" |
||||
|
:key="item.memberId" |
||||
|
:type=" |
||||
|
data.checkerList.find(checker => checker === item.memberId) |
||||
|
? 'primary' |
||||
|
: 'default' |
||||
|
" |
||||
|
@click="handleSelectChecker(item.memberId)" |
||||
|
> |
||||
|
{{ item.name }} |
||||
|
</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 其他信息 --> |
||||
|
<div class="bg-white mt-3"> |
||||
|
<div class="text-gray-500 p-4 font-semibold">其他信息</div> |
||||
|
<!-- 申请类型 --> |
||||
|
<!-- 普通票据申请 --> |
||||
|
<div> |
||||
|
<el-field |
||||
|
v-model="data.applyType" |
||||
|
is-link |
||||
|
readonly |
||||
|
label="申请类型" |
||||
|
placeholder="请选择申请类型" |
||||
|
@click="data.showType = true" |
||||
|
required |
||||
|
input-align="right" |
||||
|
/> |
||||
|
<!-- <el-popup v-model:show="data.showType" round position="bottom"> |
||||
|
<el-picker |
||||
|
title="申请类型" |
||||
|
v-if="data.applyTypeOptions && data.applyTypeOptions.length" |
||||
|
:columns="data.applyTypeOptions" |
||||
|
@confirm="finishApplyType" |
||||
|
/> |
||||
|
<el-loading v-else class="my-20 text-center" /> |
||||
|
</el-popup> --> |
||||
|
<!-- 所属项目 --> |
||||
|
<el-field |
||||
|
v-model="projectName" |
||||
|
is-link |
||||
|
readonly |
||||
|
label="所属项目" |
||||
|
placeholder="请选择所属项目" |
||||
|
required |
||||
|
input-align="right" |
||||
|
disabled |
||||
|
/> |
||||
|
<!-- <el-popup v-model:show="projectName" round position="bottom"> |
||||
|
<el-cascader active-color="#1989fa" class="p-0" /> |
||||
|
</el-popup> --> |
||||
|
<!-- 所属任务的 --> |
||||
|
<el-field |
||||
|
v-model="taskName" |
||||
|
v-show="data.isInvoice" |
||||
|
is-link |
||||
|
readonly |
||||
|
label="所属任务" |
||||
|
placeholder="请选择所属任务" |
||||
|
required |
||||
|
input-align="right" |
||||
|
disabled |
||||
|
/> |
||||
|
<!-- <el-popup v-model:show="taskName" round position="bottom"> |
||||
|
<el-cascader active-color="#1989fa" class="p-0" /> |
||||
|
</el-popup> --> |
||||
|
<!-- 类目选择 --> |
||||
|
<el-field |
||||
|
v-model="data.applyCategory" |
||||
|
is-link |
||||
|
readonly |
||||
|
label="类目" |
||||
|
placeholder="请选择类目" |
||||
|
@click="data.showCategory = true" |
||||
|
input-align="right" |
||||
|
/> |
||||
|
<!-- <el-popup v-model:show="data.showCategory" round position="bottom"> |
||||
|
<el-picker |
||||
|
title="请选择类目" |
||||
|
v-if="data.applyCategoryOptions && data.applyCategoryOptions.length" |
||||
|
:columns="data.applyCategoryOptions" |
||||
|
@confirm="finishApplyCategory" |
||||
|
/> |
||||
|
<el-loading v-else class="my-20 text-center" /> |
||||
|
</el-popup> --> |
||||
|
<!-- 名目选择 --> |
||||
|
<el-field |
||||
|
v-model="data.applyName" |
||||
|
v-show="data.isInvoice" |
||||
|
is-link |
||||
|
readonly |
||||
|
label="名目" |
||||
|
placeholder="请选择名目" |
||||
|
@click="data.showName = true" |
||||
|
input-align="right" |
||||
|
/> |
||||
|
<!-- <el-popup v-model:show="data.showName" round position="bottom"> |
||||
|
<el-picker |
||||
|
title="请选择名目" |
||||
|
v-if="data.applyNameOptions && data.applyNameOptions.length" |
||||
|
:columns="data.applyNameOptions" |
||||
|
@confirm="finishApplyName" |
||||
|
/> |
||||
|
<el-loading v-else class="my-20 text-center" /> |
||||
|
</el-popup> --> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 提交人信息 --> |
||||
|
<div class="bg-white mt-3"> |
||||
|
<div class="text-gray-500 p-4 font-semibold">提交人信息</div> |
||||
|
<el-field |
||||
|
required |
||||
|
v-model="data.submitName" |
||||
|
label="姓名" |
||||
|
placeholder="请输入姓名" |
||||
|
input-align="right" |
||||
|
/> |
||||
|
<!-- 选择所属部门 --> |
||||
|
<el-field |
||||
|
required |
||||
|
v-model="data.department" |
||||
|
label="所属部门" |
||||
|
placeholder="请输入所属部门" |
||||
|
input-align="right" |
||||
|
/> |
||||
|
</div> |
||||
|
<!-- 历史申请 --> |
||||
|
<div class="bg-white mt-3 p-4"> |
||||
|
<div class="text-gray-500 font-semibold">历史申请</div> |
||||
|
<div> |
||||
|
<Search /> |
||||
|
<HistoricalApplication /> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 底部立即提交按钮 --> |
||||
|
<div class="mx-6 mt-10"> |
||||
|
<el-button @click="submit" type="primary" size="small" block>立即提交</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup> |
||||
|
import axios from 'axios'; |
||||
|
import { ref, reactive } from 'vue'; |
||||
|
import { queryChecker } from 'apis/member'; |
||||
|
import { queryType, apply } from 'apis/finance'; |
||||
|
import { bill } from 'apis/ocr'; |
||||
|
import { ElMessage } from 'element-plus' |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import num from 'utils/num'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const token = useToken() |
||||
|
const projectName = useProjectName(); |
||||
|
console.log('projectName: ', projectName); |
||||
|
const taskName = useTaskName(); |
||||
|
const projectId = useProjectId(); |
||||
|
const taskDetailId = useTaskId(); |
||||
|
const data = reactive({ |
||||
|
isInvoice: true, |
||||
|
fileList: [], |
||||
|
showUploading: false, |
||||
|
remark: '', |
||||
|
invoiceList: [], |
||||
|
invoiceInfo: [ |
||||
|
{ |
||||
|
name: '发票代码', |
||||
|
value: 0, |
||||
|
label: 'invoiceCode', |
||||
|
}, |
||||
|
{ |
||||
|
name: '发票号码', |
||||
|
value: 0, |
||||
|
label: 'invoiceNumber', |
||||
|
}, |
||||
|
{ |
||||
|
name: '合计金额(元)', |
||||
|
value: 0, |
||||
|
label: 'money', |
||||
|
}, |
||||
|
{ |
||||
|
name: '税额(元)', |
||||
|
value: 0, |
||||
|
label: 'taxMoney', |
||||
|
}, |
||||
|
{ |
||||
|
name: '开票日期', |
||||
|
value: 0, |
||||
|
label: 'invoiceTime', |
||||
|
}, |
||||
|
{ |
||||
|
name: '备注信息', |
||||
|
value: '无', |
||||
|
label: 'remark', |
||||
|
}, |
||||
|
], |
||||
|
reviewerList: [], // 审核人数组 |
||||
|
checkerList: [], // 默认的审核人 |
||||
|
isSuccess: false, // 上传票据是否成功 |
||||
|
submitName: '', // 提交人的姓名 |
||||
|
department: '', // 选择的部门的值 |
||||
|
pplyMoney: '5000', // 手动输入时输入的申请的金额 |
||||
|
titleHidden: true, // 上传提示语隐藏 |
||||
|
currentPage: 0, // 当前显示页数 |
||||
|
personalType: '个人申请', // 上传提示语隐藏 |
||||
|
personalCategory: '用款', |
||||
|
money: '', |
||||
|
// 其他信息的多个选择按钮 |
||||
|
showType: false, // 申请类型的 |
||||
|
applyTypes: [], |
||||
|
applyTypeOptions: [], |
||||
|
applyType: '', // 选择的类型的值 |
||||
|
typeId: '', |
||||
|
showCategory: false, // 所属的类目 |
||||
|
applyCategories: [], |
||||
|
applyCategoryOptions: [], |
||||
|
applyCategory: '', // 选择的类目的值 |
||||
|
categoryId: '', |
||||
|
showName: false, // 所属的名目 |
||||
|
applyNames: [], |
||||
|
applyNameOptions: [], |
||||
|
applyName: '', // 选择的名目的值 |
||||
|
rowId: '', |
||||
|
}); |
||||
|
|
||||
|
// 上传文件 |
||||
|
function upLoaderImg(file, url) { //file为 你读取成功的回调文件信息 |
||||
|
//new 一个FormData格式的参数 |
||||
|
let params = new FormData() |
||||
|
params.append('part', file) |
||||
|
let config = { |
||||
|
headers: { //添加请求头 |
||||
|
'Content-Type': 'multipart/form-data', |
||||
|
Authorization: 'Bearer ' + token.value |
||||
|
} |
||||
|
} |
||||
|
return new Promise((resolve, reject) => { |
||||
|
//把 uploadUrl 换成自己的 上传路径 |
||||
|
axios.post(`${bill}`, params, config).then(res => { |
||||
|
resolve(res) |
||||
|
}).catch(err => { |
||||
|
reject(err) |
||||
|
}); |
||||
|
}) |
||||
|
} |
||||
|
// 图像识别 |
||||
|
async function afterRead(file){ |
||||
|
data.showUploading = true |
||||
|
// 此时可以自行将文件上传至服务器 |
||||
|
upLoaderImg(file.file, 'upload').then(res => { |
||||
|
data.showUploading = false |
||||
|
if (res.data.code == 200) { |
||||
|
for(let key in res.data.data){ |
||||
|
data.invoiceInfo.forEach(item => { |
||||
|
if(item.label === key){ |
||||
|
if(item.label === 'money' || item.label === 'taxMoney'){ |
||||
|
item.value = num.except(+res.data.data[key], 100) |
||||
|
}else{ |
||||
|
item.value = res.data.data[key] |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
console.log('data.invoiceInfo: ', data.invoiceInfo); |
||||
|
data.invoiceList.push(res.data.data) |
||||
|
data.titleHidden = false; |
||||
|
data.isSuccess = true; |
||||
|
} else { |
||||
|
ElMessage.error(res.data.msg || '上传失败') |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 发票信息 |
||||
|
function cahngeInvoiceList(e, item) { |
||||
|
data.invoiceList.forEach(invoice => { |
||||
|
for(let key in data.invoiceList){ |
||||
|
if(item.label === key){ |
||||
|
invoice[key] = item.value |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 选择申请类型 |
||||
|
function finishApplyType(e) { |
||||
|
data.showType = false; |
||||
|
data.applyType = e; |
||||
|
const type = data.applyTypes.find(option => option.name === e); |
||||
|
data.typeId = type.id; |
||||
|
// 类目 |
||||
|
handleQueryType(data.typeId, 1); |
||||
|
} |
||||
|
|
||||
|
// 所属的类目 |
||||
|
function finishApplyCategory(e) { |
||||
|
data.showCategory = false; |
||||
|
data.applyCategory = e; |
||||
|
const category = data.applyCategories.find(option => option.name === e); |
||||
|
data.categoryId = category.id; |
||||
|
// 名目 |
||||
|
handleQueryType(data.categoryId, 2); |
||||
|
} |
||||
|
|
||||
|
// 所属的名目 |
||||
|
function finishApplyName(e) { |
||||
|
data.showName = false; |
||||
|
data.applyName = e; |
||||
|
const row = data.applyNames.find(option => option.name === e); |
||||
|
data.rowId = row.id; |
||||
|
} |
||||
|
|
||||
|
// 检查被选中的审核人的状态 |
||||
|
function handleSelectChecker(id) { |
||||
|
const target = data.checkerList.find(item => item === id); |
||||
|
if (target) { |
||||
|
data.checkerList = data.checkerList.filter(item => item !== id); |
||||
|
} else { |
||||
|
data.checkerList.push(id); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询所有成员 |
||||
|
* @param { String } projectId |
||||
|
*/ |
||||
|
async function handleQueryChecker() { |
||||
|
try { |
||||
|
const params = { |
||||
|
param: { |
||||
|
projectId: projectId.value, |
||||
|
}, |
||||
|
}; |
||||
|
const res = await queryChecker(params); |
||||
|
data.reviewerList = res; |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询费用申请类型 |
||||
|
* @param { String } parentId 上级类型ID,默认为0 |
||||
|
* @param { Number } type 类型:0申请类型 1类目 2名目 |
||||
|
*/ |
||||
|
async function handleQueryType(parentId, type) { |
||||
|
try { |
||||
|
const params = { |
||||
|
param: { |
||||
|
parentId, |
||||
|
type, |
||||
|
}, |
||||
|
}; |
||||
|
const res = await queryType(params); |
||||
|
if (type === 0) { |
||||
|
data.applyTypes = res; |
||||
|
res.forEach(item => { |
||||
|
data.applyTypeOptions.push(item.name); |
||||
|
}); |
||||
|
} |
||||
|
if (type === 1) { |
||||
|
data.applyCategories = res; |
||||
|
res.forEach(item => { |
||||
|
data.applyCategoryOptions.push(item.name); |
||||
|
}); |
||||
|
} |
||||
|
if (type === 2) { |
||||
|
data.applyNames = res; |
||||
|
res.forEach(item => { |
||||
|
data.applyNameOptions.push(item.name); |
||||
|
}); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
// 查询所有成员 |
||||
|
handleQueryChecker(); |
||||
|
// 查询费用申请类型 |
||||
|
handleQueryType(0, 0); |
||||
|
}); |
||||
|
|
||||
|
/** |
||||
|
* 发起申请 |
||||
|
* @param { Object } params |
||||
|
*/ |
||||
|
async function submit() { |
||||
|
try { |
||||
|
if(!verification()) return |
||||
|
const params = {} |
||||
|
params.param = setParams() |
||||
|
await apply(params) |
||||
|
ElMessage.success('审批成功') |
||||
|
} catch (error) { |
||||
|
console.log('error: ', error); |
||||
|
ElMessage.error(error || '申请失败') |
||||
|
} |
||||
|
} |
||||
|
// 验证必填 |
||||
|
function verification(){ |
||||
|
const { isSuccess, invoiceInfo, categoryId, checkerList, department, money, rowId, submitName, typeId, isInvoice } = data |
||||
|
// 判断发票信息 |
||||
|
if(!isSuccess && isInvoice){ |
||||
|
ElMessage.error('请上传票据凭证'); |
||||
|
return |
||||
|
} |
||||
|
if(!money && !isInvoice){ |
||||
|
ElMessage.error('请输入金额'); |
||||
|
return |
||||
|
} |
||||
|
if(!checkerList || !checkerList.length){ |
||||
|
ElMessage.error('请选择审核人'); |
||||
|
return |
||||
|
} |
||||
|
if(!typeId){ |
||||
|
ElMessage.error('请选择申请类型'); |
||||
|
return |
||||
|
} |
||||
|
if(!categoryId){ |
||||
|
ElMessage.error('请选择类目'); |
||||
|
return |
||||
|
} |
||||
|
if(!rowId && isInvoice){ |
||||
|
ElMessage.error('请选择名目'); |
||||
|
return |
||||
|
} |
||||
|
if(!submitName){ |
||||
|
ElMessage.error('请输入提交人姓名'); |
||||
|
return |
||||
|
} |
||||
|
if(!department){ |
||||
|
ElMessage.error('请输入所属部门'); |
||||
|
return |
||||
|
} |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
// 设置参数 |
||||
|
function setParams(){ |
||||
|
const { remark, money, categoryId, checkerList, department, rowId, submitName, typeId, invoiceInfo, isInvoice, invoiceList } = data |
||||
|
let param = {} |
||||
|
let totleMoney = 0 |
||||
|
invoiceInfo.forEach(item => { |
||||
|
if(item.label === 'money'){ |
||||
|
totleMoney += item.value |
||||
|
} |
||||
|
}) |
||||
|
if(isInvoice){ |
||||
|
param = { |
||||
|
money: num.ride(totleMoney,100),invoiceList, remark, checkerList, typeId, projectId: projectId.value, |
||||
|
taskDetailId: taskDetailId.value, categoryId, rowId, submitName, department |
||||
|
} |
||||
|
}else{ |
||||
|
param = { |
||||
|
money: num.ride(money,100), remark, checkerList, typeId, projectId: projectId.value, categoryId, submitName, department |
||||
|
} |
||||
|
} |
||||
|
return param |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.el-cell-group { |
||||
|
padding: 0 1rem; |
||||
|
} |
||||
|
.el-cell { |
||||
|
font-size: 15px; |
||||
|
} |
||||
|
.bill-name { |
||||
|
font-weight: 600; |
||||
|
color: #6f6f6f; |
||||
|
border-bottom: 1px solid #eee; |
||||
|
padding: 0.75rem 0px; |
||||
|
} |
||||
|
.el-button { |
||||
|
border-radius: 0.2rem; |
||||
|
} |
||||
|
.button { |
||||
|
border-radius: 1rem; |
||||
|
padding: 0 0.75rem; |
||||
|
margin: 0.5rem; |
||||
|
} |
||||
|
|
||||
|
.upload-box{ |
||||
|
background: #f7f8fa; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.upload-txt{ |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
bottom: 22px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,76 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<!-- 搜索框与表格部分 --> |
||||
|
<el-tabs |
||||
|
v-model:active="active" |
||||
|
shrink |
||||
|
line-width="60px" |
||||
|
color="#59B4FF" |
||||
|
title-active-color="#59B4FF" |
||||
|
> |
||||
|
<el-tab-pane title="我的申请"> |
||||
|
<div class=" bg-white px-4"> |
||||
|
<div class="mt-4 flex flex-col overflow-hidden h-full"> |
||||
|
<div class="py-4 pb-0 text-gray-500 font-semibold">历史申请</div> |
||||
|
<Search /> |
||||
|
<HistoricalApplication /> |
||||
|
</div> |
||||
|
<!-- 底部提交按钮部分 --> |
||||
|
<div class="fixed w-11/12 box-border bottom-10 " @click="toApplication"> |
||||
|
<el-button type="primary" block size="small">发起申请</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</el-tab-pane> |
||||
|
|
||||
|
<el-tab-pane title="我的奖金"> |
||||
|
<div class="mt-4 bg-white"> |
||||
|
<div class="p-4 pb-0 text-gray-500 font-semibold">奖金领取记录</div> |
||||
|
<Search class="px-4 pt-0" /> |
||||
|
<BonusCollection class="px-4 mt-0" /> |
||||
|
</div> |
||||
|
<div class="mt-4 bg-white"> |
||||
|
<div class="text-gray-500 font-semibold m-4 py-3 border-b"> |
||||
|
待领取奖金 |
||||
|
</div> |
||||
|
<div class="text-ms text-gray-400 pl-4">可领取:</div> |
||||
|
<div |
||||
|
class="w-full h-20 text-gray-400 font-semibold text-center leading-loose" |
||||
|
v-if="!isBonus" |
||||
|
> |
||||
|
暂无可领取的奖金 |
||||
|
</div> |
||||
|
<div |
||||
|
class="w-full h-20 text-blue-500 font-semibold text-center leading-loose text-2xl" |
||||
|
v-if="isBonus" |
||||
|
> |
||||
|
500元 |
||||
|
</div> |
||||
|
<div class="px-8"> |
||||
|
<el-button type="primary" size="small" block :disabled="!isBonus" |
||||
|
>立即领取</el-button |
||||
|
> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-tab-pane> |
||||
|
</el-tabs> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref } from 'vue'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const active = ref(0); |
||||
|
const isBonus = ref(true); |
||||
|
|
||||
|
function toApplication() { |
||||
|
const routeValue = router.currentRoute.value; |
||||
|
const query = routeValue.query; |
||||
|
router.push({ path: '/Initiate-application', query }); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped></style> |
@ -0,0 +1,224 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<!-- 导航栏 --> |
||||
|
<NuxtLink to="Initiate-application"> |
||||
|
<div |
||||
|
title="申请详情" |
||||
|
left-arrow |
||||
|
@click="router.go(-1)" |
||||
|
></div> |
||||
|
</NuxtLink> |
||||
|
|
||||
|
<!-- 审核结果 --> |
||||
|
<div class="bg-white px-3"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3">审核结果</div> |
||||
|
<div v-for="(item, checkerIndex) in checkerList" :key="checkerIndex" class="flex py-3 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div> |
||||
|
<div>{{item.checkerName}}</div> |
||||
|
<div class="text-sm pt-1">{{item.remark}}</div> |
||||
|
<div class="text-sm pt-1">{{item.time}}</div> |
||||
|
</div> |
||||
|
<div class="text-center"> |
||||
|
<div :class="item.checkStatus == '1' ? 'text-green-500' : item.checkStatus == '2' ? 'text-red-500' : ''"> |
||||
|
{{item.checkStatus == '1' ? '已通过' : item.checkStatus == '2' ? '已驳回' : '待审批'}} |
||||
|
</div> |
||||
|
<div v-if="item.checkStatus == '1' || item.checkStatus == '2'" class="mt-1"> |
||||
|
<el-progress type="circle" :percentage="100" color="#ff6700" :stroke-width="100" /> |
||||
|
<!-- <van-circle |
||||
|
v-model:current-rate="currentRate" |
||||
|
:rate="100" |
||||
|
:speed="100" |
||||
|
:text="100" |
||||
|
class="w-12" |
||||
|
color="#ff6700" |
||||
|
:stroke-width="100" |
||||
|
/> --> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 发票信息 --> |
||||
|
<div class="bg-white px-3" v-if="isInvoice"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3 mt-5">发票信息</div> |
||||
|
<div v-for="(item,invoiceIndex) in invoiceList" :key="invoiceIndex"> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>发票代码</div> |
||||
|
<div>{{item.invoiceCode}}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>发票号码</div> |
||||
|
<div>{{item.invoiceNumber}}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>合计金额(元)</div> |
||||
|
<div>{{ num.except(+item.money, 100) }}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>税额(元)</div> |
||||
|
<div>{{ num.except(+item.taxMoney, 100) }}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>开票日期</div> |
||||
|
<div>{{dayjs(item.invoiceTime - 0).format('YYYY年MM月DD日')}}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>备注</div> |
||||
|
<div>{{item.remark}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 金额信息 --> |
||||
|
<div class="bg-white px-3" v-else> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3 mt-5">发票信息</div> |
||||
|
<div v-for="(item,moneyIndex) in moneyInfo" :key="moneyIndex" class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>{{item.name}}</div> |
||||
|
<div>{{item.value}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 其他信息 --> |
||||
|
<div class="bg-white px-3"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3 mt-5">其他信息</div> |
||||
|
<div v-for="(item,otherIndex) in otherData" :key="otherIndex" class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>{{item.name}}</div> |
||||
|
<div>{{item.value}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 提交人信息 --> |
||||
|
<div class="bg-white px-3 mb-5"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3 mt-5">提交人信息</div> |
||||
|
<div v-for="(item, index) in submitter" :key="index" class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>{{item.name}}</div> |
||||
|
<div>{{item.value}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import dayjs from "dayjs"; |
||||
|
import { ref, computed } from 'vue'; |
||||
|
import { getApplyDetail } from 'apis/finance'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import num from 'utils/num'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
// 审核人数据 |
||||
|
const currentRate = ref(0); |
||||
|
const text = computed(() => currentRate.value.toFixed(0)); |
||||
|
const isInvoice = ref(false) |
||||
|
const checkerList = ref([]) |
||||
|
// 发票信息数据 |
||||
|
const invoiceList = ref([]) |
||||
|
// 没有发票信息得数据 |
||||
|
const moneyInfo = ref([ |
||||
|
{ |
||||
|
name: "申请金额", |
||||
|
value: "", |
||||
|
label: "money", |
||||
|
}, |
||||
|
{ |
||||
|
name: "备注", |
||||
|
value: "", |
||||
|
label: "remark", |
||||
|
}, |
||||
|
]) |
||||
|
// 其他信息数据 |
||||
|
const otherData = ref([ |
||||
|
{ |
||||
|
name: "申请类型", |
||||
|
value: "", |
||||
|
label: "typeName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "所属项目", |
||||
|
value: "", |
||||
|
label: "projectName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "所属任务", |
||||
|
value: "", |
||||
|
label: "taskDetailName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "类目", |
||||
|
value: "", |
||||
|
label: "categoryName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "名目", |
||||
|
value: "", |
||||
|
label: "rowName", |
||||
|
}, |
||||
|
]) |
||||
|
// 提交人数据 |
||||
|
const submitter = ref([ |
||||
|
{ |
||||
|
name:'姓名', |
||||
|
value:'', |
||||
|
label: "submitName", |
||||
|
}, |
||||
|
{ |
||||
|
name:'部门', |
||||
|
value:'软件部', |
||||
|
label: "department", |
||||
|
}, |
||||
|
{ |
||||
|
name:'提交时间', |
||||
|
value:'', |
||||
|
label: "applyTime", |
||||
|
}, |
||||
|
]) |
||||
|
|
||||
|
/** |
||||
|
* 查询申请详情 |
||||
|
* @param { Number } applyId 申请记录id |
||||
|
*/ |
||||
|
async function handleApplyDetail(){ |
||||
|
try { |
||||
|
const routeValue = router.currentRoute.value; |
||||
|
const applyId = routeValue.query.applyId; |
||||
|
const params = {param : { applyId }} |
||||
|
const res = await getApplyDetail(params) |
||||
|
// 检查人 |
||||
|
checkerList.value = res.checkerList |
||||
|
// 发票信息 |
||||
|
isInvoice.value = res.invoiceList && res.invoiceList.length ? true : false; |
||||
|
invoiceList.value = res.invoiceList |
||||
|
for(let key in res){ |
||||
|
moneyInfo.value.forEach(item => { |
||||
|
if(item.label === key){ |
||||
|
item.value = res[key] |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
// 其他信息 |
||||
|
for(let key in res){ |
||||
|
otherData.value.forEach(item => { |
||||
|
if(item.label === key){ |
||||
|
item.value = res[key] |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
// 提交人信息 |
||||
|
for(let key in res){ |
||||
|
submitter.value.forEach(item => { |
||||
|
if(item.label === key){ |
||||
|
item.value = res[key] |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handleApplyDetail() |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.el-progress{ |
||||
|
width: 2.5rem !important; |
||||
|
height: 2.5rem !important; |
||||
|
} |
||||
|
|
||||
|
</style> |
@ -0,0 +1,269 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div |
||||
|
title="财务审批详情" |
||||
|
left-arrow |
||||
|
@click="router.go(-1)" |
||||
|
></div> |
||||
|
|
||||
|
<!-- 发票信息 --> |
||||
|
<div class="bg-white px-3" v-if="isInvoice"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3">发票信息</div> |
||||
|
<div v-for="(item,invoiceIndex) in invoiceList" :key="invoiceIndex"> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>发票代码</div> |
||||
|
<div>{{item.invoiceCode}}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>发票号码</div> |
||||
|
<div>{{item.invoiceNumber}}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>合计金额(元)</div> |
||||
|
<div>{{ (+item.money / 100).toFixed(2) }}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>税额(元)</div> |
||||
|
<div>{{ (+item.taxMoney / 100).toFixed(2) }}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>开票日期</div> |
||||
|
<div>{{dayjs(item.invoiceTime - 0).format('YYYY年MM月DD日')}}</div> |
||||
|
</div> |
||||
|
<div class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>备注</div> |
||||
|
<div>{{item.remark}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 金额信息 --> |
||||
|
<div class="bg-white px-3" v-else> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3">发票信息</div> |
||||
|
<div v-for="(item,moneyIndex) in moneyInfo" :key="moneyIndex" class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>{{item.name}}</div> |
||||
|
<div>{{item.value}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 其他信息 --> |
||||
|
<div class="bg-white px-3"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3 mt-5">其他信息</div> |
||||
|
<div v-for="(item,otherIndex) in otherData" :key="otherIndex" class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>{{item.name}}</div> |
||||
|
<div>{{item.value}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 提交人信息 --> |
||||
|
<div class="bg-white px-3 mb-5"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3 mt-5">提交人信息</div> |
||||
|
<div v-for="(item, index) in submitter" :key="index" class="flex py-2 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div>{{item.name}}</div> |
||||
|
<div>{{item.value}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 审核人信息 --> |
||||
|
<div class="bg-white px-3 mb-5"> |
||||
|
<div class="text-gray-500 font-semibold px-1 py-3">审核结果</div> |
||||
|
<div v-for="(item, checkerIndex) in checkerList" :key="checkerIndex" class="flex py-3 px-4 text-gray-400 text-base justify-between"> |
||||
|
<div> |
||||
|
<div>{{item.checkerName}}</div> |
||||
|
<div class="text-sm pt-1">{{item.remark}}</div> |
||||
|
<div class="text-sm pt-1">{{item.time}}</div> |
||||
|
</div> |
||||
|
<div class="text-center"> |
||||
|
<div v-if="item.checkStatus == '1' || item.checkStatus == '2'" :class="item.checkStatus == '1' ? 'text-green-500' : item.checkStatus == '2' ? 'text-red-500' : ''"> |
||||
|
{{item.checkStatus == '1' ? '已通过' : item.checkStatus == '2' ? '已驳回' : '待审批'}} |
||||
|
</div> |
||||
|
<div class="text-center" v-else> |
||||
|
<el-button type="success" round size="mini" class="button ml-5" @click="showRemark(item.financeCheckId, 1)">通过</el-button> |
||||
|
<el-button type="danger" round size="mini" class="button" @click="showRemark(item.financeCheckId, 2)">驳回</el-button> |
||||
|
</div> |
||||
|
<div v-if="item.checkStatus == '1' || item.checkStatus == '2'" class="mt-1"> |
||||
|
<el-circle |
||||
|
v-model:current-rate="currentRate" |
||||
|
:rate="100" |
||||
|
:speed="100" |
||||
|
:text="100" |
||||
|
class="w-12" |
||||
|
color="#ff6700" |
||||
|
:stroke-width="100" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<el-dialog v-model:show="data.show" title="备注" show-cancel-button @confirm="handleAudit"> |
||||
|
<el-field :border="data.border" v-model="data.remark" type="textarea" class="remark" placeholder="请输入备注" /> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import dayjs from "dayjs"; |
||||
|
import { ref, computed } from 'vue'; |
||||
|
import { getApplyDetail, audit } from 'apis/finance'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import { ElMessage } from 'element-plus' |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const data = reactive({ |
||||
|
show: false, |
||||
|
remark: '', |
||||
|
auditInfo: {}, |
||||
|
border: true |
||||
|
}) |
||||
|
// 审核人数据 |
||||
|
const currentRate = ref(0); |
||||
|
const text = computed(() => currentRate.value.toFixed(0)); |
||||
|
const isInvoice = ref(false) |
||||
|
const checkerList = ref([]) |
||||
|
// 发票信息数据 |
||||
|
const invoiceList = ref([]) |
||||
|
// 没有发票信息得数据 |
||||
|
const moneyInfo = ref([ |
||||
|
{ |
||||
|
name: "申请金额", |
||||
|
value: "", |
||||
|
label: "money", |
||||
|
}, |
||||
|
{ |
||||
|
name: "备注", |
||||
|
value: "", |
||||
|
label: "remark", |
||||
|
}, |
||||
|
]) |
||||
|
// 其他信息数据 |
||||
|
const otherData = ref([ |
||||
|
{ |
||||
|
name: "申请类型", |
||||
|
value: "", |
||||
|
label: "typeName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "所属项目", |
||||
|
value: "", |
||||
|
label: "projectName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "所属任务", |
||||
|
value: "", |
||||
|
label: "taskDetailName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "类目", |
||||
|
value: "", |
||||
|
label: "categoryName", |
||||
|
}, |
||||
|
{ |
||||
|
name: "名目", |
||||
|
value: "", |
||||
|
label: "rowName", |
||||
|
}, |
||||
|
]) |
||||
|
// 提交人数据 |
||||
|
const submitter = ref([ |
||||
|
{ |
||||
|
name:'姓名', |
||||
|
value:'', |
||||
|
label: "submitName", |
||||
|
}, |
||||
|
{ |
||||
|
name:'部门', |
||||
|
value:'软件部', |
||||
|
label: "department", |
||||
|
}, |
||||
|
{ |
||||
|
name:'提交时间', |
||||
|
value:'', |
||||
|
label: "applyTime", |
||||
|
}, |
||||
|
]) |
||||
|
|
||||
|
/** |
||||
|
* 查询申请详情 |
||||
|
* @param { Number } applyId 申请记录id |
||||
|
*/ |
||||
|
async function handleApplyDetail(){ |
||||
|
try { |
||||
|
const routeValue = router.currentRoute.value; |
||||
|
const applyId = routeValue.query.applyId; |
||||
|
const params = {param : { applyId }} |
||||
|
const res = await getApplyDetail(params) |
||||
|
// 检查人 |
||||
|
checkerList.value = res.checkerList |
||||
|
// 发票信息 |
||||
|
isInvoice.value = res.invoiceList && res.invoiceList.length ? true : false; |
||||
|
invoiceList.value = res.invoiceList |
||||
|
for(let key in res){ |
||||
|
moneyInfo.value.forEach(item => { |
||||
|
if(item.label === key){ |
||||
|
item.value = res[key] |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
// 其他信息 |
||||
|
for(let key in res){ |
||||
|
otherData.value.forEach(item => { |
||||
|
if(item.label === key){ |
||||
|
item.value = res[key] |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
// 提交人信息 |
||||
|
for(let key in res){ |
||||
|
submitter.value.forEach(item => { |
||||
|
if(item.label === key){ |
||||
|
item.value = res[key] |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handleApplyDetail() |
||||
|
|
||||
|
// 填写备注 |
||||
|
function showRemark(financeCheckId, checkStatus){ |
||||
|
data.show = true |
||||
|
data.auditInfo = { financeCheckId, checkStatus } |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 审批 |
||||
|
* @param { Number } checkStatus 审核状态 1已通过 2驳回 |
||||
|
* @param { String } financeCheckId 审核id |
||||
|
* @param { String } remark 备注 |
||||
|
*/ |
||||
|
async function handleAudit(financeCheckId, checkStatus){ |
||||
|
try { |
||||
|
const { auditInfo, remark } = data |
||||
|
const { financeCheckId, checkStatus } = data.auditInfo |
||||
|
const params = { |
||||
|
param:{ |
||||
|
financeCheckId, |
||||
|
checkStatus, |
||||
|
remark: data.remark |
||||
|
} |
||||
|
} |
||||
|
await audit(params) |
||||
|
ElMessage.success('审批成功') |
||||
|
handleFinanceOfProject() |
||||
|
data.remark = '' |
||||
|
} catch (error) { |
||||
|
console.error('error: ', error); |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.el-circle{ |
||||
|
width: 2.5rem !important; |
||||
|
height: 2.5rem !important; |
||||
|
} |
||||
|
.button{ |
||||
|
padding: 0 0.75rem; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,124 @@ |
|||||
|
<template> |
||||
|
<div class="mb-60"> |
||||
|
<!-- 财务审批页面 --> |
||||
|
<div class="bg-white p-4 flex text-gray-500 flex-col"> |
||||
|
<div> |
||||
|
<span class="font-semibold" id="finance-audit">财务审批</span> <span class="ml-2">对员工提交的申请进行审批</span> |
||||
|
</div> |
||||
|
<Search /> |
||||
|
<FinanceExamine /> |
||||
|
</div> |
||||
|
<!-- 财务统计页面 --> |
||||
|
<div class="bg-white p-4 mt-5 text-gray-500 flex-col"> |
||||
|
<div> |
||||
|
<span class="font-semibold" id="finance-statistical">财务统计</span> |
||||
|
<span class="ml-2">财务明细统计查看</span> |
||||
|
</div> |
||||
|
<!-- 任务支出统计 --> |
||||
|
<div class="h-64 overflow-hidden"> |
||||
|
<div class="mt-5 flex justify-between"> |
||||
|
<div> |
||||
|
<span class="inline-block w-2 h-2 border-2 border-blue-400 rounded-full mr-3"></span> |
||||
|
<span>任务支出统计</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button :type="taskState ? 'primary' : 'default'" size="mini" @click="taskState = true">图表</el-button> |
||||
|
<el-button :type="!taskState ? 'primary' : 'default'" size="mini" @click="taskState = false">表格</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 任务支出统计的图表展示 --> |
||||
|
<div v-show="taskState"> |
||||
|
<!-- <el-empty description="暂无图表数据信息" /> --> |
||||
|
<RingEcharts class="w-full h-full" id="taskEcharts"/> |
||||
|
</div> |
||||
|
<!-- 任务支出统计的表格展示 --> |
||||
|
<div v-show="!taskState"> |
||||
|
<FinanceExamine /> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 名目支出统计 --> |
||||
|
<div class="h-64 overflow-hidden"> |
||||
|
<div class="mt-5 flex justify-between"> |
||||
|
<div> |
||||
|
<span class="inline-block w-2 h-2 border-2 border-blue-400 rounded-full mr-3"></span> |
||||
|
<span>名目支出统计</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button :type="nameState ? 'primary' : 'default'" size="mini" @click="nameState = true">图表</el-button> |
||||
|
<el-button :type="!nameState ? 'primary' : 'default'" size="mini" @click="nameState = false">表格</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 名目支出统计的图表展示 --> |
||||
|
<div v-show="nameState"> |
||||
|
<!-- <el-empty description="暂无图表数据信息" /> --> |
||||
|
<RingEcharts class="w-full h-full" id="nameEcharts"/> |
||||
|
</div> |
||||
|
<!-- 名目支出统计的表格展示 --> |
||||
|
<div v-show="!nameState"> |
||||
|
<FinanceExamine /> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 成员财务图 --> |
||||
|
<div class="h-64 overflow-hidden"> |
||||
|
<div class="mt-5"> |
||||
|
<span class="inline-block w-2 h-2 border-2 border-blue-400 rounded-full mr-3"></span> |
||||
|
<span>成员财务图</span> |
||||
|
</div> |
||||
|
<RingEcharts class="w-full h-full" id="memberEcharts"/> |
||||
|
</div> |
||||
|
<!-- 时间财务图 --> |
||||
|
<div class="overflow-hidden"> |
||||
|
<div> |
||||
|
<span class="inline-block w-2 h-2 border-2 border-blue-400 rounded-full mr-3"></span> |
||||
|
<span>时间财务图</span> |
||||
|
</div> |
||||
|
<BarEcharts class="w-full h-full mt-5" /> |
||||
|
<!-- 没有数据展示空组件 --> |
||||
|
<!-- <el-empty description="暂无图表数据信息" /> --> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 悬浮跳转 --> |
||||
|
<ul class="menu"> |
||||
|
<a href="#finance-audit">财务审批</a> |
||||
|
<a href="#finance-statistical">财务统计</a> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
layout: 'default', |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<script setup> |
||||
|
import {ref} from 'vue' |
||||
|
const taskState = ref(true); |
||||
|
const nameState = ref(true); |
||||
|
|
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.menu{ |
||||
|
position: fixed; |
||||
|
right: 0; |
||||
|
bottom: 15px; |
||||
|
z-index: 99 |
||||
|
} |
||||
|
.menu a { |
||||
|
display: block; |
||||
|
width: 72px; |
||||
|
color: #fff; |
||||
|
background: rgba(25, 137, 250, 0.6); |
||||
|
padding: 8px 20px; |
||||
|
border-radius: 30px 0 0 30px; |
||||
|
margin-bottom: 15px; |
||||
|
} |
||||
|
.el-button--mini{ |
||||
|
padding: 0.5rem 1rem; |
||||
|
} |
||||
|
.el-button--mini+.el-button--mini{ |
||||
|
margin-left: 0px; |
||||
|
} |
||||
|
</style> |
@ -1,17 +1,8 @@ |
|||||
// 目前在 nuxt 中无法按需引入样式,因此采用手动引入的方式
|
import 'element-plus/dist/index.css'; |
||||
import 'vant/lib/index.css'; |
|
||||
|
|
||||
import { Button, Cell, CellGroup, Col, Icon, Image, Row } from 'vant'; |
|
||||
|
|
||||
|
import ElementPlus from 'element-plus/lib'; |
||||
import { defineNuxtPlugin } from '#app'; |
import { defineNuxtPlugin } from '#app'; |
||||
|
|
||||
export default defineNuxtPlugin(nuxtApp => { |
export default defineNuxtPlugin(nuxtApp => { |
||||
nuxtApp.vueApp |
nuxtApp.vueApp.use(ElementPlus); |
||||
.use(Row) |
|
||||
.use(Col) |
|
||||
.use(Image) |
|
||||
.use(Icon) |
|
||||
.use(Cell) |
|
||||
.use(Button) |
|
||||
.use(CellGroup); |
|
||||
}); |
}); |
||||
|
After Width: | Height: | Size: 182 KiB |
@ -0,0 +1,15 @@ |
|||||
|
{ |
||||
|
"$shared": { |
||||
|
"version": "v1", |
||||
|
"identifier": "wally", |
||||
|
"credential": "111111" |
||||
|
}, |
||||
|
"dev": { |
||||
|
"name": "dev", |
||||
|
"url": "https://test.tall.wiki/gateway" |
||||
|
}, |
||||
|
"local": { |
||||
|
"version": "v2", |
||||
|
"url": "https://test.tall.wiki/gateway" |
||||
|
} |
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
@localhost = http://localhost:7320/v1.0 |
||||
|
@localhost_tall = http://localhost:7130/v3.0 |
||||
|
@test_tall = http://192.168.0.99:7130/v3.0 |
||||
|
@test = https://test.tall.wiki/ptccsens/v1.0 |
||||
|
@www_tall = http://www.tall.wiki:7130/v3.0 |
||||
|
@www = http://www.tall.wiki/ptccsens/v1.0 |
||||
|
@type = content-type: application/json;charset=utf-8 |
||||
|
|
||||
|
### 登录 |
||||
|
# song 1218763410024566784 |
||||
|
# @name login |
||||
|
POST {{localhost_tall}}/users/signin |
||||
|
{{type}} |
||||
|
|
||||
|
{ |
||||
|
"client": 1, |
||||
|
"type": 3, |
||||
|
"data": { |
||||
|
"identifier": "whj", |
||||
|
"credential": "123456" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
### debug |
||||
|
GET {{test}}/debug |
||||
|
{{type}} |
||||
|
Authorization: Bearer {{login.response.body.$.data.token}} |
||||
|
|
||||
|
###查询费用申请类型 |
||||
|
POST {{localhost}}/finance/queryType |
||||
|
{{type}} |
||||
|
Authorization: Bearer {{login.response.body.$.data.token}} |
||||
|
|
||||
|
{ |
||||
|
"param":{ |
||||
|
"parentId":"4", |
||||
|
"type":2 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
###发起申请 |
||||
|
POST {{localhost}}/finance/apply |
||||
|
{{type}} |
||||
|
Authorization: Bearer {{login.response.body.$.data.token}} |
||||
|
|
||||
|
{ |
||||
|
"param":{ |
||||
|
|
||||
|
"checkerList": [ |
||||
|
123 |
||||
|
], |
||||
|
"invoiceList": [ |
||||
|
{ |
||||
|
"invoiceCode": "014002100112", |
||||
|
"invoiceNumber": "86610940", |
||||
|
"invoiceTime": 1643075118954, |
||||
|
"money": 4190, |
||||
|
"remark": "业务招待支出", |
||||
|
"taxMoney": 126, |
||||
|
"url": "https://alifei04.cfp.cn/creative/vcg/800/new/VCG211363439424.jpg" |
||||
|
} |
||||
|
], |
||||
|
"projectId": 2, |
||||
|
"taskDetailId": 3, |
||||
|
"remark": "", |
||||
|
"department": "视觉传达事业部", |
||||
|
"submitName": "黛西", |
||||
|
"money": 4190, |
||||
|
"typeId": 1, |
||||
|
"categoryId": 4, |
||||
|
"rowId": 7 |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
###查询申请详情 |
||||
|
POST {{localhost}}/finance/getApplyDetail |
||||
|
{{type}} |
||||
|
Authorization: Bearer {{login.response.body.$.data.token}} |
||||
|
|
||||
|
{ |
||||
|
"param":{ |
||||
|
"applyId":"1485797754654695424" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
###审批 |
||||
|
POST {{localhost}}/finance/audit |
||||
|
{{type}} |
||||
|
Authorization: Bearer {{login.response.body.$.data.token}} |
||||
|
|
||||
|
{ |
||||
|
"param":{ |
||||
|
"checkStatus":"2", |
||||
|
"financeCheckId":"1485797754923130880", |
||||
|
"remark":"测试" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
###通过任务id查看任务关联的财务信息 |
||||
|
POST {{localhost}}/finance/getByTask |
||||
|
{{type}} |
||||
|
Authorization: Bearer {{login.response.body.$.data.token}} |
||||
|
|
||||
|
{ |
||||
|
"param":{ |
||||
|
"taskDetailId":"3" |
||||
|
} |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
const num = { |
||||
|
// 清除浮点
|
||||
|
// 乘法
|
||||
|
ride(a, b) { |
||||
|
var as = Math.pow(10, digitLength(a)) |
||||
|
var as2 = Math.pow(10, digitLength(b)) |
||||
|
if (digitLength(a) >= digitLength(b)) { |
||||
|
return (as * a * as * b) / as / as//这里要除以最小公倍数的平方
|
||||
|
} else { |
||||
|
return (as2 * a * as2 * b) / as2 / as2 |
||||
|
} |
||||
|
function digitLength(e) { |
||||
|
var e1 = (e + '').split(''); |
||||
|
var e2 = e1.findIndex((item) => item = '.') |
||||
|
return e1.length - 1 - e2; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 除法
|
||||
|
except(a, b) { |
||||
|
var as = Math.pow(10, digitLength(a)) |
||||
|
var as2 = Math.pow(10, digitLength(b)) |
||||
|
if (digitLength(a) >= digitLength(b)) { |
||||
|
return ((as * a) / (as * b)) |
||||
|
} else { |
||||
|
return ((as2 * a) / (as2 * b)) |
||||
|
} |
||||
|
function digitLength(e) { |
||||
|
var e1 = (e + '').split(''); |
||||
|
var e2 = e1.findIndex((item) => item = '.') |
||||
|
return e1.length - 1 - e2; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
}; |
||||
|
export default num; |
Loading…
Reference in new issue