批量审批

master
lion 1 year ago
parent 5705d97d89
commit e25d898fed

@ -60,3 +60,45 @@ export function destroy(params,noloading=false) {
noloading
})
}
export function getAwayDetails(params,noloading=false) {
return request({
method: "get",
url: "/api/oa/flow/get-away-details",
params,
noloading
})
}
export function updateAwayDetails (data,noloading=false) {
return request({
method: "post",
url: "/api/oa/flow/update-away-details",
data,
noloading
})
}
export function planSave (data,noloading=false) {
return request({
method: "post",
url: "/api/ht/away-plan/save",
data,
noloading
})
}
export function awayIndex(params,noloading=false) {
return request({
method: "get",
url: "/api/oa/flow/get-away-list",
params,
noloading,
paramsSerializer: customParamsSerializer
})
}

@ -267,7 +267,9 @@ export default {
}
}
}
console.log("selections",selections)
resolve(selections.map((i) => ({
// my_plan_id:i.
plan_id: i.id,
plan_title: i.title,
plan_year: i.year,

@ -1,131 +1,355 @@
<template>
<div>
<xy-dialog
ref="dialog"
:is-show.sync="isShow"
type="normal"
title="出差审批"
@on-ok="confirm"
>
<xy-table :table-item="table" :list="records" show-summary :summary-method="summary">
<template #btns> </template>
</xy-table>
</xy-dialog>
</div>
</template>
<script>
import {getBudget} from "@/api/budget/budget";
import {addFundLog} from "@/api/paymentRegistration/fundLog";
import {save} from "@/api/away";
export default {
data() {
return {
isShow: false,
table: [
{
prop: 'plan',
label: '资金来源',
width: 140,
align: 'left',
formatter: (row) => {
return row.plan_link?.reduce((pre, cur) => {
return pre + (this.plans?.find(i => i.id === cur.plan_id)?.name ?? '') + ';'
}, '')
}
},
{
prop: 'title',
label: '事由',
minWidth: 180,
align: 'left'
},
{
prop: 'start_date',
label: '开始日期',
width: 120
},
{
prop: 'end_date',
label: '结束日期',
width: 120
},
{
prop: 'admin.name',
label: '经办人',
width: 120
},
{
prop: 'flow_title',
label: '编号',
width: 140,
formatter: (row) => row.away_flow_links?.find(i => i.tag === "chuchaibaoxiao")?.flow_title
},
{
prop: 'totalAmt',
label: '金额',
formatter: (row) => row.away_flow_links?.find(i => i.tag === "chuchaibaoxiao")?.flow_data?.totalAmt
}
],
records: [],
plans: []
}
},
methods: {
show() {
this.isShow = true;
},
hidden() {
this.isShow = false;
},
setRecords(records = []) {
this.records = records
},
summary(param) {
const { columns, data } = param;
return columns.map((column, index) => {
if(index === 0) {
return '合计'
} else {
return column.property === 'totalAmt' ? (
data.reduce((pre, cur) => pre + (isNaN(Number(cur.away_flow_links?.find(i => i.tag === "chuchaibaoxiao")?.flow_data?.totalAmt)) ? 0 : Number(cur.away_flow_links?.find(i => i.tag === "chuchaibaoxiao")?.flow_data?.totalAmt)), 0)
) : ''
}
})
},
async getBudgets() {
let res = await getBudget({
is_tree: 1
})
this.plans = res.list
},
async confirm() {
const res = await Promise.allSettled(this.records.map(record => addFundLog({
fund_type: 2,
away_id: record.id,
apply_money: record.away_flow_links?.find(i => i.tag === "chuchaibaoxiao")?.flow_data?.totalAmt,
remark: record.away_flow_links?.find(i => i.tag === "chuchaibaoxiao")?.flow_title,
contract_plan_act_links: record.plan_link?.map(plan => ({
plan_id: this.plans.find(i => i.id === plan.plan_id)?.children[0].id,
use_money: record.away_flow_links?.find(i => i.tag === "chuchaibaoxiao")?.flow_data?.totalAmt
})),
})))
await Promise.allSettled(res.map((i, index) => i.status === 'fulfilled' ? save({
financial_status: 2,
id: this.records[index].id
}) : ''))
this.$message.success('操作成功')
this.hidden()
}
},
computed: {},
created() {
this.getBudgets()
}
}
</script>
<style scoped lang="scss">
<template>
<div>
<xy-dialog ref="dialog" :is-show.sync="isShow" type="normal" title="出差报销审批" @on-ok="confirm">
<xy-table ref="awayTable" row-key="id" default-expand-all
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :table-item="table" @select-all="toggleAll"
@select="handleSelectionChange" :list="chuchaibaoxiaoDetailList">
<template v-slot:oa_ht_away_links>
<el-table-column prop="oa_ht_away_links" align="center" label="状态" width="100">
<template #default="scope">
<div v-if="scope.row.hasOwnProperty('oa_ht_away_links')">
<el-tag v-if="scope.row.oa_ht_away_links" type="success" size="small">
已完成
</el-tag>
<el-tag v-else type="warning" size="small">
待审批
</el-tag>
</div>
</template>
</el-table-column>
</template>
<template #btns> </template>
</xy-table>
</xy-dialog>
</div>
</template>
<script>
import {
getBudget
} from "@/api/budget/budget";
import {
addFundLog
} from "@/api/paymentRegistration/fundLog";
import {
save,
getAwayDetails,
updateAwayDetails,
planSave
} from "@/api/away";
export default {
data() {
return {
isShow: false,
checkdKeys: false,
table: [{
type: 'selection',
width: 54,
reserveSelection: true,
fixed: "left",
selectable: row => row.oa_ht_away_links ? false : true,
},
{
prop: 'name',
label: '人员',
width: 180,
align: 'left'
},
{
prop: 'flow.title',
label: '流程名称',
minWidth: 180,
align: 'left'
},
{
prop: 'amt',
label: '报销金额',
width: 120,
align: 'center'
},
{
prop: 'oa_ht_away_links',
label: '状态',
width: 180,
align: 'center'
},
{
prop: 'remark',
label: '备注',
align: 'left'
}, {
label: "创建日期",
width: 160,
prop: "created_at",
formatter: (cell, data, value) => {
return this.$moment(value).format("YYYY-MM-DD HH:mm");
},
},
],
records: [],
plans: [],
chuchaibaoxiaoDetailList: [],
away_ids: []
};
},
computed: {
spanMethods() {
const xingmingSpan = {};
const zijinSpan = {};
this.chuchaibaoxiaoDetailList.forEach((item, index) => {
const xingming = item.xingming_detail;
const zijin = item.zijinlaiyuan;
// xingming_detail
if (!xingmingSpan[xingming]) {
xingmingSpan[xingming] = {
count: 1,
index: index
};
} else {
xingmingSpan[xingming].count++;
}
// xingming_detail zijinlaiyuan
const combinedKey = `${xingming}-${zijin}`;
if (!zijinSpan[combinedKey]) {
zijinSpan[combinedKey] = {
count: 1,
index: index
};
} else {
zijinSpan[combinedKey].count++;
}
});
return {
xingmingSpan,
zijinSpan
};
}
},
methods: {
show() {
this.isShow = true;
},
hidden() {
this.chuchaibaoxiaoDetailList = [];
this.away_ids = [];
this.$refs['awayTable'].clearSelection();
this.isShow = false;
},
setRecords(ids) {
console.log("ids", ids);
this.getAway(ids);
},
summary(param) {
const {
columns,
data
} = param;
return columns.map((column, index) => {
if (index === 0) {
return '合计';
} else {
return column.property === 'amt' ? (
data.reduce((pre, cur) => pre + (cur.amt ? Number(cur.amt) : 0), 0)
) : '';
}
});
},
async getAway(ids) {
this.away_ids = ids;
let res = await getAwayDetails({
away_ids: ids
});
console.log("res.chuchaibaoxiaoDetailList", res.chuchaibaoxiaoDetailList)
let arr = this.transformData(res.chuchaibaoxiaoDetailList)
console.log("arr", arr);
this.chuchaibaoxiaoDetailList = arr;
this.$refs.awayTable.clearSelection()
},
transformData(originalData) {
const result = [];
for (const xingming_details in originalData) {
const person = {
id: Math.random(),
name: xingming_details,
children: [],
parent: null, //
isSelect: false //
};
const innerData = originalData[xingming_details];
for (const innerKey in innerData) {
const source = {
id: Math.random(),
name: innerKey,
children: innerData[innerKey].map((item) => ({
...item,
name: item.xingming_detail,
parent: source, //
isSelect: false //
})),
parent: person, //
isSelect: false //
};
person.children.push(source);
}
result.push(person);
}
return result;
},
toggleAll() {
this.checkdKeys = !this.checkdKeys
this.splite(this.chuchaibaoxiaoDetailList, this.checkdKeys)
},
splite(data, flag) {
data.forEach((row) => {
this.$refs.awayTable.toggleRowSelection(row, flag)
if (row.children) {
this.splite(row.children, flag)
}
})
},
handleSelectionChange(selection, row) {
const allData = this.chuchaibaoxiaoDetailList;
//
row.isSelect = !row.isSelect
console.log("selection", selection, row)
this.deselectChildren(row, row.isSelect); //
// if(!row.isSelect){
// this.deselectChildren(row,row.isSelect); //
// // this.updateParentSelection(row, true); //
// }else{
// //
// selection.forEach((item) => {
// if (!this.isSelected(item)) {
// this.selectChildren(item); //
// // this.updateParentSelection(item, true); //
// }
// });
// }
},
selectChildren(parent) {
if (parent.children) {
parent.children.forEach((child) => {
this.$refs.awayTable.toggleRowSelection(child, true); //
// child.isSelect = true; // isSelect
this.$set(child, 'isSelect', true)
this.selectChildren(child); //
});
}
},
deselectChildren(parent, isSelect) {
console.log("isSelect", isSelect, parent)
if (parent.children) {
parent.children.forEach((child, index) => {
this.$refs.awayTable.toggleRowSelection(child, isSelect); //
this.$set(child, 'isSelect', isSelect)
this.deselectChildren(child, isSelect); //
});
} else {
this.$refs.awayTable.toggleRowSelection(parent, isSelect);
this.$set(parent, 'isSelect', isSelect)
console.log("parent", parent)
}
},
// updateParentSelection(item, isSelected) {
// if (item.parent) {
// const allSelected = item.parent.children.every((child) => child.isSelect === true);
// const anySelected = item.parent.children.some((child) => child.isSelect === true);
// item.parent.isSelect = allSelected ? true : anySelected ? '' : false; //
// this.$refs.awayTable.toggleRowSelection(item.parent, allSelected);
// this.updateParentSelection(item.parent, allSelected); //
// }
// },
isSelected(item) {
return item.isSelect === true;
},
async getBudgets() {
let res = await getBudget({
is_tree: 1
});
this.plans = res.list;
},
async confirm() {
console.log("this.$refs['awayTable'].getSelection()", this.$refs['awayTable'].getSelection());
let flowsList = this.$refs['awayTable'].getSelection();
let flow_id = [];
let chuchai_pay_id = [];
let chuchai_pay_details = [];
let person_arr = []
let money = 0
flowsList.map(f => {
if (f.flow && !f.oa_ht_away_links) {
person_arr.push(f)
}
});
if (person_arr.length < 1) {
this.$message.warning('请选择待审批的出差报销')
return
}
person_arr.map(item => {
flow_id.push(item.flow.id);
chuchai_pay_id.push(item.belongs_id);
chuchai_pay_details.push(item.id);
money += parseFloat(item.amt)
})
// away/save
const away_plan_links = [];
const planMap = {};
person_arr.forEach(item => {
const {
id,
plan_id,
amt
} = item;
if (!planMap[plan_id]) {
planMap[plan_id] = {
plan_id,
use_money: 0,
chuchai_pay_details: []
};
away_plan_links.push(planMap[plan_id]);
}
planMap[plan_id].use_money += parseFloat(amt);
planMap[plan_id].chuchai_pay_details.push(id);
});
console.log("away_plan_links", away_plan_links)
const res = await updateAwayDetails({
away_ids: this.away_ids,
flow_id: flow_id,
chuchai_pay_id: chuchai_pay_id,
chuchai_pay_details: chuchai_pay_details,
money: money
}, true);
console.log("res", res)
await Promise.allSettled(away_plan_links.map((i, index) => {
console.log(i)
planSave({
plan_id: i.plan_id,
use_money: i.use_money,
chuchai_pay_details: i.chuchai_pay_details
})
}))
this.$message.success('操作成功');
this.$emit('refresh');
this.hidden();
}
},
created() {
// this.getBudgets()
}
};
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,266 @@
<template>
<div class="batch-query">
<xy-dialog ref="dialog" :is-show.sync="isShow" type="normal" title="批次查询" @on-ok="confirm">
<el-card class="box-card">
<!-- <template #header>
<div class="card-header">
<span>批次查询</span>
</div>
</template> -->
<!-- 搜索区域 -->
<!-- <div class="search-area">
<el-form :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="审批日期">
<el-date-picker
v-model="searchForm.approveDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="关键词">
<el-input
v-model="searchForm.keyword"
placeholder="请输入批次ID或用户姓名"
clearable
style="width: 200px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch"></el-button>
<el-button @click="handleReset"></el-button>
</el-form-item>
</el-form>
</div> -->
<!-- 批次列表 @row-click="handleRowClick"-->
<xy-table ref="awayTable" :showIndex="false" :default-expand-all="false" row-key="id"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :list="batchList" :table-item="table">
<template #btns> </template>
</xy-table>
<div style="display: flex; justify-content: flex-end;padding: 10px 6px;">
<Page
:total="total"
show-elevator
@on-change="e => {
select.page = e;
getList();
}"
show-sizer
@on-page-size-change="e => {
select.page = 1;
select.page_size = e;
getList();
}"
/>
</div>
<!-- 明细数据 -->
<el-table :data="detailList" style="width: 100%" v-if="showDetail">
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="姓名" width="100" />
<el-table-column prop="processName" label="流程名称" width="150" />
<el-table-column prop="source" label="资金来源" width="100" />
<el-table-column prop="amount" label="金额" width="100" align="right" />
<el-table-column prop="status" label="状态" width="80">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)" size="small">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" width="150" />
<el-table-column prop="createDate" label="创建日期" width="100" />
</el-table>
<!-- 分页 -->
<!-- <div class="pagination-container">
<el-pagination v-model="currentPage" :page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"
@current-change="handleCurrentChange" />
</div> -->
</el-card>
</xy-dialog>
</div>
</template>
<script>
import {
awayIndex
} from "@/api/away"
export default {
data() {
return {
isShow: false,
//
searchForm: {
approveDate: '',
keyword: ''
},
//
batchList: [],
table: [
{
prop: 'zijinlaiyuan',
label: '资金来源',
width: 180,
align: 'left'
},
{
prop: 'xingming_detail',
label: '人员',
width: 180,
align: 'left'
},
{
prop: 'flow.title',
label: '流程名称',
minWidth: 180,
align: 'left'
},
{
prop: 'amt',
label: '报销金额',
width: 120,
align: 'center'
},
{
prop: 'remark',
label: '备注',
align: 'left'
}, {
label: "创建日期",
width: 160,
prop: "form_date",
formatter: (cell, data, value) => {
return this.$moment(value).format("YYYY-MM-DD HH:mm");
},
},
],
//
detailList: [],
showDetail: false,
//
currentPage: 1,
pageSize: 10,
total: 0
};
},
created() {
this.getList()
},
methods: {
async getList() {
const res = await awayIndex({
page: this.currentPage,
page_size: this.pageSize
})
this.total = res.total
let arr = []
res.data.map(item=>{
arr.push({
zijinlaiyuan:item.chuchai_detail.length>0?item.chuchai_detail[0].chuchai_pay.zijinlaiyuan:'',
form_date:item.created_at,
children:item.chuchai_detail
})
})
this.batchList = arr
},
confirm() {
this.isShow = false
},
show() {
this.isShow = true
},
//
getStatusType(status) {
const statusMap = {
'已完成': 'success',
'进行中': 'warning',
'待审批': 'info'
};
return statusMap[status] || '';
},
//
handleSearch() {
console.log('搜索条件:', this.searchForm);
//
},
//
handleReset() {
this.searchForm.approveDate = '';
this.searchForm.keyword = '';
this.handleSearch();
},
//
handleRowClick(row) {
this.showDetail = true;
//
this.detailList = [{
name: row.userName,
processName: '项目A审批',
source: row.source,
amount: row.totalAmount * 0.6,
status: '已完成',
remark: '项目初期资金',
createDate: row.createTime.split(' ')[0]
},
{
name: row.userName,
processName: '项目B审批',
source: row.source,
amount: row.totalAmount * 0.4,
status: '进行中',
remark: '项目中期资金',
createDate: row.createTime.split(' ')[0]
}
];
},
//
handleSizeChange(val) {
this.pageSize = val;
this.handleSearch();
},
handleCurrentChange(val) {
this.currentPage = val;
this.handleSearch();
}
}
};
</script>
<style scoped>
.batch-query {
padding: 20px;
}
.search-area {
margin-bottom: 20px;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
.card-header {
font-weight: bold;
}
:deep(.el-tag--success) {
background-color: #f0f9eb;
}
:deep(.el-tag--warning) {
background-color: #fdf6ec;
}
:deep(.el-tag--info) {
background-color: #f4f4f5;
}
</style>

@ -113,6 +113,13 @@
>批量确认
</Button>
</div>
<div v-if="/Finance/g.test($route.path)">
<Button
type="primary"
@click="showMultiList"
>批次查询
</Button>
</div>
</div>
</slot>
</lx-header>
@ -195,7 +202,7 @@
</template>
</template>
<template v-else #default="{ row }">
<template v-if="row.FLOWSTATUS.expense.getStatus() === 1">
<!-- <template v-if="row.FLOWSTATUS.expense.getStatus() === 1">
<Button
v-if="row.FLOWSTATUS.financial.getStatus() !== 2"
style="margin: 2px;"
@ -205,7 +212,7 @@
ghost
>审核确认
</Button>
</template>
</template> -->
<template v-if="/Finance/g.test($route.path)">
<Button
v-if="isAuthCanExpense(row)"
@ -265,12 +272,14 @@
</div>
</Modal>
<MultiExamine ref="MultiExamine"></MultiExamine>
<MultiExamine ref="MultiExamine" @refresh="$refs.xyTable.clearSelection(),getList"></MultiExamine>
<MultiExamineList ref="MultiExamineList"></MultiExamineList>
</div>
</template>
<script>
import MultiExamine from "@/views/away/component/MultiExamine.vue";
import MultiExamineList from "@/views/away/component/MultiExamineList.vue";
import examineAway from "@/views/away/component/examineAway.vue";
import addAway from "@/views/away/component/addAway.vue"
import { index, destroy, save } from "@/api/away";
@ -282,7 +291,8 @@ export default {
components: {
MultiExamine,
addAway,
examineAway
examineAway,
MultiExamineList
},
data() {
return {
@ -438,9 +448,23 @@ export default {
},
methods: {
showMulti() {
this.$refs['MultiExamine'].setRecords(this.$refs['xyTable'].getSelection())
console.log("this.$refs['xyTable'].getSelection()",this.$refs['xyTable'].getSelection())
let selects = this.$refs['xyTable'].getSelection()
if(selects.length<1){
this.$message.warning('请选择需要确认的出差报销')
return
}
let ids = []
selects.map(item=>{
ids.push(item.id)
})
console.log("ids",ids)
this.$refs['MultiExamine'].setRecords(ids)
this.$refs['MultiExamine'].show()
},
showMultiList() {
this.$refs['MultiExamineList'].show()
},
async getDepartment() {
this.departments = (await listdeptNoAuth())?.data;
},

@ -412,7 +412,9 @@
>
<template slot-scope="scope">
<div class="slot-btns">
{{scope.row.FLOWSTATUS['zhifu']}}
<template v-if="scope.row.FLOWSTATUS['zhifu'].isEnabled()">
<template v-if="scope.row.is_assurance === 1">
<!-- 如果是 履约文件-->
<template v-if="scope.row.assurance_status === 1">
@ -2236,6 +2238,7 @@ export default {
//
handleContractFlow (item) {
console.log("item",item)
class Flow {
status = 0
executable = false

Loading…
Cancel
Save