index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. <template>
  2. <div class="tenant">
  3. <!-- <Banner /> -->
  4. <div class="content">
  5. <byTable
  6. :source="sourceList.data"
  7. :pagination="sourceList.pagination"
  8. :config="config"
  9. :loading="loading"
  10. highlight-current-row
  11. :selectConfig="selectConfig"
  12. :table-events="{
  13. select: select,
  14. }"
  15. :action-list="[]"
  16. @moreSearch="moreSearch"
  17. @get-list="getList">
  18. <template #amount="{ item }">
  19. <div :style="'color: ' + (item.status === '10' ? '#04cb04;' : 'red;')">
  20. <span style="padding-right: 4px">{{ item.currency }}</span>
  21. <span v-if="item.status === '20'">-</span>
  22. <span>{{ moneyFormat(item.amount, 2) }}</span>
  23. </div>
  24. </template>
  25. </byTable>
  26. </div>
  27. <el-dialog title="拆分" v-if="dialogVisible" v-model="dialogVisible" width="800" v-loading="loading">
  28. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  29. <template #money>
  30. <div style="width: 100%">
  31. <el-row :gutter="10">
  32. <el-col :span="6">
  33. <el-form-item>
  34. <el-select v-model="formData.data.status" style="width: 100%" disabled>
  35. <el-option v-for="item in status" :key="item.value" :label="item.label" :value="item.value" />
  36. </el-select>
  37. </el-form-item>
  38. </el-col>
  39. <el-col :span="12">
  40. <el-form-item>
  41. <el-input v-model="formData.data.amount" placeholder="请输入金额" class="input-with-select" disabled>
  42. <template #prepend>
  43. <el-select v-model="formData.data.currency" placeholder="请选择币种" style="width: 100px" disabled>
  44. <el-option v-for="item in accountCurrency" :key="item.value" :label="item.value" :value="item.value" />
  45. </el-select>
  46. </template>
  47. </el-input>
  48. </el-form-item>
  49. </el-col>
  50. </el-row>
  51. </div>
  52. </template>
  53. <template #slot>
  54. <div style="width: 100%">
  55. <el-button type="primary" @click="addRow"> 添加 </el-button>
  56. <br />
  57. <el-table :data="formData.data.accountDeptRunningWaterDetailList">
  58. <el-table-column prop="deptId" label="部门">
  59. <template #default="{ row, $index }">
  60. <el-form-item :prop="'accountDeptRunningWaterDetailList.' + $index + '.deptId'" :rules="rules.deptId" :inline-message="true">
  61. <el-cascader
  62. v-model="row.deptId"
  63. :options="deptTreeData"
  64. :props="{
  65. value: 'deptId',
  66. }"
  67. clearable
  68. filterable
  69. style="width: 100%" />
  70. </el-form-item>
  71. </template>
  72. </el-table-column>
  73. <el-table-column prop="amount" label="分拆金额">
  74. <template #default="{ row, $index }">
  75. <el-form-item :prop="'accountDeptRunningWaterDetailList.' + $index + '.amount'" :rules="rules.amount" :inline-message="true">
  76. <el-input-number
  77. onmousewheel="return false;"
  78. v-model="row.amount"
  79. placeholder="请输入金额"
  80. style="width: 100%"
  81. :precision="2"
  82. :controls="false"
  83. :min="0" />
  84. </el-form-item>
  85. </template>
  86. </el-table-column>
  87. <el-table-column prop="remarks" label="备注">
  88. <template #default="{ row, $index }">
  89. <el-form-item :prop="'accountDeptRunningWaterDetailList.' + $index + '.remarks'" :rules="rules.remarks" :inline-message="true">
  90. <el-input v-model="row.remarks" placeholder="请输入" />
  91. </el-form-item>
  92. </template>
  93. </el-table-column>
  94. <el-table-column prop="zip" align="center" label="操作" width="80">
  95. <template #default="{ $index }">
  96. <el-button type="primary" link @click="handleRemove($index)">删除</el-button>
  97. </template>
  98. </el-table-column>
  99. </el-table>
  100. </div>
  101. </template>
  102. </byForm>
  103. <template #footer>
  104. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  105. <el-button type="primary" @click="submitForm()" size="large" :loading="submitLoading"> 确 定 </el-button>
  106. </template>
  107. </el-dialog>
  108. <el-dialog title="调整部门" v-if="depModal" v-model="depModal" width="600" v-loading="loading">
  109. <p>部门名称</p>
  110. <el-cascader
  111. v-model="departmentId"
  112. :options="deptTreeData"
  113. :props="{
  114. value: 'deptId',
  115. }"
  116. clearable
  117. filterable
  118. style="width: 100%" />
  119. <template #footer>
  120. <el-button @click="depModal = false" size="large">取 消</el-button>
  121. <el-button type="primary" @click="submitDeptForm(departmentId)" size="large" :loading="submitLoading"> 确 定 </el-button>
  122. </template>
  123. </el-dialog>
  124. <el-dialog title="高级检索" v-if="openSearch" v-model="openSearch" width="600" :before-close="cancelSearch">
  125. <byForm :formConfig="formSearchConfig" :formOption="formOption" v-model="sourceList.pagination">
  126. <template #time>
  127. <div style="width: 100%">
  128. <el-row :gutter="10">
  129. <el-col :span="11">
  130. <el-date-picker
  131. v-model="sourceList.pagination.beginTime"
  132. type="datetime"
  133. placeholder="请选择"
  134. style="width: 100%"
  135. value-format="YYYY-MM-DD HH:mm:ss" />
  136. </el-col>
  137. <el-col :span="2" style="text-align: center">到</el-col>
  138. <el-col :span="11">
  139. <el-date-picker
  140. v-model="sourceList.pagination.endTime"
  141. type="datetime"
  142. placeholder="请选择"
  143. style="width: 100%"
  144. value-format="YYYY-MM-DD HH:mm:ss" />
  145. </el-col>
  146. </el-row>
  147. </div>
  148. </template>
  149. <template #money>
  150. <div style="width: 100%">
  151. <el-row :gutter="10">
  152. <el-col :span="11">
  153. <el-input-number
  154. onmousewheel="return false;"
  155. v-model="sourceList.pagination.beginAmount"
  156. placeholder="请输入"
  157. style="width: 100%"
  158. :precision="2"
  159. :controls="false"
  160. :min="0" />
  161. </el-col>
  162. <el-col :span="2" style="text-align: center">到</el-col>
  163. <el-col :span="11">
  164. <el-input-number
  165. onmousewheel="return false;"
  166. v-model="sourceList.pagination.endAmount"
  167. placeholder="请输入"
  168. style="width: 100%"
  169. :precision="2"
  170. :controls="false"
  171. :min="0" />
  172. </el-col>
  173. </el-row>
  174. </div>
  175. </template>
  176. </byForm>
  177. <template #footer>
  178. <el-button @click="cancelSearch()" size="large">取 消</el-button>
  179. <el-button type="primary" @click="submitSearch()" size="large">确 定</el-button>
  180. </template>
  181. </el-dialog>
  182. </div>
  183. </template>
  184. <script setup>
  185. import { ElMessage } from "element-plus";
  186. import byTable from "@/components/byTable/index";
  187. import byForm from "@/components/byForm/index";
  188. import { computed, ref } from "vue";
  189. const loading = ref(false);
  190. const submitLoading = ref(false);
  191. const sourceList = ref({
  192. data: [],
  193. pagination: {
  194. total: 3,
  195. pageNum: 1,
  196. pageSize: 10,
  197. status: "",
  198. currency: "",
  199. type: "",
  200. corporationId: "",
  201. remarks: "",
  202. beginAmount: "",
  203. endAmount: "",
  204. beginTime: "",
  205. endTime: "",
  206. },
  207. });
  208. let dialogVisible = ref(false);
  209. let modalType = ref("add");
  210. let rules = ref({
  211. type: [{ required: true, message: "请选择类型", trigger: "change" }],
  212. contactNumber: [{ required: true, message: "请输入联系号码", trigger: "blur" }],
  213. amount: [{ required: true, message: "请输入金额", trigger: "blur" }],
  214. });
  215. const status = ref([
  216. {
  217. label: "收入",
  218. value: "10",
  219. },
  220. {
  221. label: "支出",
  222. value: "20",
  223. },
  224. ]);
  225. const type = ref([
  226. {
  227. label: "是",
  228. value: 1,
  229. },
  230. {
  231. label: "否",
  232. value: 0,
  233. },
  234. ]);
  235. const accountCurrency = ref([]);
  236. import Cookies from "js-cookie";
  237. const { proxy } = getCurrentInstance();
  238. const selectConfig = [];
  239. const config = computed(() => {
  240. return [
  241. {
  242. attrs: {
  243. label: "资金账户",
  244. prop: "accountManagementName",
  245. },
  246. },
  247. {
  248. attrs: {
  249. label: "交易时间",
  250. prop: "transactionTime",
  251. },
  252. },
  253. {
  254. attrs: {
  255. label: "交易金额",
  256. slot: "amount",
  257. },
  258. },
  259. {
  260. attrs: {
  261. prop: "accountOpening",
  262. label: "对方账户",
  263. },
  264. },
  265. {
  266. attrs: {
  267. prop: "openingBank",
  268. label: "对方银行",
  269. },
  270. },
  271. {
  272. attrs: {
  273. prop: "name",
  274. label: "对方账号",
  275. },
  276. },
  277. {
  278. attrs: {
  279. prop: "remarks",
  280. label: "摘要",
  281. },
  282. },
  283. {
  284. attrs: {
  285. label: "操作",
  286. width: "200",
  287. align: "right",
  288. },
  289. renderHTML(row) {
  290. return [
  291. {
  292. attrs: {
  293. label: "调整部门",
  294. type: "primary",
  295. text: true,
  296. },
  297. el: "button",
  298. click() {
  299. depModal.value = true;
  300. dtlData.value = row;
  301. departmentId.value = [];
  302. },
  303. },
  304. {
  305. attrs: {
  306. label: "分拆",
  307. type: "primary",
  308. text: true,
  309. },
  310. el: "button",
  311. click() {
  312. getDtl(row);
  313. },
  314. },
  315. ];
  316. },
  317. },
  318. ];
  319. });
  320. const dtlData = ref({});
  321. let formData = reactive({
  322. data: {
  323. type: "1",
  324. },
  325. treeData: [],
  326. });
  327. const formOption = reactive({
  328. inline: true,
  329. labelWidth: 100,
  330. itemWidth: 100,
  331. rules: [],
  332. });
  333. const submit = ref(null);
  334. const depModal = ref(false);
  335. let deptTreeData = ref([]);
  336. let departmentId = ref([]);
  337. const getDept = async () => {
  338. // 部门树
  339. proxy
  340. .get("/tenantDept/list", {
  341. pageNum: 1,
  342. pageSize: 9999,
  343. tenantId: Cookies.get("tenantId"),
  344. })
  345. .then((message) => {
  346. recursive(message.data);
  347. deptTreeData.value = proxy.handleTree(message.data, "corporationId");
  348. });
  349. };
  350. getDept();
  351. const submitDeptForm = async (departmentId) => {
  352. if (departmentId.length == 0) {
  353. ElMessage.error("请选择部门");
  354. return;
  355. }
  356. let params = {
  357. deptId: departmentId[departmentId.length - 1],
  358. accountDeptRunningWaterId: dtlData.value.accountDeptRunningWaterId,
  359. id: dtlData.value.id,
  360. amount: dtlData.value.amount,
  361. };
  362. proxy
  363. .post("/accountDeptRunningWaterDetail/add", params)
  364. .then(() => {
  365. ElMessage.success("调整部门成功");
  366. depModal.value = false;
  367. getList();
  368. })
  369. .catch((error) => {
  370. ElMessage.error(error);
  371. });
  372. };
  373. const recursive = (data) => {
  374. data.map((item) => {
  375. item.label = item.deptName;
  376. item.id = item.corporationId;
  377. if (item.children) {
  378. recursive(item.children);
  379. } else {
  380. item.children = [];
  381. }
  382. });
  383. };
  384. const formConfig = computed(() => {
  385. return [
  386. {
  387. type: "select",
  388. prop: "accountManagementId",
  389. label: "付款账户",
  390. required: true,
  391. disabled: true,
  392. isLoad: {
  393. url: "/accountManagement/page",
  394. req: {
  395. pageNum: 1,
  396. pageSize: 9999,
  397. },
  398. labelKey: "name",
  399. labelVal: "id",
  400. method: "post",
  401. resUrl: "rows",
  402. },
  403. },
  404. {
  405. type: "date",
  406. prop: "transactionTime",
  407. label: "交易时间",
  408. disabled: true,
  409. },
  410. // {
  411. // type: "selectInput",
  412. // label: "交易金额",
  413. // itemWidth: 60,
  414. // data: accountCurrency.value,
  415. // placeholder: "请输入",
  416. // selectPlaceholder: "币种",
  417. // selectProp: "currency",
  418. // prop: "amount",
  419. // disabled: true,
  420. // },
  421. {
  422. type: "slot",
  423. prop: "money",
  424. slotName: "money",
  425. label: "交易金额",
  426. },
  427. {
  428. type: "input",
  429. prop: "remarks",
  430. label: "摘要",
  431. disabled: true,
  432. itemType: "textarea",
  433. disabled: true,
  434. },
  435. {
  436. type: "slot",
  437. label: "拆分明细",
  438. slotName: "slot",
  439. },
  440. ];
  441. });
  442. const getList = async (req) => {
  443. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  444. loading.value = true;
  445. proxy.post("/accountDeptRunningWater/page", sourceList.value.pagination).then((message) => {
  446. sourceList.value.data = message.rows;
  447. sourceList.value.pagination.total = message.total;
  448. setTimeout(() => {
  449. loading.value = false;
  450. }, 200);
  451. });
  452. };
  453. proxy.getDict(["account_currency"]).then((res) => {
  454. accountCurrency.value = res.account_currency.map((item) => {
  455. return {
  456. label: item.dictValue,
  457. value: item.dictKey,
  458. };
  459. });
  460. });
  461. const submitForm = async () => {
  462. submit.value.handleSubmit(() => {
  463. if (!(formData.data.accountDeptRunningWaterDetailList && formData.data.accountDeptRunningWaterDetailList.length > 0)) {
  464. return ElMessage("请添加拆分明细!");
  465. }
  466. let money = 0;
  467. for (let i = 0; i < formData.data.accountDeptRunningWaterDetailList.length; i++) {
  468. if (formData.data.accountDeptRunningWaterDetailList[i].amount && Number(formData.data.accountDeptRunningWaterDetailList[i].amount) !== 0) {
  469. money = Number(parseFloat(Number(money) + Number(formData.data.accountDeptRunningWaterDetailList[i].amount)));
  470. } else {
  471. return ElMessage("金额不能为0");
  472. }
  473. }
  474. if (Number(money) !== Number(formData.data.amount)) {
  475. return ElMessage("分拆总金额需等于交易金额");
  476. }
  477. submitLoading.value = true;
  478. let params = {
  479. id: formData.data.id,
  480. deptRunningWaterDetailList: formData.data.accountDeptRunningWaterDetailList,
  481. accountDeptRunningWaterId: formData.data.accountDeptRunningWaterId,
  482. };
  483. params.deptRunningWaterDetailList.map((item) => {
  484. item.deptId = item.deptId[item.deptId.length - 1];
  485. });
  486. proxy
  487. .post("/accountDeptRunningWaterDetail/add", {
  488. ...params,
  489. })
  490. .then(
  491. () => {
  492. ElMessage({
  493. message: "拆分成功",
  494. type: "success",
  495. });
  496. dialogVisible.value = false;
  497. submitLoading.value = false;
  498. getList();
  499. },
  500. (err) => (submitLoading.value = false)
  501. );
  502. });
  503. };
  504. const getDtl = (row) => {
  505. modalType.value = "edit";
  506. dialogVisible.value = true;
  507. proxy.post("/accountDeptRunningWaterDetail/detail", { id: row.id }).then((res) => {
  508. if (res.deptRunningWaterDetailList && res.deptRunningWaterDetailList.length > 0) {
  509. res.accountDeptRunningWaterDetailList = res.deptRunningWaterDetailList.map((item) => {
  510. item.deptId = [item.deptId];
  511. return item;
  512. });
  513. } else {
  514. res.accountDeptRunningWaterDetailList = [];
  515. }
  516. formData.data = res;
  517. dialogVisible.value = true;
  518. });
  519. };
  520. const addRow = () => {
  521. formData.data.accountDeptRunningWaterDetailList.push({
  522. remarks: "",
  523. amount: null,
  524. deptId: [],
  525. });
  526. };
  527. const handleRemove = (index) => {
  528. formData.data.accountDeptRunningWaterDetailList.splice(index, 1);
  529. return ElMessage({
  530. message: "删除成功!",
  531. type: "success",
  532. });
  533. };
  534. getList();
  535. const companyData = ref([]);
  536. proxy.post("/corporation/page", { pageNum: 1, pageSize: 9999 }).then((res) => {
  537. if (res.rows && res.rows.length > 0) {
  538. companyData.value = res.rows.map((item) => {
  539. return {
  540. label: item.name,
  541. value: item.id,
  542. };
  543. });
  544. }
  545. });
  546. const openSearch = ref(false);
  547. const formSearchConfig = computed(() => {
  548. return [
  549. {
  550. type: "select",
  551. prop: "status",
  552. label: "收支类型",
  553. data: status.value,
  554. clearable: true,
  555. },
  556. {
  557. type: "select",
  558. prop: "currency",
  559. label: "币种",
  560. data: accountCurrency.value,
  561. clearable: true,
  562. },
  563. {
  564. type: "select",
  565. prop: "type",
  566. label: "是否拆分",
  567. data: type.value,
  568. clearable: true,
  569. },
  570. {
  571. type: "select",
  572. prop: "corporationId",
  573. label: "归属公司",
  574. data: companyData.value,
  575. clearable: true,
  576. },
  577. {
  578. type: "slot",
  579. slotName: "time",
  580. label: "请款时间",
  581. },
  582. {
  583. type: "slot",
  584. slotName: "money",
  585. label: "请款金额",
  586. },
  587. {
  588. type: "input",
  589. itemType: "textarea",
  590. prop: "remarks",
  591. label: "摘要",
  592. },
  593. ];
  594. });
  595. let copySearch = ref({});
  596. const moreSearch = () => {
  597. copySearch.value = proxy.deepClone(sourceList.value.pagination);
  598. openSearch.value = true;
  599. };
  600. const cancelSearch = () => {
  601. sourceList.value.pagination = copySearch.value;
  602. openSearch.value = false;
  603. };
  604. const submitSearch = () => {
  605. if (
  606. sourceList.value.pagination.beginAmount &&
  607. sourceList.value.pagination.endAmount &&
  608. Number(sourceList.value.pagination.beginAmount) > Number(sourceList.value.pagination.endAmount)
  609. ) {
  610. return ElMessage("交易金额输入错误");
  611. }
  612. if (
  613. sourceList.value.pagination.beginTime &&
  614. sourceList.value.pagination.endTime &&
  615. sourceList.value.pagination.beginTime > sourceList.value.pagination.endTime
  616. ) {
  617. return ElMessage("开始时间不能大于结束时间");
  618. }
  619. openSearch.value = false;
  620. sourceList.value.pagination.keyword = "";
  621. sourceList.value.pagination.pageNum = 1;
  622. getList();
  623. };
  624. </script>
  625. <style lang="scss" scoped>
  626. .tenant {
  627. padding: 20px;
  628. }
  629. ::v-deep(.el-input-number .el-input__inner) {
  630. text-align: left;
  631. }
  632. </style>