index.vue 43 KB

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