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> |
|||
<NuxtPage /> |
|||
</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> |
|||
<div> |
|||
<div class="container"> |
|||
<slot /> |
|||
</div> |
|||
</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 'vant/lib/index.css'; |
|||
|
|||
import { Button, Cell, CellGroup, Col, Icon, Image, Row } from 'vant'; |
|||
import 'element-plus/dist/index.css'; |
|||
|
|||
import ElementPlus from 'element-plus/lib'; |
|||
import { defineNuxtPlugin } from '#app'; |
|||
|
|||
export default defineNuxtPlugin(nuxtApp => { |
|||
nuxtApp.vueApp |
|||
.use(Row) |
|||
.use(Col) |
|||
.use(Image) |
|||
.use(Icon) |
|||
.use(Cell) |
|||
.use(Button) |
|||
.use(CellGroup); |
|||
nuxtApp.vueApp.use(ElementPlus); |
|||
}); |
|||
|
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