You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
585 lines
16 KiB
585 lines
16 KiB
<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>
|
|
|