index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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. </byForm>
  150. <template #footer>
  151. <el-button @click="cancelSearch()" size="large">取 消</el-button>
  152. <el-button type="primary" @click="submitSearch()" size="large">确 定</el-button>
  153. </template>
  154. </el-dialog>
  155. </div>
  156. </template>
  157. <script setup>
  158. import { ElMessage } from "element-plus";
  159. import byTable from "@/components/byTable/index";
  160. import byForm from "@/components/byForm/index";
  161. import { computed, ref } from "vue";
  162. const loading = ref(false);
  163. const submitLoading = ref(false);
  164. const sourceList = ref({
  165. data: [],
  166. pagination: {
  167. total: 3,
  168. pageNum: 1,
  169. pageSize: 10,
  170. status: "",
  171. currency: "",
  172. type: "",
  173. corporationId: "",
  174. remarks: "",
  175. beginTime: "",
  176. endTime: "",
  177. },
  178. });
  179. let dialogVisible = ref(false);
  180. let modalType = ref("add");
  181. let rules = ref({
  182. type: [{ required: true, message: "请选择类型", trigger: "change" }],
  183. contactNumber: [{ required: true, message: "请输入联系号码", trigger: "blur" }],
  184. amount: [{ required: true, message: "请输入金额", trigger: "blur" }],
  185. });
  186. const status = ref([
  187. {
  188. label: "收入",
  189. value: "10",
  190. },
  191. {
  192. label: "支出",
  193. value: "20",
  194. },
  195. ]);
  196. const type = ref([
  197. {
  198. label: "是",
  199. value: 1,
  200. },
  201. {
  202. label: "否",
  203. value: 0,
  204. },
  205. ]);
  206. const accountCurrency = ref([]);
  207. import Cookies from "js-cookie";
  208. const { proxy } = getCurrentInstance();
  209. const selectConfig = [];
  210. const config = computed(() => {
  211. return [
  212. {
  213. attrs: {
  214. label: "资金账户",
  215. prop: "accountManagementName",
  216. },
  217. },
  218. {
  219. attrs: {
  220. label: "交易时间",
  221. prop: "transactionTime",
  222. },
  223. },
  224. {
  225. attrs: {
  226. label: "交易金额",
  227. slot: "amount",
  228. },
  229. },
  230. {
  231. attrs: {
  232. prop: "accountOpening",
  233. label: "对方账户",
  234. },
  235. },
  236. {
  237. attrs: {
  238. prop: "openingBank",
  239. label: "对方银行",
  240. },
  241. },
  242. {
  243. attrs: {
  244. prop: "name",
  245. label: "对方账号",
  246. },
  247. },
  248. {
  249. attrs: {
  250. prop: "remarks",
  251. label: "摘要",
  252. },
  253. },
  254. {
  255. attrs: {
  256. label: "操作",
  257. width: "200",
  258. align: "right",
  259. },
  260. renderHTML(row) {
  261. return [
  262. {
  263. attrs: {
  264. label: "调整部门",
  265. type: "primary",
  266. text: true,
  267. },
  268. el: "button",
  269. click() {
  270. depModal.value = true;
  271. dtlData.value = row;
  272. departmentId.value = [];
  273. },
  274. },
  275. {
  276. attrs: {
  277. label: "分拆",
  278. type: "primary",
  279. text: true,
  280. },
  281. el: "button",
  282. click() {
  283. getDtl(row);
  284. },
  285. },
  286. ];
  287. },
  288. },
  289. ];
  290. });
  291. const dtlData = ref({});
  292. let formData = reactive({
  293. data: {
  294. type: "1",
  295. },
  296. treeData: [],
  297. });
  298. const formOption = reactive({
  299. inline: true,
  300. labelWidth: 100,
  301. itemWidth: 100,
  302. rules: [],
  303. });
  304. const submit = ref(null);
  305. const depModal = ref(false);
  306. let deptTreeData = ref([]);
  307. let departmentId = ref([]);
  308. const getDept = async () => {
  309. // 部门树
  310. proxy
  311. .get("/tenantDept/list", {
  312. pageNum: 1,
  313. pageSize: 9999,
  314. tenantId: Cookies.get("tenantId"),
  315. })
  316. .then((message) => {
  317. recursive(message.data);
  318. deptTreeData.value = proxy.handleTree(message.data, "corporationId");
  319. });
  320. };
  321. getDept();
  322. const submitDeptForm = async (departmentId) => {
  323. if (departmentId.length == 0) {
  324. ElMessage.error("请选择部门");
  325. return;
  326. }
  327. let params = {
  328. deptId: departmentId[departmentId.length - 1],
  329. accountDeptRunningWaterId: dtlData.value.accountDeptRunningWaterId,
  330. id: dtlData.value.id,
  331. amount: dtlData.value.amount,
  332. };
  333. proxy
  334. .post("/accountDeptRunningWaterDetail/add", params)
  335. .then(() => {
  336. ElMessage.success("调整部门成功");
  337. depModal.value = false;
  338. getList();
  339. })
  340. .catch((error) => {
  341. ElMessage.error(error);
  342. });
  343. };
  344. const recursive = (data) => {
  345. data.map((item) => {
  346. item.label = item.deptName;
  347. item.id = item.corporationId;
  348. if (item.children) {
  349. recursive(item.children);
  350. } else {
  351. item.children = [];
  352. }
  353. });
  354. };
  355. const formConfig = computed(() => {
  356. return [
  357. {
  358. type: "select",
  359. prop: "accountManagementId",
  360. label: "付款账户",
  361. required: true,
  362. disabled: true,
  363. isLoad: {
  364. url: "/accountManagement/page",
  365. req: {
  366. pageNum: 1,
  367. pageSize: 9999,
  368. },
  369. labelKey: "name",
  370. labelVal: "id",
  371. method: "post",
  372. resUrl: "rows",
  373. },
  374. },
  375. {
  376. type: "date",
  377. prop: "transactionTime",
  378. label: "交易时间",
  379. disabled: true,
  380. },
  381. // {
  382. // type: "selectInput",
  383. // label: "交易金额",
  384. // itemWidth: 60,
  385. // data: accountCurrency.value,
  386. // placeholder: "请输入",
  387. // selectPlaceholder: "币种",
  388. // selectProp: "currency",
  389. // prop: "amount",
  390. // disabled: true,
  391. // },
  392. {
  393. type: "slot",
  394. prop: "money",
  395. slotName: "money",
  396. label: "交易金额",
  397. },
  398. {
  399. type: "input",
  400. prop: "remarks",
  401. label: "摘要",
  402. disabled: true,
  403. itemType: "textarea",
  404. disabled: true,
  405. },
  406. {
  407. type: "slot",
  408. label: "拆分明细",
  409. slotName: "slot",
  410. },
  411. ];
  412. });
  413. const getList = async (req) => {
  414. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  415. loading.value = true;
  416. proxy.post("/accountDeptRunningWater/page", sourceList.value.pagination).then((message) => {
  417. sourceList.value.data = message.rows;
  418. sourceList.value.pagination.total = message.total;
  419. setTimeout(() => {
  420. loading.value = false;
  421. }, 200);
  422. });
  423. };
  424. proxy.getDict(["account_currency"]).then((res) => {
  425. accountCurrency.value = res.account_currency.map((item) => {
  426. return {
  427. label: item.dictValue,
  428. value: item.dictKey,
  429. };
  430. });
  431. });
  432. const submitForm = async () => {
  433. submit.value.handleSubmit(() => {
  434. if (!(formData.data.accountDeptRunningWaterDetailList && formData.data.accountDeptRunningWaterDetailList.length > 0)) {
  435. return ElMessage("请添加拆分明细!");
  436. }
  437. let money = 0;
  438. for (let i = 0; i < formData.data.accountDeptRunningWaterDetailList.length; i++) {
  439. if (formData.data.accountDeptRunningWaterDetailList[i].amount && Number(formData.data.accountDeptRunningWaterDetailList[i].amount) !== 0) {
  440. money = Number(parseFloat(Number(money) + Number(formData.data.accountDeptRunningWaterDetailList[i].amount)));
  441. } else {
  442. return ElMessage("金额不能为0");
  443. }
  444. }
  445. if (Number(money) !== Number(formData.data.amount)) {
  446. return ElMessage("分拆总金额需等于交易金额");
  447. }
  448. submitLoading.value = true;
  449. let params = {
  450. id: formData.data.id,
  451. deptRunningWaterDetailList: formData.data.accountDeptRunningWaterDetailList,
  452. accountDeptRunningWaterId: formData.data.accountDeptRunningWaterId,
  453. };
  454. params.deptRunningWaterDetailList.map((item) => {
  455. item.deptId = item.deptId[item.deptId.length - 1];
  456. });
  457. proxy
  458. .post("/accountDeptRunningWaterDetail/add", {
  459. ...params,
  460. })
  461. .then(
  462. () => {
  463. ElMessage({
  464. message: "拆分成功",
  465. type: "success",
  466. });
  467. dialogVisible.value = false;
  468. submitLoading.value = false;
  469. getList();
  470. },
  471. (err) => (submitLoading.value = false)
  472. );
  473. });
  474. };
  475. const getDtl = (row) => {
  476. modalType.value = "edit";
  477. dialogVisible.value = true;
  478. proxy.post("/accountDeptRunningWaterDetail/detail", { id: row.id }).then((res) => {
  479. if (res.deptRunningWaterDetailList && res.deptRunningWaterDetailList.length > 0) {
  480. res.accountDeptRunningWaterDetailList = res.deptRunningWaterDetailList.map((item) => {
  481. item.deptId = [item.deptId];
  482. return item;
  483. });
  484. } else {
  485. res.accountDeptRunningWaterDetailList = [];
  486. }
  487. formData.data = res;
  488. dialogVisible.value = true;
  489. });
  490. };
  491. const addRow = () => {
  492. formData.data.accountDeptRunningWaterDetailList.push({
  493. remarks: "",
  494. amount: null,
  495. deptId: [],
  496. });
  497. };
  498. const handleRemove = (index) => {
  499. formData.data.accountDeptRunningWaterDetailList.splice(index, 1);
  500. return ElMessage({
  501. message: "删除成功!",
  502. type: "success",
  503. });
  504. };
  505. getList();
  506. const companyData = ref([]);
  507. proxy.post("/corporation/page", { pageNum: 1, pageSize: 9999 }).then((res) => {
  508. if (res.rows && res.rows.length > 0) {
  509. companyData.value = res.rows.map((item) => {
  510. return {
  511. label: item.name,
  512. value: item.id,
  513. };
  514. });
  515. }
  516. });
  517. const openSearch = ref(false);
  518. const formSearchConfig = computed(() => {
  519. return [
  520. {
  521. type: "select",
  522. prop: "status",
  523. label: "收支类型",
  524. data: status.value,
  525. clearable: true,
  526. },
  527. {
  528. type: "select",
  529. prop: "currency",
  530. label: "币种",
  531. data: accountCurrency.value,
  532. clearable: true,
  533. },
  534. {
  535. type: "select",
  536. prop: "type",
  537. label: "是否拆分",
  538. data: type.value,
  539. clearable: true,
  540. },
  541. {
  542. type: "select",
  543. prop: "corporationId",
  544. label: "归属公司",
  545. data: companyData.value,
  546. clearable: true,
  547. },
  548. {
  549. type: "slot",
  550. slotName: "time",
  551. label: "请款时间",
  552. },
  553. {
  554. type: "input",
  555. itemType: "textarea",
  556. prop: "remarks",
  557. label: "摘要",
  558. },
  559. ];
  560. });
  561. let copySearch = ref({});
  562. const moreSearch = () => {
  563. copySearch.value = proxy.deepClone(sourceList.value.pagination);
  564. openSearch.value = true;
  565. };
  566. const cancelSearch = () => {
  567. sourceList.value.pagination = copySearch.value;
  568. openSearch.value = false;
  569. };
  570. const submitSearch = () => {
  571. if (
  572. sourceList.value.pagination.beginTime &&
  573. sourceList.value.pagination.endTime &&
  574. sourceList.value.pagination.beginTime > sourceList.value.pagination.endTime
  575. ) {
  576. return ElMessage("开始时间不能大于结束时间");
  577. }
  578. openSearch.value = false;
  579. sourceList.value.pagination.keyword = "";
  580. sourceList.value.pagination.pageNum = 1;
  581. getList();
  582. };
  583. </script>
  584. <style lang="scss" scoped>
  585. .tenant {
  586. padding: 20px;
  587. }
  588. ::v-deep(.el-input-number .el-input__inner) {
  589. text-align: left;
  590. }
  591. </style>