出差报销 资金明细

master
lion 8 months ago
parent f6280c8a9d
commit 4c032c1f2f

@ -3,7 +3,7 @@ import request from "@/utils/request";
export function getActual(params){
return request({
method:'get',
url:'/api/ht/contract-plan-act-links/index',
url:'/api/ht/contract-plan-act-temp/index',
params
})
}
@ -11,7 +11,7 @@ export function getActual(params){
export function delActual(params){
return request({
method:'get',
url:'/api/ht/contract-plan-act-links/destroy',
url:'/api/ht/contract-plan-act-temp/destroy',
params
})
}
@ -19,7 +19,7 @@ export function delActual(params){
export function editorActual(data){
return request({
method:'post',
url:'/api/ht/contract-plan-act-links/save',
url:'/api/ht/contract-plan-act-temp/save',
data
})
}
@ -27,7 +27,15 @@ export function editorActual(data){
export function detailActual(params){
return request({
method:'get',
url:"/api/ht/contract-plan-act-links/show",
url:"/api/ht/contract-plan-act-temp/show",
params
})
}
export function carryActual(data){
return request({
method:'post',
url:"/api/ht/contract-plan-act-temp/carry",
data
})
}

@ -57,7 +57,12 @@
width: 120,
align: 'left'
},
{
prop: 'zijinlaiyuan',
label: '资金来源',
minWidth: 240,
align: 'left'
},
{
prop: 'flow.title',
label: '流程名称',
@ -133,24 +138,24 @@
parent: null, //
isSelect: false //
};
const innerData = originalData[xingming_details];
innerData.map(item=>{
item.isSelect = false
})
const innerData = originalData[xingming_details];
innerData.map(item => {
item.isSelect = false
})
person.children.push(...innerData)
// const source = {
// id: Math.random(),
// name: '',
// children: innerData.map((item) => ({
// ...item,
// name: item.xingming_detail,
// parent: source, //
// isSelect: false //
// })),
// parent: person, //
// isSelect: false //
// };
// person.children.push(source);
// const source = {
// id: Math.random(),
// name: '',
// children: innerData.map((item) => ({
// ...item,
// name: item.xingming_detail,
// parent: source, //
// isSelect: false //
// })),
// parent: person, //
// isSelect: false //
// };
// person.children.push(source);
result.push(person);
}

@ -1,163 +1,166 @@
<template>
<div style="padding: 0 20px">
<lx-header
icon="md-apps"
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
text="实际使用金额"
>
<div slot="content"></div>
<slot>
<div class="selects">
<!-- <div>
<span style="padding: 0 6px; word-break: keep-all"> 关键字 </span>
<Input
v-model="select.keyword"
placeholder="请输入关键字"
style="width: 180px"
></Input>
</div>
<Button style="margin-left: 10px" type="primary" @click=""
>重置
</Button>
<Button style="margin-left: 10px" type="primary" @click="getList"
>查询</Button
> -->
<Button
style="margin-left: 10px"
type="primary"
@click="
($refs['addActual'].type = 'add'), $refs['addActual'].show()
"
>新增</Button
>
</div>
</slot>
</lx-header>
<xy-table
:list="list"
:table-item="table"
>
<template #btns>
<el-table-column :fixed="$store.getters.device === 'mobile'?false:'right'" label="操作" align="left" width="200">
<template #default="{ row }">
<div style="display: flex;align-items: flex-start;">
<Button
ghost
size="small"
type="primary"
@click="
($refs['addActual'].id = row.id),
($refs['addActual'].type = 'editor'),
$refs['addActual'].show()
"
>编辑</Button
>
<Poptip
:transfer="true"
confirm
placement="bottom"
title="确认要删除吗"
@on-ok="destroy(row)"
>
<Button style="margin-left: 4px;" size="small" type="error" ghost>删除</Button>
</Poptip>
</div>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page
:total="total"
@on-change="e => {
select.page = e;
getList()
}"
show-elevator
show-sizer
@on-page-size-change="e => {
select.page = 1;
select.page_size = e;
getList();
}"
/>
</div>
<addActual
:plan_department_ids="depts"
ref="addActual"
@refresh="getList"
></addActual>
</div>
</template>
<script>
import { getActual, delActual } from "@/api/budget/actual";
import addActual from "./components/addActual.vue";
export default {
components: {
addActual,
},
data() {
return {
depts: [],
select: {
page: 1,
page_size: 10,
},
total: 0,
table: [
{
label: "资金来源所属年份",
prop: "plan.year",
width: 180,
},
{
label: "资金来源",
prop: "plan.name",
// width: 180,
},
{
label: "使用金额",
prop: "use_money",
width: 200,
}
],
list: [],
};
},
methods: {
async getList() {
const res = await getActual(this.select);
this.list = res.data;
this.total = res.total || 0;
},
destroy (row) {
delActual({
id: row.id
}).then(res => {
this.$message({
type: 'success',
message: '删除成功'
})
this.getList()
})
}
},
computed: {},
created() {
this.getList();
},
};
</script>
<style scoped lang="scss">
.selects {
display: flex;
align-items: center;
flex-wrap: wrap;
}
<template>
<div style="padding: 0 20px">
<lx-header icon="md-apps" style="margin-bottom: 10px; border: 0px; margin-top: 15px" text="实际使用金额">
<div slot="content"></div>
<slot>
<div class="selects">
<!-- <div>
<span style="padding: 0 6px; word-break: keep-all"> 关键字 </span>
<Input
v-model="select.keyword"
placeholder="请输入关键字"
style="width: 180px"
></Input>
</div>
<Button style="margin-left: 10px" type="primary" @click=""
>重置
</Button>
<Button style="margin-left: 10px" type="primary" @click="getList"
>查询</Button
> -->
<Button style="margin-left: 10px" type="primary" @click="
($refs['addActual'].type = 'add'), $refs['addActual'].show()
">新增</Button>
</div>
</slot>
</lx-header>
<xy-table :list="list" :table-item="table">
<template #btns>
<el-table-column :fixed="$store.getters.device === 'mobile'?false:'right'" label="操作" align="left" width="200">
<template #default="{ row }">
<div style="display: flex;align-items: flex-start;">
<Button style="margin-right: 4px;" v-if="calculateTotalUseMoney(row.plan_act_links)<parseFloat(row.money)" ghost size="small" type="primary" @click="execute(row)"></Button>
<Button style="margin-right: 4px;" ghost size="small" type="primary" @click="
($refs['addActual'].id = row.id),
($refs['addActual'].type = 'editor'),
$refs['addActual'].show()
">编辑</Button>
<Poptip :transfer="true" confirm placement="bottom"
:title="row.plan_act_links.length>0?'已有执行记录,确认要连同执行记录一同删除?':'确认要删除吗?'" @on-ok="destroy(row)">
<Button size="small" type="error" ghost>删除</Button>
</Poptip>
</div>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page :total="total" @on-change="e => {
select.page = e;
getList()
}" show-elevator show-sizer @on-page-size-change="e => {
select.page = 1;
select.page_size = e;
getList();
}" />
</div>
<addActual :plan_department_ids="depts" ref="addActual" @refresh="getList"></addActual>
<exeActual ref="exeActual" @refresh="getList"></exeActual>
</div>
</template>
<script>
import {
getActual,
delActual,
} from "@/api/budget/actual";
import addActual from "./components/addActual.vue";
import exeActual from "./components/exeActual.vue";
export default {
components: {
addActual,
exeActual
},
data() {
return {
depts: [],
select: {
page: 1,
page_size: 10,
},
visible: false,
total: 0,
table: [{
label: "资金来源所属年份",
prop: "plan.year",
width: 120,
},
{
label: "事由",
prop: "reason",
width: 180,
align: 'left'
},
{
label: "资金来源",
prop: "plan.name",
align: 'left'
// width: 180,
},
{
label: "金额",
prop: "money",
width: 180,
},
{
label: "已使用金额",
prop: "use_money",
width: 180,
formatter: (row, v2, value) => {
return this.calculateTotalUseMoney(row.plan_act_links)
}
}
],
list: [],
};
},
methods: {
async getList() {
const res = await getActual(this.select);
this.list = res.data;
this.total = res.total || 0;
},
calculateTotalUseMoney(plan_act_links) {
let total = 0;
for (let i = 0; i < plan_act_links.length; i++) {
const useMoney = parseFloat(plan_act_links[i].use_money);
if (!isNaN(useMoney)) {
total += useMoney;
}
}
return parseFloat(total).toFixed(2);
},
destroy(row) {
delActual({
id: row.id
}).then(res => {
this.$message({
type: 'success',
message: '删除成功'
})
this.getList()
})
},
execute(row) {
this.$refs.exeActual.setForm(row.id,row.plan_act_links)
this.$refs.exeActual.isShow = true
}
},
computed: {},
created() {
this.getList();
},
};
</script>
<style scoped lang="scss">
.selects {
display: flex;
align-items: center;
flex-wrap: wrap;
}
</style>

