index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. <script setup lang="ts">
  2. import AForm from '@/components/AForm/index.vue'
  3. import { FormConfigType } from '@/components/AForm/type'
  4. import { ToolbarConfigType } from '@/components/AToolbar/type'
  5. import { ColumnConfigType } from '@/components/ATable/type'
  6. import { StrAnyObj, StrAnyObjArr } from '@/typings'
  7. import { useHandleData } from '@/utils/useHandleData'
  8. import {
  9. getPageApi,
  10. getDetailApi,
  11. addApi,
  12. editApi,
  13. deleteApi
  14. } from '@/api/business/payment/requests'
  15. import {getPageApi as getCorporationPageApi} from "@/api/business/corporation/corporation";
  16. import DeptTreeSelect from "@/views/components/DeptTreeSelect/index.vue";
  17. import {getPageApi as getCapitalAccountPageApi} from "@/api/business/capital/account";
  18. const queryRef = ref<InstanceType<typeof AForm>>()
  19. const formRef = ref<InstanceType<typeof AForm>>()
  20. const showQuery = ref<boolean>(true)
  21. const selectKeys = ref<string[]>([])
  22. const pageTotal = ref<number>(0)
  23. const queryData = ref<StrAnyObj>({ pageNum: 1, pageSize: 10 })
  24. const tableData = ref<StrAnyObjArr>([])
  25. const formData = ref<StrAnyObj>({ paymentRequestsDetailList: [{}] })
  26. const dialogTitle = ref<string>('')
  27. const dialogVisible = ref<boolean>(false)
  28. const deptIdRef = ref<InstanceType<typeof DeptTreeSelect>>()
  29. const queryConfig: FormConfigType[] = [
  30. {
  31. type: 'input',
  32. prop: 'corporationId',
  33. label: '归属公司id'
  34. },
  35. {
  36. type: 'input',
  37. prop: 'deptId',
  38. label: '部门id'
  39. },
  40. {
  41. type: 'input',
  42. prop: 'type',
  43. label: '请款类型'
  44. },
  45. {
  46. type: 'input',
  47. prop: 'useTime',
  48. label: '用款时间'
  49. },
  50. {
  51. type: 'input',
  52. prop: 'useRemark',
  53. label: '用款说明'
  54. },
  55. {
  56. type: 'input',
  57. prop: 'atts',
  58. label: '附件列表'
  59. },
  60. {
  61. type: 'input',
  62. prop: 'totalAmount',
  63. label: '付款总金额'
  64. },
  65. {
  66. type: 'input',
  67. prop: 'documentQuantity',
  68. label: '单据数量'
  69. },
  70. {
  71. type: 'input',
  72. prop: 'payType',
  73. label: '付款方式'
  74. },
  75. {
  76. type: 'input',
  77. prop: 'capitalAccountId',
  78. label: '资金账户id'
  79. },
  80. {
  81. type: 'input',
  82. prop: 'accountName',
  83. label: '户名'
  84. },
  85. {
  86. type: 'input',
  87. prop: 'account',
  88. label: '银行账号'
  89. },
  90. {
  91. type: 'input',
  92. prop: 'depositBank',
  93. label: '开户银行'
  94. },
  95. {
  96. type: 'input',
  97. prop: 'correspondentNumber',
  98. label: '联行号/ SWIFT Code'
  99. }
  100. ]
  101. const toolbarConfig: ToolbarConfigType[] = [
  102. {
  103. common: 'search',
  104. click() {
  105. queryData.value.pageNum = 1
  106. getPage()
  107. }
  108. },
  109. {
  110. common: 'reset',
  111. click() {
  112. queryRef.value?.resetFields()
  113. getPage()
  114. }
  115. },
  116. {
  117. common: 'add',
  118. click() {
  119. dialogVisible.value = true
  120. dialogTitle.value = '新增'
  121. nextTick(() => deptIdRef.value?.load())
  122. }
  123. },
  124. {
  125. common: 'delete',
  126. disabled() {
  127. return selectKeys.value.length == 0
  128. },
  129. click() {
  130. handleRemove(selectKeys.value)
  131. }
  132. }
  133. ]
  134. const columnConfig: ColumnConfigType[] = [
  135. {
  136. prop: 'corporationName',
  137. label: '归属公司'
  138. },
  139. {
  140. prop: 'deptName',
  141. label: '归属部门'
  142. },
  143. {
  144. prop: 'type',
  145. label: '请款类型',
  146. dict: 'payment_requests_type'
  147. },
  148. {
  149. prop: 'userName',
  150. label: '请款人'
  151. },
  152. {
  153. prop: 'createTime',
  154. label: '请款时间'
  155. },
  156. {
  157. prop: 'useTime',
  158. label: '用款时间'
  159. },
  160. {
  161. prop: 'useRemark',
  162. label: '用款说明',
  163. showOverflowTooltip: true
  164. },
  165. {
  166. prop: 'totalAmount',
  167. label: '请款金额'
  168. },
  169. {
  170. prop: 'payType',
  171. label: '付款方式',
  172. dict: 'pay_type'
  173. },
  174. {
  175. prop: 'capitalAccountName',
  176. label: '付款账户'
  177. },
  178. {
  179. prop: 'approvalStatus',
  180. label: '审批状态'
  181. },
  182. {
  183. prop: 'paymentStatus',
  184. label: '放款状态'
  185. },
  186. {
  187. width: 250,
  188. handleConfig: [
  189. {
  190. common: 'update',
  191. click(row) {
  192. dialogVisible.value = true
  193. dialogTitle.value = '编辑'
  194. getDetailApi({ id: row.id }).then((resp: StrAnyObj) => {
  195. formData.value = resp
  196. })
  197. nextTick(() => deptIdRef.value?.load())
  198. }
  199. },
  200. {
  201. common: 'delete',
  202. click(row) {
  203. handleRemove([row.id])
  204. }
  205. }
  206. ]
  207. }
  208. ]
  209. const formConfig: FormConfigType[] = [
  210. {
  211. type: 'select',
  212. prop: 'corporationId',
  213. label: '归属公司',
  214. keyName: 'id',
  215. labelName: 'name',
  216. async option () {
  217. const data = await getCorporationPageApi({ searchAll: true })
  218. return data.records
  219. },
  220. rule: [{ required: true, message: '归属公司id不能为空', trigger: 'blur' }]
  221. },
  222. {
  223. type: 'slot',
  224. prop: 'dept',
  225. label: '归属部门',
  226. rule: [{ required: true, message: '部门id不能为空', trigger: 'blur' }]
  227. },
  228. {
  229. type: 'select',
  230. prop: 'type',
  231. label: '请款类型',
  232. dict: 'payment_requests_type',
  233. rule: [{ required: true, message: '请款类型不能为空', trigger: 'blur' }]
  234. },
  235. {
  236. type: 'datePicker',
  237. prop: 'useTime',
  238. label: '用款时间',
  239. datePickerType: 'datetime',
  240. format: 'YYYY-MM-DD 00:00:00',
  241. valueFormat: 'YYYY-MM-DD 00:00:00'
  242. },
  243. {
  244. type: 'input',
  245. itemType: 'textarea',
  246. prop: 'useRemark',
  247. label: '用款说明',
  248. rows: 3,
  249. span: 24,
  250. placeholder: '自动拼接请款明细中的款项说明',
  251. disabled: true
  252. },
  253. {
  254. type: 'slot',
  255. prop: 'atts',
  256. label: '上传附件',
  257. span: 24
  258. },
  259. {
  260. type: 'slot',
  261. prop: 'detailTable',
  262. label: '请款明细',
  263. span: 24
  264. },
  265. {
  266. type: 'input',
  267. prop: 'totalAmount',
  268. label: '付款总金额',
  269. disabled: true,
  270. placeholder: '自动统计请款明细中的请款金额'
  271. },
  272. {
  273. type: 'inputNumber',
  274. prop: 'documentQuantity',
  275. label: '单据数量',
  276. min: 0,
  277. precision: 0,
  278. rule: [{ required: true, message: '单据数量不能为空', trigger: 'blur' }]
  279. },
  280. {
  281. type: 'select',
  282. prop: 'payType',
  283. label: '付款方式',
  284. dict: 'pay_type',
  285. rule: [{ required: true, message: '付款方式不能为空', trigger: 'blur' }]
  286. },
  287. {
  288. type: 'select',
  289. prop: 'capitalAccountId',
  290. label: '付款账户',
  291. keyName: 'id',
  292. labelName: 'accountAlias',
  293. async option() {
  294. const data = await getCapitalAccountPageApi({ searchAll: true })
  295. return data.records
  296. }
  297. },
  298. {
  299. type: 'input',
  300. prop: 'accountName',
  301. label: '户名',
  302. },
  303. {
  304. type: 'input',
  305. prop: 'account',
  306. label: '银行账号',
  307. },
  308. {
  309. type: 'input',
  310. prop: 'depositBank',
  311. label: '开户银行',
  312. },
  313. {
  314. type: 'input',
  315. prop: 'correspondentNumber',
  316. label: '联行号/SWIFT Code',
  317. }
  318. ]
  319. const detailTableColumnConfig: ColumnConfigType[] = [
  320. {
  321. slot: 'expenseType',
  322. label: '费用类型',
  323. width: 250
  324. },
  325. {
  326. slot: 'remark',
  327. label: '款项说明',
  328. },
  329. {
  330. slot: 'amount',
  331. label: '请款金额',
  332. width: 180
  333. },
  334. {
  335. width: 100,
  336. handleConfig: [
  337. {
  338. common: 'delete',
  339. click(row, index) {
  340. formData.value.paymentRequestsDetailList.splice(index, 1)
  341. updateDetailRemark()
  342. updateAmount()
  343. }
  344. }
  345. ]
  346. }
  347. ]
  348. onMounted(() => {
  349. getPage()
  350. })
  351. function getPage() {
  352. getPageApi(queryData.value).then((resp) => {
  353. tableData.value = resp.records
  354. pageTotal.value = resp.total
  355. })
  356. }
  357. function tableSelectionChange(item: StrAnyObjArr) {
  358. selectKeys.value = item.map((item) => item.id)
  359. }
  360. function formSubmit() {
  361. formRef.value?.validate(() => {
  362. if (formData.value.id) {
  363. editApi(formData.value).then(() => {
  364. dialogVisible.value = false
  365. ElMessage.success('修改成功')
  366. getPage()
  367. })
  368. } else {
  369. addApi(formData.value).then(() => {
  370. dialogVisible.value = false
  371. ElMessage.success('新增成功')
  372. getPage()
  373. })
  374. }
  375. })
  376. }
  377. function formClosed() {
  378. formRef.value?.resetFields()
  379. }
  380. function handleRemove(idList: string[]) {
  381. useHandleData('是否确认删除?', () => {
  382. deleteApi({ idList }).then(() => {
  383. ElMessage.success('删除成功')
  384. getPage()
  385. })
  386. })
  387. }
  388. function addPaymentRequestsDetailList() {
  389. formData.value.paymentRequestsDetailList.push({})
  390. }
  391. function updateDetailRemark() {
  392. formData.value.useRemark = formData.value.paymentRequestsDetailList
  393. .map((item) => item.remark)
  394. .filter((item) => item !== '' && item !== null && item !== undefined)
  395. .join(' - \n')
  396. }
  397. function updateAmount() {
  398. formData.value.totalAmount = formData.value.paymentRequestsDetailList
  399. .map((item) => item.amount)
  400. .filter((item) => item !== '' && item !== null && item !== undefined)
  401. .reduce((pre, next) => pre + next, 0)
  402. }
  403. </script>
  404. <template>
  405. <div>
  406. <el-card v-if="showQuery">
  407. <a-form ref="queryRef" v-model="queryData" :config="queryConfig" :span="6"> </a-form>
  408. </el-card>
  409. <a-table
  410. selection
  411. :data="tableData"
  412. :page-total="pageTotal"
  413. :toolbar-config="toolbarConfig"
  414. :column-config="columnConfig"
  415. v-model:showQuery="showQuery"
  416. v-model:page-num="queryData.pageNum"
  417. v-model:page-size="queryData.pageSize"
  418. @page-num-change="getPage"
  419. @page-size-change="getPage"
  420. @selection-change="tableSelectionChange"
  421. >
  422. </a-table>
  423. <a-dialog
  424. v-model="dialogVisible"
  425. :title="dialogTitle"
  426. @submit="formSubmit"
  427. @closed="formClosed"
  428. width="1400px"
  429. height="200px"
  430. >
  431. <a-form ref="formRef" v-model="formData" :config="formConfig" :span="12">
  432. <template #dept>
  433. <dept-tree-select ref="deptIdRef" v-model="formData.deptId" />
  434. </template>
  435. <template #atts>
  436. </template>
  437. <template #detailTable>
  438. <a-table :data="formData.paymentRequestsDetailList" :columnConfig="detailTableColumnConfig" style="width: 100%" :card="false">
  439. <template #expenseType="scope">
  440. <a-select v-model="scope.row.expenseType" dict="expense_type"/>
  441. </template>
  442. <template #remark="scope">
  443. <a-input v-model="scope.row.remark" type="textarea" rows="2" @change="updateDetailRemark"/>
  444. </template>
  445. <template #amount="scope">
  446. <a-inputNumber v-model="scope.row.amount" :min="0.01" :precision="2" @change="updateAmount" />
  447. </template>
  448. </a-table>
  449. <el-button style="width: 100%; margin-bottom: 20px" type="primary" @click="addPaymentRequestsDetailList">
  450. 添加行
  451. </el-button>
  452. </template>
  453. </a-form>
  454. </a-dialog>
  455. </div>
  456. </template>