detailList.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. <template>
  2. <div style="width: 97%">
  3. <el-row>
  4. <el-col
  5. :span="24"
  6. >
  7. <el-form
  8. :inline="true"
  9. style="margin: 15px 0 0 10px;height: 40px"
  10. >
  11. <el-form-item label="时间类型:">
  12. <el-select
  13. v-model="timeTypeValue"
  14. placeholder="请选择日期选择器"
  15. @change="changeTimeType"
  16. >
  17. <el-option
  18. v-for="item in timeTypeList"
  19. :key="item.value"
  20. :label="item.label"
  21. :value="item.value"
  22. />
  23. </el-select>
  24. </el-form-item>
  25. <el-form-item
  26. v-if="timeTypeValue === 'date'"
  27. label="日期:"
  28. >
  29. <el-date-picker
  30. v-model="condition.dayTime"
  31. type="date"
  32. placeholder="请选择日期"
  33. format="YYYY-MM-DD"
  34. value-format="YYYY-MM-DD"
  35. clearable
  36. @clear="condition.dayTime = ''"
  37. />
  38. </el-form-item>
  39. <el-form-item
  40. v-if="timeTypeValue === 'month'"
  41. label="月份:"
  42. >
  43. <el-date-picker
  44. v-model="condition.monthTime"
  45. type="month"
  46. placeholder="请选择月份"
  47. format="YYYY-MM"
  48. value-format="YYYY-MM"
  49. clearable
  50. @clear="condition.monthTime = ''"
  51. />
  52. </el-form-item>
  53. <el-form-item
  54. v-if="timeTypeValue === 'year'"
  55. label="年份:"
  56. >
  57. <el-date-picker
  58. v-model="condition.yearTime"
  59. type="year"
  60. placeholder="请选择年份"
  61. format="YYYY"
  62. value-format="YYYY"
  63. clearable
  64. @clear="condition.yearTime = ''"
  65. />
  66. </el-form-item>
  67. <el-form-item label="类型:">
  68. <el-select
  69. v-model="genreSelect"
  70. placeholder="请选择类型"
  71. clearable
  72. @clear="clearGenre"
  73. >
  74. <el-option
  75. v-for="item in costTypeList"
  76. :key="item.ID"
  77. :label="item.name"
  78. :value="item.ID"
  79. />
  80. </el-select>
  81. </el-form-item>
  82. <el-form-item label="人员:">
  83. <el-select
  84. v-model="peopleSelect"
  85. placeholder="请选择人员名称"
  86. clearable
  87. filterable
  88. @clear="clearPeopleSelect"
  89. >
  90. <el-option
  91. v-for="item in userList"
  92. :key="item.ID"
  93. :label="item.nickName"
  94. :value="item.ID"
  95. />
  96. </el-select>
  97. </el-form-item>
  98. <el-form-item>
  99. <el-dropdown
  100. split-button
  101. type="primary"
  102. >
  103. 操作
  104. <template #dropdown>
  105. <el-dropdown-menu>
  106. <el-dropdown-item>
  107. <el-button
  108. type="primary"
  109. :icon="Search"
  110. @click="consultCostList"
  111. >查询</el-button>
  112. </el-dropdown-item>
  113. <el-dropdown-item>
  114. <el-button
  115. type="primary"
  116. :icon="Refresh"
  117. @click="costListReset"
  118. >重置</el-button>
  119. </el-dropdown-item>
  120. <el-dropdown-item>
  121. <el-button
  122. type="primary"
  123. :icon="Plus"
  124. @click="addDetailRecord"
  125. >添加</el-button>
  126. </el-dropdown-item>
  127. </el-dropdown-menu>
  128. </template>
  129. </el-dropdown>
  130. </el-form-item>
  131. <el-form-item>
  132. <el-button
  133. type="primary"
  134. @click="costTypePopup = true"
  135. >费用类型</el-button>
  136. </el-form-item>
  137. </el-form>
  138. </el-col>
  139. </el-row>
  140. <el-row style="margin-top: 15px;">
  141. <el-table
  142. :data="costList"
  143. stripe
  144. border
  145. >
  146. <el-table-column
  147. label="人员名称"
  148. align="center"
  149. prop="user.nickName"
  150. width="180"
  151. />
  152. <el-table-column
  153. label="费用类型"
  154. align="center"
  155. prop="expensesGenre.name"
  156. width="180"
  157. />
  158. <el-table-column
  159. label="时间"
  160. align="center"
  161. prop="feeTime"
  162. width="180"
  163. />
  164. <el-table-column
  165. label="部门"
  166. align="center"
  167. prop="department.name"
  168. width="180"
  169. />
  170. <el-table-column
  171. label="支入金额(元)"
  172. align="center"
  173. prop="depositAmount"
  174. width="180"
  175. />
  176. <el-table-column
  177. label="支出金额(元)"
  178. align="center"
  179. prop="expenditureAmount"
  180. width="180"
  181. />
  182. <el-table-column
  183. label="当前余额(元)"
  184. align="center"
  185. prop="thenBalance"
  186. width="180"
  187. />
  188. <el-table-column
  189. label="操作"
  190. align="center"
  191. >
  192. <template #default="scope">
  193. <el-popover
  194. placement="top"
  195. :width="300"
  196. trigger="click"
  197. :content="scope.row.expenseDetail"
  198. >
  199. <template #reference>
  200. <el-button
  201. text
  202. type="primary"
  203. :icon="Notebook"
  204. >
  205. 明细
  206. </el-button>
  207. </template>
  208. </el-popover>
  209. <el-button
  210. text
  211. type="primary"
  212. size="small"
  213. :icon="Edit"
  214. @click="costEdit(scope.row)"
  215. >编辑</el-button>
  216. <el-button
  217. text
  218. type="primary"
  219. size="small"
  220. :icon="Delete"
  221. @click="costDelete(scope.row)"
  222. >删除</el-button>
  223. </template>
  224. </el-table-column>
  225. </el-table>
  226. </el-row>
  227. <el-row
  228. v-show="costListTotal > 10"
  229. justify="end"
  230. >
  231. <el-pagination
  232. v-model:current-page="condition.pageInfo.page"
  233. background
  234. layout="prev, pager, next"
  235. :total="costListTotal"
  236. @change="changeCostPage"
  237. />
  238. </el-row>
  239. <el-drawer
  240. v-model="editDrawerShow"
  241. :title="drawerTitle"
  242. width="40%"
  243. >
  244. <el-form
  245. label-width="90"
  246. label-position="left"
  247. size="large"
  248. >
  249. <el-form-item label="人员:">
  250. <el-select
  251. v-model="editData.reimburser"
  252. placeholder="请选择人员名称"
  253. @change="changePeople"
  254. >
  255. <el-option
  256. v-for="item in userList"
  257. :key="item.ID"
  258. :label="item.nickName"
  259. :value="item.ID"
  260. />
  261. </el-select>
  262. </el-form-item>
  263. <el-form-item label="部门:">
  264. <el-select
  265. v-model="editData.departmentId"
  266. disabled
  267. placeholder="请选择费用类型"
  268. >
  269. <el-option
  270. v-for="item in departmentList"
  271. :key="item.ID"
  272. :label="item.name"
  273. :value="item.ID"
  274. />
  275. </el-select>
  276. </el-form-item>
  277. <el-form-item label="支入金额:">
  278. <el-input-number
  279. v-model="editData.depositAmount"
  280. />
  281. </el-form-item>
  282. <el-form-item label="支出金额:">
  283. <el-input-number
  284. v-model="editData.expenditureAmount"
  285. />
  286. </el-form-item>
  287. <el-form-item label="时间:">
  288. <el-date-picker
  289. v-model="editData.feeTime"
  290. type="date"
  291. placeholder="请选择日期"
  292. format="YYYY-MM-DD"
  293. value-format="YYYY-MM-DD"
  294. />
  295. </el-form-item>
  296. <el-form-item label="费用类型:">
  297. <el-select
  298. v-model="editData.genre"
  299. placeholder="请选择费用类型"
  300. >
  301. <el-option
  302. v-for="item in costTypeList"
  303. :key="item.ID"
  304. :label="item.name"
  305. :value="item.ID"
  306. />
  307. </el-select>
  308. </el-form-item>
  309. <el-form-item label="备注:">
  310. <el-input
  311. v-model="editData.remarks"
  312. placeholder="请填写费用备注"
  313. />
  314. </el-form-item>
  315. <el-form-item label="费用明细:">
  316. <el-input
  317. v-model="editData.expenseDetail"
  318. type="textarea"
  319. :rows="8"
  320. :maxlength="400"
  321. show-word-limit
  322. placeholder="请填写费用明细"
  323. />
  324. </el-form-item>
  325. <el-form-item label="余额:">
  326. <el-input-number
  327. v-model="editData.thenBalance"
  328. />
  329. </el-form-item>
  330. </el-form>
  331. <el-row
  332. style="margin-top: 50px"
  333. justify="end"
  334. >
  335. <el-button
  336. type="primary"
  337. size="large"
  338. @click="changeCostList"
  339. >确认</el-button>
  340. </el-row>
  341. </el-drawer>
  342. <el-dialog
  343. v-model="costTypePopup"
  344. title="费用类型"
  345. width="40%"
  346. >
  347. <el-form>
  348. <el-form-item
  349. label="编辑类型:"
  350. size="large"
  351. >
  352. <el-input
  353. v-model="changeCostValue"
  354. style="width: 550px"
  355. placeholder="请输入费用类型"
  356. >
  357. <template #prepend>
  358. <el-select
  359. v-model="costTypeSelect"
  360. placeholder="请选择类型"
  361. clearable
  362. style="width: 140px"
  363. @clear="clearCostType"
  364. >
  365. <el-option
  366. v-for="item in costTypeList"
  367. :key="item.ID"
  368. :label="item.name"
  369. :value="item.ID"
  370. />
  371. </el-select>
  372. </template>
  373. <template #append>
  374. <el-button @click="deleteCostType">删除</el-button>
  375. </template>
  376. </el-input>
  377. </el-form-item>
  378. </el-form>
  379. <template #footer>
  380. <div class="dialog-footer">
  381. <el-button
  382. type="primary"
  383. @click="editCostType"
  384. >
  385. 确认
  386. </el-button>
  387. </div>
  388. </template>
  389. </el-dialog>
  390. </div>
  391. </template>
  392. <script setup>
  393. import { Search, Plus, Delete, Refresh, Edit, Notebook } from '@element-plus/icons-vue'
  394. import { ref, reactive, onMounted } from 'vue'
  395. import { getAllUsers } from '@/api/user'
  396. import { createFeeGenre, deleteFeeGenre, queryExpensesGenre, updateFeeGenre } from '@/api/finance'
  397. import { queryCostList, updateCost } from '@/api/cost'
  398. import { getDepByStart } from '@/api/department'
  399. import { ElMessage, ElMessageBox } from 'element-plus'
  400. import { deleteCost, createCost } from '@/api/cost'
  401. defineOptions({
  402. name: 'DetailList'
  403. })
  404. const timeTypeList = reactive([
  405. { label: '按日期查询', value: 'date' },
  406. { label: '按月份查询', value: 'month' },
  407. { label: '按年份查询', value: 'year' }
  408. ])
  409. // 列表
  410. const userList = reactive([])
  411. const costTypeList = reactive([])
  412. const costList = reactive([])
  413. const costListTotal = ref(0)
  414. const departmentList = reactive([])
  415. // 查询数据
  416. const timeTypeValue = ref('date')
  417. const condition = reactive({
  418. pageInfo: {
  419. page: 1,
  420. pageSize: 10
  421. },
  422. reimburser: 0,
  423. genre: 0,
  424. dayTime: '',
  425. monthTime: '',
  426. yearTime: ''
  427. })
  428. const peopleSelect = ref('')
  429. const genreSelect = ref('')
  430. // 编辑数据
  431. const editDrawerShow = ref(false)
  432. const editData = reactive({
  433. id: 0,
  434. reimburser: 0,
  435. departmentId: 0,
  436. expenditureAmount: 0,
  437. depositAmount: 0,
  438. feeTime: '',
  439. genre: 0,
  440. projectId: 0,
  441. expenseDetail: '',
  442. remarks: '',
  443. thenBalance: 0
  444. })
  445. // 抽屉类型、标题
  446. const drawerType = ref('')
  447. const drawerTitle = ref('')
  448. // 费用类型修改
  449. const costTypePopup = ref(false)
  450. const changeCostValue = ref('')
  451. const costTypeSelect = ref('')
  452. const deleteCostType = () => {
  453. if (costTypeSelect.value === '') {
  454. ElMessage.error('请选择需要删除的费用类型')
  455. return
  456. }
  457. ElMessageBox.confirm(
  458. '确定进行删除该费用类型吗?',
  459. '删除',
  460. {
  461. confirmButtonText: '确定',
  462. cancelButtonText: '取消',
  463. type: 'warning',
  464. }
  465. )
  466. .then(() => {
  467. const deleteId = {
  468. id: costTypeSelect.value
  469. }
  470. deleteFeeGenre(deleteId).then(res => {
  471. if (res.code === 0) {
  472. ElMessage.success('删除成功')
  473. getCostTypeList()
  474. changeCostValue.value = ''
  475. costTypeSelect.value = ''
  476. }
  477. })
  478. })
  479. .catch(() => {
  480. ElMessage({
  481. type: 'info',
  482. message: '取消删除',
  483. })
  484. })
  485. }
  486. const editCostType = () => {
  487. if (changeCostValue.value === '') {
  488. ElMessage.error('请输入费用类型')
  489. return
  490. }
  491. if (costTypeSelect.value === '') {
  492. const createCost = {
  493. name: changeCostValue.value
  494. }
  495. createFeeGenre(createCost).then(res => {
  496. if (res.code === 0) {
  497. ElMessage.success('新增类型成功')
  498. getCostTypeList()
  499. changeCostValue.value = ''
  500. costTypeSelect.value = ''
  501. }
  502. })
  503. } else {
  504. const updateCost = {
  505. id: costTypeSelect.value,
  506. name: changeCostValue.value
  507. }
  508. updateFeeGenre(updateCost).then(res => {
  509. if (res.code === 0) {
  510. ElMessage.success('修改类型成功')
  511. getCostTypeList()
  512. changeCostValue.value = ''
  513. costTypeSelect.value = ''
  514. }
  515. })
  516. }
  517. }
  518. const clearCostType = () => {
  519. costTypeSelect.value = ''
  520. }
  521. // 方法
  522. onMounted(() => {
  523. getUserList()
  524. getCostTypeList()
  525. queryDepartmentList()
  526. getCostList(0, 0, 0)
  527. })
  528. const costListReset = () => {
  529. const initial = {
  530. pageInfo: {
  531. page: 1,
  532. pageSize: 10
  533. },
  534. reimburser: 0,
  535. projectId: 0,
  536. genre: 0,
  537. dayTime: '',
  538. monthTime: '',
  539. yearTime: ''
  540. }
  541. genreSelect.value = ''
  542. peopleSelect.value = ''
  543. Object.assign(condition, initial)
  544. consultCostList()
  545. }
  546. const getUserList = () => {
  547. getAllUsers().then(res => {
  548. if (res.code === 0) {
  549. userList.length = 0
  550. userList.push(...res.data)
  551. }
  552. })
  553. }
  554. const getCostTypeList = () => {
  555. queryExpensesGenre().then(res => {
  556. if (res.code === 0) {
  557. costTypeList.length = 0
  558. costTypeList.push(...res.data)
  559. }
  560. })
  561. }
  562. const queryDepartmentList = () => {
  563. getDepByStart().then(res => {
  564. if (res.code === 0) {
  565. departmentList.length = 0
  566. departmentList.push(...res.data)
  567. }
  568. })
  569. }
  570. const consultCostList = () => {
  571. let nameId
  572. let typeId
  573. let itemId
  574. peopleSelect.value === '' ? nameId = 0 : nameId = peopleSelect.value
  575. genreSelect.value === '' ? typeId = 0 : typeId = genreSelect.value
  576. getCostList(nameId, typeId, itemId)
  577. }
  578. const getCostList = (nameId, typeID, itemId) => {
  579. condition.reimburser = nameId
  580. condition.genre = typeID
  581. condition.projectId = itemId
  582. queryCostList(condition).then(res => {
  583. if (res.code === 0) {
  584. costList.length = 0
  585. if (res.data.list !== null) {
  586. costList.push(...res.data.list)
  587. }
  588. costListTotal.value = res.data.total
  589. }
  590. })
  591. }
  592. const costEdit = (row) => {
  593. editDrawerShow.value = true
  594. drawerType.value = 'edit'
  595. drawerTitle.value = '编辑公司费用'
  596. editData.id = row.ID
  597. editData.reimburser = row.reimburser
  598. editData.departmentId = row.departmentId
  599. editData.expenditureAmount = row.expenditureAmount
  600. editData.depositAmount = row.depositAmount
  601. editData.feeTime = row.feeTime
  602. editData.genre = row.genre
  603. editData.expenseDetail = row.expenseDetail
  604. editData.remarks = row.remarks
  605. editData.thenBalance = row.thenBalance
  606. }
  607. const costDelete = (row) => {
  608. ElMessageBox.confirm(
  609. '确定要删除此费用记录吗?',
  610. '删除记录',
  611. {
  612. confirmButtonText: '删除',
  613. cancelButtonText: '取消',
  614. type: 'warning',
  615. }
  616. )
  617. .then(() => {
  618. const data = {
  619. id: row.ID
  620. }
  621. deleteCost(data).then(res => {
  622. if (res.code === 0) {
  623. ElMessage.success('删除成功')
  624. consultCostList()
  625. }
  626. })
  627. })
  628. .catch(() => {
  629. ElMessage({
  630. type: 'info',
  631. message: '取消删除',
  632. })
  633. })
  634. }
  635. const addDetailRecord = () => {
  636. const initialData = {
  637. id: 0,
  638. reimburser: userList[0].ID,
  639. departmentId: userList[0].departmentId,
  640. expenditureAmount: 0,
  641. depositAmount: 0,
  642. feeTime: '',
  643. genre: costTypeList[0].ID,
  644. projectId: 0,
  645. expenseDetail: '',
  646. remarks: '',
  647. thenBalance: 0
  648. }
  649. Object.assign(editData, initialData)
  650. editDrawerShow.value = true
  651. drawerType.value = 'add'
  652. drawerTitle.value = '新增公司费用'
  653. }
  654. const clearPeopleSelect = () => {
  655. peopleSelect.value = ''
  656. condition.reimburser = 0
  657. }
  658. const clearGenre = () => {
  659. genreSelect.value = ''
  660. condition.genre = 0
  661. }
  662. const changeTimeType = (value) => {
  663. if (value === 'year') {
  664. condition.monthTime = ''
  665. condition.dayTime = ''
  666. } else if (value === 'month') {
  667. condition.yearTime = ''
  668. condition.dayTime = ''
  669. } else {
  670. condition.yearTime = ''
  671. condition.monthTime = ''
  672. }
  673. }
  674. const changeCostList = () => {
  675. for (const item in editData) {
  676. if (item === 'thenBalance') {
  677. continue
  678. }
  679. if (editData[item] === '' || editData[item] === null) {
  680. ElMessage({
  681. message: '请将除余额以外的信息填写完整',
  682. type: 'error',
  683. showClose: true,
  684. duration: 2000
  685. })
  686. return
  687. }
  688. }
  689. editData.thenBalance = parseFloat(editData.thenBalance)
  690. editData.expenditureAmount = parseFloat(editData.expenditureAmount)
  691. editData.depositAmount = parseFloat(editData.depositAmount)
  692. if (drawerType.value === 'add') {
  693. createCost(editData).then(res => {
  694. if (res.code === 0) {
  695. ElMessage.success('新增成功')
  696. editDrawerShow.value = false
  697. consultCostList()
  698. }
  699. })
  700. } else {
  701. updateCost(editData).then(res => {
  702. if (res.code === 0) {
  703. ElMessage.success('修改成功')
  704. editDrawerShow.value = false
  705. consultCostList()
  706. }
  707. })
  708. }
  709. }
  710. const changeCostPage = (val) => {
  711. condition.pageInfo.page = val
  712. consultCostList()
  713. }
  714. const changePeople = (val) => {
  715. userList.forEach(item => {
  716. if (item.ID === val) {
  717. editData.departmentId = item.departmentId
  718. }
  719. })
  720. }
  721. </script>
  722. <style scoped>
  723. </style>