Compare commits

...

12 Commits

@ -1,7 +1,7 @@
<template>
<div id="app">
<router-view />
<ThemePicker style="display: none;" />
<!-- <ThemePicker style="display: none;" /> -->
</div>
</template>

@ -1,28 +1,40 @@
import request from '@/utils/request'
function customParamsSerializer(params) {
let result = ''
for (const key in params) {
let result = '';
for (let key in params) {
if (params.hasOwnProperty(key)) {
if (Array.isArray(params[key])) {
params[key].forEach((item, index) => {
if (item instanceof Array) {
item.forEach((item1, index1) => {
result += `${key}[${index}][${index1}]=${item1}&`
})
} else if (typeof item === 'object') {
for (const key1 in item) {
result += `${key}[${index}][${key1}]=${item[key1]}&`
}
params[key].forEach((item,index) => {
if(item.key){
result += `${key}[${index}][key]=${item.key}&${key}[${index}][op]=${item.op}&${key}[${index}][value]=${item.value}&`;
}else{
result +=`${key}[${index}]=${item}&`
}
// result += `${key}[${index}][key]=${item.key}&${key}[${index}][op]=${item.op}&${key}[${index}][value]=${item.value}&`;
})
});
}else if( typeof params[key] === 'object' ){
for(var k in params[key]){
result +=`${key}[${k}]=${params[key][k]}&`
}
} else {
result += `${key}=${params[key]}&`
result += `${key}=${params[key]}&`;
}
}
}
return result.slice(0, -1)
// result += 'token='+getToken()
console.log("result",result, result.slice(0, -1))
return result.slice(0, -1);
}
export function endIndex2(params, noloading = false) {
return request({
method: 'get',
url: '/api/ht/contract/end-index-v2',
params,
noloading,
paramsSerializer: customParamsSerializer
})
}
export function endIndex(params, noloading = false) {
return request({

@ -0,0 +1,34 @@
import request from '@/utils/request'
export function getCollect(params, noloading = false) {
return request({
method: 'get',
url: '/api/ht/fund_log_collect/index',
params,
noloading
})
}
export function addCollect(data) {
return request({
method: 'post',
url: '/api/ht/fund_log_collect/save',
data
})
}
export function delCollect(params) {
return request({
method: 'get',
url: '/api/ht/fund_log_collect/destroy',
params
})
}
export function detailCollect(params) {
return request({
method: 'get',
url: '/api/ht/fund_log_collect/show',
params
})
}

@ -0,0 +1,18 @@
import request from '@/utils/request'
export function getPlanActLinks(params, noloading = false) {
return request({
method: 'get',
url: '/api/ht/fund_log/index',
params,
noloading
})
}
export function updateContractPlanActLinks(data) {
return request({
method: 'post',
url: '/api/ht/fund_log/update-contract-plan-act-links',
data
})
}

@ -167,7 +167,7 @@
<div class="info-item">
<span class="info-label">工作名称</span>
<span class="info-value">{{ shOaView.title? shOaView.title : '-' }}<span class="action-link" @click.stop="viewFlow(shOaView.id)">查看</span></span>
</div>
<div class="info-item">
<span class="info-label">申请人</span>
@ -660,7 +660,7 @@ export default {
flowLinksOfRound(roundIndex) {
const list = Array.isArray(this.fundLogs) ? this.fundLogs : []
const item = list[roundIndex]
const links = item && Array.isArray(item.fund_log_flow_links) ? item.fund_log_flow_links : []
const links = item && Array.isArray(item.fund_log_collect.flow_links) ? item.fund_log_collect.flow_links : []
return links
},
//
@ -677,7 +677,7 @@ export default {
//
this.resetComponent()
},
//
resetComponent() {
this.id = ''
@ -692,13 +692,13 @@ export default {
this.contractApprovalFlows = []
this.paymentApprovalFlows = []
},
// URL
resetAndLoadFromUrl() {
this.resetComponent()
this.checkUrlAndLoadData()
},
//
retryLoad() {
if (this.id) {
@ -707,7 +707,7 @@ export default {
this.detail = this.contractData
}
},
// URL
checkUrlAndLoadData() {
const outContractId = this.$route.query.out_contract_id
@ -947,7 +947,7 @@ export default {
console.log('合同详情抽屉组件加载完成')
// immediate
},
beforeDestroy() {
//
this.resetComponent()
@ -1479,43 +1479,43 @@ export default {
.step-content {
grid-template-columns: 1fr;
}
.expense-info-content {
grid-template-columns: 1fr;
}
.expense-info-item {
flex-direction: column;
align-items: flex-start;
gap: 5px;
}
.expense-info-value {
text-align: left;
}
.overview-step {
width: 80px;
height: 50px;
font-size: 0.7rem;
}
.overview-step.payment {
width: 60px;
height: 40px;
font-size: 0.6rem;
}
.payment-group-container {
padding: 5px;
gap: 5px;
}
.round-step-detail {
width: 120px;
height: 70px;
}
.round-step-title-detail {
font-size: 0.7rem;
}

@ -0,0 +1,125 @@
import axios from "axios";
import { getToken } from "@/utils/auth";
import { Loading, Message } from "element-ui";
/*
* @params {string} url 请求拼接地址
* @params {object} info 请求参数params或data
*/
let loading;
function customParamsSerializer(params) {
let result = '';
for (let key in params) {
if (params.hasOwnProperty(key)) {
if (Array.isArray(params[key])) {
params[key].forEach((item,index) => {
if(item.key){
result += `${key}[${index}][key]=${item.key}&${key}[${index}][op]=${item.op}&${key}[${index}][value]=${item.value}&`;
}else{
result +=`${key}[${index}]=${item}&`
}
});
}else if( typeof params[key] === 'object' ){
for(var k in params[key]){
result +=`${key}[${k}]=${params[key][k]}&`
}
} else {
result += `${key}=${params[key]}&`;
}
}
}
// result += 'token='+getToken()
console.log("result",result, result.slice(0, -1))
return result.slice(0, -1);
}
export async function download(url, method = "get", info, filename) {
loading = Loading.service({
lock: true,
background: "rgba(0,0,0,0.4)",
text: "文件正在生成中...",
});
let options = {
baseURL: process.env.VUE_APP_BASE_API,
url,
method,
responseType: "blob",
timeout: 10000,
headers: {
Accept: "application/json",
"Content-Type": "application/json; charset=utf-8",
withCredentials: true,
Authorization: "Bearer " + getToken(),
},
};
if (method === "get") {
// options.url = url+'?'+customParamsSerializer(info)
Object.defineProperty(options, "params", {
value: info,
enumerable: true,
writable: false,
});
}
if (method === "post") {
Object.defineProperty(options, "data", {
value: info,
enumerable: true,
writable: false,
});
}
try {
if(options.method==='get'){
options.paramsSerializer = customParamsSerializer
}
console.log("options",options)
const response = await axios.request(options);
loading.close();
// 提取文件名
if (!filename) {
filename =
response.headers["content-disposition"]?.match(/filename=(.*)/)[1] ||
"";
}
// 将二进制流转为blob
const blob = new Blob([response.data], {
type: "application/octet-stream",
});
if (typeof window.navigator.msSaveBlob !== "undefined") {
// 兼容IEwindow.navigator.msSaveBlob以本地方式保存文件
window.navigator.msSaveBlob(blob, decodeURI(filename));
} else {
// 创建新的URL并指向File对象或者Blob对象的地址
const blobURL = window.URL.createObjectURL(blob);
// 创建a标签用于跳转至下载链接
const tempLink = document.createElement("a");
tempLink.style.display = "none";
tempLink.href = blobURL;
tempLink.setAttribute("download", decodeURI(filename));
// 兼容某些浏览器不支持HTML5的download属性
if (typeof tempLink.download === "undefined") {
tempLink.setAttribute("target", "_blank");
}
// 挂载a标签
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
// 释放blob URL地址
window.URL.revokeObjectURL(blobURL);
}
} catch (err) {
console.error(err);
loading.close();
Message({
type: "error",
message: err,
});
}
}

@ -16,12 +16,12 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item
prop="meeting_flow_id"
<el-form-item
prop="meeting_flow_id"
label="资金上会流程"
>
<el-select
v-model="form.meeting_flow_id"
<el-select
v-model="form.meeting_flow_id"
style="width: 100%"
:disabled="isMeetingFlowDisabled"
placeholder="请选择资金上会流程"
@ -32,11 +32,11 @@
v-for="item in shList"
:key="item.id"
:value="item.id"
:label="item.data.yiti+'-'+item.title"
:label="item.data?(item.data.yiti?item.data.yiti:''):''+'-'+item.title"
>
<span style="float: left">{{ item.data.yiti }}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
<span style="float: left">{{ item.data?(item.data.yiti?item.data.yiti:''):''}}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
@click.stop="viewOaFlow(item.id)"
>查看</span>
</el-option>
@ -1056,12 +1056,12 @@ export default {
}
}
},
//
isMeetingFlowRequired() {
return !this.form.is_common_purchase && this.form.total_money && Number(this.form.total_money) >= 100000
},
//
isMeetingFlowDisabled() {
//
@ -1082,7 +1082,7 @@ export default {
// toOaDetail
// toOaDetail
let url = `${process.env.VUE_APP_OUT_URL}/#/flow/detail?auth_token=${window.encodeURIComponent(getToken())}&isSinglePage=1&flow_id=${flowId}`
this.oaUrl = url
this.isShowOaModal = true
},
@ -1093,7 +1093,8 @@ export default {
page_size:999,
custom_model_id:103,
sort_name:'created_at',
sort_type:'DESC'
sort_type:'DESC',
is_simple: 1
})
this.shList = res.data.data
},

@ -40,11 +40,11 @@
v-for="item in shList"
:key="item.id"
:value="item.id"
:label="item.data.yiti+'-'+item.title"
:label="item.data?(item.data.yiti?item.data.yiti:''):'' +'-'+item.title"
>
<span style="float: left">{{ item.data.yiti }}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
<span style="float: left">{{ item.data?(item.data.yiti?item.data.yiti:''):'' }}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
@click.stop="viewOaFlow(item.id)"
>查看</span>
</el-option>
@ -189,7 +189,7 @@
<!-- </div>-->
</template>
</xy-dialog>
<!-- OA流程Modal -->
<Modal
v-model="isShowOaModal"
@ -336,12 +336,12 @@ export default {
return moneyFormatter(money)
}
},
//
isMeetingFlowRequired() {
return this.form.apply_money && Number(this.form.apply_money) >= 50000
},
//
isMeetingFlowDisabled() {
return this.form.apply_money && Number(this.form.apply_money) < 50000
@ -355,7 +355,7 @@ export default {
// OA
viewOaFlow(flowId) {
const url = `${process.env.VUE_APP_OUT_URL}/#/flow/detail?auth_token=${window.encodeURIComponent(getToken())}&isSinglePage=1&flow_id=${flowId}`
this.oaUrl = url
this.isShowOaModal = true
},
@ -368,7 +368,8 @@ export default {
page_size: 999,
custom_model_id: 103,
sort_name: 'created_at',
sort_type: 'DESC'
sort_type: 'DESC',
is_simple: 1
})
this.shList = res?.data?.data || []
} catch (e) {

File diff suppressed because it is too large Load Diff

@ -192,14 +192,14 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item
prop="meeting_flow_id"
<el-form-item
prop="meeting_flow_id"
label="资金上会流程"
>
<!-- 调试信息 -->
<el-select
v-model="form.meeting_flow_id"
<el-select
v-model="form.meeting_flow_id"
style="width: 100%"
:disabled="isMeetingFlowDisabled"
placeholder="请选择资金上会流程"
@ -210,11 +210,11 @@
v-for="item in shList"
:key="item.id"
:value="item.id"
:label="item.data.yiti+'-'+item.title"
:label="item.data?(item.data.yiti?item.data.yiti:''):''+'-'+item.title"
>
<span style="float: left">{{ item.data.yiti }}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
<span style="float: left">{{ item.data?(item.data.yiti?item.data.yiti:''):'' }}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
@click.stop="viewOaFlow(item.id)"
>查看</span>
</el-option>
@ -327,7 +327,7 @@
<el-form-item
prop="flow_mod_id"
label="事前流程"
label="采购事项类别"
v-if="!form.is_simple"
>
<el-select v-model="form.flow_mod_id" style="width: 100%">
@ -695,14 +695,14 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item
prop="meeting_flow_id"
<el-form-item
prop="meeting_flow_id"
label="资金上会流程"
>
<!-- 调试信息 -->
<el-select
v-model="form.meeting_flow_id"
<el-select
v-model="form.meeting_flow_id"
style="width: 100%"
:disabled="isMeetingFlowDisabled"
placeholder="请选择资金上会流程"
@ -713,11 +713,11 @@
v-for="item in shList"
:key="item.id"
:value="item.id"
:label="item.data.yiti+'-'+item.title"
:label="item.data?(item.data.yiti?item.data.yiti:''):''+'-'+item.title"
>
<span style="float: left">{{ item.data.yiti }}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
<span style="float: left">{{ item.data?(item.data.yiti?item.data.yiti:''):'' }}-{{ item.title }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px; cursor: pointer;"
@click.stop="viewOaFlow(item.id)"
>查看</span>
</el-option>
@ -1230,7 +1230,7 @@
>
</div>
<div>
<el-button
<!-- <el-button
@click="
(showTypes = false),
(myPurchaseType = 1),
@ -1239,8 +1239,23 @@
(step = 2),
(showEdit = true)
"
>维修相关</el-button
>
>采购事项类别</el-button
> -->
<el-select
v-model="form.flow_mod_id"
style="width: 220px; margin-bottom: 16px"
placeholder="请选择采购事项类别"
filterable
clearable
@change="handlePurchaseTypeChange"
>
<el-option
v-for="item in flowIdsFormat"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</div>
<div>
<el-button
@ -1253,14 +1268,14 @@
(showEdit = true),
toggleBudgetByFlowModId()
"
>预算计划支出</el-button
>直接支付</el-button
>
</div>
</div>
</div>
</div>
<otherPlan ref="otherPlan" @getPlan="getSelectionPlan"></otherPlan>
<!-- OA流程Modal -->
<Modal
v-model="isShowOaModal"
@ -1276,7 +1291,7 @@
<iframe style="width: 100%;height: 100%;border-radius: 0 0 6px 6px;" :src="oaUrl" frameborder="0" />
</div>
</Modal>
<!-- <span>请选择类型</span>
<span slot="footer" class="dialog-footer" style="display: flex;justify-content: flex-end;">
<el-button @click="step = 2,myPurchaseType = 2,isWeixiu=false,form.is_common_purchase = 1,form.flow_mod_id = 99,showTypes = false,showEdit=true">一般采购</el-button>
@ -1727,11 +1742,19 @@ export default {
};
},
methods: {
handlePurchaseTypeChange(id) {
this.showTypes = false;
this.myPurchaseType = 1;
this.isWeixiu = true;
this.form.is_common_purchase = 0;
this.step = 2;
this.showEdit = true;
},
// OA
viewOaFlow(flowId) {
// toOaDetail
let url = `${process.env.VUE_APP_OUT_URL}/#/flow/detail?auth_token=${window.encodeURIComponent(getToken())}&isSinglePage=1&flow_id=${flowId}`
this.oaUrl = url
this.isShowOaModal = true
},
@ -1743,7 +1766,8 @@ export default {
page_size:999,
custom_model_id:103,
sort_name:'created_at',
sort_type:'DESC'
sort_type:'DESC',
is_simple: 1
})
this.shList = res.data.data
},
@ -1814,6 +1838,14 @@ export default {
if (this.form.hasOwnProperty(key)) {
this.form[key] = defaultJSON[key];
}
if(this.form.flow_mod_id){
this.showEdit = true;
this.showTypes = false;
this.isWeixiu = true;
this.myPurchaseType = 1;
this.form.is_common_purchase = 0;
this.step = 2;
}
}
} catch (e) {
console.error(e);
@ -2288,8 +2320,8 @@ export default {
this.step = 3;
})
.catch((_) => (this.btnLoading = false));
}
},
}
},
computed: {
flowIdsFormat() {
let temp = this.form.is_trade;
@ -2355,7 +2387,7 @@ export default {
let temp = this.form.contract_to_contracts;
return this.$refs["contractToContractsTable"]?.getSelection() || [];
},
//
isMeetingFlowRequired() {
console.log("isMeetingFlowRequired triggered:", {
@ -2365,7 +2397,7 @@ export default {
})
return !this.form.is_common_purchase && this.form.total_money && Number(this.form.total_money) >= 100000
},
//
isMeetingFlowDisabled() {
console.log("isMeetingFlowDisabled triggered:", {
@ -2374,13 +2406,13 @@ export default {
is_common_purchase_result: this.form.is_common_purchase,
amount_check: this.form.total_money && Number(this.form.total_money) < 100000
})
//
if (this.form.is_common_purchase) {
console.log("is_common_purchase is true, returning false")
return false
}
// 10
const result = this.form.total_money && Number(this.form.total_money) < 100000
console.log("Final result:", result)
@ -2433,6 +2465,7 @@ export default {
},
beforeRouteEnter(to, from, next) {
const { contractId, myPurchaseType } = to.query;
console.log('to.query',to)
if (contractId) {
next((vm) => {
vm.contractId = contractId;
@ -2499,6 +2532,7 @@ export default {
}
&-types {
width: 30%;
margin-left:15px;
.el-button {
margin-bottom: 10px;
}

@ -615,11 +615,10 @@
>
流程附件
</Button>
<!--
($refs['editor'].isShowEditor = true,
$refs['editor'].getDetail(scope.row.id))
-->
// <!--
// ($refs['editor'].isShowEditor = true,
// $refs['editor'].getDetail(scope.row.id))
// -->
<template v-if="scope.row.status != 2 || hasEdit">
<Button
class="slot-btns-item"
@ -2769,9 +2768,19 @@ export default {
this.select.is_contract = 1
// TODO:
// / this.select.purchase_status = 3;
this.select.invite_status = 3
this.select['flow_link[0][custom_model_id]'] = 71
this.select['flow_link[0][flow_status]'] = 1
// this.select.invite_status = 3
// this.select['flow_link[0][custom_model_id]'] = 71
// this.select['flow_link[0][flow_status]'] = 1
this.select.is_simple = ''
this.select.is_purchase = ''
this.select.outcome_type = ''
this.select.invite_status = ''
}
if(this.$route.path.split('_')[1]){
this.select.is_simple = ''
this.select.is_purchase = ''
this.select.outcome_type = ''
this.select.invite_status = ''
}
if (/contractAll/g.test(this.$route.path)) {
this.select.is_simple = ''

@ -0,0 +1,518 @@
<template>
<div style="padding: 0 20px">
<lx-header
icon="md-apps"
text="付款登记"
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
>
<div slot="content" />
<slot>
<span style="padding: 0 6px; word-break: keep-all">创建日期</span>
<span>
<DatePicker
:value="selectDate"
placeholder="请选择日期"
type="date"
placement="bottom-start"
style="width: 180px"
@on-change="(e) => (selectDate = e)"
/>
</span>
<span style="padding: 0 6px; word-break: keep-all">关键字</span>
<span>
<Input
v-model="keywords"
placeholder="请输入关键字"
style="width: 180px"
/>
</span>
<span style="padding: 0 6px; word-break: keep-all"> 状态 </span>
<Select
v-model="status"
clearable
placeholder="请选择"
style="width: 100px"
>
<Option
v-for="item in [
{ label: '待审核', value: 0 },
{ label: '已审核', value: 1 },
]"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</Option>
</Select>
<Button
type="primary"
style="margin-left: 10px"
ghost
@click="
(contractId = ''),
(pageIndex = 1),
(keywords = ''),
(selectDate = '')
"
>重置</Button>
<Button
type="primary"
style="margin-left: 10px"
@click="getFundLogs(false)"
>查询</Button>
</slot>
</lx-header>
<xy-table :list="list" :table-item="table">
<template v-slot:btns>
<el-table-column
label="操作"
:fixed="$store.getters.device === 'mobile'?false:'right'"
width="300"
header-align="center"
>
<template slot-scope="scope">
<template v-if="scope.row.status === 0 && type === 1 && scope.row.fund_log_collect && scope.row.fund_log_collect.flow_links && scope.row.fund_log_collect.flow_links.length === 0">
<Poptip
placement="bottom"
confirm
:transfer="true"
title="确认要删除吗"
@on-ok="deleteFundLog(scope.row)"
>
<Button
size="small"
type="error"
style="margin-left: 10px; margin-bottom: 4px"
ghost
>删除</Button>
</Poptip>
<Button
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="
$refs['detailPaymentRegistration'].getFundLog(scope.row.id),
($refs['detailPaymentRegistration'].isShow = true)
"
>编辑</Button>
</template>
<!-- <Button
v-if="false"
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="
$refs['printRegistration'].getDetailFundLog(scope.row.id),
($refs['printRegistration'].isShow = true)
"
>打印</Button> -->
<!-- 申请金额是否为0 -->
<template v-if="authOa(scope.row) && scope.row.status===0">
<Poptip
v-if="parseFloat(scope.row.apply_money) === 0"
placement="bottom"
confirm
:transfer="true"
title="该申请付款金额为0,是否直接审核?"
@on-ok="saveFundLog(scope.row)"
>
<Button
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
>
支付审批
</Button>
</Poptip>
<Button
v-else
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="toOutPay(scope.row)"
>
支付审批
</Button>
</template>
<Button
v-if="scope.row.property && scope.row.property_type_id"
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="toOutAsset(scope.row)"
>
资产申请
</Button>
<Button
v-if="
scope.row.fund_log_collect &&
scope.row.fund_log_collect.flow_links &&
scope.row.fund_log_collect.flow_links.find(i => i.tag === 'pay') &&
scope.row.fund_log_collect.flow_links.find(i => i.tag === 'pay').flow_status === 1
"
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="toOaDetail(scope.row)"
>查看</Button>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page
:total="total"
show-elevator
show-sizer
@on-change="pageChange"
@on-page-size-change="pageSizeChange"
/>
</div>
<printRegistration ref="printRegistration" />
<detailPaymentRegistration
ref="detailPaymentRegistration"
@success="getFundLogs"
/>
<!-- oa办理-->
<Modal
v-model="isShowOaModal"
:width="86"
class-name="oa-modal"
title="流程办理"
fullscreen
:mask-closable="false"
footer-hide
>
<div style="width: 100%;height: 100%;">
<iframe style="width: 100%;height: 100%;border-radius: 0 0 6px 6px;" :src="oaUrl" frameborder="0" />
</div>
</Modal>
</div>
</template>
<script>
import { detailContract } from '@/api/contract/contract'
// import { fundlogFlow, httpCurl } from '@/api/out'
import { getFundLog, delFundLog, editorFundLog } from '@/api/paymentRegistration/fundLog'
import { getCollect} from '@/api/paymentRegistration/collect'
import { parseTime } from '@/utils'
import { Message } from 'element-ui'
import { show } from '@/api/away'
import printRegistration from './components/printRegistration'
import detailPaymentRegistration from './components/detailPaymentRegistration'
import { getToken } from '@/utils/auth'
export default {
components: {
printRegistration,
detailPaymentRegistration
},
data() {
return {
isShowOaModal: false,
oaUrl: '',
selectDate: '',
keywords: '',
list: [],
contractId: '',
total: 0,
pageIndex: 1,
pageSize: 10,
is_auth: 1,
status: '',
table: [
{
label: '项目名称',
minWidth: 250,
prop: 'contract.name',
align: 'left',
// fixed: this.$store.getters.device === 'mobile' ? false : 'left',
customFn: row => {
return (<span>{ row.contract_id ? (row.contract ? row.contract.name : '') : row.away.title }</span>)
}
},
{
label: '付款申请金额(元)',
prop: 'apply_money',
align: 'right',
width: 180,
formatter: (v1, v2, value) => {
return Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: '实际支付金额(元)',
prop: 'act_money',
align: 'right',
width: 180,
formatter: (v1, v2, value) => {
return Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: '款项类型',
prop: 'type',
width: 120
},
{
label: '预算计划',
width: 330,
align: 'left',
customFn: (row) => {
if (row.plan_link && row.plan_link.length > 0) {
return row.plan_link.map((item) => {
return (
<div>
[{item.plan?.year}] {(item.plan && item.plan.pid_info) ? item.plan.pid_info.name : ''} - {item.plan?.name}
<br/>
[使用金额] {item.use_money}{' '}
</div>
)
})
}
}
},
{
prop: 'status',
label: '审核状态',
width: 120,
formatter: (cell, data, value) => {
if (value === 0) return '待审核'
else return '已审核'
}
},
{
prop: 'fund_log_collect.flow_links',
label: '流程状态',
formatter: (cell, data, value) => {
const map = new Map([
[-1, '已退回'],
[0, '办理中'],
[1, '已完成']
])
return map.get(value?.find(i => i.tag === 'pay')?.flow_status)
}
},
{
label: '次数',
prop: 'pay_count',
width: 95,
customFn: row => {
return (<span>{ row.contract_id ? row.pay_count : row.pay_count_away }</span>)
}
},
{
label: '是否为最后一笔',
prop: 'is_end',
width: 145,
formatter: (cell, data, value) => {
return value === 1 ? '是' : '否'
}
},
{
label: '经办人',
minWidth: 160,
prop: 'admin.name',
align: 'center'
},
{
label: '业务科室',
minWidth: 160,
prop: 'department.name',
align: 'center'
},
{
label: '备注',
minWidth: 460,
prop: 'remark',
align: 'left'
},
{
label: '创建信息',
prop: 'created_at',
width: 160,
formatter: (cell, data, value) => {
return parseTime(new Date(value), '{y}-{m}-{d}')
}
}
]
}
},
computed: {
authOa() {
return function(row) {
return !row.fund_log_collect?.flow_links?.find(i => i.tag === 'pay')?.flow_id
}
}
},
watch: {
isShowOaModal(newVal) {
if (newVal) {
// Modal opened
} else {
this.oaUrl = ''
}
}
},
mounted() {
this.getFdCollect()
this.getFundLogs()
window.onfocus = () => {
this.getFundLogs(true)
}
},
destroyed() {
window.onfocus = null
},
created() {
const type = parseInt(this.$route.path.split('_')[1])
this.type = this.is_auth = type
},
methods: {
async toOaDetail(row) {
let url = `${process.env.VUE_APP_OUT_URL}/#/flow/detail?auth_token=${window.encodeURIComponent(getToken())}&isSinglePage=1&flow_id=`
const pay = row.fund_log_collect?.flow_links?.find(i => i.tag === 'pay')
// url += `&to=/flow/detail?flow_id=${caigou.id}`
url += pay?.flow_id
this.oaUrl = url
this.isShowOaModal = true
},
async toOutAsset(row) {
try {
const flow_id = JSON.parse(row.property_type_detail.remark).flow_id
const url = `${process.env.VUE_APP_OUT_OLD}/flow/create/${flow_id}?auth_token=${this.$store.getters.oa_token}`
window.open(
url,
'signProcess',
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
)
} catch (e) {
// ignore
}
},
saveFundLog(row) {
editorFundLog({
...row,
status: 1
}).then(res => {
this.getFundLogs()
})
},
async toOutPay(row) {
let payments = []
const actNumsTotal = () => {
return payments.reduce((pre, cur) => {
return pre + (Number(cur.act_money) ? Number(cur.act_money) : 0)
}, 0)
}
let contract
if (row.contract_id) {
contract = await detailContract({ id: row.contract_id })
} else {
contract = await show({ id: row.away_id })
}
payments =
(
await getFundLog({
contract_id: row.contract_id,
show_type: 1
})
)?.data || []
const baseInfo = {
'oaUrl': row?.contract?.number,
'zhifutitle': contract?.name,
out_pay_id: row?.id,
'xiangxishuoming': row?.remark,
'yifujine': actNumsTotal(),
'xiangmuzonge': contract.money,
'zhifucishu': contract?.sign_plan?.length,
'cishu': payments.length,
'amt': row?.apply_money,
'liezhiqudao': contract?.plans.map(i => i.name)?.toString(),
'contractno': contract?.number,
'guanlianliucheng': contract?.contract_flow_links?.map(i => i.flow_id)?.toString()
}
console.log(baseInfo)
const url = `${process.env.VUE_APP_OUT_OLD}/#/flow/create?auth_token=${window.encodeURIComponent(getToken())}&module_name=oa&isSinglePage=1&module_id=75&out_pay_id=${row.id}&default_json=${window.encodeURIComponent(JSON.stringify(baseInfo))}`
this.oaUrl = url
this.isShowOaModal = true
},
pageSizeChange(e) {
this.pageSize = e
this.pageIndex = 1
this.getFundLogs()
},
pageChange(e) {
this.pageIndex = e
this.getFundLogs()
},
async getFdCollect(){
const res = await getCollect({
})
},
async getFundLogs(noloading = false) {
// await fundlogFlow();
const res = await getFundLog({
page_size: this.pageSize,
page: this.pageIndex,
contract_id: this.contractId,
keyword: this.keywords,
date: this.selectDate,
is_auth: this.is_auth,
status: this.status,
show_type: 1
}, noloading)
this.list = res.data
this.total = res.total
},
deleteFundLog(row) {
delFundLog({
id: row.id
}).then((res) => {
Message({
type: 'success',
message: '操作成功'
})
this.getFundLogs()
})
}
}
}
</script>
<style scoped lang="scss"></style>
<style lang="scss">
.oa-modal {
.ivu-modal-body {
max-height: calc(100vh - 51px)!important;
padding: 0 !important;
overflow: hidden;
}
}
</style>

@ -19,14 +19,14 @@
/>
</span>
<span style="padding: 0 6px; word-break: keep-all">关键字</span>
<!-- <span style="padding: 0 6px; word-break: keep-all">关键字</span>
<span>
<Input
v-model="keywords"
placeholder="请输入关键字"
style="width: 180px"
/>
</span>
</span> -->
<span style="padding: 0 6px; word-break: keep-all"> 状态 </span>
<Select
v-model="status"
@ -59,12 +59,12 @@
<Button
type="primary"
style="margin-left: 10px"
@click="getFundLogs(false)"
@click="getFdCollect(false)"
>查询</Button>
</slot>
</lx-header>
<xy-table :list="list" :table-item="table">
<xy-table :list="list" :table-item="table" :row-key="'pid'" :treeProps="{ children: 'fund_logs', hasChildren: 'hasChildren' }">
<template v-slot:btns>
<el-table-column
label="操作"
@ -73,7 +73,9 @@
header-align="center"
>
<template slot-scope="scope">
<template v-if="scope.row.status === 0 && type == 1 && scope.row.fund_log_flow_links.length === 0">
<!-- 编辑删除 只针对 fund_log ,父级的 flow_link 为空 -->
<template v-if="scope.row.parent&&authOa(scope.row.parent)&&scope.row.status === 0 && type === 1 ">
<Poptip
placement="bottom"
confirm
@ -99,7 +101,8 @@
"
>编辑</Button>
</template>
<Button
<!-- <Button
v-if="false"
size="small"
type="primary"
@ -108,16 +111,16 @@
$refs['printRegistration'].getDetailFundLog(scope.row.id),
($refs['printRegistration'].isShow = true)
"
>打印</Button>
>打印</Button> -->
<!-- 申请金额是否为0 -->
<template v-if="authOa(scope.row) && scope.row.status===0">
<Poptip
v-if="parseFloat(scope.row.apply_money)==0"
v-if="parseFloat(scope.row.apply_money) === 0"
placement="bottom"
confirm
:transfer="true"
title="该申请付款金额为0,是否直接审核?"
@on-ok="saveFundLog(scope.row)"
@on-ok="updateCollect(scope.row)"
>
<Button
size="small"
@ -150,7 +153,11 @@
资产申请
</Button>
<Button
v-if="scope.row.fund_log_flow_links.find(i => i.tag === 'pay') ? scope.row.fund_log_flow_links.find(i => i.tag === 'pay').flow_status === 1 : false"
v-if="
scope.row.flow_links &&
scope.row.flow_links.find(i => i.tag === 'pay') &&
scope.row.flow_links.find(i => i.tag === 'pay').flow_status === 1
"
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@ -175,7 +182,7 @@
<detailPaymentRegistration
ref="detailPaymentRegistration"
@success="getFundLogs"
@success="getFdCollect"
/>
<!-- oa办理-->
@ -197,8 +204,11 @@
<script>
import { detailContract } from '@/api/contract/contract'
import { fundlogFlow, httpCurl } from '@/api/out'
// import { fundlogFlow, httpCurl } from '@/api/out'
import { getFundLog, delFundLog, editorFundLog } from '@/api/paymentRegistration/fundLog'
import { getCollect,addCollect} from '@/api/paymentRegistration/collect'
import { parseTime } from '@/utils'
import { Message } from 'element-ui'
import { show } from '@/api/away'
@ -230,9 +240,9 @@ export default {
minWidth: 250,
prop: 'contract.name',
align: 'left',
fixed: this.$store.getters.device === 'mobile' ? false : 'left',
// fixed: this.$store.getters.device === 'mobile' ? false : 'left',
customFn: row => {
return (<span>{ row.contract_id ? (row.contract ? row.contract.name : '') : row.away.title }</span>)
return (<span>{ row.contract_id ? (row.contract ? row.contract.name : '') : (row.away?row.away.title:row.name) }</span>)
}
},
{
@ -241,9 +251,9 @@ export default {
align: 'right',
width: 180,
formatter: (v1, v2, value) => {
return Number(value)
return value?Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,'):''
}
},
{
@ -252,9 +262,9 @@ export default {
align: 'right',
width: 180,
formatter: (v1, v2, value) => {
return Number(value)
return value?Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,'):''
}
},
{
@ -272,7 +282,7 @@ export default {
return (
<div>
[{item.plan?.year}] {(item.plan && item.plan.pid_info) ? item.plan.pid_info.name : ''} - {item.plan?.name}
<br />
<br/>
[使用金额] {item.use_money}{' '}
</div>
)
@ -284,13 +294,18 @@ export default {
prop: 'status',
label: '审核状态',
width: 120,
formatter: (cell, data, value) => {
if (value === 0) return '待审核'
else return '已审核'
customFn: (row) => {
if (row.fund_logs) {
return (
<div>
{ row.status===0? '待审核':'已审核'}
</div>
)
}
}
},
{
prop: 'fund_log_flow_links',
prop: 'flow_links',
label: '流程状态',
formatter: (cell, data, value) => {
const map = new Map([
@ -298,23 +313,24 @@ export default {
[0, '办理中'],
[1, '已完成']
])
return map.get(value.find(i => i.tag === 'pay')?.flow_status)
}
},
{
label: '次数',
prop: 'pay_count',
width: 95,
customFn: row => {
return (<span>{ row.contract_id ? row.pay_count : row.pay_count_away }</span>)
return map.get(value?.find(i => i.tag === 'pay')?.flow_status)
}
},
//{
// label: '',
//prop: 'pay_count',
//width: 95,
//customFn: row => {
// return (<span>{ row.contract_id ? row.pay_count : row.pay_count_away }</span>)
//}
//},
{
label: '是否为最后一笔',
prop: 'is_end',
width: 145,
formatter: (cell, data, value) => {
return value == 1 ? '是' : '否'
return value===0?'否':(value === 1 ? '是' : '')
}
},
{
@ -349,25 +365,26 @@ export default {
computed: {
authOa() {
return function(row) {
return !row.fund_log_flow_links.find(i => i.tag === 'pay')?.flow_id
return row.flow_links && !row.flow_links?.find(i => i.tag === 'pay')?.flow_id
}
}
},
watch: {
isShowOaModal(newVal) {
if (newVal) {
// Modal opened
} else {
this.oaUrl = ''
}
}
},
mounted() {
this.getFundLogs()
this.getFdCollect()
//this.getFundLogs()
window.onfocus = () => {
this.getFundLogs(true)
}
// window.onfocus = () => {
// this.getFundLogs(true)
//}
},
destroyed() {
window.onfocus = null
@ -379,7 +396,7 @@ export default {
methods: {
async toOaDetail(row) {
let url = `${process.env.VUE_APP_OUT_URL}/#/flow/detail?auth_token=${window.encodeURIComponent(getToken())}&isSinglePage=1&flow_id=`
const pay = row.fund_log_flow_links.find(i => i.tag === 'pay')
const pay = row.flow_links?.find(i => i.tag === 'pay')
// url += `&to=/flow/detail?flow_id=${caigou.id}`
url += pay?.flow_id
this.oaUrl = url
@ -396,18 +413,24 @@ export default {
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
)
} catch (e) {
// ignore
}
},
saveFundLog(row) {
editorFundLog({
...row,
updateCollect(row) {
addCollect({
id:row.id,
status: 1
}).then(res => {
this.getFundLogs()
this.getFdCollect()
})
},
async toOutPay(row) {
async toOutPay(par) {
let row = []
if(par.fund_logs && par.fund_logs.length>0){
row = par.fund_logs[0]
}else{
return
}
let payments = []
const actNumsTotal = () => {
return payments.reduce((pre, cur) => {
@ -431,7 +454,7 @@ export default {
const baseInfo = {
'oaUrl': row?.contract?.number,
'zhifutitle': contract?.name,
out_pay_id: row?.id,
out_pay_id: par?.id,
'xiangxishuoming': row?.remark,
'yifujine': actNumsTotal(),
'xiangmuzonge': contract.money,
@ -452,13 +475,40 @@ export default {
pageSizeChange(e) {
this.pageSize = e
this.pageIndex = 1
this.getFundLogs()
this.getFdCollect()
},
pageChange(e) {
this.pageIndex = e
this.getFundLogs()
this.getFdCollect()
},
async getFdCollect(){
const res = await getCollect({
start_date: this.selectDate,
is_auth: this.is_auth,
status: this.status,
page_size: this.pageSize,
page: this.pageIndex,
})
this.addParentReference(res.list.data)
this.list = res.list.data
console.log("this.list",this.list)
this.total = res.list.total
},
addParentReference(data, parent = null) {
if (!Array.isArray(data)) return;
data.forEach(node => {
node.parent = parent;
if (node.fund_logs && node.fund_logs.length > 0) {
node.pid = 'p' + node.id;
this.addParentReference(node.fund_logs, node);
}else{
node.pid = node.id;
}
});
},
async getFundLogs(noloading = false) {
// await fundlogFlow();
const res = await getFundLog({
@ -471,8 +521,8 @@ export default {
status: this.status,
show_type: 1
}, noloading)
this.list = res.data
this.total = res.total
// this.list = res.data
// this.total = res.total
},
deleteFundLog(row) {
@ -483,7 +533,7 @@ export default {
type: 'success',
message: '操作成功'
})
this.getFundLogs()
this.getFdCollect()
})
}
}

@ -1,370 +1,428 @@
<template>
<div>
<Modal v-model="isShowModal" fullscreen class-name="oa-modal" footer-hide title="科室资金执行率明细" :mask-closable="false">
<div class="department-progress-detail">
<el-container>
<el-main>
<!-- 科室标题 -->
<div class="department-title">
<h3>{{ row?(row.plan_department?row.plan_department.name:''):'' }} - 资金执行率明细</h3>
</div>
<!-- 执行率统计卡片 -->
<el-row :gutter="20" class="mb-4">
<el-col :span="8">
<el-card class="summary-card" shadow="hover">
<div class="card-title">当前执行率</div>
<div class="execution-rate">{{ getCompletionRate(row.rate) }}%</div>
<div class="card-desc">已财务确认的资金比例</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="summary-card" shadow="hover">
<div class="card-title">预计执行率</div>
<div class="execution-rate">{{ getCompletionRate(row.rate_end) }}%</div>
<div class="card-desc">全部付款确认后预计的执行率</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="summary-card" shadow="hover">
<div class="card-title">预算金额</div>
<div class="execution-rate">{{ formatToWan(row.money_total) }}</div>
<div class="card-desc">科室预算金额</div>
</el-card>
</el-col>
</el-row>
<!-- 已执行项目表格 -->
<el-card class="table-container mb-4">
<div class="section-title" style="display:flex;align-items:center;justify-content:space-between;">
<span>已执行项目财务付款确认</span>
<el-button type="primary" size="mini" @click="exportEnd"></el-button>
</div>
<xy-table ref="xyTable" :list="endList" :table-item="table" :height="300">
<template v-slot:status>
<el-table-column header-align="center" label="当前状态" width="120">
<template slot-scope="scope">
<el-tag type="success">已完成</el-tag>
</template>
</el-table-column>
</template>
<template v-slot:btns>
<el-table-column
:fixed="$store.getters.device === 'mobile'?false:'right'"
header-align="center"
label="操作"
width="120"
>
<template slot-scope="scope">
<el-button type="primary" size="small" @click="showContractDetail(scope.row)"></el-button>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page :total="endTotal" show-elevator @on-change="endPageChange" />
</div>
</el-card>
<!-- 未执行完项目表格 -->
<el-card class="table-container">
<div class="section-title" style="display:flex;align-items:center;justify-content:space-between;">
<span>未执行完项目流程中/预算流转中</span>
<el-button type="primary" size="mini" @click="exportPart"></el-button>
</div>
<xy-table ref="xyTable" :list="partList" :table-item="table" :height="300">
<template v-slot:status>
<el-table-column header-align="center" label="当前状态" width="120" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.funds_count>0" type="warning"></el-tag>
<el-tag v-else type="warning">oa流程中</el-tag>
</template>
</el-table-column>
</template>
<template v-slot:btns>
<el-table-column
:fixed="$store.getters.device === 'mobile'?false:'right'"
header-align="center"
label="操作"
width="120"
align="center"
>
<template slot-scope="scope">
<el-button type="primary" size="small" @click="showContractDetail(scope.row)"></el-button>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page :total="partTotal" show-elevator @on-change="partPageChange" />
</div>
</el-card>
</el-main>
</el-container>
</div>
</Modal>
<!-- <detail ref="detail" /> -->
<ContractDetailDrawer ref="contractDetailDrawer" :visible.sync="isShowContractDetail" />
</div>
</template>
<script>
import {
endIndex,
partIndex
} from '@/api/departmentProgress'
// import detail from '../components/detail.vue'
import ContractDetailDrawer from '@/components/contractIntegration/index.vue'
import { getToken } from '@/utils/auth'
export default {
name: 'DepartmentProgressDetail',
components: {
// detail,
ContractDetailDrawer
},
data() {
return {
isShowModal: false,
isShowContractDetail: false,
row: {},
endTotal: 0,
partTotal: 0,
endSelect: {
page: 1,
page_size: 10
},
partSelect: {
page: 1,
page_size: 10
},
endList: [],
partList: [],
table: [{
prop: 'name',
label: '项目名称',
// fixed: 'left',
// width: 240,
align: 'left'
}, {
prop: 'department.name',
label: '科室',
width: 240
}, {
prop: 'admin.name',
label: '经办人',
width: 100
}, {
prop: 'money',
label: '预算金额',
width: 100,
formatter(v1, v2, value) {
return value || '0.00'
}
}, {
prop: 'funds_count',
label: '发起支付笔数',
width: 100
}, {
prop: 'contract_plan_act_sum',
label: '已确认付款金额',
width: 120,
formatter(v1, v2, value) {
return value || '0.00'
}
}, {
prop: 'status',
label: '当前状态',
export:'funds_count_text',
width: 120
}]
}
},
watch: {
isShowModal(newval) {
if (newval) {
} else {
this.row = {}
}
},
row(newval) {
if (newval) {
this.getEndIndex(newval.plan_department_id)
this.getPartIndex(newval.plan_department_id)
}
}
},
methods: {
partPageChange(e) {
this.partSelect.page = e
this.getPartIndex(this.row.plan_department_id)
},
endPageChange(e) {
this.endSelect.page = e
this.getEndIndex(this.row.plan_department_id)
},
async getEndIndex(id) {
const res = await endIndex({
department_id: id,
page: this.endSelect.page,
page_size: this.endSelect.page_size
})
this.endList = res.list.data
this.endTotal = res.list.total
},
async getPartIndex(id) {
const res = await partIndex({
department_id: id,
page: this.partSelect.page,
page_size: this.partSelect.page_size
})
this.partList = res.list.data
this.partTotal = res.list.total
},
getDetail(row, type) {
this.$refs.detail.type = type
this.$refs.detail.detailRow = row
this.$refs.detail.detailDrawerVisible = true
},
showContractDetail(row) {
this.isShowContractDetail = true
this.$nextTick(() => {
this.$refs.contractDetailDrawer.getDetail(row.id)
})
},
getCompletionRate(dept) {
return dept ? Number(dept.toFixed(2)) : 0
},
formatToWan(num) {
if (num === null || num === undefined) return '0元'
num = Number(num)
if (isNaN(num)) return '0元'
if (Math.abs(num) < 10000) {
return num.toFixed(2).toString() + '元' // 1
} else {
return (num / 10000).toFixed(2) + '万元' // 1
}
},
exportEnd() {
const name = this.row?(this.row.plan_department?this.row.plan_department.name:''):''
const file_name = name+'已执行项目(财务付款确认)'
const export_fields = 'export_fields[name]=项目名称&export_fields[department.name]=科室&export_fields[admin.name]=经办人&export_fields[money]=预算金额&export_fields[funds_count]=发起支付笔数&export_fields[contract_plan_act_sum]=已确认付款金额&export_fields[funds_count_text]=当前状态'
window.open(`${process.env.VUE_APP_BASE_API}/api/ht/contract/end-index?token=${getToken()}&is_export=1&page=1&page_size=999&department_id=${this.row.plan_department_id}&${export_fields}&file_name=${file_name}`, '_blank')
},
exportPart() {
const name = this.row?(this.row.plan_department?this.row.plan_department.name:''):''
const file_name = name+'未执行完项目'
const export_fields = 'export_fields[name]=项目名称&export_fields[department.name]=科室&export_fields[admin.name]=经办人&export_fields[money]=预算金额&export_fields[funds_count]=发起支付笔数&export_fields[contract_plan_act_sum]=已确认付款金额&export_fields[funds_count_text]=当前状态'
window.open(`${process.env.VUE_APP_BASE_API}/api/ht/contract/part-index?token=${getToken()}&is_export=1&page=1&page_size=999&department_id=${this.row.plan_department_id}&${export_fields}&file_name=${file_name}`, '_blank')
}
}
}
</script>
<style scoped lang="scss">
::v-deep .ivu-modal-body {
max-height: none !important;
overflow: scroll!important;
}
.department-progress-detail {
min-height: 100vh;
background: #f4f6fa;
}
.header-bg {
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
color: white;
padding: 0;
height: 70px;
display: flex;
align-items: center;
}
.header-container {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 0 30px;
}
.header-title {
font-size: 20px;
font-weight: bold;
}
.header-user {
font-size: 14px;
}
.sidebar {
background-color: #f8f9fa;
min-height: calc(100vh - 70px);
border-right: 1px solid #dee2e6;
}
.department-title {
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
color: white;
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
text-align: center;
}
.action-buttons {
margin-bottom: 20px;
text-align: right;
}
.summary-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
text-align: center;
}
.card-title {
font-size: 16px;
margin-bottom: 10px;
}
.execution-rate {
font-size: 32px;
font-weight: bold;
margin-bottom: 5px;
}
.card-desc {
font-size: 13px;
}
.section-title {
background-color: #f8f9fa;
padding: 15px;
margin: 20px 0 15px 0;
border-left: 4px solid #007bff;
border-radius: 5px;
font-size: 16px;
font-weight: bold;
}
.table-container {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.detail-table {
font-size: 14px;
}
</style>
<template>
<div>
<Modal v-model="isShowModal" fullscreen class-name="oa-modal" footer-hide title="科室资金执行率明细" :mask-closable="false">
<div class="department-progress-detail">
<el-container>
<el-main>
<!-- 科室标题 -->
<div class="department-title">
<h3>{{ row?(row.plan_department?row.plan_department.name:''):'' }} - 资金执行率明细</h3>
</div>
<!-- 执行率统计卡片 -->
<el-row :gutter="20" class="mb-4">
<el-col :span="8">
<el-card class="summary-card" shadow="hover">
<div class="card-title">当前执行率</div>
<div class="execution-rate">{{ getCompletionRate(row.rate) }}%</div>
<div class="card-desc">已财务确认的资金比例</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="summary-card" shadow="hover">
<div class="card-title">预计执行率</div>
<div class="execution-rate">{{ getCompletionRate(row.rate_end) }}%</div>
<div class="card-desc">全部付款确认后预计的执行率</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="summary-card" shadow="hover">
<div class="card-title">预算金额</div>
<div class="execution-rate">{{ formatToWan(row.money_total) }}</div>
<div class="card-desc">科室预算金额</div>
</el-card>
</el-col>
</el-row>
<!-- 已执行项目表格 -->
<el-card class="table-container mb-4">
<div class="section-title" style="display:flex;align-items:center;justify-content:space-between;">
<span>资金执行明细</span>
<el-button type="primary" size="mini" @click="exportEnd"></el-button>
</div>
<xy-table ref="xyTable" :list="endList" :table-item="endTable" :height="300">
<template v-slot:status>
<el-table-column header-align="center" label="当前状态" width="120">
<template>
<el-tag type="success">已完成</el-tag>
</template>
</el-table-column>
</template>
<template v-slot:btns>
<el-table-column
:fixed="$store.getters.device === 'mobile'?false:'right'"
header-align="center"
label="操作"
width="120"
>
<template slot-scope="scope">
<el-button v-if="scope.row.contract_id" type="primary" size="small" @click="showContractDetail(scope.row)"></el-button>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page :total="endTotal" show-elevator @on-change="endPageChange" />
</div>
</el-card>
<!-- 未执行完项目表格 -->
<el-card class="table-container">
<div class="section-title" style="display:flex;align-items:center;justify-content:space-between;">
<span>未执行完项目流程中/预算流转中</span>
<el-button type="primary" size="mini" @click="exportPart"></el-button>
</div>
<xy-table ref="xyTable" :list="partList" :table-item="table" :height="300">
<template v-slot:status>
<el-table-column header-align="center" label="当前状态" width="120" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.funds_count>0" type="warning"></el-tag>
<el-tag v-else type="warning">oa流程中</el-tag>
</template>
</el-table-column>
</template>
<template v-slot:btns>
<el-table-column
:fixed="$store.getters.device === 'mobile'?false:'right'"
header-align="center"
label="操作"
width="120"
align="center"
>
<template slot-scope="scope">
<el-button type="primary" size="small" @click="showContractDetail(scope.row)"></el-button>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page :total="partTotal" show-elevator @on-change="partPageChange" />
</div>
</el-card>
</el-main>
</el-container>
</div>
</Modal>
<!-- <detail ref="detail" /> -->
<ContractDetailDrawer ref="contractDetailDrawer" :visible.sync="isShowContractDetail" />
</div>
</template>
<script>
import {
endIndex2,
partIndex
} from '@/api/departmentProgress'
// import detail from '../components/detail.vue'
import ContractDetailDrawer from '@/components/contractIntegration/index.vue'
import { getToken } from '@/utils/auth'
export default {
name: 'DepartmentProgressDetail',
components: {
// detail,
ContractDetailDrawer
},
data() {
return {
isShowModal: false,
isShowContractDetail: false,
row: {},
endTotal: 0,
partTotal: 0,
endSelect: {
page: 1,
page_size: 10
},
partSelect: {
page: 1,
page_size: 10
},
endList: [],
partList: [],
endTable: [{
prop: 'model_type_text',
label: '类型',
width: 120,
align: 'center'
}, {
prop: 'name',
label: '关联名称',
width: 240,
align: 'center'
}, {
prop: 'use_money',
label: '使用金额',
width: 240
}, {
prop: 'admin_name',
label: '发起人',
width: 120,
align: 'center'
}, {
prop: 'created_at',
label: '发起时间',
width: 180,
align: 'center',
formatter: (v1, v2, value) => {
return this.formatDateTime(value)
}
}, {
prop: 'status',
label: '状态',
width: 120,
align: 'center'
}],
table: [{
prop: 'name',
label: '项目名称',
// fixed: 'left',
// width: 240,
align: 'left'
}, {
prop: 'department.name',
label: '科室',
width: 240,
align: 'left'
}, {
prop: 'admin.name',
label: '经办人',
width: 100
}, {
prop: 'money',
label: '预算金额',
width: 100,
formatter(v1, v2, value) {
return value || '0.00'
}
}, {
prop: 'funds_count',
label: '发起支付笔数',
width: 100
}, {
prop: 'contract_plan_act_sum',
label: '已确认付款金额',
width: 120,
formatter(v1, v2, value) {
return value || '0.00'
}
}, {
prop: 'status',
label: '当前状态',
export: 'funds_count_text',
width: 120
}]
}
},
watch: {
isShowModal(newval) {
if (newval) {
// Modal opened
} else {
this.row = {}
}
},
row(newval) {
if (newval) {
this.getEndIndex(newval.plan_department_id)
this.getPartIndex(newval.plan_department_id)
}
}
},
methods: {
partPageChange(e) {
this.partSelect.page = e
this.getPartIndex(this.row.plan_department_id)
},
endPageChange(e) {
this.endSelect.page = e
this.getEndIndex(this.row.plan_department_id)
},
async getEndIndex(id) {
const res = await endIndex2({
department_id: id,
page: this.endSelect.page,
page_size: this.endSelect.page_size
})
this.endList = res.list.data
this.endTotal = res.list.total
},
async getPartIndex(id) {
const res = await partIndex({
department_id: id,
page: this.partSelect.page,
page_size: this.partSelect.page_size
})
this.partList = res.list.data
this.partTotal = res.list.total
},
getDetail(row, type) {
this.$refs.detail.type = type
this.$refs.detail.detailRow = row
this.$refs.detail.detailDrawerVisible = true
},
showContractDetail(row) {
this.isShowContractDetail = true
this.$nextTick(() => {
this.$refs.contractDetailDrawer.getDetail(row.contract_id)
})
},
getCompletionRate(dept) {
return dept ? Number(dept.toFixed(2)) : 0
},
formatToWan(num) {
if (num === null || num === undefined) return '0元'
num = Number(num)
if (isNaN(num)) return '0元'
if (Math.abs(num) < 10000) {
return num.toFixed(2).toString() + '元' // 1
} else {
return (num / 10000).toFixed(2) + '万元' // 1
}
},
formatDateTime(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const today = new Date()
//
const isToday = date.getFullYear() === today.getFullYear() &&
date.getMonth() === today.getMonth() &&
date.getDate() === today.getDate()
if (isToday) {
//
return date.toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
} else {
//
return date.toLocaleDateString('zh-CN')
}
},
exportEnd() {
const name = this.row ? (this.row.plan_department ? this.row.plan_department.name : '') : ''
const file_name = name + '资金执行明细'
// const export_fields = 'export_fields[name]=&export_fields[department.name]=&export_fields[admin.name]=&export_fields[money]=&export_fields[funds_count]=&export_fields[contract_plan_act_sum]=&export_fields[funds_count_text]='
const export_fields = 'export_fields[model_type_text]=类型&export_fields[name]=关联名称&export_fields[use_money]=使用金额&export_fields[created_at]=发起时间&export_fields[funds_count_text]=状态&export_fields[admin_name]=发起人'
window.open(`${process.env.VUE_APP_BASE_API}/api/ht/contract/end-index-v2?token=${getToken()}&is_export=1&page=1&page_size=999&department_id=${this.row.plan_department_id}&${export_fields}&file_name=${file_name}`, '_blank')
},
exportPart() {
const name = this.row ? (this.row.plan_department ? this.row.plan_department.name : '') : ''
const file_name = name + '未执行完项目'
const export_fields = 'export_fields[name]=项目名称&export_fields[department.name]=科室&export_fields[admin.name]=经办人&export_fields[money]=预算金额&export_fields[funds_count]=发起支付笔数&export_fields[contract_plan_act_sum]=已确认付款金额&export_fields[funds_count_text]=当前状态'
window.open(`${process.env.VUE_APP_BASE_API}/api/ht/contract/part-index?token=${getToken()}&is_export=1&page=1&page_size=999&department_id=${this.row.plan_department_id}&${export_fields}&file_name=${file_name}`, '_blank')
}
}
}
</script>
<style scoped lang="scss">
::v-deep .ivu-modal-body {
max-height: none !important;
overflow: scroll!important;
}
.department-progress-detail {
min-height: 100vh;
background: #f4f6fa;
}
.header-bg {
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
color: white;
padding: 0;
height: 70px;
display: flex;
align-items: center;
}
.header-container {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 0 30px;
}
.header-title {
font-size: 20px;
font-weight: bold;
}
.header-user {
font-size: 14px;
}
.sidebar {
background-color: #f8f9fa;
min-height: calc(100vh - 70px);
border-right: 1px solid #dee2e6;
}
.department-title {
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
color: white;
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
text-align: center;
}
.action-buttons {
margin-bottom: 20px;
text-align: right;
}
.summary-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
text-align: center;
}
.card-title {
font-size: 16px;
margin-bottom: 10px;
}
.execution-rate {
font-size: 32px;
font-weight: bold;
margin-bottom: 5px;
}
.card-desc {
font-size: 13px;
}
.section-title {
background-color: #f8f9fa;
padding: 15px;
margin: 20px 0 15px 0;
border-left: 4px solid #007bff;
border-radius: 5px;
font-size: 16px;
font-weight: bold;
}
.table-container {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.detail-table {
font-size: 14px;
}
</style>

@ -0,0 +1,624 @@
<template>
<div style="padding: 0 20px">
<lx-header
icon="md-apps"
text="付款登记"
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
>
<div slot="content" />
<slot>
<div class="selects">
<div>
<span style="padding: 0 6px; word-break: keep-all">关键字</span>
<span>
<Input
v-model="keyword"
placeholder="请输入关键字"
style="width: 180px"
/>
</span>
</div>
<div>
<span style="padding: 0 6px; word-break: keep-all">部门</span>
<el-select v-model="select.department_id" style="width: 140px" size="small" clearable placeholder="部门选择">
<el-option v-for="dept in departments" :key="dept.id" :value="dept.id" :label="dept.name" />
</el-select>
</div>
<div>
<span style="padding: 0 6px; word-break: keep-all">预算计划</span>
<span>
<Input
v-model="select.plan_name"
clearable
placeholder="请选择预算计划"
style="width: 200px"
@on-focus="showPlanForSearch"
@on-clear="clearSelectForSearch"
/>
</span>
</div>
<div>
<span style="padding: 0 6px; word-break: keep-all"> 财务确认状态 </span>
<Select
v-model="status"
clearable
placeholder="请选择"
style="width: 100px"
>
<Option
v-for="item in [
{ label: '待审核', value: 0 },
{ label: '已审核', value: 1 },
]"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px; word-break: keep-all">流转状态</span>
<el-select v-model="select.flow_status" style="width: 100px" size="small" clearable placeholder="状态选择">
<el-option value="" label="待申请" />
<el-option :value="0" label="流转中" />
<el-option :value="1" label="已办结" />
</el-select>
</div>
<div>
<span style="padding: 0 6px; word-break: keep-all">创建日期</span>
<span>
<DatePicker
:value="selectDate"
placeholder="请选择日期"
type="date"
placement="bottom-start"
style="width: 180px"
@on-change="(e) => (selectDate = e)"
/>
</span>
</div>
<div>
<Button
type="primary"
@click="doSearch()"
>查询</Button>
</div>
<div>
<Button type="primary" ghost>重置</Button>
</div>
<div>
<Button
type="primary"
@click="toExport()"
>导出</Button>
</div>
</div>
</slot>
</lx-header>
<!-- 搜索使用 预算计划 -->
<xy-dialog
:is-show.sync="isShowPlanForSearch"
title="预算计划"
:width="720"
@on-ok="planSelectForSearch"
>
<template>
<Input
v-model="planSearch.name"
search
enter-button="搜 索"
placeholder="搜索预算计划.."
@on-search="searchBudgets"
/>
<div
style="
margin: 10px 0;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<div>
已选择<span style="margin-right: 10px">{{
select.plan_name
}}</span>
</div>
<el-link
type="success"
@click="clearSelectForSearch"
>清空选择</el-link>
</div>
<xy-table
ref="singlePlanTable"
highlight-current-row
:list="plans"
:show-index="false"
:table-item="planTableSearch"
:height="310"
style="margin-top: 10px"
@rowClick="selectPlanForSearch"
>
<template v-slot:btns />
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page :total="planTotal" show-elevator @on-change="planPageChange" />
</div>
<el-tag type="warning">点击行进行选择</el-tag>
</template>
<template v-slot:footerContent>
<Button type="primary" @click="confirmPlanForSearch"></Button>
</template>
</xy-dialog>
<xy-table :list="list" :table-item="table">
<template v-slot:btns>
<el-table-column
label="操作"
:fixed="$store.getters.device === 'mobile'?false:'right'"
width="160"
header-align="center"
>
<template v-if="authOa(scope.row)" slot-scope="scope">
<template v-if="scope.row.status === 0">
<Button
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="
($refs['examineRegistration'].isShow = true),
$refs['examineRegistration'].getRegistration(scope.row.id)
"
>审核确认</Button>
</template>
<!-- <template v-else>
<Button
size="small"
type="error"
ghost
style="margin-left: 10px; margin-bottom: 4px"
@click="cancelExamine(scope.row)"
>审核撤销</Button
>
</template> -->
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page
:total="total"
show-elevator
show-sizer
@on-change="pageChange"
@on-page-size-change="pageSizeChange"
/>
</div>
<examineRegistration
ref="examineRegistration"
@refresh="getFundLogs"
/>
</div>
</template>
<script>
import {
getFundLog,
delFundLog,
editorFundLog
} from '@/api/paymentRegistration/fundLog'
import { getToken } from '@/utils/auth'
import { parseTime } from '@/utils'
import { Message } from 'element-ui'
import { getBudget } from '@/api/budget/budget'
import { getparameter } from '@/api/system/dictionary'
import examineRegistration from './components/examineRegistration'
import { listdeptNoAuth } from '@/api/system/department'
export default {
components: {
examineRegistration
},
data() {
return {
departments: [],
moneyWay: [],
plan: [],
planTableSearch: [
{
label: '分类',
prop: 'type',
formatter: (cell, data, value) => {
const res = this.moneyWay.filter((item) => {
return item.id === value
})
return res[0]?.value || '未知'
},
width: 120
},
{
label: '年份',
prop: 'year',
align: 'center',
width: 90
},
{
label: '名称',
prop: 'name',
width: 200,
align: 'left'
},
{
label: '计划金额',
prop: 'money',
align: 'right',
width: 160
}
],
plans: [], //
planSearch: {
name: '',
plan_department_id: ''
},
planTotal: 0,
plansPageIndex: 1,
isShowPlanForSearch: false,
status: 0,
keyword: '',
select: {
plan_id: '',
plan_name: '',
flow_status: 1,
department_id: ''
},
selectDate: '',
list: [],
total: 0,
flowStatus: new Map([
[2, '待申请'],
[-1, '已退回'],
[-2, '-'],
[0, '流转中'],
[1, '已办结']
]),
flowStatusColor: new Map([
[-2, 'rgb(140, 140, 140)'],
[-1, '#dca550'],
[2, 'rgb(96, 109, 241)'],
[0, 'rgb(219, 122, 122)'],
[1, 'rgb(147, 201, 134)']
]),
pageIndex: 1,
pageSize: 10,
table: [
{
label: '项目名称',
minWidth: 300,
prop: 'contract.name',
fixed: this.$store.getters.device === 'mobile' ? false : 'left',
align: 'left',
customFn: row => {
return (<span>{ row.contract_id ? (row.contract ? row.contract.name : '') : (row.away ? row.away.title : '') }</span>)
}
},
{
label: '付款申请金额(元)',
prop: 'apply_money',
align: 'right',
width: 170,
formatter: (v1, v2, value) => {
return Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: '实际付款金额(元)',
prop: 'act_money',
align: 'right',
width: 170,
formatter: (v1, v2, value) => {
return Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: '预算计划',
width: 320,
align: 'left',
customFn: (row) => {
if (row.plan_link && row.plan_link.length > 0) {
return row.plan_link.map((item) => {
return (
<div>
{' '}
[{item.plan.year}] {(item.plan && item.plan.pid_info) ? item.plan.pid_info.name : ''} - {item.plan.name} <br /> [使用金额]{' '}
{item.use_money}{' '}
</div>
)
})
}
}
},
{
label: '款项类型',
prop: 'type',
width: 120
},
{
prop: 'fund_log_collect.flow_links',
label: '流程状态',
customFn: row => {
return (
<span style={'color:' + this.flowStatusColor.get(row.fund_log_collect?.flow_links?.find(i => i.tag === 'pay')?.flow_status)
}>{this.flowStatus.get(row.fund_log_collect?.flow_links?.find(i => i.tag === 'pay')?.flow_status)}</span>)
}
// formatter: (cell, data, value) => {
// return this.flowStatus.get(value.find(i => i.tag === 'pay')?.flow_status)
// }
},
{
prop: 'status',
label: '财务确认状态',
width: 100,
customFn: row => {
return (row.status === 0)
? (<span style='color:rgb(96, 109, 241)'>待审核</span>)
: (<span style='color: rgb(147, 201, 134)'>已审核</span>)
}
},
{
label: '次数',
prop: 'pay_count',
width: 95,
customFn: row => {
return (<span>{ row.contract_id ? row.pay_count : row.pay_count_away }</span>)
}
},
{
label: '最后一笔',
prop: 'is_end',
width: 125,
formatter: (cell, data, value) => {
return value === 1 ? '是' : '否'
}
},
{
label: '经办人',
minWidth: 120,
prop: 'admin.name',
align: 'center'
},
{
label: '业务科室',
minWidth: 140,
prop: 'department.name',
align: 'center'
},
{
label: '备注',
minWidth: 360,
prop: 'remark',
align: 'left'
},
{
label: '创建信息',
prop: 'created_at',
width: 160,
formatter: (cell, data, value) => {
return parseTime(new Date(value), '{y}-{m}-{d}')
}
}
]
}
},
computed: {
authOa() {
return function(row) {
return row.fund_log_collect?.flow_links?.find(i => i.tag === 'pay')?.flow_status === 1
}
}
},
mounted() {
this.getDepartment()
this.getMoneyWay()
this.getFundLogs()
},
methods: {
planPageChange(e) {
this.plansPageIndex = e
this.getBudgets()
},
//
async getDepartment() {
this.departments = (await listdeptNoAuth())?.data
},
//
async getMoneyWay() {
this.moneyWay = (
await getparameter({
number: 'money_way'
})
).detail
},
clearSelectForSearch() {
this.select.plan_id = ''
this.select.plan_name = '请选择预算计划'
},
//
searchBudgets() {
this.plansPageIndex = 1
this.getBudgets()
},
doSearch() {
this.pageIndex = 1
this.getFundLogs()
},
confirmPlanForSearch() {
this.isShowPlanForSearch = false
this.getFundLogs()
},
//
toggleSelection(plans, type) {
if (plans) {
this.plans
.filter((plan) => {
if (plans.includes(plan.id)) {
plan.useMoney = this.plan[plans.indexOf(plan.id)].value.use_money
return true
}
})
.map((row) => {
this.$refs.planTable.toggleRowSelection(row)
})
} else {
this.$refs.planTable.clearSelection()
}
},
//
async getBudgets() {
await getBudget({
name: this.planSearch.name,
page_size: 10,
page: this.plansPageIndex,
plan_department_id: this.planSearch.plan_department_id,
top_pid: 1
}).then((res) => {
this.plans = res.list.data
this.planTotal = res.list.total
this.toggleSelection(
this.plan.map((item) => {
return item.value.plan_id
}),
1
)
})
},
async showPlanForSearch() {
this.isShowPlanForSearch = true
await this.getBudgets()
},
//
selectPlanForSearch(sel) {
console.log(sel)
if (sel) {
this.select.plan_id = sel.id
this.select.plan_name = '[' + sel.year + ']-' + sel.name
} else {
this.select.plan_id = ''
this.select.plan_name = ''
}
},
//
planSelectForSearch() {
if (this.select.plan_id === '') {
Message({
type: 'warning',
message: '选择计划不能为空'
})
return
}
this.isShowPlanForSearch = false
},
pageSizeChange(e) {
this.pageSize = e
this.pageIndex = 1
this.getFundLogs()
},
pageChange(e) {
this.pageIndex = e
this.getFundLogs()
},
toExport() {
this.is_export = 1
this.getFundLogs(true)
},
async getFundLogs(is_export) {
await getFundLog({
page_size: this.pageSize,
page: this.pageIndex,
keyword: this.keyword,
date: this.selectDate,
status: this.status,
act_plan_link_id: this.select.plan_id,
show_type: 1,
'flow_link[0][custom_model_id]': 75,
'flow_link[0][flow_status]': this.select.flow_status,
department_id: this.select.department_id
}).then((res) => {
const tokens = getToken()
if (is_export) {
var url = '/api/ht/fund_log/index?token=' + tokens
if (this.selectDate) url += '&date=' + this.selectDate
if (this.keyword) url += '&keyword=' + this.keyword
if (typeof this.status !== 'undefined') { url += '&status=' + this.status }
if (this.select.plan_id) { url += '&act_plan_link_id=' + this.select.plan_id }
url += '&is_export=' + this.is_export
url = location.host + url
console.log(url)
window.open('http://' + url, '_blank')
this.select.is_export = 0
return
}
this.list = res.data
this.total = res.total
})
},
deleteFundLog(row) {
delFundLog({
id: row.id
}).then((res) => {
Message({
type: 'success',
message: '操作成功'
})
this.getFundLogs()
})
},
cancelExamine(row) {
editorFundLog({
id: row.id,
contract_id: row.contract_id,
status: 0
}).then((res) => {
this.getFundLogs()
Message({
type: 'success',
message: '操作成功'
})
})
}
}
}
</script>
<style scoped lang="scss">
.selects {
display: flex;
flex-wrap: wrap;
& > div {
margin-bottom: 6px;
margin-right: 4px;
& > span {
word-break: keep-all;
padding: 0 4px ;
}
}
}
</style>

@ -8,7 +8,7 @@
<div slot="content" />
<slot>
<div class="selects">
<div>
<!-- <div>
<span style="padding: 0 6px; word-break: keep-all">关键字</span>
<span>
<Input
@ -17,14 +17,14 @@
style="width: 180px"
/>
</span>
</div>
</div> -->
<div>
<span style="padding: 0 6px; word-break: keep-all">部门</span>
<el-select v-model="select.department_id" style="width: 140px" size="small" clearable placeholder="部门选择">
<el-option v-for="dept in departments" :value="dept.id" :label="dept.name" />
<el-option v-for="dept in departments" :key="dept.id" :value="dept.id" :label="dept.name" />
</el-select>
</div>
<div>
<!-- <div>
<span style="padding: 0 6px; word-break: keep-all">预算计划</span>
<span>
<Input
@ -36,7 +36,7 @@
@on-clear="clearSelectForSearch"
/>
</span>
</div>
</div> -->
<div>
<span style="padding: 0 6px; word-break: keep-all"> 财务确认状态 </span>
<Select
@ -60,7 +60,7 @@
<div>
<span style="padding: 0 6px; word-break: keep-all">流转状态</span>
<el-select v-model="select.flow_status" style="width: 100px" size="small" clearable placeholder="状态选择">
<el-option value="" label="待申请" />
<!-- <el-option value="" label="待申请" /> -->
<el-option :value="0" label="流转中" />
<el-option :value="1" label="已办结" />
</el-select>
@ -87,12 +87,12 @@
<div>
<Button type="primary" ghost>重置</Button>
</div>
<div>
<!-- <div>
<Button
type="primary"
@click="toExport()"
>导出</Button>
</div>
</div> -->
</div>
</slot>
@ -132,8 +132,8 @@
>清空选择</el-link>
</div>
<xy-table
highlight-current-row
ref="singlePlanTable"
highlight-current-row
:list="plans"
:show-index="false"
:table-item="planTableSearch"
@ -155,7 +155,7 @@
</template>
</xy-dialog>
<xy-table :list="list" :table-item="table">
<xy-table :list="list" :table-item="table" :row-key="'pid'" :tree-props="{ children: 'fund_logs', hasChildren: 'hasChildren' }">
<template v-slot:btns>
<el-table-column
label="操作"
@ -165,15 +165,19 @@
>
<template v-if="authOa(scope.row)" slot-scope="scope">
<template v-if="scope.row.status === 0">
<Poptip
placement="bottom"
confirm
:transfer="true"
title="确认要审核吗?"
@on-ok="showAuditDialog(scope.row)"
>
<Button
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="
($refs['examineRegistration'].isShow = true),
$refs['examineRegistration'].getRegistration(scope.row.id)
"
>审核确认</Button>
</Poptip>
</template>
<!-- <template v-else>
<Button
@ -186,6 +190,17 @@
>
</template> -->
</template>
<!-- <template slot-scope="scope">
<Button
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="
($refs['examineRegistration'].isShow = true),
$refs['examineRegistration'].getRegistration(scope.row.id)
"
>审核确认123</Button>
</template> -->
</el-table-column>
</template>
</xy-table>
@ -202,18 +217,107 @@
<examineRegistration
ref="examineRegistration"
@refresh="getFundLogs"
@refresh="getCollects"
/>
<!-- 审核确认弹窗 -->
<el-dialog
title="审核确认"
:visible.sync="auditDialogVisible"
width="80%"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div v-if="currentAuditRow">
<!-- 基本信息表格 -->
<div style="margin-bottom: 20px;color:#000">
{{ currentAuditRow.contract_id ? (currentAuditRow.contract ? currentAuditRow.contract.name : '') : (currentAuditRow.away ? currentAuditRow.away.title : currentAuditRow.name) }}
</div>
<!-- 每个fund_logs及其plan_link的区块 -->
<div v-if="currentAuditRow.fund_logs && currentAuditRow.fund_logs.length > 0">
<div v-for="(fundLog, fundLogIndex) in currentAuditRow.fund_logs" :key="fundLog.id" style="margin-bottom: 30px;">
<h4 style="margin-bottom: 15px; color: #409EFF;">付款记录 #{{ fundLogIndex + 1 }}</h4>
<!-- fund_logs信息表格 -->
<el-table :data="[fundLog]" border style="margin-bottom: 15px;">
<el-table-column prop="contract.name" label="项目名称" min-width="200">
<template slot-scope="scope">
{{ scope.row.contract_id ? (scope.row.contract ? scope.row.contract.name : '') : (scope.row.away ? scope.row.away.title : scope.row.name) }}
</template>
</el-table-column>
<el-table-column prop="apply_money" label="付款申请金额(元)" width="150" align="right">
<template slot-scope="scope">
{{ scope.row.apply_money ? Number(scope.row.apply_money).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : '' }}
</template>
</el-table-column>
<el-table-column prop="act_money" label="实际支付金额(元)" width="150" align="right">
<template slot-scope="scope">
{{ scope.row.act_money ? Number(scope.row.act_money).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : '' }}
</template>
</el-table-column>
<el-table-column prop="type" label="款项类型" width="120" />
<el-table-column prop="admin.name" label="经办人" width="120" align="center" />
<el-table-column prop="department.name" label="业务科室" width="140" align="center" />
<el-table-column prop="remark" label="备注" min-width="200" />
<el-table-column prop="created_at" label="创建信息" width="160" />
</el-table>
<!-- 对应的plan_link表格 -->
<div v-if="fundLog.plan_link && fundLog.plan_link.length > 0">
<h5 style="margin-bottom: 10px; color: #67C23A;">预算计划使用情况</h5>
<el-table :data="getPlanLinkData(fundLog)" border>
<el-table-column label="" width="55" align="center">
<template slot-scope="scope">
<el-checkbox v-model="scope.row.selected" @change="handleSelectionChange(scope.row, fundLog.id)" />
</template>
</el-table-column>
<el-table-column prop="year" label="年份" width="100" align="center" />
<el-table-column prop="name" label="名称" min-width="200" />
<el-table-column prop="content" label="内容" min-width="200" />
<el-table-column prop="money" label="计划金额" width="150" align="right">
<template slot-scope="scope">
{{ scope.row.money ? Number(scope.row.money).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : '' }}
</template>
</el-table-column>
<el-table-column label="使用金额" width="150" align="right">
<template slot-scope="scope">
<el-input-number
v-model="scope.row.use_money"
:precision="2"
:min="0"
:max="999999999"
:disabled="!scope.row.selected"
controls-position="right"
size="small"
style="width: 100%"
/>
</template>
</el-table-column>
</el-table>
</div>
<div v-else style="text-align: center; color: #909399; padding: 20px;">
暂无预算计划关联
</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="auditDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmAudit"></el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getFundLog,
delFundLog,
editorFundLog
} from '@/api/paymentRegistration/fundLog'
import { getToken } from '@/utils/auth'
import { getCollect, addCollect } from '@/api/paymentRegistration/collect'
import { parseTime } from '@/utils'
import { Message } from 'element-ui'
import { getBudget } from '@/api/budget/budget'
@ -280,6 +384,9 @@ export default {
selectDate: '',
list: [],
total: 0,
auditDialogVisible: false,
currentAuditRow: null,
planLinkDataMap: {},
flowStatus: new Map([
[2, '待申请'],
[-1, '已退回'],
@ -299,72 +406,67 @@ export default {
table: [
{
label: '项目名称',
minWidth: 300,
minWidth: 250,
prop: 'contract.name',
fixed: this.$store.getters.device === 'mobile' ? false : 'left',
align: 'left',
// fixed: this.$store.getters.device === 'mobile' ? false : 'left',
customFn: row => {
return (<span>{ row.contract_id ? (row.contract ? row.contract.name : '') : (row.away ? row.away.title : '') }</span>)
return (<span>{ row.contract_id ? (row.contract ? row.contract.name : '') : (row.away ? row.away.title : row.name) }</span>)
}
},
{
label: '付款申请金额(元)',
prop: 'apply_money',
align: 'right',
width: 170,
width: 180,
formatter: (v1, v2, value) => {
return Number(value)
return value ? Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : ''
}
},
{
label: '实际金额(元)',
label: '实际付金额(元)',
prop: 'act_money',
align: 'right',
width: 170,
width: 180,
formatter: (v1, v2, value) => {
return Number(value)
return value ? Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : ''
}
},
{
}, {
label: '预算计划',
width: 320,
width: 330,
align: 'left',
customFn: (row) => {
{
if (row.plan_link && row.plan_link.length > 0) {
return row.plan_link.map((item) => {
return (
<div>
{' '}
[{item.plan.year}] {(item.plan && item.plan.pid_info) ? item.plan.pid_info.name : ''} - {item.plan.name} <br /> [使用金额]{' '}
{item.use_money}{' '}
</div>
)
})
}
if (row.plan_link && row.plan_link.length > 0) {
return row.plan_link.map((item) => {
return (
<div>
[{item.plan?.year}] - {item.plan?.name}
<br/>
[使用金额] {item.use_money}{' '}
</div>
)
})
}
}
},{
}, {
label: '已纳入资金执行率金额',
width: 320,
width: 300,
align: 'left',
customFn: (row) => {
{
if (row.plan_act_links && row.plan_act_links.length > 0) {
return row.plan_act_links.map((item) => {
return (
<div>
{' '}
[{item.plan.year}] {(item.plan && item.plan.pid_info) ? item.plan.pid_info.name : ''} - {item.plan.name} <br /> [使用金额]{' '}
[{item.plan.year}] - {item.plan.name} <br /> [使用金额]{' '}
{item.use_money}{' '}
</div>
)
})
}
}
}
},
@ -374,13 +476,12 @@ export default {
width: 120
},
{
prop: 'fund_log_flow_links',
prop: 'flow_links',
label: '流程状态',
customFn: row => {
return (
<span style={'color:' + this.flowStatusColor.get(row.fund_log_flow_links.find(i => i.tag === 'pay')?.flow_status)
}>{this.flowStatus.get(row.fund_log_flow_links.find(i => i.tag === 'pay')?.flow_status)}</span>)
<span style={'color:' + this.flowStatusColor.get(row.flow_links?.find(i => i.tag === 'pay')?.flow_status)
}>{this.flowStatus.get(row.flow_links?.find(i => i.tag === 'pay')?.flow_status)}</span>)
}
// formatter: (cell, data, value) => {
@ -392,26 +493,28 @@ export default {
label: '财务确认状态',
width: 100,
customFn: row => {
if (row.fund_logs) {
return (row.status === 0)
? (<span style='color:rgb(96, 109, 241)'>待审核</span>)
: (<span style='color: rgb(147, 201, 134)'>已审核</span>)
}
},
{
label: '次数',
prop: 'pay_count',
width: 95,
customFn: row => {
return (<span>{ row.contract_id ? row.pay_count : row.pay_count_away }</span>)
}
},
// {
// label: '',
// prop: 'pay_count',
// width: 95,
// customFn: row => {
// return (<span>{ row.contract_id ? row.pay_count : row.pay_count_away }</span>)
// }
// },
{
label: '最后一笔',
prop: 'is_end',
width: 125,
formatter: (cell, data, value) => {
return value == 1 ? '是' : '否'
return value === 0 ? '否' : (value === 1 ? '是' : '')
}
},
{
@ -446,14 +549,14 @@ export default {
computed: {
authOa() {
return function(row) {
return row.fund_log_flow_links.find(i => i.tag === 'pay')?.flow_status === 1
return row.flow_links?.find(i => i.tag === 'pay')?.flow_status === 1
}
}
},
mounted() {
this.getDepartment()
this.getMoneyWay()
this.getFundLogs()
this.getCollects()
},
methods: {
planPageChange(e) {
@ -483,11 +586,11 @@ export default {
},
doSearch() {
this.pageIndex = 1
this.getFundLogs()
this.getCollects()
},
confirmPlanForSearch() {
this.isShowPlanForSearch = false
this.getFundLogs()
this.getCollects()
},
//
@ -545,7 +648,7 @@ export default {
},
//
planSelectForSearch() {
if (this.select.plan_id == '') {
if (this.select.plan_id === '') {
Message({
type: 'warning',
message: '选择计划不能为空'
@ -557,48 +660,51 @@ export default {
pageSizeChange(e) {
this.pageSize = e
this.pageIndex = 1
this.getFundLogs()
this.getCollects()
},
pageChange(e) {
this.pageIndex = e
this.getFundLogs()
this.getCollects()
},
toExport() {
this.is_export = 1
this.getFundLogs(true)
this.getCollects(true)
},
async getFundLogs(is_export) {
await getFundLog({
async getCollects(is_export) {
const res = await getCollect({
page_size: this.pageSize,
page: this.pageIndex,
keyword: this.keyword,
date: this.selectDate,
// keyword: this.keyword,
start_date: this.selectDate,
status: this.status,
act_plan_link_id: this.select.plan_id,
show_type: 1,
// show_type: 1,
'flow_link[0][custom_model_id]': 75,
'flow_link[0][flow_status]': this.select.flow_status,
department_id: this.select.department_id
}).then((res) => {
const tokens = getToken()
if (is_export) {
var url = '/api/ht/fund_log/index?token=' + tokens
if (this.selectDate) url += '&date=' + this.selectDate
if (this.keyword) url += '&keyword=' + this.keyword
if (typeof this.status !== 'undefined') { url += '&status=' + this.status }
if (this.select.plan_id) { url += '&act_plan_link_id=' + this.select.plan_id }
url += '&is_export=' + this.is_export
url = location.host + url
console.log(url)
window.open('http://' + url, '_blank')
this.select.is_export = 0
return
}
this.list = res.data
this.total = res.total
})
this.addParentReference(res.list.data)
this.list = []
this.list = res.list.data
console.log('this.list', this.list)
this.total = res.list.total
this.$forceUpdate()
},
addParentReference(data, parent = null) {
if (!Array.isArray(data)) return
data.forEach(node => {
node.parent = parent
if (node.fund_logs && node.fund_logs.length > 0) {
node.pid = 'p' + node.id
this.addParentReference(node.fund_logs, node)
} else {
node.pid = node.id
}
})
},
deleteFundLog(row) {
delFundLog({
id: row.id
@ -607,17 +713,162 @@ export default {
type: 'success',
message: '操作成功'
})
this.getFundLogs()
this.getCollects()
})
},
getPlanLinkData(fundLog) {
// planLinkDataMap
if (this.planLinkDataMap[fundLog.id]) {
return this.planLinkDataMap[fundLog.id]
}
// fundLog
if (!fundLog.plan_link || fundLog.plan_link.length === 0) {
return []
}
return fundLog.plan_link.map(planItem => ({
year: planItem.plan?.year || '',
name: planItem.plan?.name || '',
content: planItem.plan?.content || '',
money: planItem.plan?.money || 0,
use_money: fundLog.act_money || 0, // fund_logsact_money
selected: true, //
fund_log_id: fundLog.id,
plan_id: planItem.plan?.id || '',
plan_link_id: planItem.id
}))
},
handleSelectionChange(row, fundLogId) {
//
console.log('Selection changed:', row, fundLogId)
},
showAuditDialog(row) {
this.currentAuditRow = row
this.planLinkDataMap = {}
// fund_logsplan_link
if (row.fund_logs && row.fund_logs.length > 0) {
row.fund_logs.forEach(fundLog => {
if (fundLog.plan_link && fundLog.plan_link.length > 0) {
this.planLinkDataMap[fundLog.id] = fundLog.plan_link.map(planItem => ({
year: planItem.plan?.year || '',
name: planItem.plan?.name || '',
content: planItem.plan?.content || '',
money: planItem.plan?.money || 0,
use_money: fundLog.act_money || 0, // fund_logsact_money
selected: true, //
fund_log_id: fundLog.id,
plan_id: planItem.plan?.id || '', // planid
plan_link_id: planItem.id
}))
}
})
}
this.auditDialogVisible = true
},
confirmAudit() {
// fund_logs
if (!this.currentAuditRow.fund_logs || this.currentAuditRow.fund_logs.length === 0) {
Message({
type: 'warning',
message: '没有付款记录'
})
return
}
// contract_plan_act_links
const contract_plan_act_links = []
for (const fundLog of this.currentAuditRow.fund_logs) {
//
const fundLogProjectName = fundLog.contract_id
? (fundLog.contract ? fundLog.contract.name : '')
: (fundLog.away ? fundLog.away.title : fundLog.name)
const planLinkData = this.planLinkDataMap[fundLog.id] || []
const selectedItems = planLinkData.filter(item => item.selected)
if (selectedItems.length === 0) {
//
Message({
type: 'warning',
message: `付款登记"${fundLogProjectName}"未选择预算计划`
})
return
}
// 使
const totalUseMoney = selectedItems.reduce((sum, item) => sum + (parseFloat(item.use_money) || 0), 0)
//
const actualMoney = parseFloat(fundLog.act_money) || 0
// 使
if (totalUseMoney !== actualMoney) {
//
Message({
type: 'warning',
message: `项目"${fundLogProjectName}"的预算计划金额与实际支付金额不相等`
})
return
}
//
selectedItems.forEach(item => {
contract_plan_act_links.push({
fund_log_id: fundLog.id,
contract_id: fundLog.contract_id,
plan_id: item.plan_id,
use_money: item.use_money
})
})
}
//
console.log('准备提交的数据:', {
id: this.currentAuditRow.id,
status: 1,
contract_plan_act_links
})
//
addCollect({
id: this.currentAuditRow.id,
status: 1,
contract_plan_act_links
}).then((res) => {
Message({
type: 'success',
message: '操作成功'
})
this.auditDialogVisible = false
this.getCollects()
})
},
updateCollect(row) {
console.log('123')
addCollect({
id: row.id,
status: 1
}).then((res) => {
Message({
type: 'success',
message: '操作成功'
})
this.getCollects()
})
},
cancelExamine(row) {
editorFundLog({
id: row.id,
contract_id: row.contract_id,
status: 0
}).then((res) => {
this.getFundLogs()
this.getCollects()
Message({
type: 'success',
message: '操作成功'

@ -0,0 +1,758 @@
<template>
<div style="padding: 0 20px">
<lx-header
icon="md-apps"
text="计划执行关联"
style="margin-bottom: 10px; border: 0px; margin-top: 15px"
>
<div slot="content" />
<slot>
<div class="selects">
<div>
<span style="padding: 0 6px; word-break: keep-all">关键词</span>
<span>
<Input
v-model="keyword"
placeholder="请输入关键字"
style="width: 180px"
/>
</span>
</div>
<div>
<span style="padding: 0 6px; word-break: keep-all">是否进入资金执行率</span>
<Select
v-model="enter_act_link"
clearable
placeholder="请选择"
style="width: 120px"
>
<Option :value="0" label="否" />
<Option :value="1" label="是" />
</Select>
</div>
<div>
<span style="padding: 0 6px; word-break: keep-all">状态</span>
<Select
v-model="status"
clearable
placeholder="请选择"
style="width: 100px"
>
<Option :value="0" label="待审核" />
<Option :value="1" label="已审核" />
</Select>
</div>
<div>
<Button
type="primary"
@click="doSearch()"
>查询</Button>
</div>
<div>
<Button type="primary" ghost @click="resetSearch"></Button>
</div>
</div>
</slot>
</lx-header>
<xy-table :list="list" :table-item="table">
<template v-slot:btns>
<el-table-column
label="操作"
:fixed="$store.getters.device === 'mobile'?false:'right'"
width="180"
header-align="center"
>
<template slot-scope="scope">
<Button
size="small"
type="primary"
style="margin-left: 10px; margin-bottom: 4px"
@click="showEditDialog(scope.row)"
>修改资金执行率</Button>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex; justify-content: flex-end">
<Page
:total="total"
show-elevator
show-sizer
@on-change="pageChange"
@on-page-size-change="pageSizeChange"
/>
</div>
<!-- 修改资金执行率弹窗 -->
<el-dialog
title="修改资金执行率"
:visible.sync="editDialogVisible"
width="80%"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div v-if="currentEditRow">
<!-- 基本信息 -->
<div style="margin-bottom: 20px; color: #000;display: flex;justify-content: space-between;">
<div v-if="currentEditRow.contract">
<strong>合同名称</strong>{{ currentEditRow.contract.name }}
</div>
<div v-if="currentEditRow.fund_log_collect">
<strong>付款集合</strong>{{ currentEditRow.fund_log_collect.name }}
</div>
<div>
<strong>金额</strong>{{ currentEditRow.apply_money ? Number(currentEditRow.apply_money).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : '' }}
</div>
</div>
<!-- 预算计划搜索区域 -->
<div class="select-container" style="margin-bottom: 20px;">
<DatePicker
:value="planSelect.year"
placeholder="选择所属年份"
placement="bottom-start"
style="width: 180px; margin-right: 10px"
type="year"
@on-change="handleYearChange"
/>
<el-select
v-model="planSelect.plan_department_id"
placeholder="科室选择"
clearable
size="small"
style="width: 180px; margin-right: 10px"
@change="getBudgets(true)"
>
<el-option
v-for="item in departments"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-cascader
:value="planSelect.type"
:options="planTypes"
:props="{
checkStrictly: false,
label: 'name',
value: 'id',
}"
placeholder="资金类型选择"
clearable
size="small"
style="width: 220px; margin-right: 10px"
@change="handleTypeChange"
/>
<Input
v-model="planSelect.name"
search
enter-button="搜 索"
clearable
placeholder="搜索预算计划.."
@on-search="getBudgets(true)"
/>
</div>
<!-- plan_link表格有数据时显示 -->
<div v-if="showPlanLinkTable && currentEditRow.plan_link && currentEditRow.plan_link.length > 0">
<h5 style="margin-bottom: 10px; color: #67C23A;">预算计划使用情况</h5>
<el-table :data="getPlanLinkData(currentEditRow)" border>
<el-table-column label="" width="55" align="center">
<template slot-scope="scope">
<el-checkbox v-model="scope.row.selected" @change="handleSelectionChange(scope.row)" />
</template>
</el-table-column>
<el-table-column prop="year" label="年份" width="100" align="center" />
<el-table-column prop="name" label="名称" min-width="200" />
<el-table-column prop="content" label="内容" min-width="200" />
<el-table-column prop="money" label="计划金额" width="150" align="right">
<template slot-scope="scope">
{{ scope.row.money ? Number(scope.row.money).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : '' }}
</template>
</el-table-column>
<el-table-column label="使用金额" width="150" align="right">
<template slot-scope="scope">
<el-input-number
v-model="scope.row.use_money"
:precision="2"
:min="0"
:max="999999999"
:disabled="!scope.row.selected"
controls-position="right"
size="small"
style="width: 100%"
/>
</template>
</el-table-column>
</el-table>
</div>
<!-- 预算计划选择表格没有plan_link数据或搜索后显示 -->
<div v-if="!showPlanLinkTable">
<h5 style="margin-bottom: 10px; color: #67C23A;">选择预算计划</h5>
<xy-table
:header-cell-class-name="cellClassName"
:list="plans"
:show-index="false"
:table-item="planTable"
:height="400"
style="margin-top: 10px"
ref="planSelectTable"
row-key="id"
border
default-expand-all
@select="planPick"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<template v-slot:btns>
<el-table-column
label="使用金额(元)"
:fixed="$store.getters.device === 'mobile' ? false : 'right'"
header-align="center"
width="144"
>
<template slot-scope="scope" v-if="scope.row.pid > 0">
<InputNumber
style="width: 120px"
:min="0"
:precision="2"
:active-change="false"
v-model="scope.row._inputMoney"
:formatter="
(value) =>
`${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
"
:parser="(value) => value.replace(/\$\s?|(,*)/g, '')"
/>
</template>
</el-table-column>
</template>
</xy-table>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="handleDialogClose"></el-button>
<el-button type="primary" @click="confirmEdit"></el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getPlanActLinks, updateContractPlanActLinks } from '@/api/planActLink/index'
import { Message } from 'element-ui'
import { getBudget } from '@/api/budget/budget'
import { getparameterTree } from '@/api/system/dictionary'
import { listdeptNoAuth } from '@/api/system/department'
export default {
data() {
return {
keyword: '',
enter_act_link: '',
status: '',
list: [],
total: 0,
pageIndex: 1,
pageSize: 10,
editDialogVisible: false,
currentEditRow: null,
planLinkDataMap: {},
showPlanLinkTable: false, // plan_link
plans: [], //
departments: [], //
planTypes: [], //
planSelect: {
name: '',
page_size: 20,
page: 1,
is_tree: 1,
year: new Date().getFullYear().toString(),
plan_department_id: '',
type: ''
},
planTable: [
{
sortable: false,
width: 44,
type: 'selection',
reserveSelection: true,
fixed: 'left',
selectable: (row, index) => {
return row.pid > 0
}
},
{
label: '科室',
prop: 'plan_department.name',
width: 120,
align: 'center'
},
{
label: '年份',
prop: 'year',
width: 80,
align: 'center'
},
{
label: '分类',
prop: 'type_detail.value',
width: 120
},
{
label: '名称',
prop: 'name',
minWidth: 180,
align: 'left'
},
{
label: '内容',
prop: 'content',
minWidth: 240,
align: 'left',
showOverflowTooltip: true
},
{
label: '计划金额',
prop: 'money',
align: 'right',
width: 120,
formatter: (v1, v2, value) => {
return `${
value && parseFloat(value) !== 0 ? value : v1.update_money
}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
},
{
label: '实付金额',
prop: 'use_money_total',
width: 120,
align: 'right',
formatter: (v1, v2, value) =>
value ? `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',') : ''
},
{
label: '已用金额',
prop: 'has_money_total',
width: 120,
align: 'right',
formatter: (v1, v2, value) =>
value ? `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',') : ''
}
],
table: [
{
label: '合同名称',
prop: 'contract.name',
minWidth: 200,
align: 'left'
},
{
label: '付款集合',
prop: 'fund_log_collect.name',
minWidth: 200,
align: 'left'
},
{
label: '金额',
prop: 'apply_money',
width: 150,
align: 'right',
formatter: (cell, data, value) => {
return value ? Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, '$1,') : ''
}
},
{
label: '状态',
prop: 'status',
width: 100,
align: 'center',
customFn: row => {
return row.status === 0
? (<span style='color:rgb(96, 109, 241)'>待审核</span>)
: (<span style='color: rgb(147, 201, 134)'>已审核</span>)
}
},
{
label: '计划预算资金',
width: 300,
align: 'left',
customFn: (row) => {
if (row.plan_link && row.plan_link.length > 0) {
return row.plan_link.map((item) => {
const planId = item.plan_id || ''
const year = item.plan?.year || ''
const planName = item.plan?.name || ''
const useMoney = item.use_money || 0
return (
<div>
{planId} - [{year}] - {planName} -{useMoney}
</div>
)
})
}
return null
}
},
{
label: '实际预算资金',
width: 300,
align: 'left',
customFn: (row) => {
if (row.plan_act_links && row.plan_act_links.length > 0) {
return row.plan_act_links.map((item) => {
const planId = item.plan_id || ''
const year = item.plan?.year || ''
const planName = item.plan?.name || ''
const useMoney = item.use_money || 0
return (
<div key={planId}>
{planId} - [{year}] - {planName} -{useMoney}
</div>
)
})
}
return null
}
}
]
}
},
mounted() {
this.getList()
this.getDepartment()
this.getPlanTypes()
},
methods: {
//
async getList() {
try {
const params = {
page: this.pageIndex,
page_size: this.pageSize
}
if (this.keyword) {
params.keyword = this.keyword
}
if (this.enter_act_link !== '') {
params.enter_act_link = this.enter_act_link
}
if (this.status !== '') {
params.status = this.status
}
const res = await getPlanActLinks(params)
this.list = res.list?.data || res.data || []
this.total = res.list?.total || res.total || 0
} catch (error) {
Message({
type: 'error',
message: '获取数据失败'
})
console.error('获取列表数据失败:', error)
}
},
//
doSearch() {
this.pageIndex = 1
this.getList()
},
//
resetSearch() {
this.keyword = ''
this.enter_act_link = ''
this.status = ''
this.pageIndex = 1
this.pageSize = 10
this.getList()
},
//
pageChange(e) {
this.pageIndex = e
this.getList()
},
//
pageSizeChange(e) {
this.pageSize = e
this.pageIndex = 1
this.getList()
},
//
showEditDialog(row) {
this.currentEditRow = row
this.planLinkDataMap = {}
this.plans = []
// plan_linkplan_link
if (row.plan_link && row.plan_link.length > 0) {
this.showPlanLinkTable = true
this.planLinkDataMap[row.id] = row.plan_link.map(planItem => ({
year: planItem.plan?.year || '',
name: planItem.plan?.name || '',
content: planItem.plan?.content || '',
money: planItem.plan?.money || 0,
use_money: planItem.use_money || 0,
selected: true, //
plan_id: planItem.plan?.id || '',
plan_link_id: planItem.id
}))
} else {
// plan_link
this.showPlanLinkTable = false
this.getBudgets(false)
}
this.editDialogVisible = true
},
// plan_link
getPlanLinkData(row) {
// planLinkDataMap
if (this.planLinkDataMap[row.id]) {
return this.planLinkDataMap[row.id]
}
// row
if (!row.plan_link || row.plan_link.length === 0) {
return []
}
return row.plan_link.map(planItem => ({
year: planItem.plan?.year || '',
name: planItem.plan?.name || '',
content: planItem.plan?.content || '',
money: planItem.plan?.money || 0,
use_money: planItem.use_money || 0,
selected: true, //
plan_id: planItem.plan?.id || '',
plan_link_id: planItem.id
}))
},
//
handleSelectionChange(row) {
//
},
//
clearDialogData() {
//
this.$refs.planSelectTable?.clearSelection()
//
this.currentEditRow = null
this.planLinkDataMap = {}
this.plans = []
this.showPlanLinkTable = false
//
this.planSelect = {
name: '',
page_size: 20,
page: 1,
is_tree: 1,
year: new Date().getFullYear().toString(),
plan_department_id: '',
type: ''
}
},
//
handleDialogClose() {
this.clearDialogData()
this.editDialogVisible = false
},
//
async confirmEdit() {
if (!this.currentEditRow) {
return
}
let act_plan = []
if (this.showPlanLinkTable) {
// plan_link
const planLinkData = this.planLinkDataMap[this.currentEditRow.id] || []
const selectedItems = planLinkData.filter(item => item.selected)
if (selectedItems.length === 0) {
Message({
type: 'warning',
message: '请至少选择一条预算计划'
})
return
}
// 使0
for (let i = 0; i < selectedItems.length; i++) {
const item = selectedItems[i]
const useMoney = parseFloat(item.use_money) || 0
if (useMoney <= 0) {
Message({
type: 'warning',
message: `预算计划"${item.name}"的使用金额必须大于0`
})
return
}
}
act_plan = selectedItems.map(item => ({
plan_id: item.plan_id,
use_money: parseFloat(item.use_money) || 0
}))
} else {
//
const selections = this.$refs.planSelectTable?.getSelection() || []
const validSelections = selections.filter(item => item.pid > 0)
if (validSelections.length === 0) {
Message({
type: 'warning',
message: '请至少选择一条预算计划'
})
return
}
// 使0
for (let i = 0; i < validSelections.length; i++) {
const item = validSelections[i]
const useMoney = parseFloat(item._inputMoney) || 0
if (useMoney <= 0) {
Message({
type: 'warning',
message: `预算计划"${item.name}"的使用金额必须大于0`
})
return
}
}
act_plan = validSelections.map(item => ({
plan_id: item.id,
use_money: parseFloat(item._inputMoney) || 0
}))
}
console.log('act_plan', act_plan,this.currentEditRow.contract_id,this.currentEditRow.id)
// return
await updateContractPlanActLinks({
contract_id: this.currentEditRow.contract_id,
fund_log_id: this.currentEditRow.id,
act_plan
})
Message({
type: 'success',
message: '保存成功'
})
this.clearDialogData()
this.editDialogVisible = false
this.getList()
},
//
getDepartment() {
listdeptNoAuth().then((res) => {
this.departments = res.data || []
})
},
//
async getPlanTypes() {
const res = await getparameterTree({
id: 3
})
const dataHandler = (data) => {
data.forEach((i) => {
if (Object.prototype.hasOwnProperty.call(i, 'detail')) {
i.children = i.detail.map((j) => {
j.name = j.value
return j
})
} else if (i.children) {
dataHandler(i.children)
}
})
return data
}
this.planTypes = dataHandler(res?.children) || []
},
//
handleYearChange(e) {
this.planSelect.year = e
this.getBudgets(true)
},
//
handleTypeChange(e) {
this.planSelect.type = e && e.length > 0 ? e[e.length - 1] : ''
this.getBudgets(true)
},
//
async getBudgets(refresh) {
if (refresh) {
//
this.$refs.planSelectTable?.clearSelection()
// plan_link
if (this.showPlanLinkTable) {
this.showPlanLinkTable = false
this.planLinkDataMap = {}
}
}
const res = await getBudget(this.planSelect)
this.initInputMoney(res.list)
this.plans = res.list || []
},
//
initInputMoney(list) {
if (!Array.isArray(list)) return []
return list.map((item) => {
this.$set(item, '_inputMoney', 0)
if (Array.isArray(item.children)) {
item.children = this.initInputMoney(item.children)
}
return item
})
},
//
cellClassName({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
return 'allSelect'
}
},
//
planPick(selection, row) {
if (row.year != new Date().getFullYear()) {
this.$confirm('您选择了非本年预算,是否继续?').catch(() => {
this.$refs.planSelectTable.toggleRowSelection(row)
})
}
}
}
}
</script>
<style scoped lang="scss">
.select-container {
display: flex;
justify-content: space-between;
align-items: center;
}
::v-deep .allSelect .cell {
display: none;
}
.selects {
display: flex;
flex-wrap: wrap;
& > div {
margin-bottom: 6px;
margin-right: 4px;
& > span {
word-break: keep-all;
padding: 0 4px;
}
}
}
</style>
Loading…
Cancel
Save