nut-collapse折叠面板(案例)
nut-collapse折叠面板(案例)
官方文档地址:
- nut-collapse折叠面板
- 基础用法
CollapseItem 组件必须设置 name 属性作为唯一标识符。- 绑定数据与事件
通过 v-model 可以控制展开的 CollapseItem,默认情况下为数组类型,其中的值是对应 CollapseItem 的 name 属性。- 手风琴
通过 accordion 可以设置为手风琴模式,最多展开一个面板,此时 v-model 为单个 name。
场景问题
- 可解决多个折叠配置下,每次点击只打开一个,
- 可解决,每次打开只打开一个
- 自定义显示name及删除按钮,插槽位置等排版布局问题
(具体参考代码及效果图,不再赘述。)
案例截图
- 案例截图:
附:案例代码
-
案例代码:
<template> <view id="detailsHeight"> <nut-form ref="ruleForm" :disabled="otherData.globalDisabled" :model-value="formData" :rules="rules"> <view class='nut_form_module'> <view class="formHeader"> <view class="titleHeader">费用报销单-基本信息<text v-if="formData.receiptNo">(单号:{{formData.receiptNo}})</text></view> </view> <nut-form-item label="公司名称" prop="companyName"> <nut-input input-align="right" disabled v-model="formData.companyName" class="nut-input-text" clearable placeholder="自动带出" type="text" /> </nut-form-item> <nut-form-item label="费用归属部门" label-width="100px" prop="budgetDeptId" required :rules="rules.budgetDeptId"> <CascaderSelect :disabled="otherData.globalDisabled" :options="attributionOptions" :backData="formData.budgetDeptId" @changeDept="handleChangeDept1" /> </nut-form-item> <nut-form-item label="预算承担部门" label-width="100px" prop="budgetOrgId" required :rules="rules.budgetOrgId" > <CascaderSelect :disabled="otherData.globalDisabled" :options="budgetOptions" :back-data="formData.budgetOrgId" @changeDept="handleChangeDept2" /> </nut-form-item> <nut-form-item label="报销人" prop="creatorName" > <nut-input disabled input-align="right" v-model="formData.creatorName" class="nut-input-text" clearable placeholder="请输入" type="text" /> </nut-form-item> <!-- <nut-form-item label="选择申请单" prop="receiptApply.applyId" :rules="[{required:otherData.setup?.budgetCostSuit == '1',message:'请选择申请单',trigger:'change'}]" > <PickerInput :disabled="otherData.globalDisabled" v-model='formData.receiptApply.applyId' :columns='otherData.myApplyListOptions' :fieldNames="{text:'receiptNo',value:'id',children: 'children'}"></PickerInput> </nut-form-item>--> <nut-form-item label="选择申请单" :label-width="100" prop="receiptApply" v-if="otherData.setup?.budgetCostSuit == '1'" :required="otherData.setup?.budgetCostSuit == '1'"> <template v-if="!otherData.globalDisabled"> <SingleChoice :disabled="otherData.globalDisabled" v-model="formData.receiptApply.applyId" :columns="otherData.myApplyListOptions" :options="{text: 'receiptNo',value: 'id',children: 'children'}" @change="watchThen" /> </template> <view v-else class="item-link" @click="pageTo(formData.receiptApply.applyId)" style="text-align: right"> {{formData.receiptApply.applyReceiptNo}} </view> </nut-form-item> <nut-form-item label="业务项目" prop="busiProjectId"> <SingleChoice :disabled="true" placeholder="自动带出" v-model="formData.busiProjectId" :columns="busiProjectOptions" :options="{text: 'projectName',value: 'pkProject',children: 'children'}" @change='businessChange' /> </nut-form-item> <nut-form-item label="可用额度" :label-width="100" v-if="!otherData.globalDisabled" v-show="otherData.setup?.budgetCostSuit=='1'"> <nut-input v-model="otherData.applyRemainMoneySum" disabled class="nut-input-text" clearable placeholder="自动计算" type="digit"> <template #right><span style="color: #666666">元</span></template> </nut-input> </nut-form-item> <nut-form-item label="费用合计" prop="receiptMoney" > <nut-input input-align="right" v-model="formData.receiptMoney" disabled class="nut-input-text" clearable placeholder="自动计算" type="digit" > <template #right><span style="color: #666666">元</span></template> </nut-input> </nut-form-item> <nut-form-item label="借款余额" prop="borrowRemainMoneySum"> <nut-input input-align="right" v-model="otherData.borrowRemainMoneySum" disabled class="nut-input-text" clearable placeholder="自动计算" type="digit" > <template #right><span style="color: #666666">元</span></template> </nut-input> </nut-form-item> <nut-form-item label="冲销金额" prop="coverMoneySum"> <nut-input input-align="right" v-model="otherData.coverMoneySum" disabled class="nut-input-text" clearable placeholder="自动计算" type="digit" > <template #right><span style="color: #666666">元</span></template> </nut-input> </nut-form-item> <nut-form-item label="支付金额" prop="payMoney"> <nut-input input-align="right" v-model="formData.payMoney" disabled class="nut-input-text" clearable placeholder="自动计算" type="digit" > <template #right><span style="color: #666666">元</span></template> </nut-input> </nut-form-item> <nut-form-item label="报销事由" label-position="top" prop="reason" required> <nut-textarea :disabled="otherData.globalDisabled" v-model="formData.reason" :rows="4" placeholder="请填写申请事由" limit-show max-length="100" @blur="customBlurValidate('reason')" /> </nut-form-item> </view> <view class="nut_form_module nut-cell-module collpase_xj-css2"> <view class="divide"></view> <view class="formHeader"> <view class="titleHeader">费用导入(合计:{{otherData.myfeeMoneySum?otherData.myfeeMoneySum:0}}元)</view> <nut-button plain size="small" type="primary" @click="addInfo()" v-if="!otherData.globalDisabled">导入费用</nut-button> </view> <!--<nut-form-item label="费用导入" label-position="top" prop='fee'>--> <!--<template v-slot:label> <view class="flex"> <view>费用明细</view> <view> <nut-icon name="uploader" @click="addInfo" v-if="!otherData.globalDisabled"></nut-icon> </view> </view> </template>--> <nut-collapse v-model:activate='activateFee' @change="onChange"> <view v-for="(item, index) in formData.myfeeList" :key="item.id" > <nut-collapse-item :title="item.myfeeInfo.modelItemName" :name="item.myfeeNo+'_'+index"> <template v-slot:value> <nut-icon v-if="!otherData.globalDisabled" name="del" custom-color="red" @click="delInfo(index)" ></nut-icon> </template> <view style="padding: 0 5px; margin-bottom: 10px"> <nut-input disabled input-align="right" class="input_info" v-model="item.myfeeInfo.modelItemName" :border="true" type="text" > <template #left> <view class='color-black'>费用科目</view> </template> </nut-input> <nut-input disabled input-align="right" class="input_info" v-model="item.myfeeInfo.myfeeNo" :border="true" placeholder="费用单号" type="text" v-if="!otherData.globalDisabled" > <template #left> <view class='color-black'>费用单号</view> </template> </nut-input> <view v-else class="nut-input nut-input--disabled nut-input--border nut-input-text input_info"> <view class="nut-input-value"> <view class="nut-input-inner"> <view class="nut-input-left-box"> <text class="color-black">费用单号</text> </view> <view class="nut-input-box"> <view class="input-text"> <view class="item-link" @click="pageToFee(item.myfeeInfo.id)"> {{item.myfeeInfo.myfeeNo}} </view> </view> </view> </view> </view> </view> <nut-input disabled input-align="right" class="input_info" :model-value='getDictLabel(DICT_TYPE.FEE_MYFEE_STATUS,item.myfeeInfo.status)' :border="true" placeholder="自动带出" type="text" > <template #left> <view class='color-black'>报销状态</view> </template> </nut-input> <nut-input disabled input-align="right" class="input_info" v-model="item.myfeeInfo.myfeeMoney" :border="true" placeholder="金额(元)" type="text" > <template #left> <view class='color-black'>金额</view> </template> <template #right> <view class='color-black'>元</view> </template> </nut-input> <nut-input disabled input-align="right" class="input_info" :model-value='formatToDateTime(item.myfeeInfo.myfeeDate)' :border="true" placeholder="日期" type="text" > <template #left> <view class='color-black'>日期</view> </template> </nut-input> <nut-input disabled v-if="!otherData.globalDisabled && otherData.setup?.budgetLevel!='1'" input-align="right" class="input_info" v-model="item.budgetRemainMoney" :border="true" placeholder="可用预算" type="text" > <template #left> <view class='color-black'>可用预算</view> </template> </nut-input> </view> </nut-collapse-item> </view> </nut-collapse> <!--</nut-form-item>--> </view> <view class="nut_form_module"> <view class="divide"></view> <view class="formHeader"> <view class="titleHeader">账户信息</view> </view> <nut-form-item label="账户类型" prop="payTarget" :label-width="100"> <view style="text-align: right;"> <nut-radio-group v-model="formData.payTarget" :disabled="otherData.globalDisabled" direction="horizontal" @change='handleChangePayTarget'> <nut-radio label="1">个人</nut-radio> <nut-radio label="3">供应商</nut-radio> </nut-radio-group> </view> </nut-form-item> <nut-form-item :label="formData.payTarget != '1'?'供应商':'选择账户'" prop="payAccountName" > <template v-if="formData.payTarget != '1'"> <SingleChoice :disabled="otherData.globalDisabled" v-model="formData.payAccountName" :columns="customerList" :options="{text: 'supplierName',value: 'id',children: 'children'}" @change="e => handleSupplierChange(e, 'handle')" /> </template> <template v-else> <nut-input input-align="right" v-model="formData.payAccountName" class="nut-input-text" clearable disabled placeholder="请输入" type="text" /> </template> </nut-form-item> <nut-form-item label="账号" prop="payAccountNo"> <template v-if="formData.payTarget != '1'"> <SingleChoice :disabled="otherData.globalDisabled" v-model="formData.payAccountNo" :columns="accountDataList" :options="{text: 'accountName',value: 'id',children: 'children'}" @change="e => confirmSupplierAccount(e)" /> </template> <template v-else> <nut-input input-align="right" v-model="formData.payAccountNo" class="nut-input-text" clearable disabled placeholder="请输入" type="text" /> </template> </nut-form-item> <nut-form-item label="开户行" prop="payAccountBank"> <nut-input disabled input-align="right" v-model="formData.payAccountBank" class="nut-input-text" clearable placeholder="请输入" type="text" /> </nut-form-item> <template v-if="formData.payTarget !=='1'"> <nut-form-item label="行号" prop="payBankSerial"> <nut-input disabled input-align="right" v-model="formData.payBankSerial" class="nut-input-text" clearable placeholder="请输入" type="text" /> </nut-form-item> </template> </view> <view class="nut_form_module nut-cell-module collpase_xj-css2" v-if="formData.payTarget == '1'"> <view class="divide"></view> <view class="formHeader"> <view class="titleHeader">借款单信息</view> <nut-button plain size="small" type="primary" @click="handleBorrowAdd" v-if="!otherData.globalDisabled">添加借款单</nut-button> </view> <!--<nut-form-item label="添加借款单" label-position="top" prop='borrow'>--> <!--<template v-slot:label> <view class="flex"> <view>添加借款单</view> <view> <nut-icon name="uploader" @click="handleBorrowAdd" v-if="!otherData.globalDisabled"></nut-icon> </view> </view> </template>--> <nut-collapse v-model:activate='activateBorrow' @change="onChange"> <view v-for="(item, index) in formData.borrowList" :key="item.id"> <nut-collapse-item :title="item.borrowInfo.receiptNo" :name="item.receiptNo+'_'+index"> <template v-slot:value> <nut-icon v-if="!otherData.globalDisabled" name="del" custom-color="red" @click="handleBorrowDelete(index)" ></nut-icon> </template> <view style="padding: 0 5px; margin-bottom: 10px"> <nut-input disabled input-align="right" class="input_info" v-model="item.borrowInfo.receiptNo" :border="true" type="text" v-if="!otherData.globalDisabled" > <template #left> <view class='color-black'>借款单号</view> </template> </nut-input> <view v-else class="nut-input nut-input--disabled nut-input--border nut-input-text input_info"> <view class="nut-input-value"> <view class="nut-input-inner"> <view class="nut-input-left-box"> <text class="color-black">借款单号</text> </view> <view class="nut-input-box"> <view class="input-text"> <view class="item-link" @click="pageToLoan(item.borrowInfo.id)"> {{item.borrowInfo.receiptNo}} </view> </view> </view> </view> </view> </view> <nut-input disabled input-align="right" class="input_info" v-model="item.borrowInfo.receiptMoney" :border="true" placeholder="借款金额" type="text" > <template #left> <view class='color-black'>借款金额</view> </template> <template #right> <view class='color-black'>元</view> </template> </nut-input> <nut-input disabled input-align="right" class="input_info" v-model="item.borrowInfo.remainMoney" :border="true" type="text" > <template #left> <view class='color-black'>借款余额</view> </template> <template #right> <view class='color-black'>元</view> </template> </nut-input> <nut-input :disabled="otherData.globalDisabled" input-align="right" class="input_info" v-model="item.coverMoney" :border="true" type="text" placeholder='请输入' > <template #left> <view >冲销金额</view> </template> <template #right> <view>元</view> </template> </nut-input> </view> </nut-collapse-item> </view> </nut-collapse> <!--</nut-form-item>--> </view> <view class="nut_form_module nut-cell-module collpase_xj-css2" v-if="formData.payTarget != '1'"> <view class="divide"></view> <view class="formHeader"> <view class="titleHeader">预付单信息</view> <nut-button plain size="small" type="primary" @click="addLoanPrepayClick" v-if="!otherData.globalDisabled">添加预付单</nut-button> <LoanPrepay code="YFGD" ref="LoanPrepayRef" :getListApi="getMyReceiptPageBy" @change="e=>handleChangeLoanPrepay(e,'prepayList')" /> </view> <!--<nut-form-item label="添加借款单" label-position="top" prop='borrow'>--> <!--<template v-slot:label> <view class="flex"> <view>添加预付单</view> <view> <nut-icon name="uploader" @click="addLoanPrepayClick" v-if="!otherData.globalDisabled"></nut-icon> <LoanPrepay code="YFGD" ref="LoanPrepayRef" :getListApi="getMyReceiptPageBy" @change="e=>handleChangeLoanPrepay(e,'prepayList')" /> </view> </view> </template>--> <nut-collapse v-model:activate='activatePrepay' @change="onChange"> <view v-for="(item, index) in formData.prepayList" :key="item.id"> <nut-collapse-item :title="item.prepayInfo.receiptNo" :name="item.receiptNo+'_'+index"> <template v-slot:value> <nut-icon v-if="!otherData.globalDisabled" name="del" custom-color="red" @click="removePrepay(index)" ></nut-icon> </template> <view style="padding: 0 5px; margin-bottom: 10px"> <nut-input disabled input-align="right" class="input_info" v-model="item.prepayInfo.receiptNo" :border="true" type="text" v-if="!otherData.globalDisabled" > <template #left> <view class='color-black'>预付单号</view> </template> </nut-input> <view v-else class="nut-input nut-input--disabled nut-input--border nut-input-text input_info"> <view class="nut-input-value"> <view class="nut-input-inner"> <view class="nut-input-left-box"> <text class="color-black">预付单号</text> </view> <view class="nut-input-box"> <view class="input-text"> <view class="item-link" @click="pageToPrepay(item.prepayInfo.id)"> {{item.prepayInfo.receiptNo}} </view> </view> </view> </view> </view> </view> <nut-input disabled input-align="right" class="input_info" v-model="item.prepayInfo.receiptMoney" :border="true" placeholder="预付金额" type="text" > <template #left> <view class='color-black'>预付金额</view> </template> <template #right> <view class='color-black'>元</view> </template> </nut-input> <nut-input disabled input-align="right" class="input_info" v-model="item.prepayInfo.remainMoney" :border="true" type="text" > <template #left> <view class='color-black'>预付余额</view> </template> <template #right> <view class='color-black'>元</view> </template> </nut-input> <nut-input :disabled="otherData.globalDisabled" input-align="right" class="input_info" v-model="item.coverMoney" :border="true" type="text" placeholder='请输入' > <template #left> <view >冲销金额</view> </template> <template #right> <view>元</view> </template> </nut-input> </view> </nut-collapse-item> </view> </nut-collapse> <!--</nut-form-item>--> </view> <view > <view class="divide"></view> <view class="formHeader"> <view class="titleHeader">附件信息</view> <nut-button v-if="!otherData.globalDisabled" :disabled="otherData.globalDisabled" plain size="small" type="primary" @click="handleUpload">上传文件</nut-button> </view> <Uploader :disabled="otherData.globalDisabled" ref="uploader" :isBtn="false" :business-id="formId" :business-type="MinioBusinessType.FYBX" @onSuccess="handleSuccess" @onChange="handleChange" /> </view> </nut-form> </view> <!--tabbar底部导航区--> <nut-tabbar v-if="showTabbar === 'no'" bottom class="tabbar-bottom-fixed" placeholder safe-area-inset-bottom> <nut-row v-if="!source" :gutter="10"> <nut-col :span="24"> <nut-button block shape="square" @click="close" >取消 </nut-button> </nut-col> </nut-row> </nut-tabbar> <nut-tabbar v-else bottom class="tabbar-bottom-fixed" placeholder safe-area-inset-bottom > <nut-row v-if="!source" :gutter="10"> <nut-col :span="!otherData.globalDisabled?8:(((btnReceiptStatus == '2' && formData.userId == userInfo.id) || (btnReceiptStatus == 3 && formData.category == 1 && formData.caseStatus == 1 && formData.userId == userInfo.id))?12:24)"> <nut-button block :loading='formLoading' shape="square" @click="close" >取消 </nut-button> </nut-col> <nut-col :span="8"> <nut-button v-show="!otherData.globalDisabled" block custom-color="#4869D9" shape="square" type="primary" @click="submit('1')" >保存 </nut-button> </nut-col> <nut-col :span="8"> <nut-button v-show="!otherData.globalDisabled" block custom-color="#4869D9" shape="square" type="primary" @click="submit('2')" >提交 </nut-button> </nut-col> <nut-col :span="12" v-if="otherData.globalDisabled && btnReceiptStatus == 2 && formData.userId == userInfo.id"> <nut-button block custom-color="#4869D9" shape="square" type="primary" @click="handleBackReceipt(formData.id)">撤回</nut-button> </nut-col> <nut-col :span="12" v-if="otherData.globalDisabled && btnReceiptStatus == 3 && formData.category == 1 && formData.caseStatus == 1 && formData.userId == userInfo.id"> <nut-button block custom-color="#4869D9" shape="square" type="primary" @click="handleCaseReceipt(formData.id)">结案</nut-button> </nut-col> </nut-row> </nut-tabbar> </template> <script lang="ts" setup> import { backReceiptInfo, caseReceiptInfo, getMyReceiptPageBy, type ReceiptPrepayVO } from '@/api/fee/receipt' import type {ReceiptBorrowVO,ReceiptMyfeeVO} from "@/api/fee/receipt"; import {handleTree} from "@/utils/tree"; import * as AreaApi from '@/api/system/area' import * as BaseFeeApi from '@/api/fee/baseFee' import * as BusiProjectApi from '@/api/fee/busiProject' import * as BudgetInfoApi from '@/api/fee/budgetinfo' import * as SetupApi from "@/api/fee/setup"; import * as DeptApi from "@/api/system/dept"; import * as SelfAccountApi from '@/api/fee/selfAccount' import * as ReceiptInfoApi from '@/api/fee/receipt' import Uploader from '@/components/Uploader/index.vue' import SingleChoice from '@/components/selectItem/SingleChoice.vue' import { MinioBusinessType } from "@/config" import { computed, nextTick, reactive, ref, watch, watchEffect } from 'vue' import { getBaseFeeTreeListByOrg } from '@/api/fee/baseFee' import CascaderSelect from '@/components/selectItem/CascaderSelect.vue' import { getMyBusiProjectList } from '@/api/fee/busiProject' import { useUserStore } from '@/store/user' const disabled = ref(false) //禁用表单 const btnReceiptStatus = ref('')//区分按钮显示 const { userInfo } = useUserStore() import { onLoad,onShow,onUnload } from "@dcloudio/uni-app"; import { routerTo, toast } from '@/utils/tool' import { getDictLabel,DICT_TYPE} from '@/utils/dict' import { formatToDateTime }from'@/utils/dateUtil' import LoanPrepay from '@/components/selectItem/LoanPrepay.vue' const formType = ref('') const formId = ref() const showBtnGroup = ref(true) const activateFee = reactive([]) const activateBorrow = reactive([]) const activatePrepay = reactive([]) const source = ref('') const showTabbar = ref('') onLoad((options:any)=>{ formData.value.companyName = userInfo.companyName formData.value.creatorName = userInfo.nickname formType.value = options.type ?? 'create' showTabbar.value = options?.tabbar formId.value = options.id otherData.globalDisabled = options.type === 'preview' || Number(options.globalDisabled) == 1; disabled.value = options.type === 'preview' || Number(options.globalDisabled) == 1; if(options.id){ showBtnGroup.value = false //隐藏按钮组 } getProject() initPageInfo(options.id) source.value = options.source nextTick(() => { setTimeout(()=>{ console.log(document.getElementById('detailsHeight')?.getBoundingClientRect()) window.parent.postMessage({height:document.getElementById('detailsHeight')?.getBoundingClientRect().height}, '*') },300) }) }) const onChange = () => { nextTick(() => { setTimeout(()=>{ console.log(document.getElementById('detailsHeight')?.getBoundingClientRect()) window.parent.postMessage({height:document.getElementById('detailsHeight')?.getBoundingClientRect().height}, '*') },300) }) } const reshowAllCascader = async () => { //待编辑 if (formData.value.receiptStatus == 1) { //实时查询已导入费用的实时预算 if (formData.value.myfeeList) { for (const item of formData.value.myfeeList) { //实时查询费用科目的预算 const budgetData = await BudgetInfoApi.getRemainMoney({modelItemId:item.myfeeInfo.modelItemId, deptId:formData.value.budgetOrgId}); let budgetList = budgetData.data item.budgetRemainMoney = budgetList.list&&budgetList.list.length>0?budgetList.remainMoneySum:'--无科目预算--'; } } } } onShow(()=>{ uni.$on('selectList',async (res)=>{ const tempArr: ReceiptMyfeeVO[]=[] for (const item of res) { const myfeeObj = {myfeeId:item.id, myfeeInfo: item} as ReceiptMyfeeVO; if (otherData.setup.budgetLevel !='1') { //非 无管控场景,查询实时科目预算 const res = await BudgetInfoApi.getRemainMoney({modelItemId:item.modelItemId, deptId:formData.value.budgetOrgId}); const budgetData = res.data myfeeObj.budgetRemainMoney = budgetData.list&&budgetData.list.length>0?budgetData.remainMoneySum:'--无科目预算--'; } tempArr.push(myfeeObj); } formData.value.myfeeList = JSON.parse(JSON.stringify(tempArr)) console.log(formData.value.myfeeList,'formData.value.myfeeList') }) uni.$on('feeBorrowList',(res)=>{ const newBorrowList:ReceiptBorrowVO[] = []; res.forEach(item => { const existingBorrow = formData.value.borrowList.find(borrow => borrow.borrowId === item.id); if (existingBorrow) { newBorrowList.push(existingBorrow); } else { // newBorrowList.push({borrowId: item.id,borrowMoney: item.receiptMoney,coverMoney: '',borrowInfo: item} as ReceiptBorrowVO); newBorrowList.push({borrowId: item.id,borrowMoney: item.receiptMoney,coverMoney: item.remainMoney, borrowInfo: item} as ReceiptBorrowVO);//默认带出:冲销金额=借款余额 } }); formData.value.borrowList=JSON.parse(JSON.stringify(newBorrowList)) ; console.log(formData.value.borrowList,'formData.value.borrowList') }) uni.$on('feePrepayList',(res)=>{ const newPrepayList:ReceiptPrepayVO[] = []; res.forEach(item => { const existingPrepay = formData.value.prepayList.find(prepay => prepay.prepayId === item.id); if (existingPrepay) { newPrepayList.push(existingPrepay); } else { newPrepayList.push({prepayId: item.id,prepayMoney: item.receiptMoney,coverMoney: '',prepayInfo: item} as ReceiptPrepayVO); } }); formData.value.prepayList=JSON.parse(JSON.stringify(newPrepayList)) ; console.log(formData.value.prepayList,'formData.value.prepayList') }) }) onUnload(()=>{ uni.$off('selectList') uni.$off('feeBorrowList') uni.$off('feePrepayList') }) // 地址 const fieldNamesRules = ref({ text: 'label', value: 'label', children: 'children' }) const formData = ref({ id: undefined, receiptCode: 'FYBX', category: '2', receiptNo: undefined, receiptStatus: undefined, caseStatus: undefined, budgetDeptId: undefined, budgetOrgId: undefined, travelPurpose: undefined, costPurpose: undefined, busiProjectId: undefined, colleagueList:[], colleagueUserIds: undefined, colleagueUserNames: undefined, colleagueClaimSet: undefined, reason: undefined, receiptMoney: undefined, receiptAuditMoney: undefined, usedMoney: undefined, remainMoney: undefined, travelDays: undefined, payMoney: 0, payTarget: '1', payAccountName: undefined, payAccountId: '', payAccountBank: undefined, payAccountNo: undefined, payBankSerial: undefined, borrowFor: undefined, expectReturnDate: undefined, expectCoverDate: undefined, companyDeptId: undefined, lastAuditTime: undefined, userId: undefined, deptId: undefined, receiptTripList: [], modelItemList: [], myfeeList:[] as ReceiptMyfeeVO[], receiptApply: { applyId:undefined, applyReceiptNo:undefined, applyInfo:{} }, borrowList: [] as ReceiptBorrowVO[], prepayList: [] as ReceiptPrepayVO[], selectCountList:{}, processInstanceId:undefined,//审批流ID creatorName:undefined, deptName:undefined, companyName:undefined, fileIds: [], fileList:[], teamIds:null, borrowRemainMoneySum:0, coverMoneySum:0 }) const rules = ref({ budgetDeptId: [{ required: true, message: '费用归属部门不能为空', trigger: ['blur', 'change'] }], budgetOrgId: [{ required: true, message: '预算承担部门不能为空', trigger: ['blur', 'change'] }], reason: [{ required: true, message: '请输入报销事由', trigger: ['blur', 'change']}], payAccountName: [{ required: true, message: '账户不能为空', trigger: ['blur', 'change'] }], }) const validate = (item: any) => { console.log(item) } const ruleForm = ref<any>(null) const close = ()=>{ uni.navigateBack() } function validOtherForm() { //费用申请适用 if (otherData.setup.budgetCostSuit == '1') { if(!formData.value.receiptApply || !formData.value.receiptApply.applyId) { toast('当前报销需要先选择申请单'); return false; } } //个人费用必填 if (!formData.value.myfeeList || formData.value.myfeeList.length<=0) { toast('请导入个人费用'); return false; } //报销单金额校验 if (Number(formData.value.receiptMoney)==0) { toast('报销单金额不能为0'); return false; } //申请适用时,校验报销单金额 > 申请单可用额度 if (otherData.setup.budgetCostSuit == '1') { if (Number(formData.value.receiptMoney) > Number(otherData.applyRemainMoneySum)) { toast('报销单金额不能超过申请单可用额度'); return false; } } //冲销金额合计不能超过报销单金额 if (Number(otherData.coverMoneySum) > Number(formData.value.receiptMoney)) { toast('冲销金额合计不能超过报销单金额'); return false; } //表单提交-校验个人费用对应费用科目,有无预算信息 (且 非无管控) if (formData.value.receiptStatus == '2' && otherData.setup.budgetLevel !='1') { otherData.myfeeMergedList = myfeeMerged.value; const noMoneyItem = otherData.myfeeMergedList.filter(item => item.budgetRemainMoney == '--无科目预算--'); if (noMoneyItem.length > 0) { const msg = noMoneyItem.map(item => `个人费用[${item.myfeeInfo.modelItemName}]无科目预算`).join(';'); toast(msg); return false; } } //强管控,校验每个费用科目的费用金额合计,是否超过可用预算 if (otherData.setup.budgetLevel == '3') { const overMoneyItems = otherData.myfeeMergedList.filter(item => Number(item.myfeeInfo.myfeeMoney) > Number(item.budgetRemainMoney)); if (overMoneyItems.length > 0) { const msg = overMoneyItems.map(item => `个人费用[${item.myfeeInfo.modelItemName}]费用金额合计[${item.myfeeInfo.myfeeMoney}]超过可用预算[${item.budgetRemainMoney}]`).join(';'); toast(msg); return false; } } return true; } const formLoading = ref(false) const submit =async (receiptStatus:any) => { formData.value.receiptStatus = receiptStatus; const res = await ruleForm.value.validate().catch((err:any) => { return err }) if(!res.valid){ return } let otherValid = validOtherForm() formLoading.value = true if (!otherValid) { formLoading.value = false return; } try { const data = formData.value console.log("提交data:", data) if (formType.value === 'create') { if (otherData.setup.budgetLevel == '2') { //弱管控 - 需要前台提示 const overMoneyItems = otherData.myfeeMergedList.filter(item => Number(item.myfeeInfo.myfeeMoney) > Number(item.budgetRemainMoney)); console.log(overMoneyItems,"overMoneyItems") if (overMoneyItems.length > 0) { const msg = overMoneyItems.map(item => `个人费用[${item.myfeeInfo.modelItemName}]费用金额合计[${item.myfeeInfo.myfeeMoney}]超过可用预算[${item.budgetRemainMoney}]`).join(';'); uni.showModal({ title: '提示', content: msg+',是否继续提交呢', confirmText: '确定', confirmColor: "#4869D9", success: function(res) { if (res.confirm) { ReceiptInfoApi.createReceiptInfo(data).then((response)=>{ if(response.code == 0){ toast('新增成功!') uni.navigateBack() } else { toast(response.msg) } }) } } }); } }else{ ReceiptInfoApi.createReceiptInfo(data).then((response)=>{ if(response.code == 0){ toast('新增成功!') uni.navigateBack() } else { toast(response.msg) } }) } } else { if (otherData.setup.budgetLevel == '2') { //弱管控 - 需要前台提示 const overMoneyItems = otherData.myfeeMergedList.filter(item => item.myfeeInfo.myfeeMoney > item.budgetRemainMoney); if (overMoneyItems.length > 0) { const msg = overMoneyItems.map(item => `个人费用[${item.myfeeInfo.modelItemName}]费用金额合计[${item.myfeeInfo.myfeeMoney}]超过可用预算[${item.budgetRemainMoney}]`).join(';'); uni.showModal({ title: '提示', content: msg+',是否继续提交', confirmText: '确定', confirmColor: "#4869D9", success: function(res) { if (res.confirm) { ReceiptInfoApi.updateReceiptInfo(data).then((response)=>{ if(response.code == 0){ toast('修改成功!') uni.navigateBack() } else { toast(response.msg) } }) } } }); }else{ ReceiptInfoApi.updateReceiptInfo(data).then((response)=>{ if(response.code == 0){ toast('修改成功!') uni.navigateBack() } else { toast(response.msg) } }) } }else{ ReceiptInfoApi.updateReceiptInfo(data).then((response)=>{ if(response.code == 0){ toast('修改成功!') uni.navigateBack() } else { toast(response.msg) } }) } } } finally { formLoading.value = false } } /** 撤回 */ const handleBackReceipt = async (id: any) => { uni.showModal({ title: '提示:', content: '确定要撤回单据吗?', success: async (res)=> { if (res.confirm) { const res = await backReceiptInfo(id) if(res.code == 0){ toast("单据撤回成功~") await uni.navigateBack({ delta: 1 }); }else{ toast(res['msg']) } } else if (res.cancel) { toast("已取消~") } } }); } /** 结案 */ const handleCaseReceipt = async (id: any) => { uni.showModal({ title: '提示:', content: '结案后,单据将不可进行后续核销!', success: async (res)=> { if (res.confirm) { const res = await caseReceiptInfo(id) if(res.code == 0){ toast("结案成功~") await uni.navigateBack({ delta: 1 }); }else{ toast(res['msg']) } } else if (res.cancel) { toast("已取消~") } } }); } const save = () => { console.log('save') console.log(formData) } const reset = () => { ruleForm.value.reset() } // 失去焦点校验 const customBlurValidate = (prop: string) => { ruleForm.value.validate(prop).then(({valid, errors}: any) => { if (valid) console.log('success', formData) else console.log('error submit!!', errors) }) } // 日期选择 const show = ref(false) const time = ref('2024-03-14') const bussinessKey = ref('') //字段标识 const bussinessIndex = ref(0) //当前操作的item下标 function openCalendar(type, index) { console.log(type) bussinessKey.value = type bussinessIndex.value = index show.value = true } // 归属部门 const handleChangeDept1 = (e:any) => { formData.value.budgetDeptId = e[1] } // 预算部门 const handleChangeDept2 =async (e:any) => { console.log(e,"预算承担部门") formData.value.budgetOrgId = e[e.length-1].value await getModelItemOptions(e[e.length-1].value) otherData.modelItemOptions = await BaseFeeApi.getBaseFeeTreeListByOrg(e[e.length-1].value); //更新已导入费用的实时预算 if (formData.value.myfeeList) { for (const item of formData.value.myfeeList) { //实时查询费用科目的预算 const budgetData = await BudgetInfoApi.getRemainMoney({modelItemId:item.myfeeInfo.modelItemId, deptId:formData.value.budgetOrgId}); item.budgetRemainMoney = budgetData.list&&budgetData.list.length>0?budgetData.remainMoneySum:'--无科目预算--'; } } } // 获取费用项目 const modelItemOptions = ref<any[]>([]) const getModelItemOptions = async (id) => { const { data } = await getBaseFeeTreeListByOrg({deptId:id}) modelItemOptions.value = data } const busiProjectOptions = ref([]) const getProject = async ()=>{ const { data } = await getMyBusiProjectList({}) busiProjectOptions.value = data } const otherData = reactive(initOtherData() as any) function initOtherData() { return { myInfo: { userId: undefined, nickname: undefined, companyName: undefined },//个人信息 applyRemainMoneySum: 0,//可用预算 tripMoneySum: 0,//行程金额合计 myfeeMoneySum: 0,//个人费用合计 borrowRemainMoneySum:0,//借款单金额合计 coverMoneySum:0,//冲销金额合计 deptOptions: [],//部门树 orgOptions:[],//预算组织树(根据设置) busiProjectOptions: [],//业务项目list cityOptions: [], /** 城市数据 */ modelItemOptions: [],//费用科目list teamList: [],// teamIds: [], setup: undefined, globalDisabled: undefined, applyId:null, myfeeMergedList:[], selfAcc:undefined } } const showDel = ref(false) const addInfo = () => { if(!formData.value.budgetOrgId){ toast("请先选择预算承担部门") return } let selectList = formData.value.myfeeList.map(item=>{ return item.myfeeInfo.myfeeNo }) routerTo('/pages/invoiceForm/feeExpense/feeDetailSelect/index?selectList='+JSON.stringify(selectList)) } const delInfo = (index) => { formData.value.myfeeList.splice(index, 1) } const uploader = ref() const handleUpload=()=>{ uploader.value.handleUpload() } const handleSuccess = (data)=>{ formData.value.fileIds = [] formData.value.fileList = data data.forEach(el=>{ formData.value.fileIds.push(el.id); }) } const handleChange = (data)=>{ formData.value.fileIds = [] formData.value.fileList = data data.forEach(el=>{ formData.value.fileIds.push(el.id); }) } //申请单-单据可用预算总金额监听 const applyRemainMoneySum = computed(() => { //申请适用 if (otherData.setup?.budgetCostSuit == '1') { return formData.value.receiptApply?.applyInfo?.remainMoney; } }); //借款金额合计 const borrowRemainMoneySum = computed(() => { return formData.value.borrowList?.reduce((acc, item) => acc + Number(item.borrowInfo.remainMoney || 0), 0); }); //冲销金额合计 const coverMoneySum = computed(() => { return formData.value.borrowList?.reduce((acc, item) => acc + Number(item.coverMoney || 0), 0); }); //报销单费用合计 const myfeeMoneySum = computed(() => { // countFeeChildren() return formData.value.myfeeList.reduce((acc:any, item:any) => acc + Number(item.myfeeInfo.myfeeMoney || 0), 0); }); const myfeeMerged = computed(() => { let myfeeNewList = JSON.parse(JSON.stringify(formData.value.myfeeList)); return myfeeNewList.reduce((acc, curr) => { let existingItem = acc.find(item => item.myfeeInfo.modelItemId === curr.myfeeInfo.modelItemId); if (existingItem) { existingItem.myfeeInfo.myfeeMoney += curr.myfeeInfo.myfeeMoney; } else { acc.push(curr); } return acc; }, []); }); watchEffect(() => { //费用合计 = 个人费用合计 nextTick() otherData.applyRemainMoneySum = applyRemainMoneySum.value; otherData.borrowRemainMoneySum = borrowRemainMoneySum.value; otherData.coverMoneySum = coverMoneySum.value; otherData.myfeeMoneySum = myfeeMoneySum.value; formData.value.receiptMoney = myfeeMoneySum.value; formData.value.coverMoneySum = coverMoneySum.value; formData.value.payMoney = otherData.myfeeMoneySum - otherData.coverMoneySum; formData.value.borrowRemainMoneySum = borrowRemainMoneySum.value; }); const handleBorrowAdd = ()=>{ let selectList = formData.value.borrowList.map(item=>{ return item.borrowInfo.receiptNo }) routerTo('/pages/invoiceForm/feeExpense/feeDetailSelect/feeBorrow?selectList='+JSON.stringify(selectList)) } /** 预付单/借款单---开始 **/ const LoanPrepayRef = ref(); const addLoanPrepayClick = () => { LoanPrepayRef.value.handleOpen() } const removePrepay = (i) => { formData.value.prepayList.splice(i,1) } const handleChangeLoanPrepay = (e:any,list:string) => { if(list == 'prepayList'){ const newPrepayList:any = []; e.forEach(item => { const existingPrepay = formData.value.prepayList.find(prepay => prepay.prepayId === item.id); if (existingPrepay) { newPrepayList.push(existingPrepay); } else { // newPrepayList.push({prepayId: item.id,prepayMoney: item.receiptMoney,coverMoney: '',prepayInfo: item}); newPrepayList.push({prepayId: item.id,prepayMoney: item.receiptMoney,coverMoney: item.remainMoney, prepayInfo: item});//默认带出:冲销金额=预付余额 } }); formData.value.prepayList = newPrepayList; }else{ const newBorrowList:any = []; e.forEach(item => { const existingBorrow = formData.value.borrowList.find(borrow => borrow.borrowId === item.id); if (existingBorrow) { newBorrowList.push(existingBorrow); } else { // newBorrowList.push({borrowId: item.id,borrowMoney: item.receiptMoney,coverMoney: '',borrowInfo: item}); newBorrowList.push({borrowId: item.id,borrowMoney: item.receiptMoney,coverMoney: item.remainMoney, borrowInfo: item});//默认带出:冲销金额 } }); formData.value.borrowList = newBorrowList; } } /** 预付单/借款单---结束 **/ const handleBorrowDelete =(index)=>{ formData.value.borrowList.splice(index, 1) } const handleChangeTeams = (e)=>{ formData.value.selectCountList = e formData.value.payAccountName = e.username formData.value.payAccountNo = e.userId formData.value.payAccountBank = e.dept.name formData.value.payBankSerial = e.dept.id } const customerList = ref<any>([]) const accountDataList = ref<[]>([]) /** 获取供应商list */ const getSupplierList = async () => { let res = await DeptApi.getSupplierList() customerList.value = res.data } /** * 获取供应商账户信息 * 返回的paymentInfoList 就是供应商账户信息了 * */ const getSuplierAccountInfor = async (busindessId:number) => { const response = await DeptApi.getSupplier({id:busindessId}) accountDataList.value = response.data.paymentInfoList // 查找defaultAccout为true的对象 let foundObject = accountDataList.value.find(item => item.defaultAccout == true) as any; // 如果找到符合条件的对象,则返回该对象的id,否则返回null let id = foundObject ? foundObject.id : null; if(id){ confirmSupplierAccount(foundObject) } } /** 处理切换供应商 */ const handleSupplierChange = async (e:any,resetType?: string) => { if(resetType === 'handle'){ resetSupplierAccountInfor() } await getSuplierAccountInfor(e.id) } const resetSupplierAccountInfor = () => { formData.value.payAccountNo = undefined //账号 formData.value.payAccountBank = undefined //开户行 formData.value.payBankSerial = undefined //行号 } const confirmSupplierAccount = (e: any) => { let data = accountDataList.value.find(item => item.id == e.id) if(data){ formData.value.payAccountNo = e.id //银行账号 formData.value.payAccountBank = data.accountOpeningBank //开户行 地址 formData.value.payBankSerial = data.bankAccountNumber //行号 } } function handleChangePayTarget(e:any){ formData.value.payTarget = e; let accountName = ''; let accountBank = ''; let accountNo = ''; let bankSerial = ''; if (e == '1') { //个人 accountName = otherData.selfAcc?.accountName; accountBank = otherData.selfAcc?.accountBank; accountNo = otherData.selfAcc?.accountNo; formData.value.prepayList = []; (formData.value.payAccountName as any) = accountName; (formData.value.payAccountBank as any) = accountBank; (formData.value.payAccountNo as any) = accountNo; (formData.value.payBankSerial as any) = bankSerial } else if (e == '3') { //供应商 TODO hong formData.value.borrowList = []; //获取供应商列表 getSupplierList() } } const attributionOptions = ref<any[]>([]) const budgetOptions = ref<any[]>([]) async function initPageInfo(id:number){ //初始化费用设置 otherData.setup = (await SetupApi.getMyCompanySetupCost()).data otherData.myInfo = (await SetupApi.getMyInfo()).data; //初始化-业务项目List otherData.busiProjectOptions = (await BusiProjectApi.getMyBusiProjectList()).data; //初始化-城市list otherData.cityOptions = (await AreaApi.getAreaTreeByCondition(1,3)).data; //初始化我能用的申请单列表 let params = {receiptCode:"FYSQ",receiptStatus:"3",caseStatus:"1", remainMoneyReq:'1'} let applyData = (await getMyReceiptPageBy(params)).data; otherData.myApplyListOptions = applyData.list; //初始化部门list let deptType = otherData.setup?.budgetOrgEnable?'2':'1'; let deptData = (await DeptApi.getPermissionDeptList({deptType: '1'} as DeptApi.DeptByConditionReqVo)).data;//行政部门data otherData.deptOptions = handleTree(deptData); attributionOptions.value = handleTree(deptData); if (otherData.setup.budgetOrgEnable == '1') { let orgData = (await DeptApi.getPermissionDeptList({deptType: deptType} as DeptApi.DeptByConditionReqVo)).data;//预算组织部门data otherData.orgOptions = handleTree(orgData); } else { otherData.orgOptions = handleTree(deptData); } budgetOptions.value = otherData.orgOptions //初始化个人账户 otherData.selfAcc = (await SelfAccountApi.getDefaultAccountByUser()).data; if (id) { //编辑 try { let response = await ReceiptInfoApi.getReceiptFullInfo({id}) formData.value = response.data btnReceiptStatus.value = response.data.receiptStatus console.log('编辑-----------', formData.value) console.log(formData.value.receiptApply.applyId, formData.value.receiptApply.applyReceiptNo, '👆') // watchThen() if(formData.value.payTarget == '3'){ console.log(formData.value.payTarget) await getSupplierList().then(()=>{ if(formData.value.payAccountName){ getSuplierAccountInfor(formData.value.payAccountName) } }) } } finally { } } else { //新增 formData.value.companyName = userInfo.companyName formData.value.creatorName = userInfo.nickname if (otherData.myInfo.deptId) { formData.value.budgetDeptId = otherData.myInfo.deptId;//初始化默认值为当前登录人的行政部门 } //启用预算组织,则取当前所属的预算组织,否则为行政组织 if (otherData.setup.budgetOrgEnable) { if (otherData.myInfo.businessDeptIds!=null && otherData.myInfo.businessDeptIds.length>0) { formData.value.budgetOrgId = otherData.myInfo.businessDeptIds[0];//初始化默认值为当前登录人的预算部门 } } else { formData.value.budgetOrgId = otherData.myInfo.deptId; } formData.value.payTarget = '1'; formData.value.payAccountName = otherData.selfAcc.accountName; formData.value.payAccountBank = otherData.selfAcc.accountBank; formData.value.payAccountNo = otherData.selfAcc.accountNo; } //初始化所有级联 reshowAllCascader() } const watchThen = () => { //根据ID 查询receptNo let applyObj = otherData.myApplyListOptions.find(item => item.id == formData.value.receiptApply.applyId); if (applyObj) { //选择到了申请单,自动带出相关字段 formData.value.receiptApply = { applyId: formData.value.receiptApply.applyId, applyReceiptNo: applyObj.receiptNo, applyInfo: applyObj } formData.value.colleagueUserIds = applyObj.colleagueUserIds; formData.value.colleagueList = applyObj.colleagueList; otherData.teamIds = formData.value.colleagueList?.map(teamMate => teamMate.id); formData.value.busiProjectId = applyObj.busiProjectId; } else { formData.value.receiptApply = { applyId: undefined, applyReceiptNo:undefined, applyInfo: {} } formData.value.colleagueUserIds = undefined; formData.value.colleagueList = []; otherData.teamIds = []; formData.value.busiProjectId = undefined; } } // watch(()=>formData.value.receiptApply.applyId,(newVal,oldVal)=>{ // watchThen() // }) const businessChange =(value)=>{ console.log(value,11111) } const pageTo = (id: any) => { routerTo('/pages/invoiceForm/feeApply/index?type=preview&id='+id) } const pageToFee = (id:any) => { routerTo('/pages/user/expense/edit?type=preview&id='+id) } const pageToLoan = (id:any) => { routerTo('/pages/invoiceForm/loanBill/add?type=preview&id='+id) } const pageToPrepay = (id:any) => { routerTo('/pages/invoiceForm/advancedOrder/add?type=preview&id='+id) } </script> <style lang="scss" scoped> @import '@/static/styles/public.scss'; :deep(.input-text){ text-align: right !important; } /*自定义容器*/ :deep(.nut-tabbar) { height: var(--nut-tabbar-height, 40px); border-top: var(--nut-tabbar-border-top, 0px solid #eee); } .nut-form-item__label { font-size: var(--nut-form-item-label-font-size, 12px); } /*区间选择*/ .rangeSection { display: flex; flex-direction: row; align-items: center; justify-content: space-between; .start, .end { flex: 2; display: flex; justify-content: center; } .to { flex: 1; display: flex; justify-content: center; } .start, .end { color: $form-item-self-color; } .to { color: $color-gray; } } /*卡片定义*/ .card-box { .travel-title { position: relative; .btn { position: absolute; right: 0; top: -5px; padding: 5px; width: 30px; height: 30px; line-height: normal; border: red 1px solid; box-sizing: border-box; } } } .item-link{ color: #007aff!important; :deep(.nut-input){ color: #007aff!important; } } </style>
完结。