details.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. <template>
  2. <div class="edit">
  3. <van-nav-bar title="报销凭证详情" left-text="返回" @click-left="back" fixed left-arrow />
  4. <van-form class="edit_form" label-width="140">
  5. <!-- 报销人 -->
  6. <van-field
  7. v-model="editForm.ownerId"
  8. label="报销人"
  9. @click="ownerIdShow = true"
  10. readonly
  11. clickable
  12. required
  13. >
  14. <template #input>
  15. <span v-if="user.userNameNeedTranslate == 1"><ww-open-data type='userName' :openid='formshowText.name'></ww-open-data></span>
  16. <span v-else>{{formshowText.name}}</span>
  17. </template>
  18. </van-field>
  19. <van-popup v-model="ownerIdShow" position="bottom" v-if="false">
  20. <van-picker
  21. value-key="name"
  22. show-toolbar
  23. :columns="userList"
  24. @confirm="ownerIdChange"
  25. @cancel="
  26. ownerIdShow = false;
  27. $forceUpdate();
  28. "
  29. />
  30. </van-popup>
  31. <!-- 填报日期 -->
  32. <van-field
  33. v-model="editForm.createDate"
  34. label="填报日期"
  35. @click="createDateShow = true"
  36. readonly
  37. clickable
  38. required
  39. ></van-field>
  40. <van-popup v-model="createDateShow" position="bottom" v-if="canEdit">
  41. <van-datetime-picker
  42. type="date"
  43. title="选择填报日期"
  44. @confirm="createDateChange"
  45. @cancel="
  46. createDateShow = false;
  47. $forceUpdate();
  48. "
  49. :min-date="minDate"
  50. :max-date="maxDate"
  51. />
  52. </van-popup>
  53. <!-- 发票张数 -->
  54. <van-field label="发票张数" :readonly="!canEdit">
  55. <template #input>
  56. <van-stepper v-model="editForm.ticketNum" :disabled="!canEdit" />
  57. </template>
  58. </van-field>
  59. <!-- 费用类型 -->
  60. <van-field
  61. v-model="editForm.type"
  62. label="费用类型"
  63. @click="typeShow = true"
  64. readonly
  65. clickable
  66. >
  67. <template #input>{{ typeList[editForm.type] }}</template>
  68. </van-field>
  69. <van-popup v-model="typeShow" position="bottom" v-if="canEdit">
  70. <van-picker
  71. show-toolbar
  72. :columns="typeList"
  73. @confirm="typeChange"
  74. @cancel="
  75. typeShow = false;
  76. $forceUpdate();
  77. "
  78. />
  79. </van-popup>
  80. <!-- 备注 -->
  81. <van-field v-model="editForm.remark" label="备注" :readonly="!canEdit" type="textarea"></van-field>
  82. <!-- 发票 -->
  83. <van-field label="发票" readonly>
  84. <template #input
  85. >总费用:{{ totalCost | numtosum }} 元</template
  86. >
  87. </van-field>
  88. <div class="invoice" v-if="invoiceList.length != 0">
  89. <div
  90. v-for="(item, index) in invoiceList"
  91. :key="item.id"
  92. style="position: relative"
  93. :class="index == 0 ? '' : 'invoice_item'"
  94. >
  95. <van-icon
  96. name="delete-o"
  97. class="deletebtn"
  98. @click="deleteInvoice(index)"
  99. v-if="canEdit"
  100. />
  101. <van-field
  102. label="所属项目:"
  103. v-model="item.projectId"
  104. @click="(in_projectShow = true), (invoiceIndex = index)"
  105. readonly
  106. clickable
  107. >
  108. <template #input>{{
  109. formshowText.inProjectName[index]
  110. }}</template>
  111. </van-field>
  112. <van-field
  113. label="费用日期:"
  114. v-model="item.happenDate"
  115. @click="(in_dateShow = true), (invoiceIndex = index)"
  116. readonly
  117. clickable
  118. ></van-field>
  119. <van-field
  120. label="发票种类:"
  121. v-model="item.invoiceType"
  122. @click="(in_typeShow = true), (invoiceIndex = index)"
  123. readonly
  124. clickable
  125. >
  126. <template #input>{{
  127. inTypeList[item.invoiceType]
  128. }}</template>
  129. </van-field>
  130. <van-field
  131. label="费用类型:"
  132. v-model="item.expenseType"
  133. @click="(in_exTypeShow = true), (invoiceIndex = index)"
  134. readonly
  135. clickable
  136. ></van-field>
  137. <van-field
  138. label="费用金额(含税):"
  139. v-model="item.amount"
  140. type="number"
  141. @input="costCount"
  142. :readonly="!canEdit"
  143. ></van-field>
  144. <van-field
  145. label="发票号:"
  146. v-model="item.invoiceNo"
  147. readonly
  148. ></van-field>
  149. <van-field
  150. label="税率%:"
  151. v-model="item.taxPercent"
  152. :readonly="!canEdit"
  153. ></van-field>
  154. <van-field
  155. label="税额:"
  156. readonly
  157. ><template #input>¥{{getTaxValue(item.amount,item.taxPercent)}}</template></van-field>
  158. <van-field label="备注:" v-model="item.remark" :readonly="!canEdit"></van-field>
  159. <van-field
  160. label="报销凭证:"
  161. @click="invoiceIndex = index"
  162. :clickable="!canEdit"
  163. >
  164. <template #input>
  165. <van-uploader
  166. v-model="uploader[index]"
  167. :before-read="beforeRead"
  168. :after-read="afterRead"
  169. @delete="item.pic = null"
  170. :max-count="1"
  171. :disabled="!canEdit"
  172. :deletable="canEdit"
  173. />
  174. </template>
  175. </van-field>
  176. </div>
  177. </div>
  178. <!-- 发票-popup -->
  179. <span>
  180. <!-- 所属项目 -->
  181. <van-popup v-model="in_projectShow" position="bottom" v-if="canEdit">
  182. <van-picker
  183. value-key="projectName"
  184. show-toolbar
  185. :columns="inProjectList"
  186. @confirm="inProjectChange"
  187. @cancel="
  188. in_projectShow = false;
  189. $forceUpdate();
  190. "
  191. />
  192. </van-popup>
  193. <!-- 费用日期 -->
  194. <van-popup v-model="in_dateShow" position="bottom" v-if="canEdit">
  195. <van-datetime-picker
  196. type="date"
  197. title="选择费用日期"
  198. @confirm="inDateChange"
  199. @cancel="
  200. in_dateShow = false;
  201. $forceUpdate();
  202. "
  203. :min-date="minDate"
  204. :max-date="maxDate"
  205. />
  206. </van-popup>
  207. <!-- 发票种类 -->
  208. <van-popup v-model="in_typeShow" position="bottom" v-if="canEdit">
  209. <van-picker
  210. show-toolbar
  211. :columns="inTypeList"
  212. @confirm="inTypeChange"
  213. @cancel="
  214. in_typeShow = false;
  215. $forceUpdate();
  216. "
  217. />
  218. </van-popup>
  219. <!-- 费用类型 -->
  220. <van-popup v-model="in_exTypeShow" position="bottom" v-if="canEdit">
  221. <van-picker
  222. value-key="typeName"
  223. show-toolbar
  224. :columns="inexTypeList"
  225. @confirm="inexTypeChange"
  226. @cancel="
  227. in_exTypeShow = false;
  228. $forceUpdate();
  229. "
  230. />
  231. </van-popup>
  232. </span>
  233. </van-form>
  234. <!-- 提交 -->
  235. <div class="form_btn" style="position: fixed; bottom: 0px; width: 100%" v-if="canEdit">
  236. <div style="padding-bottom: 10px">
  237. <van-button
  238. square
  239. block
  240. type="info"
  241. @click="submitExpense"
  242. style="width: 100%; float: left"
  243. >提交</van-button
  244. >
  245. </div>
  246. </div>
  247. </div>
  248. </template>
  249. <script>
  250. export default {
  251. data() {
  252. return {
  253. user: JSON.parse(localStorage.userInfo),
  254. canEdit: this.$route.params.canEdit,
  255. canExamine: false,
  256. minDate: new Date(2020,0,1),
  257. maxDate: new Date(2025,11,31),
  258. editForm: {
  259. ownerId: '',
  260. createDate: '',
  261. ticketNum: 0,
  262. type: 0,
  263. remark: ''
  264. },
  265. invoiceList: [],
  266. formshowText: {
  267. name: '',
  268. inProjectName: []
  269. },
  270. ownerIdShow: false,
  271. userList: [],
  272. createDateShow: false,
  273. typeShow: false,
  274. typeList: ['一般','差旅','外包'],
  275. totalCost: 0,
  276. invoiceIndex: 0,
  277. in_projectShow: false,
  278. inProjectList: [],
  279. in_dateShow: false,
  280. in_typeShow: false,
  281. inTypeList: ['增值税专用发票','增值税普通发票'],
  282. in_exTypeShow: false,
  283. allexTypeList: [],
  284. inexTypeList: [],
  285. uploader: [[]],
  286. }
  287. },
  288. filters: {
  289. numtosum(value) {
  290. if (value == undefined || !value) return '0.00'
  291. value = value.toFixed(2)
  292. const intPart = Math.trunc(value)
  293. const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
  294. let floatPart = '.00'
  295. const valueArray = value.toString().split('.')
  296. if (valueArray.length === 2) { // 有小数部分
  297. floatPart = valueArray[1].toString() // 取得小数部分
  298. return intPartFormat + '.' + floatPart
  299. }
  300. return intPartFormat + floatPart
  301. },
  302. },
  303. mounted() {
  304. console.log(this.$route.params);
  305. for(let i in this.user.functionList){
  306. if(this.user.functionList[i].name == '费用审核'){
  307. this.canExamine = true
  308. }
  309. }
  310. this.getDetail()
  311. if(this.canEdit){
  312. // if(this.canExamine){
  313. // this.getUserList()
  314. // }
  315. this.getProjectList()
  316. }
  317. },
  318. methods: {
  319. back(){
  320. history.back();
  321. },
  322. formatDate(date) {
  323. let mon = date.getMonth() + 1
  324. return `${date.getFullYear()}-${mon<10?'0'+mon:mon}-${date.getDate()<10?'0'+date.getDate():date.getDate()}`;
  325. },
  326. getTaxValue(amount,percent){
  327. let per = percent / 100
  328. let amo = amount / (1 + per)*per
  329. return amo.toFixed(2)
  330. },
  331. costCount(){
  332. let costnum = 0
  333. for(let i in this.invoiceList){
  334. costnum += this.invoiceList[i].amount*1
  335. }
  336. this.totalCost = costnum
  337. },
  338. ownerIdChange(value,key){
  339. this.editForm.ownerId = value.id
  340. this.formshowText.name = value.name
  341. this.ownerIdShow = false
  342. },
  343. createDateChange(value,key){
  344. this.editForm.createDate = this.formatDate(value)
  345. this.createDateShow = false
  346. },
  347. typeChange(value,key){
  348. this.editForm.type = key
  349. this.typeShow = false
  350. this.inexTypeList = this.allexTypeList.filter(a=>a.mainType == this.editForm.type)
  351. },
  352. deleteInvoice(index){
  353. this.invoiceList.splice(index,1)
  354. this.uploader.splice(index,1)
  355. },
  356. inProjectChange(value,key){
  357. this.formshowText.inProjectName[this.invoiceIndex] = value.projectName
  358. this.invoiceList[this.invoiceIndex].projectId = value.id
  359. this.in_projectShow = false
  360. },
  361. inDateChange(value,key){
  362. this.invoiceList[this.invoiceIndex].happenDate = this.formatDate(value)
  363. this.in_dateShow = false
  364. },
  365. inTypeChange(value,key){
  366. this.invoiceList[this.invoiceIndex].invoiceType = key
  367. this.in_typeShow = false
  368. },
  369. inexTypeChange(value,key){
  370. this.invoiceList[this.invoiceIndex].expenseType = value.typeName
  371. this.in_exTypeShow = false
  372. },
  373. beforeRead(file){
  374. if(file.type != 'image/jpeg' && file.type != 'image/png'){
  375. this.$toast.fail('请选择jpg或png格式的图片')
  376. return false
  377. }
  378. return true
  379. },
  380. afterRead(file){
  381. let formData = new FormData();
  382. formData.append("multipartFile", file.file);
  383. this.$axios.post("/common/uploadFile", formData)
  384. .then(res => {
  385. if(res.code == "ok") {
  386. this.invoiceList[this.invoiceIndex].pic = res.data
  387. } else {
  388. this.$toast.fail('上传失败');
  389. this.uploader[this.invoiceIndex] = []
  390. }
  391. }).catch(err=> {this.$toast.clear();console.log(err);this.uploader[this.invoiceIndex]=[]});
  392. },
  393. submitExpense(){
  394. if(!this.editForm.ownerId){
  395. this.$toast.fail('请选择报销人')
  396. return
  397. }
  398. if(!this.editForm.createDate){
  399. this.$toast.fail('请选择填报日期')
  400. return
  401. }
  402. if(this.invoiceList.length == 0){
  403. this.$toast.fail('请添加发票')
  404. return
  405. }
  406. delete this.editForm.invoiceList
  407. this.editForm.items = JSON.stringify(this.invoiceList)
  408. this.editForm.totalAmount = this.totalCost
  409. this.$axios.post("/expense-sheet/add", this.editForm)
  410. .then(res => {
  411. if(res.code == "ok") {
  412. this.$toast.success('提交成功')
  413. this.back()
  414. } else {
  415. this.$toast.fail('获取失败');
  416. }
  417. }).catch(err=> {this.$toast.clear();console.log(err)});
  418. },
  419. getDetail(){
  420. this.$axios.post("/expense-sheet/getDetail", {id: this.$route.params.id})
  421. .then(res => {
  422. if(res.code == "ok") {
  423. this.editForm = res.data
  424. if(this.canEdit){this.getExTypeList()}
  425. this.formshowText.name = res.data.ownerName
  426. this.totalCost = res.data.totalAmount
  427. this.invoiceList = res.data.invoiceList
  428. for(let i in res.data.invoiceList){
  429. this.formshowText.inProjectName.push(res.data.invoiceList[i].projectName)
  430. if(res.data.invoiceList[i].pic){
  431. this.uploader[i] = [{url:'/upload/' + res.data.invoiceList[i].pic}]
  432. }else{
  433. this.uploader[i] = []
  434. }
  435. }
  436. } else {
  437. this.$toast.fail('获取失败');
  438. }
  439. }).catch(err=> {this.$toast.clear();console.log(err)});
  440. },
  441. getUserList(){
  442. this.$axios.post("/user/getSimpleActiveUserList", {})
  443. .then(res => {
  444. if(res.code == "ok") {
  445. this.userList = res.data
  446. } else {
  447. this.$toast.fail('获取失败');
  448. }
  449. }).catch(err=> {this.$toast.clear();console.log(err)});
  450. },
  451. getProjectList(){
  452. this.$axios.post("/project/getProjectList", {})
  453. .then(res => {
  454. if(res.code == "ok") {
  455. this.inProjectList = res.data
  456. } else {
  457. this.$toast.fail('获取失败');
  458. }
  459. }).catch(err=> {this.$toast.clear();console.log(err)});
  460. },
  461. getExTypeList(){
  462. this.$axios.post("/expense-type/getList", {})
  463. .then(res => {
  464. if(res.code == "ok") {
  465. this.allexTypeList = res.data
  466. this.inexTypeList = this.allexTypeList.filter(a=>a.mainType == this.editForm.type)
  467. } else {
  468. this.$toast.fail('获取失败');
  469. }
  470. }).catch(err=> {this.$toast.clear();console.log(err)});
  471. },
  472. },
  473. };
  474. </script>
  475. <style lang="less" scoped>
  476. .edit{
  477. margin-top: 46px;
  478. overflow: auto;
  479. .form_btn{
  480. z-index: 1000;
  481. }
  482. .edit_form{
  483. .userCheckbox {
  484. padding: 10px;
  485. }
  486. padding-bottom: 46px;
  487. .invoice{
  488. border: 0.5px solid rgb(135, 195, 255);
  489. margin: 0.2rem;
  490. .deletebtn{
  491. position: absolute;
  492. z-index: 1000;
  493. font-size: 24px;
  494. right: 0.08rem;
  495. top: 0.08rem;
  496. color: #c03131;
  497. }
  498. .invoice_item{
  499. border-top: 0.5px solid rgb(135, 195, 255);
  500. }
  501. }
  502. }
  503. }
  504. </style>
  505. <style>
  506. .edit_form .invoice .van-field__label{
  507. color: #999;
  508. }
  509. .edit_form .invoice .van-field__control{
  510. color: #999;
  511. }
  512. </style>