@ -1,240 +1,252 @@
<template>
<div>
<xy-dialog
ref="dialog"
:is-show.sync="isShow"
type="form"
:title="type === 'add' ? '新增实际使用金额' : '编辑实际使用金额'"
:form="form"
:rules="rules"
@submit="submit"
>
<template v-slot:plan_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red; font-weight: 600; padding-right: 4px"
>*</span
>
资金来源
</div>
<div class="xy-table-item-content">
<div class="planTitle" @click="$refs.actualPicker.isShow=true">{{form.plan_title}}</div>
<!-- <el-input
v-model="form.plan_title"
disabled
clearable
placeholder="请输入备注"
style="width: 300px"
@click="$refs.actualPicker.isShow=true"
></el-input> -->
</div>
</div>
</template>
<template v-slot:use_money>
<div class="xy-table-item">
<div class="xy-table-item-label"><span style="color: red; font-weight: 600; padding-right: 4px"
>*</span
>使用金额 </div>
<div class="xy-table-item-content">
<el-input
v-model="form.use_money"
clearable
placeholder="请输入备注"
style="width: 300px"
></el-input>
</div>
</div>
</template>
</xy-dialog>
<actualPicker ref="actualPicker" @refresh="getPlanId"></actualPicker>
</div>
</template>
<script>
import { editorActual, detailActual } from "@/api/budget/actual";
import actualPicker from "@/components/PlanPicker/actualPicker.vue"
export default {
components:{
actualPicker
},
data() {
return {
isShow: false,
id: "",
type: "",
form: {
plan_id:'',
use_money:'',
plan_title:''
},
rules: {
plan_id: [
{
required: true,
message: "请选择资金来源",
},
],
use_money: [
{
required: true,
message: "请填写使用金额",
},
],
},
};
},
methods: {
show() {
this.isShow = true;
},
hidden() {
this.isShow = false;
},
init() {
this.form = {
plan_id:'',
use_money:''
};
},
setForm(key = [], value = []) {
if (key instanceof Array) {
key.forEach((key, index) => {
this.form[key] = value[index] ?? "";
});
}
if (typeof key === "string") {
this.form[key] = value;
}
if (!key) {
this.init();
}
},
async getDetail() {
const res = await detailActual({ id: this.id });
this.$integrateData(this.form, res);
this.form.plan_title = res.plan?res.plan.name:''
},
getPlanId(e){
console.log("e",e)
this.form.plan_id = e.plan_id?e.plan_id:''
this.form.plan_title = e.plan_title?e.plan_title:''
},
submit() {
if (this.type === "add") {
if (this.form.hasOwnProperty("id")) {
delete this.form.id;
}
}
if (this.type === "editor") {
Object.defineProperty(this.form, "id", {
value: this.id,
enumerable: true,
configurable: true,
writable: true,
});
}
editorActual(this.form).then((res) => {
this.$message({
type: "success",
message:
this.type === "add"
? "新增实际使用金额"
: "编辑实际使用金额" + "成功",
});
this.isShow = false;
this.$emit("refresh");
});
},
},
watch: {
isShow(val) {
if (val) {
if (this.type === "editor") {
this.getDetail();
}
} else {
this.id = "";
this.type = "";
this.init();
this.$refs["dialog"].clearValidate();
delete this.form.id;
}
},
},
};
</script>
<style scoped lang="scss">
.xy-table-item-label{
width: 180px;
}
::v-deep .el-input__inner {
text-align: left;
}
::v-deep .planTitle{
width:300px;
display: flex;
background-color: #FFF;
background-image: none;
border-radius: 4px;
border: 1px solid #DCDFE6;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: 0;
padding: 0 15px;
}
.img__delete {
transform: scale(0.8, 0.8);
position: absolute;
top: 4px;
right: 4px;
}
::v-deep .avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
::v-deep .avatar-uploader .el-upload:hover {
border-color: #338de3;
}
::v-deep .el-upload--picture-card {
font-size: 28px;
color: #8c939d;
width: 80px !important;
height: 80px !important;
line-height: 80px !important;
text-align: center;
}
::v-deep .avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 80px !important;
height: 80px !important;
line-height: 80px !important;
text-align: center;
}
::v-deep .avatar {
width: 80px !important;
display: block;
border-radius: 6px;
}
::v-deep .el-input__inner {
text-align: left;
}
<template>
<div>
<xy-dialog ref="dialog" :is-show.sync="isShow" type="form" :title="type === 'add' ? '新增实际使用金额' : '编辑实际使用金额'"
:form="form" :rules="rules" @submit="submit">
<template v-slot:reason>
<div class="xy-table-item">
<div class="xy-table-item-label"><span style="color: red; font-weight: 600; padding-right: 4px">*</span>事由
</div>
<div class="xy-table-item-content">
<el-input v-model="form.reason" clearable placeholder="请输入事由" style="width: 300px"></el-input>
</div>
</div>
</template>
<template v-slot:plan_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red; font-weight: 600; padding-right: 4px">*</span>
资金来源
</div>
<div class="xy-table-item-content">
<div class="planTitle" @click="$refs.actualPicker.isShow=true">{{form.plan_title}}</div>
</div>
</div>
</template>
<template v-slot:money>
<div class="xy-table-item">
<div class="xy-table-item-label"><span style="color: red; font-weight: 600; padding-right: 4px">*</span>金额
</div>
<div class="xy-table-item-content">
<el-input v-model="form.money" clearable placeholder="请输入金额" style="width: 300px"></el-input>
</div>
</div>
</template>
<!-- <template v-slot:use_money>
<div class="xy-table-item">
<div class="xy-table-item-label"><span style="color: red; font-weight: 600; padding-right: 4px">*</span>已使用金额
</div>
<div class="xy-table-item-content">
<el-input v-model="form.use_money" clearable placeholder="请输入已使用金额" style="width: 300px"></el-input>
</div>
</div>
</template> -->
</xy-dialog>
<actualPicker ref="actualPicker" @refresh="getPlanId"></actualPicker>
</div>
</template>
<script>
import {
editorActual,
detailActual
} from "@/api/budget/actual";
import actualPicker from "@/components/PlanPicker/actualPicker.vue"
export default {
components: {
actualPicker
},
data() {
return {
isShow: false,
id: "",
type: "",
form: {
reason: '',
plan_id: '',
money: '',
// use_money: '',
plan_title: ''
},
rules: {
reason: [{
required: true,
message: "请填写事由",
}],
plan_id: [{
required: true,
message: "请选择资金来源",
}],
money:[{
required: true,
message: "请填写金额",
}],
// use_money: [{
// required: true,
// message: "使",
// }],
},
}
},
methods: {
show() {
this.isShow = true;
},
hidden() {
this.isShow = false;
},
init() {
this.form = {
reason: '',
plan_id: '',
money:'',
// use_money: '',
plan_title: ''
};
},
setForm(key = [], value = []) {
if (key instanceof Array) {
key.forEach((key, index) => {
this.form[key] = value[index] ?? "";
});
}
if (typeof key === "string") {
this.form[key] = value;
}
if (!key) {
this.init();
}
},
async getDetail() {
const res = await detailActual({
id: this.id
});
this.$integrateData(this.form, res);
this.form.plan_title = res.plan ? res.plan.name : ''
},
getPlanId(e) {
console.log("e", e)
this.form.plan_id = e.plan_id ? e.plan_id : ''
this.form.plan_title = e.plan_title ? e.plan_title : ''
},
submit() {
if (this.type === "add") {
if (this.form.hasOwnProperty("id")) {
delete this.form.id;
}
}
if (this.type === "editor") {
Object.defineProperty(this.form, "id", {
value: this.id,
enumerable: true,
configurable: true,
writable: true,
});
}
editorActual(this.form).then((res) => {
this.$message({
type: "success",
message: this.type === "add" ?
"新增资金调节记录" :
"编辑资金调节记录" + "成功",
});
this.isShow = false;
this.$emit("refresh");
});
},
},
watch: {
isShow(val) {
if (val) {
if (this.type === "editor") {
this.getDetail();
}
} else {
this.id = "";
this.type = "";
this.init();
this.$refs["dialog"].clearValidate();
delete this.form.id;
}
},
},
};
</script>
<style scoped lang="scss">
.xy-table-item-label {
width: 180px;
}
::v-deep .el-input__inner {
text-align: left;
}
::v-deep .planTitle {
width: 300px;
display: flex;
background-color: #FFF;
background-image: none;
border-radius: 4px;
border: 1px solid #DCDFE6;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: 0;
padding: 0 15px;
}
.img__delete {
transform: scale(0.8, 0.8);
position: absolute;
top: 4px;
right: 4px;
}
::v-deep .avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
::v-deep .avatar-uploader .el-upload:hover {
border-color: #338de3;
}
::v-deep .el-upload--picture-card {
font-size: 28px;
color: #8c939d;
width: 80px !important;
height: 80px !important;
line-height: 80px !important;
text-align: center;
}
::v-deep .avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 80px !important;
height: 80px !important;
line-height: 80px !important;
text-align: center;
}
::v-deep .avatar {
width: 80px !important;
display: block;
border-radius: 6px;
}
::v-deep .el-input__inner {
text-align: left;
}
</style>

