SendFunds.vue 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  1. <template>
  2. <div style="width: 100%; padding: 0px 15px">
  3. <el-form :model="formData.data" :rules="rules" ref="formDom" label-position="top" :disabled="judgeStatus()">
  4. <div class="_t">基础信息</div>
  5. <el-row :gutter="20">
  6. <el-col :span="6">
  7. <el-form-item label="归属公司" prop="corporationId">
  8. <el-select v-model="formData.data.corporationId" placeholder="请选择" filterable style="width: 100%" @change="changeType">
  9. <el-option v-for="item in companyData" :label="item.name" :value="item.id"> </el-option>
  10. </el-select>
  11. </el-form-item>
  12. </el-col>
  13. <el-col :span="6">
  14. <el-form-item label="归属部门" prop="departmentId">
  15. <el-tree-select
  16. v-model="formData.data.departmentId"
  17. :data="deptTreeData"
  18. check-strictly
  19. :render-after-expand="false"
  20. node-key="deptId"
  21. style="width: 100%"
  22. :props="defaultProps" />
  23. </el-form-item>
  24. </el-col>
  25. </el-row>
  26. <el-row :gutter="20">
  27. <el-col :span="6">
  28. <el-form-item label="币种" prop="currency">
  29. <el-select v-model="formData.data.currency" placeholder="请选择" filterable style="width: 100%">
  30. <el-option v-for="item in currencyType" :label="item.dictValue" :value="item.dictKey"> </el-option>
  31. </el-select>
  32. </el-form-item>
  33. </el-col>
  34. <el-col :span="6">
  35. <el-form-item label="请款类型" prop="type">
  36. <el-select v-model="formData.data.type" placeholder="请选择" filterable style="width: 100%" @change="changeType">
  37. <el-option v-for="item in fundsType" :label="item.dictValue" :value="item.dictKey"> </el-option>
  38. </el-select>
  39. </el-form-item>
  40. </el-col>
  41. <el-col :span="6" v-if="formData.data.type === '3'">
  42. <el-form-item label="关联预支" prop="advanceId">
  43. <el-select v-model="formData.data.advanceId" placeholder="请选择" filterable style="width: 100%" @change="changeAdvanceId">
  44. <el-option v-for="item in advanceList" :label="item.createTime.substr(0, 10) + ' ' + item.currency + item.total" :value="item.id"> </el-option>
  45. </el-select>
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="6" v-if="formData.data.type === '3'">
  49. <el-form-item label=" ">
  50. <el-button type="primary" @click="clickPrint" text>查看</el-button>
  51. </el-form-item>
  52. </el-col>
  53. </el-row>
  54. <el-row :gutter="20">
  55. <el-col :span="6">
  56. <el-form-item label="用款时间" prop="paymentTime">
  57. <el-date-picker v-model="formData.data.paymentTime" type="datetime" placeholder="请选择" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
  58. </el-form-item>
  59. </el-col>
  60. </el-row>
  61. <el-row :gutter="20">
  62. <el-col :span="12">
  63. <el-form-item label="用款说明" prop="paymentRemarks">
  64. <el-input v-model="formData.data.paymentRemarks" placeholder="请输入" type="textarea" disabled :rows="4"> </el-input>
  65. </el-form-item>
  66. <el-form-item label="上传附件">
  67. <div style="width: 100%">
  68. <el-upload
  69. v-model:fileList="fileList"
  70. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  71. :data="uploadData"
  72. multiple
  73. :before-upload="handleBeforeUpload"
  74. :on-success="handleSuccess"
  75. :on-preview="onPreviewFile">
  76. <el-button>选择</el-button>
  77. </el-upload>
  78. </div>
  79. </el-form-item>
  80. </el-col>
  81. </el-row>
  82. <div class="_t">请款明细</div>
  83. <el-form-item>
  84. <el-button type="primary" @click="handleAddRow" v-if="formData.data.type !== '3'" style="margin: 10px 0"> 添加行 </el-button>
  85. <el-table :data="formData.data.accountRequestFundsDetailList">
  86. <el-table-column prop="count" label="费用类型" width="220">
  87. <template #default="{ row, $index }">
  88. <el-form-item :prop="'accountRequestFundsDetailList.' + $index + '.costType'" :rules="rules.costType" :inline-message="true">
  89. <el-select v-model="row.costType" placeholder="请选择" filterable style="width: 100%" @change="generatePaymentRemarks">
  90. <el-option v-for="item in fundsCostType" :label="item.dictValue" :value="item.dictKey"> </el-option>
  91. </el-select>
  92. </el-form-item>
  93. </template>
  94. </el-table-column>
  95. <el-table-column prop="count" label="关联合同" width="220">
  96. <template #default="{ row, $index }">
  97. <el-form-item :prop="'accountRequestFundsDetailList.' + $index + '.contractId'" :rules="rules.contractId" :inline-message="true">
  98. <el-select v-model="row.contractId" placeholder="请选择" filterable style="width: 100%" @change="generatePaymentRemarks">
  99. <el-option v-for="item in contractList" :label="item.code" :value="item.id"> </el-option>
  100. </el-select>
  101. </el-form-item>
  102. </template>
  103. </el-table-column>
  104. <el-table-column prop="count" label="款项说明" min-width="200">
  105. <template #default="{ row, $index }">
  106. <el-form-item :prop="'accountRequestFundsDetailList.' + $index + '.remarks'" :rules="rules.remarks" :inline-message="true">
  107. <el-input v-model="row.remarks" placeholder="请输入" type="textarea" @change="generatePaymentRemarks" />
  108. </el-form-item>
  109. </template>
  110. </el-table-column>
  111. <el-table-column prop="advanceAmount" label="预支金额" width="140" v-if="formData.data.type === '3'" />
  112. <el-table-column prop="amount" :label="formData.data.type !== '3' ? '请款金额' : '核销金额'" width="160">
  113. <template #default="{ row, $index }">
  114. <el-form-item :prop="'accountRequestFundsDetailList.' + $index + '.amount'" :rules="rules.amount" :inline-message="true">
  115. <el-input-number
  116. onmousewheel="return false;"
  117. v-model="row.amount"
  118. :precision="2"
  119. :controls="false"
  120. :min="0"
  121. style="width: 100%"
  122. @change="handleChangeAmount" />
  123. </el-form-item>
  124. </template>
  125. </el-table-column>
  126. <el-table-column prop="zip" label="操作" width="100" align="center" v-if="formData.data.type !== '3'">
  127. <template #default="{ $index }">
  128. <el-button type="primary" link @click="handleRemove($index)">删除</el-button>
  129. </template>
  130. </el-table-column>
  131. </el-table>
  132. </el-form-item>
  133. <el-row :gutter="20">
  134. <el-col :span="6" v-if="formData.data.type === '3'">
  135. <el-form-item label="预支总额" prop="advanceAmounts">
  136. <el-input v-model="formData.data.advanceAmounts" placeholder="请输入" disabled />
  137. </el-form-item>
  138. </el-col>
  139. <el-col :span="6">
  140. <el-form-item :label="formData.data.type !== '3' ? '请款总额' : '核销总额'" prop="total">
  141. <el-input v-model="formData.data.total" placeholder="请输入" disabled />
  142. </el-form-item>
  143. </el-col>
  144. <el-col :span="6">
  145. <el-form-item label="单据数量" prop="quantity">
  146. <el-input-number
  147. onmousewheel="return false;"
  148. v-model="formData.data.quantity"
  149. placeholder="请输入"
  150. style="width: 100%"
  151. :precision="0"
  152. :controls="false"
  153. :min="0" />
  154. </el-form-item>
  155. </el-col>
  156. </el-row>
  157. <div class="_t">收付款信息</div>
  158. <el-row :gutter="20">
  159. <el-col :span="6">
  160. <el-form-item label="付款方式" prop="paymentMethod">
  161. <el-select v-model="formData.data.paymentMethod" placeholder="请选择" filterable style="width: 100%">
  162. <el-option v-for="item in fundsPaymentMethod" :label="item.dictValue" :value="item.dictKey"> </el-option>
  163. </el-select>
  164. </el-form-item>
  165. </el-col>
  166. <el-col :span="6">
  167. <el-form-item label="付款账户" prop="accountManagementId">
  168. <el-select v-model="formData.data.accountManagementId" placeholder="请选择" filterable style="width: 100%">
  169. <el-option v-for="item in accountData" :label="item.alias" :value="item.id"> </el-option>
  170. </el-select>
  171. </el-form-item>
  172. </el-col>
  173. </el-row>
  174. <el-row :gutter="20">
  175. <el-col :span="6">
  176. <el-form-item label="户名" prop="name">
  177. <el-input v-model="formData.data.name" placeholder="请输入" />
  178. </el-form-item>
  179. </el-col>
  180. <el-col :span="6">
  181. <el-form-item label="银行账号" prop="accountOpening">
  182. <el-input v-model="formData.data.accountOpening" placeholder="请输入" />
  183. </el-form-item>
  184. </el-col>
  185. <el-col :span="3">
  186. <el-form-item label=" ">
  187. <el-button type="primary" @click="clickSelect" text>选择</el-button>
  188. </el-form-item>
  189. </el-col>
  190. </el-row>
  191. <el-row :gutter="20">
  192. <el-col :span="6">
  193. <el-form-item label="开户银行" prop="openingBank">
  194. <el-input v-model="formData.data.openingBank" placeholder="请输入" />
  195. </el-form-item>
  196. </el-col>
  197. <el-col :span="6">
  198. <el-form-item label="联行号 / SWIFT Code" prop="interbankNumber">
  199. <el-input v-model="formData.data.interbankNumber" placeholder="请输入" />
  200. </el-form-item>
  201. </el-col>
  202. </el-row>
  203. </el-form>
  204. <el-dialog title="查看" v-if="openPrint" v-model="openPrint" width="840px">
  205. <div id="pdfDom" style="width: 776px">
  206. <div style="padding: 60px 30px; font-size: 12px !important; color: black">
  207. <div style="font-size: 16px; text-align: center; padding: 8px">
  208. <span>{{ dictDataEcho(printDetails.type, fundsType) }}审批单</span>
  209. </div>
  210. <div style="padding: 8px 0">
  211. <span>{{ printDetails.corporationName }}</span>
  212. <span style="padding-left: 32px">创建时间: {{ printDetails.createTime }}</span>
  213. </div>
  214. <div style="border: 1px solid black">
  215. <div style="display: flex; border-bottom: 1px solid black">
  216. <div style="width: 126px; border-right: 1px solid black; padding: 8px">创建人</div>
  217. <div style="width: calc(100% - 126px); padding: 8px">
  218. {{ dictValueLabel(printDetails.createUser, userList) }}
  219. </div>
  220. </div>
  221. <div style="display: flex; border-bottom: 1px solid black">
  222. <div style="width: 126px; border-right: 1px solid black; padding: 8px">创建人部门</div>
  223. <div style="width: calc(100% - 126px); padding: 8px">
  224. {{ printDetails.deptName }}
  225. </div>
  226. </div>
  227. <div style="display: flex; border-bottom: 1px solid black" v-if="printDetails.type !== '3'">
  228. <div style="width: 126px; border-right: 1px solid black; padding: 4px 8px; display: flex; align-items: center">费用明细</div>
  229. <div style="width: calc(100% - 126px)">
  230. <div style="border-bottom: 1px solid black; display: flex">
  231. <div style="width: 80px; padding: 4px 8px; border-right: 1px solid black; text-align: center">费用类型</div>
  232. <div style="width: 120px; padding: 4px 8px; border-right: 1px solid black; text-align: center">关联合同</div>
  233. <div style="width: calc(100% - 360px); padding: 4px 8px; border-right: 1px solid black; text-align: center">款项说明</div>
  234. <div style="width: 60px; padding: 4px 8px; border-right: 1px solid black; text-align: center">货币</div>
  235. <div style="width: 100px; padding: 4px 8px; text-align: center">付款金额</div>
  236. </div>
  237. <template v-if="printDetails.accountRequestFundsDetailList && printDetails.accountRequestFundsDetailList.length > 0">
  238. <div v-for="(item, index) in printDetails.accountRequestFundsDetailList" :key="index">
  239. <div
  240. :style="
  241. index + 1 !== printDetails.accountRequestFundsDetailList.length ? 'border-bottom: 1px solid black; display: flex' : ' display: flex'
  242. ">
  243. <div style="width: 80px; padding: 4px 8px; border-right: 1px solid black; text-align: center">
  244. {{ dictDataEcho(item.costType, fundsCostType) }}
  245. </div>
  246. <div style="width: 120px; padding: 4px 8px; border-right: 1px solid black; display: flex; align-items: center">
  247. {{ item.contractCode }}
  248. </div>
  249. <div style="width: calc(100% - 360px); padding: 4px 8px; border-right: 1px solid black; display: flex; align-items: center">
  250. {{ item.remarks }}
  251. </div>
  252. <div style="width: 60px; padding: 4px 8px; border-right: 1px solid black; display: flex; align-items: center">
  253. {{ dictDataEcho(printDetails.currency, currencyType) }}
  254. </div>
  255. <div style="width: 100px; padding: 4px 8px; display: flex; align-items: center">
  256. {{ item.amount }}
  257. </div>
  258. </div>
  259. </div>
  260. </template>
  261. </div>
  262. </div>
  263. <div style="display: flex; border-bottom: 1px solid black" v-else>
  264. <div style="width: 126px; border-right: 1px solid black; padding: 4px 8px; display: flex; align-items: center">费用明细</div>
  265. <div style="width: calc(100% - 126px)">
  266. <div style="border-bottom: 1px solid black; display: flex">
  267. <div style="width: 80px; padding: 4px 8px; border-right: 1px solid black; text-align: center">费用类型</div>
  268. <div style="width: 120px; padding: 4px 8px; border-right: 1px solid black; text-align: center">关联合同</div>
  269. <div style="width: calc(100% - 420px); padding: 4px 8px; border-right: 1px solid black; text-align: center">款项说明</div>
  270. <div style="width: 60px; padding: 4px 8px; border-right: 1px solid black; text-align: center">货币</div>
  271. <div style="width: 80px; padding: 4px 8px; border-right: 1px solid black; text-align: center">预支金额</div>
  272. <div style="width: 80px; padding: 4px 8px; text-align: center">付款金额</div>
  273. </div>
  274. <template v-if="printDetails.accountRequestFundsDetailList && printDetails.accountRequestFundsDetailList.length > 0">
  275. <div v-for="(item, index) in printDetails.accountRequestFundsDetailList" :key="index">
  276. <div
  277. :style="
  278. index + 1 !== printDetails.accountRequestFundsDetailList.length ? 'border-bottom: 1px solid black; display: flex' : ' display: flex'
  279. ">
  280. <div style="width: 80px; padding: 4px 8px; border-right: 1px solid black; text-align: center">
  281. {{ dictDataEcho(item.costType, fundsCostType) }}
  282. </div>
  283. <div style="width: 120px; padding: 4px 8px; border-right: 1px solid black; display: flex; align-items: center">
  284. {{ item.contractCode }}
  285. </div>
  286. <div style="width: calc(100% - 420px); padding: 4px 8px; border-right: 1px solid black; display: flex; align-items: center">
  287. {{ item.remarks }}
  288. </div>
  289. <div style="width: 60px; padding: 4px 8px; border-right: 1px solid black; display: flex; align-items: center">
  290. {{ dictDataEcho(printDetails.currency, currencyType) }}
  291. </div>
  292. <div style="width: 80px; padding: 4px 8px; border-right: 1px solid black; display: flex; align-items: center">
  293. {{ item.advanceAmount }}
  294. </div>
  295. <div style="width: 80px; padding: 4px 8px; display: flex; align-items: center">
  296. {{ item.amount }}
  297. </div>
  298. </div>
  299. </div>
  300. </template>
  301. </div>
  302. </div>
  303. <div style="display: flex; border-bottom: 1px solid black" v-if="printDetails.type !== '3'">
  304. <div style="width: 126px; border-right: 1px solid black; padding: 8px">总报销金额</div>
  305. <div style="width: calc(100% - 126px); display: flex">
  306. <div style="width: calc(100% - 100px); padding: 8px; border-right: 1px solid black">
  307. {{ NumberToChinese(computeMoney("amount")) }}
  308. </div>
  309. <div style="width: 100px; padding: 8px">
  310. {{ computeMoney("amount") }}
  311. </div>
  312. </div>
  313. </div>
  314. <div v-else>
  315. <div style="display: flex; border-bottom: 1px solid black">
  316. <div style="display: flex; border-bottom: 1px solid black">
  317. <div style="width: 126px; border-right: 1px solid black; padding: 8px">核销总金额</div>
  318. <div style="width: calc(100% - 126px); display: flex">
  319. <div style="width: calc(100% - 100px); padding: 8px; border-right: 1px solid black">
  320. {{ NumberToChinese(computeMoney("amount")) }}
  321. </div>
  322. <div style="width: 100px; padding: 8px">
  323. {{ computeMoney("amount") }}
  324. </div>
  325. </div>
  326. </div>
  327. <div style="width: 126px; border-right: 1px solid black; padding: 8px">预支总金额</div>
  328. <div style="width: calc(100% - 126px); display: flex">
  329. <div style="width: calc(100% - 100px); padding: 8px; border-right: 1px solid black">
  330. {{ NumberToChinese(computeMoney("advanceAmount")) }}
  331. </div>
  332. <div style="width: 100px; padding: 8px">
  333. {{ computeMoney("advanceAmount") }}
  334. </div>
  335. </div>
  336. </div>
  337. <div style="display: flex; border-bottom: 1px solid black">
  338. <div style="width: 126px; border-right: 1px solid black; padding: 8px">差额 (核销 - 预支)</div>
  339. <div style="width: calc(100% - 126px); display: flex">
  340. <div style="width: calc(100% - 100px); padding: 8px; border-right: 1px solid black">
  341. {{ NumberToChinese(computeBalance()) }}
  342. </div>
  343. <div style="width: 100px; padding: 8px">
  344. {{ computeBalance() }}
  345. </div>
  346. </div>
  347. </div>
  348. </div>
  349. <div style="display: flex; border-bottom: 1px solid black">
  350. <div style="width: 126px; border-right: 1px solid black; padding: 8px">单据数量</div>
  351. <div style="width: calc(100% - 126px); padding: 8px">
  352. {{ printDetails.quantity }}
  353. </div>
  354. </div>
  355. <div style="display: flex; border-bottom: 1px solid black">
  356. <div style="width: 126px; border-right: 1px solid black; padding: 0 8px; display: flex; align-items: center">收款信息</div>
  357. <div style="width: calc(100% - 126px)">
  358. <div style="border-bottom: 1px solid black; display: flex">
  359. <div style="width: 19%; padding: 0 8px; border-right: 1px solid black; text-align: center">支付方式</div>
  360. <div style="width: 27%; padding: 0 8px; border-right: 1px solid black; text-align: center">收款方户名</div>
  361. <div style="width: 27%; padding: 0 8px; border-right: 1px solid black; text-align: center">开户行</div>
  362. <div style="width: 27%; padding: 0 8px; text-align: center">收款方账号</div>
  363. </div>
  364. <div style="display: flex">
  365. <div style="width: 19%; padding: 0 8px; border-right: 1px solid black; display: flex; align-items: center">
  366. {{ dictDataEcho(printDetails.paymentMethod, fundsPaymentMethod) }}
  367. </div>
  368. <div style="width: 27%; padding: 0 8px; border-right: 1px solid black; display: flex; align-items: center">
  369. {{ printDetails.name }}
  370. </div>
  371. <div style="width: 27%; padding: 0 8px; border-right: 1px solid black; display: flex; align-items: center">
  372. {{ printDetails.openingBank }}
  373. </div>
  374. <div style="width: 27%; padding: 0 8px; display: flex; align-items: center">
  375. {{ printDetails.accountOpening }}
  376. </div>
  377. </div>
  378. </div>
  379. </div>
  380. <div style="display: flex; border-bottom: 1px solid black">
  381. <div style="width: 126px; border-right: 1px solid black; padding: 8px">电子发票(PDF/JPG)</div>
  382. <div style="width: calc(100% - 126px); padding: 8px">
  383. {{ printDetails.electronicInvoiceText }}
  384. </div>
  385. </div>
  386. <div style="display: flex">
  387. <div style="width: 126px; border-right: 1px solid black; padding: 4px 8px; display: flex; align-items: center">审批流程</div>
  388. <div style="width: calc(100% - 126px)">
  389. <template v-if="printDetails.recordList && printDetails.recordList.length > 0">
  390. <div v-for="(item, index) in printDetails.recordList" :key="index">
  391. <div
  392. :style="
  393. index + 1 !== printDetails.recordList.length
  394. ? 'border-bottom: 1px solid black; padding: 4px 8px; display: flex'
  395. : 'padding: 4px 8px; display: flex'
  396. ">
  397. <div style="width: calc(100% - 120px); word-wrap: break-word">
  398. <span>{{ item.nodeName }}: </span>
  399. <span style="padding-left: 4px">{{ item.processedUser }}</span>
  400. <span style="padding-left: 4px">{{ item.remark }}</span>
  401. </div>
  402. <div style="width: 120px">{{ item.processedDate }}</div>
  403. </div>
  404. </div>
  405. </template>
  406. </div>
  407. </div>
  408. </div>
  409. <div style="padding-top: 16px">
  410. <span>打印时间: {{ presentTime }}</span>
  411. <span style="padding-left: 32px">打印人: {{ useUserStore().user.nickName }}</span>
  412. </div>
  413. </div>
  414. </div>
  415. <template #footer>
  416. <el-button @click="openPrint = false" size="large">取消</el-button>
  417. <el-button type="primary" @click="clickDownload()" size="large">下载PDF</el-button>
  418. </template>
  419. </el-dialog>
  420. <el-dialog title="选择付款信息" v-if="openSelect" v-model="openSelect" width="800">
  421. <el-table :data="bankList" style="width: 100%">
  422. <el-table-column prop="name" label="户名" />
  423. <el-table-column prop="accountOpening" label="银行账号" />
  424. <el-table-column prop="openingBank" label="开户银行" width="140" />
  425. <el-table-column prop="interbankNumber" label="联行号 / SWIFT Code" />
  426. <el-table-column align="center" label="操作" width="80">
  427. <template #default="{ row }">
  428. <el-button type="primary" link @click="handleSelect(row)">选择</el-button>
  429. </template>
  430. </el-table-column>
  431. </el-table>
  432. <template #footer>
  433. <el-button @click="openSelect = false" size="large">取 消</el-button>
  434. </template>
  435. </el-dialog>
  436. </div>
  437. </template>
  438. <script setup>
  439. import { ElMessage } from "element-plus";
  440. import useUserStore from "@/store/modules/user";
  441. import { useRoute } from "vue-router";
  442. import moment from "moment";
  443. import { NumberToChinese } from "@/utils/util.js";
  444. const route = useRoute();
  445. const { proxy } = getCurrentInstance();
  446. const defaultProps = {
  447. children: "children",
  448. label: "deptName",
  449. };
  450. const userList = ref([]);
  451. const formData = reactive({
  452. data: {
  453. currency: "CNY",
  454. type: "2",
  455. paymentTime: "",
  456. departmentId: useUserStore().user.deptId,
  457. quantity: 0,
  458. paymentMethod: "bank",
  459. accountRequestFundsDetailList: [
  460. {
  461. costType: "",
  462. contractId: "",
  463. remarks: "",
  464. amount: undefined,
  465. },
  466. ],
  467. fileList: [],
  468. },
  469. });
  470. let rules = ref({
  471. corporationId: [{ required: true, message: "请选择归属公司", trigger: "change" }],
  472. departmentId: [{ required: true, message: "请选择归属部门", trigger: "change" }],
  473. type: [{ required: true, message: "请选择请款类型", trigger: "change" }],
  474. // paymentTime: [{ required: true, message: "请选择用款时间", trigger: "change" }],
  475. currency: [{ required: true, message: "请选择币种", trigger: "change" }],
  476. paymentMethod: [{ required: true, message: "请选择付款方式", trigger: "change" }],
  477. advanceId: [{ required: true, message: "请选择关联预支", trigger: "change" }],
  478. // accountManagementId: [
  479. // { required: true, message: "请选择付款账号", trigger: "change" },
  480. // ],
  481. costType: [{ required: true, message: "请选择费用类型", trigger: "change" }],
  482. quantity: [{ required: true, message: "请输入单据数量", trigger: "blur" }],
  483. remarks: [{ required: true, message: "请输入款项说明", trigger: "blur" }],
  484. amount: [{ required: true, message: "请输入请款金额", trigger: "blur" }],
  485. });
  486. const handleAddRow = () => {
  487. formData.data.accountRequestFundsDetailList.push({
  488. costType: "",
  489. contractId: "",
  490. remarks: "",
  491. amount: undefined,
  492. });
  493. };
  494. const handleRemove = (index) => {
  495. formData.data.accountRequestFundsDetailList.splice(index, 1);
  496. handleChangeAmount();
  497. };
  498. // 提交方法
  499. const formDom = ref(null);
  500. const handleSubmit = async () => {
  501. let status = await formDom.value.validate();
  502. if (status) {
  503. if (fileList.value && fileList.value.length > 0) {
  504. for (let i = 0; i < fileList.value.length; i++) {
  505. if (fileList.value[i].raw.uploadState) {
  506. ElMessage("文件上传中,请稍后提交");
  507. return false;
  508. }
  509. }
  510. formData.data.fileList = fileList.value.map((item) => {
  511. return {
  512. id: item.raw.id,
  513. fileName: item.raw.fileName,
  514. fileUrl: item.raw.fileUrl,
  515. uploadState: item.raw.uploadState,
  516. };
  517. });
  518. } else {
  519. formData.data.fileList = [];
  520. }
  521. if (!(formData.data.accountRequestFundsDetailList.length > 0)) {
  522. ElMessage("请添加请款明细!");
  523. return false;
  524. }
  525. for (let i = 0; i < formData.data.accountRequestFundsDetailList.length; i++) {
  526. if (!formData.data.accountRequestFundsDetailList[i].amount || Number(formData.data.accountRequestFundsDetailList[i].amount) === 0) {
  527. ElMessage("请款金额不能为0");
  528. return false;
  529. }
  530. }
  531. return true;
  532. } else {
  533. setTimeout(() => {
  534. const errorDiv = document.getElementsByClassName("is-error");
  535. errorDiv[0].scrollIntoView();
  536. }, 0);
  537. }
  538. return status;
  539. };
  540. // 获取用户信息并赋默认值
  541. const userInfo = useUserStore().user;
  542. // const tenantId = "@福建宏星!#¥%……&*()";
  543. const tenantId = userInfo.tenantId;
  544. watch(
  545. props.queryData,
  546. () => {
  547. if (props.queryData && ["10", "20", "30"].includes(route.query.processType)) {
  548. for (var text in props.queryData) {
  549. formData.data[text] = props.queryData[text];
  550. }
  551. oldType.value = proxy.deepClone(formData.data.type);
  552. if (formData.data.fileList && formData.data.fileList.length > 0) {
  553. fileList.value = formData.data.fileList.map((item) => {
  554. return {
  555. raw: item,
  556. name: item.fileName,
  557. url: item.fileUrl,
  558. };
  559. });
  560. }
  561. }
  562. },
  563. {
  564. deep: true,
  565. }
  566. );
  567. onMounted(() => {
  568. // formData.data.paymentTime = proxy.parseTime(new Date());
  569. // 核销
  570. if (route.query.advanceId) {
  571. formData.data.type = "3";
  572. formData.data.corporationId = route.query.corporationId;
  573. changeType();
  574. formData.data.advanceId = route.query.advanceId;
  575. changeAdvanceId(formData.data.advanceId);
  576. }
  577. });
  578. const companyData = ref([]);
  579. const accountData = ref([]);
  580. const deptTreeData = ref([]);
  581. const fundsType = ref([]);
  582. const fundsCostType = ref([]);
  583. const fundsPaymentMethod = ref([]);
  584. const currencyType = ref([]);
  585. const advanceList = ref([]);
  586. const contractList = ref([]);
  587. const bankList = ref([]);
  588. const getDictData = () => {
  589. // 获取归属公司数据
  590. proxy.post("/corporation/page", { pageNum: 1, pageSize: 9999 }).then((res) => {
  591. companyData.value = res.rows;
  592. });
  593. // 账户数据
  594. proxy.post("/accountManagement/page", { pageNum: 1, pageSize: 9999 }).then((res) => {
  595. accountData.value = res.rows;
  596. });
  597. // 关联合同
  598. proxy.post("/contract/page1", { pageNum: 1, pageSize: 9999, status: 30 }).then((res) => {
  599. if (res.rows && res.rows.length > 0) {
  600. contractList.value = res.rows.map((item) => {
  601. return {
  602. ...item,
  603. dictKey: item.id,
  604. dictValue: item.code,
  605. };
  606. });
  607. }
  608. });
  609. // 部门树
  610. proxy
  611. .get("/tenantDept/list", {
  612. pageNum: 1,
  613. pageSize: 9999,
  614. tenantId: userInfo.tenantId,
  615. })
  616. .then((message) => {
  617. recursive(message.data);
  618. deptTreeData.value = [];
  619. let data = proxy.handleTree(message.data, "deptId");
  620. if (data && data.length > 0) {
  621. for (let i = 0; i < data.length; i++) {
  622. if (data[i].children && data[i].children.length > 0) {
  623. deptTreeData.value = deptTreeData.value.concat(data[i].children);
  624. }
  625. }
  626. }
  627. });
  628. // 请款类型数据
  629. proxy
  630. .post("/dictTenantData/page", {
  631. pageNum: 1,
  632. pageSize: 999,
  633. tenantId: tenantId,
  634. dictCode: "founds_type",
  635. })
  636. .then((res) => {
  637. fundsType.value = res.rows;
  638. });
  639. // 请款费用类型数据
  640. proxy
  641. .post("/dictTenantData/page", {
  642. pageNum: 1,
  643. pageSize: 999,
  644. tenantId: tenantId,
  645. dictCode: "funds_cost_type",
  646. })
  647. .then((res) => {
  648. fundsCostType.value = res.rows;
  649. });
  650. // 请款付款方式数据
  651. proxy
  652. .post("/dictTenantData/page", {
  653. pageNum: 1,
  654. pageSize: 999,
  655. tenantId: tenantId,
  656. dictCode: "funds_payment_method",
  657. })
  658. .then((res) => {
  659. if (res.rows && res.rows.length > 0) {
  660. fundsPaymentMethod.value = res.rows;
  661. let list = res.rows.filter((item) => item.dictKey === "bank");
  662. if (!(list && list.length > 0) && formData.data.paymentMethod === "bank") {
  663. formData.data.paymentMethod = "";
  664. }
  665. }
  666. });
  667. // 币种数据
  668. proxy
  669. .post("/dictTenantData/page", {
  670. pageNum: 1,
  671. pageSize: 999,
  672. tenantId: tenantId,
  673. dictCode: "account_currency",
  674. })
  675. .then((res) => {
  676. currencyType.value = res.rows;
  677. let list = res.rows.filter((item) => item.dictKey === "CNY");
  678. if (!(list && list.length > 0) && formData.data.currency === "CNY") {
  679. formData.data.currency = "";
  680. }
  681. });
  682. proxy
  683. .get("/tenantUser/list", {
  684. pageNum: 1,
  685. pageSize: 10000,
  686. tenantId: useUserStore().user.tenantId,
  687. })
  688. .then((res) => {
  689. if (res.rows && res.rows.length > 0) {
  690. userList.value = res.rows.map((item) => {
  691. return {
  692. deptId: item.deptId,
  693. label: item.nickName,
  694. value: item.userId,
  695. };
  696. });
  697. }
  698. });
  699. proxy.get("/accountRequestFunds/getPayHistoricalInfo", {}).then((res) => {
  700. bankList.value = res.data;
  701. });
  702. };
  703. getDictData();
  704. const recursive = (data) => {
  705. data.map((item) => {
  706. item.label = item.deptName;
  707. item.id = item.corporationId;
  708. if (item.children) {
  709. recursive(item.children);
  710. } else {
  711. item.children = [];
  712. }
  713. });
  714. };
  715. // 接收父组件的传值
  716. const props = defineProps({
  717. queryData: String,
  718. });
  719. // 计算请款总金额
  720. const handleChangeAmount = () => {
  721. let sum = 0;
  722. for (let i = 0; i < formData.data.accountRequestFundsDetailList.length; i++) {
  723. const e = formData.data.accountRequestFundsDetailList[i];
  724. if (e.amount) {
  725. sum = Number(parseFloat(Number(sum) + Number(e.amount)).toFixed(2));
  726. }
  727. }
  728. formData.data.total = sum;
  729. generatePaymentRemarks();
  730. };
  731. // 上传附件
  732. const uploadData = ref({});
  733. const fileList = ref([]);
  734. const handleBeforeUpload = async (file) => {
  735. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  736. uploadData.value = res.uploadBody;
  737. file.id = res.id;
  738. file.fileName = res.fileName;
  739. file.fileUrl = res.fileUrl;
  740. file.uploadState = true;
  741. return true;
  742. };
  743. const handleSuccess = (any, UploadFile) => {
  744. UploadFile.raw.uploadState = false;
  745. };
  746. const onPreviewFile = (file) => {
  747. window.open(file.raw.fileUrl, "_blank");
  748. };
  749. const getFormData = () => {
  750. return proxy.deepClone(formData.data);
  751. };
  752. // 向父组件暴露
  753. defineExpose({
  754. getFormData,
  755. handleSubmit,
  756. });
  757. const judgeStatus = () => {
  758. if (route.query.processType == 20 || route.query.processType == 10) {
  759. return true;
  760. }
  761. if (props.queryData.recordList && props.queryData.recordList.length > 0) {
  762. let data = props.queryData.recordList.filter((item) => item.status === 2 && item.nodeType !== 1);
  763. if (data && data.length > 0) {
  764. return true;
  765. }
  766. }
  767. return false;
  768. };
  769. const oldType = ref("");
  770. const changeType = () => {
  771. if (formData.data.type === "3" || oldType.value === "3") {
  772. for (var text in formData.data) {
  773. if (text === "advanceId") {
  774. formData.data.advanceId = "";
  775. } else if (text === "corporationId") {
  776. formData.data.corporationId = proxy.deepClone(formData.data.corporationId);
  777. } else if (text === "type") {
  778. formData.data.type = proxy.deepClone(formData.data.type);
  779. } else if (text === "paymentTime") {
  780. formData.data.paymentTime = proxy.deepClone(formData.data.paymentTime);
  781. } else if (text === "accountRequestFundsDetailList") {
  782. formData.data.accountRequestFundsDetailList = [];
  783. } else if (text === "fileList") {
  784. formData.data.fileList = [];
  785. } else {
  786. delete formData.data[text];
  787. }
  788. }
  789. }
  790. oldType.value = proxy.deepClone(formData.data.type);
  791. proxy
  792. .post("/accountRequestFunds/page", {
  793. pageNum: 1,
  794. pageSize: 999,
  795. type: "1",
  796. writeOffStatus: "0",
  797. corporationId: formData.data.corporationId,
  798. status: "30",
  799. createUser: useUserStore().user.userId,
  800. })
  801. .then((res) => {
  802. advanceList.value = res.rows;
  803. });
  804. };
  805. const openPrint = ref(false);
  806. const printDetails = ref({});
  807. const presentTime = ref("");
  808. const changeAdvanceId = (val) => {
  809. if (val) {
  810. proxy.post("/accountRequestFunds/detail", { id: val }).then((res) => {
  811. printDetails.value = res;
  812. if (res.flowInfoId) {
  813. proxy.post("/flowExample/getApprovalRecord", { id: res.flowInfoId }).then((record) => {
  814. printDetails.value.recordList = record.recordList;
  815. });
  816. }
  817. formData.data.departmentId = res.departmentId;
  818. formData.data.currency = res.currency;
  819. formData.data.paymentRemarks = res.paymentRemarks;
  820. proxy.post("/fileInfo/getList", { businessIdList: [val] }).then((resFile) => {
  821. formData.data.fileList = resFile[val] || [];
  822. if (formData.data.fileList && formData.data.fileList.length > 0) {
  823. fileList.value = formData.data.fileList.map((item) => {
  824. return {
  825. raw: item,
  826. name: item.fileName,
  827. url: item.fileUrl,
  828. };
  829. });
  830. let electronicInvoiceText = "";
  831. for (let i = 0; i < resFile[val].length; i++) {
  832. if (i === 0) {
  833. electronicInvoiceText = resFile[val][0].fileName;
  834. } else {
  835. electronicInvoiceText = electronicInvoiceText + ", " + resFile[val][i].fileName;
  836. }
  837. }
  838. printDetails.value.electronicInvoiceText = electronicInvoiceText;
  839. }
  840. });
  841. formData.data.accountRequestFundsDetailList = res.accountRequestFundsDetailList.map((item) => {
  842. return {
  843. costType: item.costType,
  844. amount: item.amount,
  845. contractId: item.contractId,
  846. advanceAmount: item.amount,
  847. remarks: item.remarks,
  848. };
  849. });
  850. handleChangeAmount();
  851. formData.data.advanceAmounts = res.total;
  852. formData.data.quantity = res.quantity;
  853. formData.data.paymentMethod = res.paymentMethod;
  854. formData.data.accountManagementId = res.accountManagementId;
  855. formData.data.name = res.name;
  856. formData.data.accountOpening = res.accountOpening;
  857. formData.data.openingBank = res.openingBank;
  858. formData.data.interbankNumber = res.interbankNumber;
  859. });
  860. }
  861. };
  862. const clickDownload = () => {
  863. proxy.getPdf("请款PDF文件");
  864. };
  865. const clickPrint = () => {
  866. if (formData.data.advanceId) {
  867. presentTime.value = moment().format("yyyy-MM-DD HH:mm:ss");
  868. openPrint.value = true;
  869. } else {
  870. ElMessage("请选择关联预支");
  871. }
  872. };
  873. const computeMoney = (label) => {
  874. let amount = 0;
  875. if (printDetails.value.accountRequestFundsDetailList && printDetails.value.accountRequestFundsDetailList.length > 0) {
  876. for (let i = 0; i < printDetails.value.accountRequestFundsDetailList.length; i++) {
  877. if (printDetails.value.accountRequestFundsDetailList[i][label]) {
  878. amount = Number(parseFloat(Number(amount) + Number(printDetails.value.accountRequestFundsDetailList[i][label])).toFixed(2));
  879. }
  880. }
  881. }
  882. return amount;
  883. };
  884. const computeBalance = () => {
  885. let balance = 0;
  886. let advanceAmount = computeMoney("advanceAmount");
  887. let amount = computeMoney("amount");
  888. if (amount) {
  889. balance = Number(amount);
  890. }
  891. if (advanceAmount) {
  892. balance = Number(parseFloat(Number(balance) - Number(advanceAmount)).toFixed(2));
  893. }
  894. return balance;
  895. };
  896. const openSelect = ref(false);
  897. const clickSelect = () => {
  898. openSelect.value = true;
  899. };
  900. const handleSelect = (item) => {
  901. formData.data.name = item.name;
  902. formData.data.accountOpening = item.accountOpening;
  903. formData.data.openingBank = item.openingBank;
  904. formData.data.interbankNumber = item.interbankNumber;
  905. openSelect.value = false;
  906. };
  907. const generatePaymentRemarks = () => {
  908. let paymentRemarks = "";
  909. if (formData.data.accountRequestFundsDetailList && formData.data.accountRequestFundsDetailList.length > 0) {
  910. for (let i = 0; i < formData.data.accountRequestFundsDetailList.length; i++) {
  911. if (i !== 0) {
  912. paymentRemarks = paymentRemarks + "\n";
  913. }
  914. if (formData.data.accountRequestFundsDetailList[i].costType) {
  915. paymentRemarks = paymentRemarks + "【" + proxy.dictDataEcho(formData.data.accountRequestFundsDetailList[i].costType, fundsCostType.value) + "】";
  916. }
  917. if (formData.data.accountRequestFundsDetailList[i].contractId) {
  918. paymentRemarks = paymentRemarks + proxy.dictDataEcho(formData.data.accountRequestFundsDetailList[i].contractId, contractList.value) + " - ";
  919. }
  920. if (formData.data.accountRequestFundsDetailList[i].remarks) {
  921. paymentRemarks = paymentRemarks + formData.data.accountRequestFundsDetailList[i].remarks + " - ";
  922. }
  923. if (formData.data.accountRequestFundsDetailList[i].amount) {
  924. paymentRemarks = paymentRemarks + formData.data.accountRequestFundsDetailList[i].amount;
  925. }
  926. }
  927. }
  928. formData.data.paymentRemarks = proxy.deepClone(paymentRemarks);
  929. };
  930. </script>
  931. <style lang="scss" scoped>
  932. ._t {
  933. margin-bottom: 5px;
  934. font-size: 14px;
  935. }
  936. ::v-deep(.el-input-number .el-input__inner) {
  937. text-align: left;
  938. }
  939. </style>