index.vue 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. <template>
  2. <div>
  3. <van-nav-bar title="费用报销" left-text="返回" @click-left="back" fixed left-arrow style="z-index:1000" />
  4. <div class="content">
  5. <van-tabs v-model="active" @change="activeChange">
  6. <van-tab title="费用报销" :name="0"></van-tab>
  7. <van-tab title="单据列表" :name="1"></van-tab>
  8. <van-tab title="单据审核" :name="2" v-if="canExamine"></van-tab>
  9. </van-tabs>
  10. <!-- #region 费用报销 -->
  11. <div class="edit" v-if="active == 0">
  12. <van-form class="edit_form" label-width="140">
  13. <!-- 报销人 -->
  14. <van-field label="报销人" @click="ownerIdShow = true" readonly clickable required>
  15. <template #input>
  16. <span v-if="user.userNameNeedTranslate == 1 && formshowText.name"><ww-open-data type='userName'
  17. :openid='formshowText.name'></ww-open-data></span>
  18. <span v-else>{{ formshowText.name }}</span>
  19. </template>
  20. </van-field>
  21. <van-popup v-model="ownerIdShow" position="bottom" v-if="canExamine">
  22. <div style="minHeight:300px;">
  23. <van-radio-group v-model="userRadio" v-if="user.userNameNeedTranslate == '1'">
  24. <van-radio v-for="item in userList" :key="item.id" :name="item" class="userCheckbox">
  25. <ww-open-data type='userName' :openid='item.name'></ww-open-data>
  26. </van-radio>
  27. </van-radio-group>
  28. <van-radio-group v-model="userRadio" v-else>
  29. <van-radio v-for="item in userList" :key="item.id" :name="item" class="userCheckbox">{{
  30. item.name }}</van-radio>
  31. </van-radio-group>
  32. <van-button style="width:100%;position: -webkit-sticky;position: sticky;bottom: 0;"
  33. @click="ownerIdChange()">确定</van-button>
  34. </div>
  35. </van-popup>
  36. <!-- 填报日期 -->
  37. <van-field v-model="editForm.createDate" label="填报日期" @click="createDateShow = true" readonly clickable
  38. required></van-field>
  39. <van-popup v-model="createDateShow" position="bottom">
  40. <van-datetime-picker type="date" title="选择填报日期" @confirm="createDateChange" v-model="currentDate1"
  41. @cancel="createDateShow = false; $forceUpdate();" :min-date="minDate" :max-date="maxDate" />
  42. </van-popup>
  43. <!-- 发票张数 -->
  44. <van-field label="发票张数" v-if="user.timeType.easyExpense==0">
  45. <template #input>
  46. <van-stepper v-model="editForm.ticketNum" disable-input @plus="ticNumChange(1)"
  47. @minus="ticNumChange(0)" />
  48. </template>
  49. </van-field>
  50. <!-- 费用类型 -->
  51. <van-field v-model="editForm.type" label="费用主类型" @click="typeShow = true" readonly clickable>
  52. <template #input>{{ expenseMainType.text }}</template>
  53. </van-field>
  54. <van-popup v-model="typeShow" position="bottom">
  55. <van-picker show-toolbar :columns="typeList" @confirm="typeChange"
  56. @cancel="typeShow = false; $forceUpdate();" />
  57. </van-popup>
  58. <!-- 备注 -->
  59. <van-field v-model="editForm.remark" label="备注" type="textarea"></van-field>
  60. <!-- 发票 -->
  61. <van-field label="发票" readonly>
  62. <template #input>总费用: ¥{{ totalCost }}</template>
  63. </van-field>
  64. <div class="invoice" v-if="invoiceList.length != 0">
  65. <div v-for="item, index in invoiceList" :key="item.id" style="position:relative"
  66. :class="index == 0 ? '' : 'invoice_item'">
  67. <!-- <van-button class="deletebtn" size="mini" type="default" @click="deleteInvoice(index)">删除</van-button> -->
  68. <van-icon name="delete-o" class="deletebtn" v-if="index != 0" @click="deleteInvoice(index)" />
  69. <van-field label="所属项目:" v-model="item.projectId"
  70. @click="in_projectShow = true, invoiceIndex = index" readonly clickable required>
  71. <template #input>{{ formshowText.inProjectName[index] }}</template>
  72. </van-field>
  73. <van-field label="费用日期:" v-model="item.happenDate"
  74. @click="in_dateShow = true, invoiceIndex = index" readonly clickable required></van-field>
  75. <van-field label="发票种类:" v-model="item.invoiceType" v-if="user.timeType.easyExpense==0"
  76. @click="in_typeShow = true, invoiceIndex = index" readonly clickable required>
  77. <template #input>{{ inTypeList[item.invoiceType] }}</template>
  78. </van-field>
  79. <van-field label="费用类型:" v-model="item.expenseType"
  80. @click="in_exTypeShow = true, invoiceIndex = index" readonly clickable required></van-field>
  81. <van-field :label="`${user.timeType.easyExpense==0?'费用金额(含税)':'费用金额'}:`" v-model="item.amount" type="number" required></van-field>
  82. <van-field label="发票号:" v-model="item.invoiceNo" v-if="user.timeType.easyExpense==0"></van-field>
  83. <van-field label="税率%:" v-model="item.taxPercent" v-if="user.timeType.easyExpense==0"></van-field>
  84. <van-field label="税额:" readonly v-if="user.timeType.easyExpense==0">
  85. <template #input>¥{{ getTaxValue(item.amount, item.taxPercent) }}</template>
  86. </van-field>
  87. <van-field label="备注:" v-model="item.remark" autosize></van-field>
  88. <van-field label="报销凭证:" @click="invoiceIndex = index" clickable>
  89. <template #input>
  90. <van-uploader v-model="uploader[index]" :before-read="beforeRead"
  91. :after-read="afterRead" @delete="item.pic = null" :max-count="1" />
  92. </template>
  93. </van-field>
  94. </div>
  95. </div>
  96. <div class="addinvoice"><van-button size="small" icon="plus" type="info" plain hairline
  97. @click="addInvoice">添加发票</van-button></div>
  98. <!-- 发票-popup -->
  99. <span>
  100. <!-- 所属项目 -->
  101. <van-popup v-model="in_projectShow" position="bottom">
  102. <van-picker value-key="projectName" show-toolbar :columns="inProjectList"
  103. @confirm="inProjectChange" @cancel="in_projectShow = false; $forceUpdate();" />
  104. </van-popup>
  105. <!-- 费用日期 -->
  106. <van-popup v-model="in_dateShow" position="bottom">
  107. <van-datetime-picker type="date" title="选择费用日期" @confirm="inDateChange" v-model="currentDate2"
  108. @cancel="in_dateShow = false; $forceUpdate();" :min-date="minDate" :max-date="maxDate" />
  109. </van-popup>
  110. <!-- 发票种类 -->
  111. <van-popup v-model="in_typeShow" position="bottom">
  112. <van-picker show-toolbar :columns="inTypeList" @confirm="inTypeChange"
  113. @cancel="in_typeShow = false; $forceUpdate();" />
  114. </van-popup>
  115. <!-- 费用类型 -->
  116. <van-popup v-model="in_exTypeShow" position="bottom">
  117. <van-picker value-key="typeName" show-toolbar :columns="inexTypeList" @confirm="inexTypeChange"
  118. @cancel="in_exTypeShow = false; $forceUpdate();" />
  119. </van-popup>
  120. </span>
  121. </van-form>
  122. <!-- 提交 -->
  123. <div class="form_btn" style="position:fixed; bottom:0px;width:100%;">
  124. <div style="padding-bottom:10px;">
  125. <van-button square block type="info" @click="submitExpense" :loading="confirmLoading"
  126. style="width:100%;float:left;">提交</van-button>
  127. </div>
  128. </div>
  129. </div>
  130. <!-- #endregion -->
  131. <!-- 单据列表 -->
  132. <div class="list" v-if="active == 1">
  133. <!-- <van-pull-refresh v-model="downLoading" @refresh="onDownRefresh">
  134. <van-list v-model="uploading" :finished="upFinished" :immediate-check="false" :offset="100" finished-text="没有更多了" @load="onLoadList"></van-list>
  135. </van-pull-refresh> -->
  136. <van-collapse v-model="activeName" accordion class="list_collapse">
  137. <van-collapse-item v-for="item in billList" :key="item.id" title="标题1" :name="item.id">
  138. <template #title>
  139. <div class="collapse_label_l">票据编号:{{ item.code }}</div>
  140. <div class="collapse_label_r">报销人:
  141. <span v-if="user.userNameNeedTranslate == 1"><ww-open-data type='userName'
  142. :openid='item.ownerName'></ww-open-data></span>
  143. <span v-else>{{ item.ownerName }}</span>
  144. </div>
  145. <div class="collapse_label_l">金额: ¥{{ item.totalAmount | numtosum }}</div>
  146. <div class="collapse_label_r">状态:<span :class="statusClass[item.status]">{{
  147. statusList[item.status] }}</span></div>
  148. </template>
  149. <div class="wrapper">
  150. <div><span>票据编号:</span><span>{{ item.code }}</span></div>
  151. <div><span>金额:</span><span>¥{{ item.totalAmount | numtosum }}</span></div>
  152. <div><span>报销人:</span>
  153. <span v-if="user.userNameNeedTranslate == 1"><ww-open-data type='userName'
  154. :openid='item.ownerName'></ww-open-data></span>
  155. <span v-else>{{ item.ownerName }}</span>
  156. </div>
  157. <div><span>填报日期:</span><span>{{ item.createDate }}</span></div>
  158. <div v-if="user.timeType.easyExpense==0"><span>发票张数:</span><span>{{ item.ticketNum }}</span></div>
  159. <div><span>费用类型:</span><span>{{ item.expenseMainTypeName }}</span></div>
  160. <!-- <div><span>状态:</span><span>{{item.status}}</span></div> -->
  161. <!-- <div><span>驳回原因:</span><span>{{item.denyReason}}</span></div> -->
  162. <div><span>备注:</span><span>{{ item.remark }}</span></div>
  163. </div>
  164. <div class="operation">
  165. <van-button size="small" type="info"
  166. :to="{ name: 'expenseDetails', params: { id: item.id, canEdit: false } }">查看</van-button>
  167. <van-button style="margin-left:10px" size="small" type="info"
  168. :to="{ name: 'expenseDetails', params: { id: item.id, canEdit: true } }">编辑</van-button>
  169. <van-button style="margin-left:10px" size="small" type="danger"
  170. @click="deleteBill(item.id)">删除</van-button>
  171. </div>
  172. </van-collapse-item>
  173. </van-collapse>
  174. </div>
  175. <!-- 单据审核 -->
  176. <div class="audit" v-if="active == 2">
  177. <van-collapse v-model="auditName" accordion class="list_collapse">
  178. <van-collapse-item v-for="item in examineList" :key="item.id" title="标题2" :name="item.id">
  179. <template #title>
  180. <div class="collapse_label_l">票据编号:{{ item.code }}</div>
  181. <div class="collapse_label_r">报销人:
  182. <span v-if="user.userNameNeedTranslate == 1"><ww-open-data type='userName'
  183. :openid='item.ownerName'></ww-open-data></span>
  184. <span v-else>{{ item.ownerName }}</span>
  185. </div>
  186. <div class="collapse_label_l">金额: ¥{{ item.totalAmount | numtosum }}</div>
  187. <div class="collapse_label_r">状态:<span :class="statusClass[item.status]">{{
  188. statusList[item.status] }}</span></div>
  189. <div class="operation">
  190. <van-button size="small" type="info" :loading="item.approveLoading"
  191. @click.stop="approve(item)">通过</van-button>
  192. <van-button style="margin-left:15px" size="small" type="danger"
  193. @click.stop="denyToReason(item.id)">驳回</van-button>
  194. </div>
  195. </template>
  196. <div class="wrapper">
  197. <div><span>票据编号:</span><span>{{ item.code }}</span></div>
  198. <div><span>金额:</span><span>¥{{ item.totalAmount | numtosum }}</span></div>
  199. <div><span>报销人:</span>
  200. <span v-if="user.userNameNeedTranslate == 1"><ww-open-data type='userName'
  201. :openid='item.ownerName'></ww-open-data></span>
  202. <span v-else>{{ item.ownerName }}</span>
  203. </div>
  204. <div><span>填报日期:</span><span>{{ item.createDate }}</span></div>
  205. <div v-if="user.timeType.easyExpense==0"><span>发票张数:</span><span>{{ item.ticketNum }}</span></div>
  206. <div><span>费用类型:</span><span>{{ item.expenseMainTypeName }}</span></div>
  207. <!-- <div><span>状态:</span><span>{{item.status}}</span></div> -->
  208. <!-- <div><span>驳回原因:</span><span>{{item.denyReason}}</span></div> -->
  209. <div><span>备注:</span><span>{{ item.remark }}</span></div>
  210. </div>
  211. <div class="lookup">
  212. <van-button size="small" type="info"
  213. :to="{ name: 'expenseDetails', params: { id: item.id, canEdit: false } }">查看单据信息</van-button>
  214. </div>
  215. </van-collapse-item>
  216. </van-collapse>
  217. <!-- <van-popup v-model="denyReasonDialog" position="bottom" closeable >
  218. <van-cell>请输入原因</van-cell>
  219. <van-field class="form_input"
  220. v-model="denyParm.denyReason" name="reason" type="textarea" placeholder="请输入您决定驳回的原因"
  221. rows="3" autosize />
  222. <van-button style="width:100%;" type="info" :loading="denyLoading" @click="deny()">提交</van-button>
  223. </van-popup> -->
  224. </div>
  225. </div>
  226. </div>
  227. </template>
  228. <script>
  229. export default {
  230. data() {
  231. return {
  232. active: sessionStorage.page ? JSON.parse(sessionStorage.page) : 0,
  233. user: JSON.parse(localStorage.userInfo),
  234. userList: [],
  235. canExamine: false,
  236. currentDate1: new Date(),
  237. currentDate2: new Date(),
  238. minDate: new Date(2020, 0, 1),
  239. maxDate: new Date(2025, 11, 31),
  240. confirmLoading: false,
  241. denyLoading: false,
  242. formshowText: {
  243. name: '',
  244. inProjectName: []
  245. },
  246. // #region 费用报销
  247. editForm: {
  248. ownerId: '',
  249. createDate: this.formatDate(new Date()),
  250. ticketNum: 0,
  251. type: 0,
  252. remark: ''
  253. },
  254. userRadio: null,
  255. ownerIdShow: false,
  256. createDateShow: false,
  257. typeShow: false,
  258. typeList: [],
  259. invoiceIndex: 0,
  260. invoiceList: [
  261. {
  262. projectId: '',
  263. happenDate: '',
  264. invoiceType: '',
  265. expenseType: '',
  266. amount: '',
  267. invoiceNo: '',
  268. taxPercent: '',
  269. taxValue: '',
  270. remark: '',
  271. pic: '',
  272. }
  273. ],
  274. in_projectShow: false,
  275. in_dateShow: false,
  276. in_typeShow: false,
  277. in_exTypeShow: false,
  278. inProjectList: [],
  279. inTypeList: ['增值税专用发票', '增值税普通发票'],
  280. allexTypeList: [],
  281. inexTypeList: [],
  282. uploader: [[]],
  283. // #endregion
  284. // 单据列表
  285. activeName: '',
  286. billList: [],
  287. statusList: ['审核通过', '待审核', '已驳回', '已撤销'],
  288. statusClass: ['', 'waiting', 'rejected', ''],
  289. uploading: false,
  290. // 单据审核
  291. auditName: '',
  292. examineList: [],
  293. denyReasonDialog: false,
  294. denyParm: {
  295. id: '',
  296. denyReason: ''
  297. },
  298. expenseMainType: {
  299. text: ''
  300. }
  301. }
  302. },
  303. computed: {
  304. totalCost() {
  305. let costnum = 0
  306. for (let i in this.invoiceList) {
  307. costnum += (this.invoiceList[i].amount ? parseFloat(this.invoiceList[i].amount) : 0)
  308. }
  309. return costnum.toFixed(2)
  310. }
  311. },
  312. filters: {
  313. numtosum(value) {
  314. if (value == undefined || !value) return '0.00'
  315. value = value.toFixed(2)
  316. const intPart = Math.trunc(value)
  317. const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
  318. let floatPart = '.00'
  319. const valueArray = value.toString().split('.')
  320. if (valueArray.length === 2) { // 有小数部分
  321. floatPart = valueArray[1].toString() // 取得小数部分
  322. return intPartFormat + '.' + floatPart
  323. }
  324. return intPartFormat + floatPart
  325. },
  326. },
  327. mounted() {
  328. this.formshowText.name = this.user.name;
  329. this.editForm.ownerId = this.user.id;
  330. this.userRadio = {
  331. name: this.user.name,
  332. id: this.user.id
  333. }
  334. this.activeChange()
  335. for (let i in this.user.functionList) {
  336. if (this.user.functionList[i].name == '费用审核') {
  337. this.canExamine = true
  338. }
  339. }
  340. if (!this.canExamine) {
  341. this.editForm.ownerId = this.user.id
  342. this.formshowText.name = this.user.name
  343. } else {
  344. this.getUserList()
  345. }
  346. this.getProjectList()
  347. this.getExpensMainTypes()
  348. this.getExTypeList()
  349. },
  350. methods: {
  351. back() {
  352. sessionStorage.removeItem("page");
  353. history.back();
  354. },
  355. formatDate(date) {
  356. let mon = date.getMonth() + 1
  357. return `${date.getFullYear()}-${mon < 10 ? '0' + mon : mon}-${date.getDate() < 10 ? '0' + date.getDate() : date.getDate()}`;
  358. },
  359. getTaxValue(amount, percent) {
  360. let per = percent / 100
  361. let amo = amount / (1 + per) * per
  362. return amo.toFixed(2)
  363. },
  364. activeChange() {
  365. sessionStorage.setItem('page', JSON.stringify(this.active))
  366. if (this.active == 1) {
  367. this.getBillList()
  368. }
  369. if (this.active == 2) {
  370. this.getExamineList()
  371. }
  372. },
  373. // #region 费用报销
  374. ownerIdChange() {
  375. this.editForm.ownerId = this.userRadio.id
  376. this.formshowText.name = this.userRadio.name
  377. this.ownerIdShow = false
  378. },
  379. createDateChange(value, key) {
  380. this.editForm.createDate = this.formatDate(value)
  381. this.createDateShow = false
  382. },
  383. typeChange(value, key) {
  384. this.editForm.type = value.id
  385. this.expenseMainType.text = value.name
  386. this.typeShow = false
  387. for (let i in this.invoiceList) {
  388. this.invoiceList[i].expenseType = ''
  389. }
  390. this.inexTypeList = this.allexTypeList.filter(a => a.mainType == this.editForm.type)
  391. },
  392. ticNumChange(value) {
  393. if (value) {
  394. this.invoiceList.push({
  395. projectId: '',
  396. happenDate: '',
  397. invoiceType: '',
  398. expenseType: '',
  399. amount: '',
  400. invoiceNo: '',
  401. taxPercent: '',
  402. taxValue: '',
  403. remark: '',
  404. pic: '',
  405. })
  406. } else {
  407. this.invoiceList.pop()
  408. }
  409. },
  410. // 发票
  411. inProjectChange(value, key) {
  412. this.formshowText.inProjectName[this.invoiceIndex] = value.projectName
  413. this.invoiceList[this.invoiceIndex].projectId = value.id
  414. this.in_projectShow = false
  415. },
  416. inDateChange(value, key) {
  417. this.invoiceList[this.invoiceIndex].happenDate = this.formatDate(value)
  418. this.in_dateShow = false
  419. },
  420. inTypeChange(value, key) {
  421. this.invoiceList[this.invoiceIndex].invoiceType = key
  422. this.in_typeShow = false
  423. },
  424. inexTypeChange(value, key) {
  425. this.invoiceList[this.invoiceIndex].expenseType = value.typeName
  426. this.in_exTypeShow = false
  427. },
  428. addInvoice() {
  429. this.invoiceList.push({
  430. projectId: '',
  431. happenDate: '',
  432. invoiceType: '',
  433. expenseType: '',
  434. amount: '',
  435. invoiceNo: '',
  436. taxPercent: '',
  437. taxValue: '',
  438. remark: '',
  439. pic: '',
  440. })
  441. this.uploader.push([])
  442. this.editForm.ticketNum = this.invoiceList.length
  443. },
  444. deleteInvoice(index) {
  445. this.invoiceList.splice(index, 1)
  446. this.uploader.splice(index, 1)
  447. this.editForm.ticketNum = this.invoiceList.length
  448. },
  449. // 上传报销凭证
  450. beforeRead(file) {
  451. if (file.type != 'image/jpeg' && file.type != 'image/png') {
  452. this.$toast.fail('请选择jpg或png格式的图片')
  453. return false
  454. }
  455. return true
  456. },
  457. afterRead(file) {
  458. let formData = new FormData();
  459. formData.append("multipartFile", file.file);
  460. this.$axios.post("/common/uploadFile", formData)
  461. .then(res => {
  462. if (res.code == "ok") {
  463. this.invoiceList[this.invoiceIndex].pic = res.data
  464. } else {
  465. this.$toast.fail('上传失败');
  466. this.uploader[this.invoiceIndex] = []
  467. }
  468. }).catch(err => { this.$toast.clear(); console.log(err); this.uploader[this.invoiceIndex] = [] });
  469. },
  470. // 提交
  471. submitExpense() {
  472. if (!this.editForm.ownerId) {
  473. this.$toast.fail('请选择报销人')
  474. return
  475. }
  476. if (!this.editForm.createDate) {
  477. this.$toast.fail('请选择填报日期')
  478. return
  479. }
  480. let required1 = false
  481. let required2 = false
  482. let required3 = false
  483. let required4 = false
  484. let required5 = false
  485. for (let i in this.invoiceList) {
  486. if (!this.invoiceList[i].projectId) {
  487. required1 = '所属项目'
  488. }
  489. if (!this.invoiceList[i].happenDate) {
  490. required2 = '费用日期'
  491. }
  492. // if (!this.invoiceList[i].invoiceType) {
  493. // required3 = '发票种类'
  494. // }
  495. if (!this.invoiceList[i].expenseType) {
  496. required4 = '费用类型'
  497. }
  498. if (!this.invoiceList[i].amount) {
  499. required5 = this.user.timeType.easyExpense==0?'费用金额(含税)':'费用金额'
  500. }
  501. }
  502. if (required1 || required2 || required3 || required4 || required5) {
  503. let requiredStr = (required1 ? required1 + '、' : '')
  504. + (required2 ? required2 + '、' : '')
  505. + (required3 ? required3 + '、' : '')
  506. + (required4 ? required4 + '、' : '')
  507. + (required5 ? required5 + '、' : '')
  508. requiredStr = requiredStr.substring(0, requiredStr.length - 1)
  509. this.$toast.fail('请添加发票的[' + requiredStr + ']')
  510. return
  511. }
  512. if (this.invoiceList.length == 0) {
  513. this.$toast.fail('请添加发票')
  514. return
  515. }
  516. for (let i in this.invoiceList) {
  517. this.invoiceList[i].taxValue = this.getTaxValue(this.invoiceList[i].amount, this.invoiceList[i].taxPercent)
  518. }
  519. this.editForm.items = JSON.stringify(this.invoiceList)
  520. this.editForm.totalAmount = this.totalCost
  521. // 获取新的票据编号
  522. this.confirmLoading = true
  523. this.$axios.post("/expense-sheet/getNextCode", {})
  524. .then(res => {
  525. if (res.code == "ok") {
  526. this.editForm.code = res.data
  527. // 提交
  528. this.$axios.post("/expense-sheet/add", this.editForm)
  529. .then(res => {
  530. this.confirmLoading = false;
  531. if (res.code == "ok") {
  532. this.$toast.success('填报成功')
  533. this.editForm = {
  534. ownerId: '',
  535. createDate: this.formatDate(new Date()),
  536. ticketNum: 0,
  537. type: 0,
  538. remark: ''
  539. }
  540. // this.formshowText = {
  541. // name: '',
  542. // inProjectName: []
  543. // }
  544. this.formshowText.name = ''
  545. this.formshowText.inProjectName = []
  546. this.expenseMainType.text=''
  547. this.invoiceList = []
  548. this.uploader = []
  549. this.formshowText.name = this.user.name;
  550. this.editForm.ownerId = this.user.id;
  551. this.userRadio = {
  552. name: this.user.name,
  553. id: this.user.id
  554. }
  555. } else {
  556. this.$toast.fail('获取失败');
  557. }
  558. }).catch(err => { this.confirmLoading = false; this.$toast.clear(); console.log(err) });
  559. } else {
  560. this.confirmLoading = false
  561. this.$toast.fail('获取失败');
  562. }
  563. }).catch(err => {
  564. this.confirmLoading = false;
  565. this.$toast.clear();
  566. console.log(err)
  567. });
  568. },
  569. // #endregion
  570. // 单据列表
  571. deleteBill(pid) {
  572. this.$dialog.confirm({
  573. message: '确认删除?',
  574. })
  575. .then(() => {
  576. // on confirm
  577. this.$axios.post("/expense-sheet/delete", { id: pid })
  578. .then(res => {
  579. if (res.code == "ok") {
  580. this.$toast.success('删除成功')
  581. this.getBillList()
  582. } else {
  583. this.$toast.fail('获取失败');
  584. }
  585. }).catch(err => { this.$toast.clear(); console.log(err) });
  586. })
  587. .catch(() => {
  588. // on cancel
  589. });
  590. },
  591. // 单据审核
  592. approve(item) {
  593. item.approveLoading = true
  594. this.$axios.post("/expense-sheet/approve", { id: item.id })
  595. .then(res => {
  596. if (res.code == "ok") {
  597. this.$toast.success('已通过')
  598. item.approveLoading = false
  599. this.getExamineList()
  600. } else {
  601. this.$toast.fail('获取失败');
  602. }
  603. }).catch(err => { this.$toast.clear(); console.log(err) });
  604. },
  605. denyToReason(pid) {
  606. this.denyParm.id = pid
  607. this.denyReasonDialog = true
  608. this.denyParm.denyReason = ''
  609. this.deny()
  610. },
  611. deny() {
  612. this.denyLoading = true
  613. this.$axios.post("/expense-sheet/deny", this.denyParm)
  614. .then(res => {
  615. if (res.code == "ok") {
  616. this.$toast.success('已驳回')
  617. this.denyReasonDialog = false
  618. this.denyLoading = false
  619. this.getExamineList()
  620. } else {
  621. this.$toast.fail('获取失败');
  622. }
  623. }).catch(err => { this.$toast.clear(); console.log(err) });
  624. },
  625. getUserList() {
  626. this.$axios.post("/user/getSimpleActiveUserList", {})
  627. .then(res => {
  628. if (res.code == "ok") {
  629. this.userList = res.data
  630. } else {
  631. this.$toast.fail('获取失败');
  632. }
  633. }).catch(err => { this.$toast.clear(); console.log(err) });
  634. },
  635. getProjectList() {
  636. this.$axios.post("/project/getProjectList", {})
  637. .then(res => {
  638. if (res.code == "ok") {
  639. this.inProjectList = res.data
  640. } else {
  641. this.$toast.fail('获取失败');
  642. }
  643. }).catch(err => { this.$toast.clear(); console.log(err) });
  644. },
  645. getExTypeList() {
  646. this.$axios.post("/expense-type/getList", {})
  647. .then(res => {
  648. if (res.code == "ok") {
  649. this.allexTypeList = res.data
  650. this.inexTypeList = this.allexTypeList.filter(a => a.mainType == this.editForm.type)
  651. } else {
  652. this.$toast.fail('获取失败');
  653. }
  654. }).catch(err => { this.$toast.clear(); console.log(err) });
  655. },
  656. getExpensMainTypes() {
  657. this.$axios.post("/expense-main-type/list", {})
  658. .then(res => {
  659. if (res.code == "ok") {
  660. for (var i in res.data) {
  661. res.data[i].text = res.data[i].name
  662. }
  663. this.typeList = res.data
  664. this.expenseMainType.text = res.data[0].name
  665. this.editForm.type = res.data[0].id
  666. this.getExTypeList
  667. } else {
  668. this.$toast.fail('获取失败');
  669. }
  670. }).catch(err => { this.$toast.clear(); console.log(err) });
  671. },
  672. getBillList() {
  673. this.$axios.post("/expense-sheet/list", {
  674. pageSize: 999,
  675. pageIndex: 1,
  676. startDate: '',
  677. endDate: '',
  678. ownerId: '',
  679. type: ''
  680. }).then(res => {
  681. if (res.code == "ok") {
  682. this.billList = res.data.records
  683. } else {
  684. this.$toast.fail('获取失败');
  685. }
  686. }).catch(err => { this.$toast.clear(); console.log(err) });
  687. },
  688. getExamineList() {
  689. this.$axios.post("/expense-sheet/list", {
  690. pageSize: 999,
  691. pageIndex: 1,
  692. startDate: '',
  693. endDate: '',
  694. ownerId: '',
  695. type: '',
  696. status: 1
  697. }).then(res => {
  698. if (res.code == "ok") {
  699. this.examineList = res.data.records
  700. for (let i in this.examineList) {
  701. this.$set(this.examineList[i], 'approveLoading', false)
  702. }
  703. } else {
  704. this.$toast.fail('获取失败');
  705. }
  706. }).catch(err => { this.$toast.clear(); console.log(err) });
  707. }
  708. },
  709. }
  710. </script>
  711. <style lang="less" scoped>
  712. .content {
  713. margin-top: 46px;
  714. overflow: auto;
  715. .edit {
  716. .userCheckbox {
  717. padding: 10px;
  718. }
  719. padding-bottom: 46px;
  720. .form_btn {
  721. z-index: 1000;
  722. }
  723. .edit_form {
  724. .invoice {
  725. border: 0.5px solid rgb(135, 195, 255);
  726. margin: 0.2rem;
  727. .deletebtn {
  728. position: absolute;
  729. z-index: 900;
  730. font-size: 24px;
  731. right: 0.08rem;
  732. top: 0.08rem;
  733. color: #c03131;
  734. }
  735. .invoice_item {
  736. border-top: 0.5px solid rgb(135, 195, 255);
  737. }
  738. }
  739. .addinvoice {
  740. padding: 0 0.3rem 0.3rem;
  741. margin-top: 0.2rem;
  742. text-align: right;
  743. }
  744. }
  745. }
  746. .list {
  747. .list_collapse>div {
  748. margin: 4px;
  749. }
  750. .list_collapse {
  751. .collapse_label_l {
  752. width: 50%;
  753. padding: 4px;
  754. display: inline-block;
  755. }
  756. .collapse_label_r {
  757. width: 50%;
  758. padding: 4px;
  759. display: inline-block;
  760. .waiting {
  761. color: orange;
  762. }
  763. .rejected {
  764. color: red;
  765. }
  766. }
  767. .wrapper {
  768. div {
  769. margin: 8px 16px;
  770. }
  771. div span:nth-child(1) {
  772. width: 30%;
  773. display: inline-block;
  774. }
  775. div span:nth-child(2) {
  776. width: 70%;
  777. display: inline-block;
  778. }
  779. }
  780. .operation {
  781. display: flex;
  782. align-items: center;
  783. justify-content: flex-end;
  784. }
  785. }
  786. }
  787. .audit {
  788. .list_collapse>div {
  789. margin: 4px;
  790. }
  791. .list_collapse {
  792. .collapse_label_l {
  793. width: 60%;
  794. padding: 4px;
  795. display: inline-block;
  796. }
  797. .collapse_label_r {
  798. width: 40%;
  799. padding: 4px;
  800. display: inline-block;
  801. .waiting {
  802. color: orange;
  803. }
  804. .rejected {
  805. color: red;
  806. }
  807. }
  808. .operation {
  809. margin-top: 5px;
  810. padding-top: 5px;
  811. border-top: 0.5px solid #ebedf0;
  812. display: flex;
  813. align-items: center;
  814. justify-content: flex-end;
  815. button {
  816. width: 1.2rem;
  817. }
  818. }
  819. .wrapper {
  820. div {
  821. margin: 8px 16px;
  822. }
  823. div span:nth-child(1) {
  824. width: 30%;
  825. display: inline-block;
  826. }
  827. div span:nth-child(2) {
  828. width: 70%;
  829. display: inline-block;
  830. }
  831. }
  832. .lookup {
  833. display: flex;
  834. align-items: center;
  835. justify-content: flex-end;
  836. }
  837. }
  838. }
  839. }
  840. </style>
  841. <style>
  842. .edit_form .invoice .van-field__label {
  843. color: #999;
  844. }
  845. .edit_form .invoice .van-field__control {
  846. color: #999;
  847. }
  848. </style>