@ -0,0 +1,177 @@
<template>
<div>
<xy-dialog ref="dialog" :is-show.sync="isShow" type="form" title="确认执行" :form="form" :rules="rules"
@submit="submit">
<template v-slot:use_money>
<div class="xy-table-item">
<div class="xy-table-item-label"><span style="color: red; font-weight: 600; padding-right: 4px">*</span>使用金额
</div>
<div class="xy-table-item-content">
<el-input v-model="form.use_money" clearable placeholder="请输入本次使用金额" style="width: 300px"></el-input>
</div>
</div>
</template>
<template v-slot:plan_act_links>
<div class="xy-table-item">
<div class="xy-table-item-label"><span style="color: red; font-weight: 600; padding-right: 4px"></span>执行记录
</div>
<div class="xy-table-item-content">
<xy-table style="width:500px" :list="form.plan_act_links" :table-item="table">
<template #btns>
<div></div>
</template>
</xy-table>
</div>
</div>
</template>
</xy-dialog>
</div>
</template>
<script>
import {
carryActual
} from "@/api/budget/actual";
export default {
components: {},
data() {
return {
isShow: false,
form: {
use_money: '',
plan_act_links: '',
contract_plan_act_temp_id: ''
},
table: [{
label: "使用金额",
prop: "use_money",
}, {
label: "执行时间",
prop: "created_at",
width: 180,
}],
rules: {
use_money: [{
required: true,
message: "请填写使用金额",
}],
},
}
},
methods: {
show() {
this.isShow = true;
},
hidden() {
this.isShow = false;
},
init() {
this.form = {
use_money: '',
plan_act_links: [],
contract_plan_act_temp_id: ''
};
},
setForm(contract_plan_act_temp_id, plan_act_links) {
this.form.contract_plan_act_temp_id = contract_plan_act_temp_id
this.form.plan_act_links = plan_act_links
},
submit() {
carryActual(this.form).then((res) => {
this.$message({
type: "success",
message: "执行成功",
});
this.isShow = false;
this.$emit("refresh");
});
},
},
watch: {
isShow(val) {
if (val) {
} else {
this.init();
this.$refs["dialog"].clearValidate();
}
},
},
};
</script>
<style scoped lang="scss">
.xy-table-item-label {
width: 180px;
}
::v-deep .el-input__inner {
text-align: left;
}
::v-deep .planTitle {
width: 300px;
display: flex;
background-color: #FFF;
background-image: none;
border-radius: 4px;
border: 1px solid #DCDFE6;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: 0;
padding: 0 15px;
}
.img__delete {
transform: scale(0.8, 0.8);
position: absolute;
top: 4px;
right: 4px;
}
::v-deep .avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
::v-deep .avatar-uploader .el-upload:hover {
border-color: #338de3;
}
::v-deep .el-upload--picture-card {
font-size: 28px;
color: #8c939d;
width: 80px !important;
height: 80px !important;
line-height: 80px !important;
text-align: center;
}
::v-deep .avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 80px !important;
height: 80px !important;
line-height: 80px !important;
text-align: center;
}
::v-deep .avatar {
width: 80px !important;
display: block;
border-radius: 6px;
}
::v-deep .el-input__inner {
text-align: left;
}
</style>
Loading…
Cancel
Save