add.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. <template>
  2. <div class="expenseReimbursementAddwrap">
  3. <a-spin :spinning="spinning" tip="Loading...">
  4. <a-page-header :ghost="false" :backIcon="false" class="expenseReimbursementAddcont" >
  5. <!-- 自定义的二级文字标题 -->
  6. <template slot="subTitle">
  7. <a id="expenseEdit-back-btn" href="javascript:;" @click="handleBack(0)"><a-icon type="left" /> 返回列表</a>
  8. <span style="margin: 0 15px;color: #666;font-weight: bold;">单号:{{ detailData&&detailData.expenseAccountNo }}</span>
  9. <span style="margin: 0 10px;color: #666;">申请人:{{ detailData&&detailData.applyPersonName || '--' }}</span>
  10. <a-button size="small" type="link" class="button-default" id="expenseEdit-showdesc" @click="showDetail=!showDetail">
  11. <a-icon :type="showDetail ? 'eye-invisible' : 'eye'"/> {{ showDetail?'隐藏':'查看' }}信息
  12. </a-button>
  13. </template>
  14. </a-page-header>
  15. <a-card :bordered="false" size="small" class="expenseReimbursementAddcont" v-show="showDetail">
  16. <div slot="title">
  17. <span>基础信息</span>
  18. <div style="cursor:pointer;color: #00aaff;float:right;" id="expenseEdit-showEditModal" @click.stop="handleEditBase" >
  19. <a-icon type="edit" /> 编辑基础信息
  20. </div>
  21. </div>
  22. <a-descriptions :column="{ xs: 2, sm: 3, md: 4}" v-if="detailData">
  23. <a-descriptions-item label="费用单号">{{ detailData&&detailData.expenseAccountNo || '--' }}</a-descriptions-item>
  24. <a-descriptions-item label="申请人">{{ detailData&&detailData.applyPersonName || '--' }}</a-descriptions-item>
  25. <a-descriptions-item label="申请部门">{{ detailData&&detailData.applyDepartmentName || '--' }}</a-descriptions-item>
  26. <a-descriptions-item label="费用类型">{{ detailData&&detailData.expenseTypeName || '--' }}<span v-if="detailData&&detailData.expenseType2">/{{ detailData&&detailData.expenseTypeName2 || '--' }}</span><span v-if="detailData&&detailData.expenseType3">/{{ detailData&&detailData.expenseTypeName3 || '--' }}</span></a-descriptions-item>
  27. <a-descriptions-item label="费用归属品牌">
  28. {{ (detailData&&detailData.productBrandName) || '--' }}
  29. </a-descriptions-item>
  30. <a-descriptions-item label="费用归属品类">
  31. <div>
  32. <span v-if="detailData&&detailData.productTypeName1">{{ detailData.productTypeName1 || '--' }}</span>
  33. <span v-else>--</span>
  34. <span v-if="detailData&&detailData.productTypeName2">/{{ detailData.productTypeName2 || '--' }}</span>
  35. <span v-if="detailData&&detailData.productTypeName3">/{{ detailData.productTypeName3 || '--' }}</span>
  36. </div>
  37. </a-descriptions-item>
  38. <a-descriptions-item label="费用发生月份">{{ detailData&&detailData.expenseDate?detailData.expenseDate.substring(0, 7) : '--' }}</a-descriptions-item>
  39. <a-descriptions-item label="合计金额">{{ (detailData.applyExpenseTotal || detailData.applyExpenseTotal == 0) ? toThousands(detailData.applyExpenseTotal)+' 元' : '--' }}</a-descriptions-item>
  40. <a-descriptions-item label="状态">{{ detailData&&detailData.stateDictValue || '--' }}</a-descriptions-item>
  41. <a-descriptions-item label="创建时间">{{ detailData&&detailData.createDate || '--' }}</a-descriptions-item>
  42. <a-descriptions-item label="审核时间">{{ detailData&&detailData.finishDate || '--' }}</a-descriptions-item>
  43. <a-descriptions-item label="关联单号" v-if="detailData&&detailData.bizNo">{{ detailData&&detailData.bizNo || '--' }}</a-descriptions-item>
  44. <a-descriptions-item label="主题" :span="3">{{ detailData&&detailData.title || '--' }}</a-descriptions-item>
  45. <a-descriptions-item label="详细说明" :span="4">{{ detailData&&detailData.content.join(',')||'' }}</a-descriptions-item>
  46. <a-descriptions-item label="摘要" :span="4">
  47. {{ detailData.digestInfo||'' }}
  48. </a-descriptions-item>
  49. <a-descriptions-item label="附件" :span="4">
  50. <a
  51. target="_blank"
  52. style="color: #00aaff;text-decoration: underline;margin-right: 15px;"
  53. :href="item.filePath"
  54. v-for="item in detailData.expenseAccountFilesList"
  55. :id="item.id"
  56. :key="item.id">
  57. {{ item.fileName }}
  58. </a>
  59. </a-descriptions-item>
  60. </a-descriptions>
  61. </a-card>
  62. <!-- 费用明细 -->
  63. <a-card :bordered="false" size="small" class="expenseContent">
  64. <div slot="title">
  65. <div style="display: flex;justify-content: space-between;align-items: center;">
  66. <div>费用明细</div>
  67. <div>
  68. <a-button id="expenseEdit-plEdit" size="small" class="button-info" type="primary" @click="plEdit">变更记账名称</a-button>
  69. <a-button id="expenseEdit-import" size="small" class="button-info" type="primary" @click="openGuideModal=true">导入费用明细</a-button>
  70. <a-button id="expenseEdit-new" size="small" class="button-error" type="primary" @click="newExpenseDetail">新增费用明细</a-button>
  71. </div>
  72. </div>
  73. </div>
  74. <a-alert type="info" style="margin-bottom:10px">
  75. <div slot="message">
  76. 共{{ total }}条费用明细,合计金额{{ detailData&&detailData.applyExpenseTotal?toThousands(detailData.applyExpenseTotal) :'¥0.00' }}元
  77. </div>
  78. </a-alert>
  79. <!-- 列表 -->
  80. <s-table
  81. class="sTable"
  82. ref="table"
  83. size="small"
  84. :rowKey="(record) => record.id"
  85. :columns="columns"
  86. :data="loadData"
  87. :row-selection="{ columnWidth: 40 }"
  88. @rowSelection="rowSelectionFun"
  89. :defaultLoadData="false"
  90. :showPagination="false"
  91. bordered>
  92. <template slot="action" slot-scope="text,record">
  93. <a-button
  94. size="small"
  95. type="link"
  96. class="button-info"
  97. @click="setProduct(record)"
  98. :id="'expenseEdit-set-'+record.id"
  99. >设置产品信息</a-button>
  100. <a-button
  101. size="small"
  102. type="link"
  103. class="button-info"
  104. @click="handleEdit(record)"
  105. :id="'expenseEdit-edit-'+record.id"
  106. >编辑</a-button>
  107. <a-button
  108. size="small"
  109. type="link"
  110. class="button-error"
  111. @click="handleDel(record)"
  112. :id="'expenseEdit-del-'+record.id"
  113. >删除</a-button>
  114. </template>
  115. <!-- 记账名称 -->
  116. <template slot="jzname" slot-scope="text,record">
  117. <div>{{ text }}</div>
  118. <div v-if="record.accountNameFnumber">({{ record.accountNameFnumber }})</div>
  119. </template>
  120. <!-- 原记账名称 -->
  121. <template slot="yjzname" slot-scope="text,record">
  122. <div>{{ text == record.accountName || !text ? '--' : text }}</div>
  123. </template>
  124. <!-- 费用承担方 -->
  125. <template slot="fycdf" slot-scope="text,record">
  126. <div v-for="(item,index) in record.detailSplitList" :key="item.id+'-'+index">
  127. {{ item.splitObjName }}
  128. <span v-if="item.splitObjFnumber">({{ item.splitObjFnumber }})</span>
  129. <span v-if="item.childDetailSplit&&item.childDetailSplit.splitObjName">/</span>
  130. {{ item.childDetailSplit?item.childDetailSplit.splitObjName:'' }}: ¥{{ item.childDetailSplit?item.childDetailSplit.splitAmount:item.splitAmount }}
  131. </div>
  132. </template>
  133. <!-- 产品信息 -->
  134. <template slot="cpxx" slot-scope="text,record">
  135. <div v-if="record.detailProductsList">
  136. <div>
  137. <div v-for="item in record.detailProductsList" :key="item.id">
  138. <div v-if="item.productCode">{{ item.productCode }}</div>
  139. <div v-else-if="item.productBrandName">{{ item.productBrandName }}<span v-if="item.productTypeShowName">/</span>{{ item.productTypeShowName }}</div>
  140. <div v-else>{{ item.productTypeShowName }}</div>
  141. </div>
  142. </div>
  143. </div>
  144. <div v-else>--</div>
  145. </template>
  146. </s-table>
  147. </a-card>
  148. </a-spin>
  149. <div class="affix-cont">
  150. <a-button
  151. type="primary"
  152. class="button-primary"
  153. :disabled="spinning"
  154. id="expenseReimbursementAddsubmit-btn"
  155. size="large"
  156. @click="beforeSubmit"
  157. style="padding: 0 60px;">提交</a-button>
  158. </div>
  159. <!-- 费用明细 -->
  160. <epenseDetailModal
  161. ref="epenseDetailForm"
  162. :openModal="openEpenseDetailModal"
  163. :expenseAccountSn="$route.params.sn"
  164. :expenseAccountNo="detailData?detailData.expenseAccountNo:''"
  165. :expenseAccountDetailSn="expenseAccountDetailSn"
  166. :isBatch="isBatch"
  167. @ok="epenseDetailOk"
  168. @close="epenseDetailClose"></epenseDetailModal>
  169. <!-- 产品信息设置 -->
  170. <productInfoModal
  171. ref="productInfo"
  172. :openModal="openProductInfoModal"
  173. :expenseAccountSn="$route.params.sn"
  174. :expenseAccountNo="detailData?detailData.expenseAccountNo:''"
  175. :expenseAccountDetailSn="expenseAccountDetailSn"
  176. @ok="productInfoOk"
  177. @close="openProductInfoModal=false"></productInfoModal>
  178. <!-- 基础信息编辑 -->
  179. <baseDataModal :show="openBaseModal" @close="openBaseModal=false" :itemSn="$route.params.sn" @refashData="refashData"></baseDataModal>
  180. <!-- 导入费用明细 -->
  181. <ImportGuideModal :openModal="openGuideModal" :params="{expenseAccountSn: $route.params.sn, expenseAccountNo:detailData?detailData.expenseAccountNo:''}" @close="openGuideModal=false" @ok="hanldeImprotOk" />
  182. <!-- 选择审核人员 -->
  183. <chooseDepartUserModal :openModal="openDepartUserModal" @close="openDepartUserModal=false" @submit="handleSubmit"></chooseDepartUserModal>
  184. </div>
  185. </template>
  186. <script>
  187. import { commonMixin } from '@/utils/mixin'
  188. import { VSelect, Upload, STable } from '@/components'
  189. import epenseDetailModal from './epenseDetailModal.vue'
  190. import productInfoModal from './productInfoModal.vue'
  191. import baseDataModal from './baseDataModal.vue'
  192. import ImportGuideModal from './importGuideModal.vue'
  193. import chooseDepartUserModal from './chooseDepartUserModal.vue'
  194. import { expenseAccountDetail, expenseAcctDetailDelete, updateBatchExpenseAcctDetail, expenseAcctDetailFindList, expenseAccountSubmit, expenseInsertImport } from '@/api/expenseManagement.js'
  195. export default {
  196. name: 'ExpenseReimbursementEdit',
  197. mixins: [commonMixin],
  198. components: { VSelect, Upload, STable, epenseDetailModal, productInfoModal, baseDataModal, ImportGuideModal, chooseDepartUserModal },
  199. data () {
  200. const _this = this
  201. return {
  202. spinning: false,
  203. detailData: null, // 详情信息
  204. openBaseModal: false, // 基础信息编辑弹框
  205. openGuideModal: false, // 导入费用明细弹框
  206. openDepartUserModal: false, // 选择审核人员弹框
  207. openEpenseDetailModal: false, // 费用明细弹框
  208. expenseAccountDetailSn: '', // 费用明细sn
  209. openProductInfoModal: false, // 产品信息弹框
  210. showDetail: false, // 是否显示详细信息
  211. total: 0, // 总记录数
  212. loadData: parameter => {
  213. const params = Object.assign(parameter, { expenseAccountSn: this.$route.params.sn })
  214. return expenseAcctDetailFindList(params).then(res => {
  215. let data
  216. if (res.status == 200) {
  217. data = res.data
  218. const no = 0
  219. for (var i = 0; i < data.length; i++) {
  220. data[i].no = no + i + 1
  221. // 产品信息合计
  222. if (data[i].detailProductsList) {
  223. data[i].productTotalAmount = 0
  224. data[i].detailProductsList.map(item => {
  225. data[i].productTotalAmount += item.expense
  226. })
  227. }
  228. }
  229. this.total = data.length
  230. this.disabled = false
  231. this.spinning = false
  232. }
  233. return data
  234. })
  235. },
  236. columns: [
  237. { title: '序号', dataIndex: 'no', width: '4%', align: 'center' },
  238. { title: '记账类型', dataIndex: 'accountTypeDictValue', align: 'center', width: '8%', customRender: function (text) { return text || '--' } },
  239. { title: '记账名称', dataIndex: 'accountName', scopedSlots: { customRender: 'jzname' }, align: 'center', width: '10%' },
  240. { title: '原记账名称', dataIndex: 'origAccountName', scopedSlots: { customRender: 'yjzname' }, align: 'center', width: '10%' },
  241. { title: '所属区域', dataIndex: 'subareaNames', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
  242. { title: '所属分区', dataIndex: 'subareaAreaName', width: '5%', align: 'center', customRender: function (text) { return text || '--' } },
  243. { title: '所属省份', dataIndex: 'provinceName', align: 'center', width: '5%', customRender: function (text) { return text || '--' } },
  244. { title: '所属城市', dataIndex: 'cityName', align: 'center', width: '5%', customRender: function (text) { return text || '--' } },
  245. { title: '记账费用', dataIndex: 'expense', align: 'center', width: '8%', customRender: function (text) { return (text == 0 || text) ? _this.toThousands(text) : '--' } },
  246. { title: '费用承担方', scopedSlots: { customRender: 'fycdf' }, align: 'center', width: '15%' },
  247. { title: '产品信息', scopedSlots: { customRender: 'cpxx' }, align: 'center', width: '10%' },
  248. { title: '销售单号', dataIndex: 'salesBillNo', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
  249. { title: '备注', dataIndex: 'remarks', align: 'center', width: '10%', customRender: function (text) { return text || '--' } },
  250. { title: '操作', scopedSlots: { customRender: 'action' }, width: '100px', align: 'center' }
  251. ],
  252. isBatch: false, // 是否变更记账名称
  253. rowSelectionInfo: null // 批量选择的数据
  254. }
  255. },
  256. methods: {
  257. // 编辑基础信息
  258. handleEditBase (event) {
  259. this.openBaseModal = true
  260. },
  261. // 刷新列表
  262. refashData () {
  263. this.getDetail(true)
  264. },
  265. // 获取费用单基础详情
  266. getDetail (type) {
  267. this.spinning = true
  268. this.disabled = true
  269. expenseAccountDetail({ expenseAccountSn: this.$route.params.sn }).then(res => {
  270. if (res.status == 200) {
  271. this.detailData = res.data
  272. this.detailData.content = res.data.content.replace(/\n+/, '\n').split('\n')
  273. if (!type) {
  274. // 获取费用明细列表
  275. this.getExpenseDetailList()
  276. } else {
  277. this.spinning = false
  278. this.disabled = false
  279. }
  280. }
  281. })
  282. },
  283. // 查询列表
  284. getExpenseDetailList () {
  285. this.$refs.table.refresh()
  286. },
  287. // 确认导入明细
  288. hanldeImprotOk (obj) {
  289. expenseInsertImport(obj).then(res => {
  290. if (res.status == 200) {
  291. this.getDetail(false)
  292. }
  293. })
  294. },
  295. // 批量修改明细
  296. plEdit () {
  297. if (!this.rowSelectionInfo || (this.rowSelectionInfo && this.rowSelectionInfo.selectedRowKeys.length < 1)) {
  298. this.$message.warning('请在列表勾选后再进行操作!')
  299. return
  300. }
  301. this.expenseAccountDetailSn = ''
  302. this.openEpenseDetailModal = true
  303. this.isBatch = true
  304. },
  305. // 表格选中项
  306. rowSelectionFun (obj) {
  307. this.rowSelectionInfo = obj || null
  308. },
  309. // 新增明细
  310. newExpenseDetail () {
  311. this.expenseAccountDetailSn = ''
  312. this.openEpenseDetailModal = true
  313. },
  314. // 编辑明细
  315. handleEdit (row) {
  316. this.openEpenseDetailModal = true
  317. this.expenseAccountDetailSn = row.expenseAccountDetailSn
  318. },
  319. // 新增修改明细成功
  320. epenseDetailOk (data) {
  321. // 如果是批量修改
  322. if (this.isBatch) {
  323. const rows = this.rowSelectionInfo && this.rowSelectionInfo.selectedRows || []
  324. const params = []
  325. if (rows.length) {
  326. rows.forEach(item => {
  327. params.push({
  328. expenseAccountDetailSn: item.expenseAccountDetailSn,
  329. origAccountName: item.origAccountName,
  330. origAccountNameSn: item.origAccountNameSn,
  331. accountNameSn: data.accountNameSn,
  332. accountType: data.accountType,
  333. provinceName: data.provinceName,
  334. provinceSn: data.provinceSn,
  335. subareaArea: data.subareaArea,
  336. cityName: data.cityName,
  337. citySn: data.citySn,
  338. expenseAccountNo: data.expenseAccountNo,
  339. expenseAccountSn: data.expenseAccountSn,
  340. remarks: data.remarks
  341. })
  342. })
  343. // 组织数据
  344. updateBatchExpenseAcctDetail(params).then(res => {
  345. if (res.status == 200) {
  346. this.$message.success(res.message)
  347. // 修改成功
  348. this.$refs.table.clearTable()
  349. this.epenseDetailClose()
  350. this.getDetail(false)// 刷新列表
  351. }
  352. this.$refs.epenseDetailForm.spinning = false
  353. })
  354. } else {
  355. this.$message.warning('请在列表勾选后再进行操作!')
  356. this.$refs.epenseDetailForm.spinning = false
  357. }
  358. } else {
  359. // 单个修改成功
  360. this.epenseDetailClose()
  361. this.getDetail(false)// 刷新列表
  362. }
  363. },
  364. // 明细弹框关闭
  365. epenseDetailClose () {
  366. this.openEpenseDetailModal = false
  367. this.isBatch = false
  368. },
  369. // 删除明细
  370. handleDel (row) {
  371. const _this = this
  372. this.$confirm({
  373. title: '提示',
  374. content: '确认要删除吗?',
  375. centered: true,
  376. closable: true,
  377. onOk () {
  378. _this.spinning = true
  379. expenseAcctDetailDelete({ detailSn: row.expenseAccountDetailSn }).then(res => {
  380. if (res.status == 200) {
  381. _this.$message.success(res.message)
  382. _this.getDetail(false)
  383. _this.spinning = false
  384. } else {
  385. _this.spinning = false
  386. }
  387. })
  388. }
  389. })
  390. },
  391. // 设置产品
  392. setProduct (row) {
  393. this.openProductInfoModal = true
  394. this.expenseAccountDetailSn = row.expenseAccountDetailSn
  395. this.$refs.productInfo.setBaseData(row)
  396. },
  397. // 新增产品成功
  398. productInfoOk () {
  399. // 刷新列表
  400. this.openProductInfoModal = false
  401. this.getDetail(false)
  402. },
  403. // 提交前,选择审批人员
  404. beforeSubmit () {
  405. if (this.total) {
  406. this.openDepartUserModal = true
  407. } else {
  408. this.$message.info('请新增费用明细')
  409. }
  410. },
  411. // 提交信息
  412. handleSubmit (data) {
  413. this.spinning = true
  414. expenseAccountSubmit({ expenseAccountSn: this.$route.params.sn, ...data }).then(res => {
  415. if (res.status == '200') {
  416. this.$message.success(res.message)
  417. this.handleBack()
  418. }
  419. this.spinning = false
  420. })
  421. },
  422. // 返回
  423. handleBack (data) {
  424. this.$router.push({ name: 'expenseReimbursementList' })
  425. },
  426. // 初始化页面
  427. pageInit () {
  428. this.$refs.table.clearTable()
  429. if (this.$route.params.sn) { // 编辑页
  430. this.getDetail(false)
  431. }
  432. }
  433. },
  434. mounted () {
  435. if (!this.$store.state.app.isNewTab) { // 页签刷新时调用
  436. this.pageInit()
  437. }
  438. },
  439. activated () {
  440. this.pageInit()
  441. },
  442. beforeRouteEnter (to, from, next) {
  443. next(vm => {})
  444. }
  445. }
  446. </script>
  447. <style lang="less">
  448. .expenseReimbursementAddwrap{
  449. position: relative;
  450. height: 100%;
  451. padding-bottom: 51px;
  452. box-sizing: border-box;
  453. >.ant-spin-nested-loading{
  454. overflow-y: scroll;
  455. height: 100%;
  456. }
  457. .expenseReimbursementAddcont{
  458. margin-bottom: 6px;
  459. }
  460. .expenseContent{
  461. min-height: calc(100vh - 190px);
  462. }
  463. .upload{
  464. width: 100%!important;
  465. }
  466. .affix{
  467. .ant-affix{
  468. z-index: 101;
  469. }
  470. }
  471. }
  472. </style>