receipt_trave_component.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * @description: 费用-差旅组件
  3. * @Author: CP
  4. * @Date: 2020-11-16 14:52:08
  5. * @FilePath: \cld\global\vue\fee\receipt_trave_component.js
  6. */
  7. Vue.component("trave", {
  8. data: function () {
  9. return {
  10. // 行程时间
  11. traveDay: 0,
  12. tripTime: "",
  13. regionOption: region,
  14. // regionLeve2Option: region[0].child,
  15. // arrivalLeve2Option: region[0].child,
  16. regionLeve2Option: region[defaultTraveProvinceIndex].child,
  17. arrivalLeve2Option: region[defaultTraveProvinceIndex].child,
  18. // 出发地 省 市
  19. // departureProvince: region[0].name,
  20. // departureCity: region[0].child[0].name,
  21. departureProvince: defaultTraveProvince,
  22. departureCity: region[defaultTraveProvinceIndex].child[0].name,
  23. // 结束地 省 市
  24. // arrivalProvince: region[0].name,
  25. // arrivalCity: region[0].child[0].name,
  26. arrivalProvince: defaultTraveProvince,
  27. arrivalCity: region[defaultTraveProvinceIndex].child[0].name,
  28. // 目的地数组
  29. arrivalList: [],
  30. tripTimeEdi: "",
  31. departureProvinceEdi: '',
  32. departureCityEdi: '',
  33. arrivalProvinceEdi: '',
  34. arrivalCityEdi: '',
  35. ediIndex: '',
  36. // arrivalListEdi: [],
  37. }
  38. },
  39. props: ['traveItem', 'alertDia', 'traveList', 'traveExplain'],
  40. computed: {
  41. travePrice: function () {
  42. return travePrice(this.traveList);
  43. }
  44. },
  45. methods: {
  46. //行程时间验证
  47. changeCount: function (event) {
  48. this.tripTime = event.target.value;
  49. this.tripTimeEdi = event.target.value;
  50. let dateArray = event.target.value.split(" - ");
  51. if (dateArray.length != 2) {
  52. this.alertDia("差旅行程时间填写有误");
  53. return
  54. }
  55. let dateFormat = /^(\d{4})-(\d{2})-(\d{2})$/;
  56. if (!dateFormat.test(dateArray[0])) {
  57. this.alertDia("差旅行程时间填写有误");
  58. return
  59. }
  60. if (!dateFormat.test(dateArray[1])) {
  61. this.alertDia("差旅行程时间填写有误");
  62. return
  63. }
  64. traveDay = (Math.abs(Date.parse(dateArray[0]) - Date.parse(dateArray[1]))) / (1000 * 60 * 60 * 24) + 1;
  65. if (!isNaN(traveDay)) {
  66. this.traveDay = traveDay;
  67. let alertDia = this.alertDia;
  68. // 验证时间
  69. $.ajax({
  70. type: "GET",
  71. url: "/json/trave/date/all",
  72. dataType: "json",
  73. processData: false,
  74. contentType: false,
  75. }).success(function (sortList) {
  76. let item = new Array(new Date(Math.round(new Date(dateArray[0]).getTime() / 1000 - 28800)).getTime(), new Date(Math.round(new Date(dateArray[1]).getTime() / 1000 - 28800)).getTime());
  77. sortList.push(item);
  78. let TraveStatus = isTraveDate(sortList);
  79. if (TraveStatus == 2) {
  80. alertDia("差旅行程日期段-有重复");
  81. }
  82. // console.log(sortList);
  83. // sortList.forEach((element,index) => {
  84. // const start = element[0];
  85. // const end = element[1];
  86. // itemIndex=index+1;
  87. // if(sortList.length===itemIndex){
  88. // return
  89. // }
  90. // const isRangeStartAndEnd = sortList.some(item => {
  91. // return (sortList[itemIndex][0]<=start&&sortList[itemIndex][1]>=start)||(sortList[itemIndex][0]<=end&&sortList[itemIndex][1]>=end)
  92. // })
  93. // if(isRangeStartAndEnd) {
  94. // // 有重复区间
  95. // alertDia("历史差旅行程时间段-有重复");
  96. // flag = true;
  97. // return ;
  98. // }
  99. // });
  100. }).fail(function (msg) {
  101. alertDia("历史差旅时间获取失败");
  102. });
  103. }
  104. // this.traveDay=new Date(dateArray[1]).getDate()-new Date(dateArray[0]).getDate()+1;
  105. },
  106. changeRegionLeve2: function (event, model) {
  107. this.regionOption.forEach(element => {
  108. if (element.name == event.target.value) {
  109. if (model == "departureCity") {
  110. this.regionLeve2Option = element.child;
  111. this.departureCity = element.child[0].name;
  112. this.departureCityEdi = element.child[0].name;
  113. this.arrivalProvinceEdi = element.name;
  114. this.arrivalProvince = element.name;
  115. this.arrivalLeve2Option = element.child;
  116. this.arrivalCity = element.child[0].name;
  117. this.arrivalCityEdi = element.child[0].name;
  118. } else if (model == "arrivalCity") {
  119. this.arrivalLeve2Option = element.child;
  120. this.arrivalCity = element.child[0].name;
  121. this.arrivalCityEdi = element.child[0].name;
  122. }
  123. return
  124. }
  125. });
  126. },
  127. changeArrivalCity: function (event) {
  128. this.arrivalCity = event.target.value
  129. this.arrivalCityEdi = event.target.value
  130. },
  131. // 行程单相关
  132. // 打开行程单
  133. openTrip: function () {
  134. this.arrivalList = [];
  135. this.tripTime = "";
  136. },
  137. deleteTrip(index) {
  138. this.traveList.splice(index, 1)
  139. },
  140. addTrip: function () {
  141. if (this.tripTime == "") {
  142. this.alertDia("请选择行程时间");
  143. return
  144. }
  145. // 构建行程信息
  146. tripList = [];
  147. // 出发地
  148. var newTripItem = NewTraveItem();
  149. tripList.push({
  150. province: this.departureProvince,
  151. city: this.departureCity,
  152. tripItem: newTripItem,
  153. subtotal: 0,
  154. });
  155. // 目的地
  156. this.arrivalList.forEach(element => {
  157. var newTripItem = NewTraveItem();
  158. tripList.push({
  159. province: element.arrivalProvince,
  160. city: element.arrivalCity,
  161. tripItem: newTripItem,
  162. subtotal: 0,
  163. });
  164. });
  165. // 结束地
  166. var newTripItem = NewTraveItem();
  167. tripList.push({
  168. province: this.arrivalProvince,
  169. city: this.arrivalCity,
  170. tripItem: newTripItem,
  171. subtotal: 0.00,
  172. });
  173. // 构建差旅信息
  174. trave = {
  175. tripTime: this.tripTime,
  176. tripList: tripList,
  177. total: 0.00,
  178. };
  179. this.traveList.push(trave);
  180. $('#route-add').modal('hide')
  181. },
  182. openEdiTrip(index) {
  183. this.ediIndex = index;
  184. let tripData = this.traveList[index];
  185. this.tripTimeEdi = tripData.tripTime;
  186. // 出发地
  187. this.departureProvinceEdi = tripData.tripList[0].province;
  188. this.departureCityEdi = tripData.tripList[0].city;
  189. // 结束
  190. let endIndex = tripData.tripList.length - 1
  191. this.arrivalProvinceEdi = tripData.tripList[endIndex].province;
  192. this.arrivalCityEdi = tripData.tripList[endIndex].city;
  193. // 目的地
  194. this.arrivalList = [];
  195. tripData.tripList.forEach((element, index) => {
  196. // 获得目的城市下拉菜单
  197. let arrivalCityOption = [];
  198. this.regionOption.forEach(el => {
  199. if (el.name == element.province) {
  200. arrivalCityOption = el.child;
  201. return
  202. }
  203. });
  204. if (index !== 0 && index !== endIndex) {
  205. this.arrivalList.push({
  206. "arrivalProvince": element.province,
  207. "arrivalCity": element.city,
  208. "arrivalCityOption": arrivalCityOption
  209. });
  210. }
  211. });
  212. },
  213. ediTrip() {
  214. if (this.tripTime == "") {
  215. this.alertDia("请选择行程时间");
  216. return
  217. }
  218. // 构建行程信息
  219. tripList = [];
  220. // 出发地
  221. var newTripItem = NewTraveItem();
  222. tripList.push({
  223. province: this.departureProvinceEdi,
  224. city: this.departureCityEdi,
  225. tripItem: newTripItem,
  226. subtotal: 0,
  227. });
  228. // 目的地
  229. this.arrivalList.forEach(element => {
  230. var newTripItem = NewTraveItem();
  231. tripList.push({
  232. province: element.arrivalProvince,
  233. city: element.arrivalCity,
  234. tripItem: newTripItem,
  235. subtotal: 0,
  236. });
  237. });
  238. // 结束地
  239. var newTripItem = NewTraveItem();
  240. tripList.push({
  241. province: this.arrivalProvinceEdi,
  242. city: this.arrivalCityEdi,
  243. tripItem: newTripItem,
  244. subtotal: 0.00,
  245. });
  246. // 构建差旅信息
  247. trave = {
  248. tripTime: this.tripTime,
  249. tripList: tripList,
  250. total: 0.00,
  251. };
  252. this.traveList[this.ediIndex] = trave;
  253. // 更新完成
  254. this.ediIndex = '';
  255. this.tripTimeEdi = '';
  256. this.departureProvinceEdi = '';
  257. this.departureCityEdi = '';
  258. this.arrivalProvinceEdi = '';
  259. this.arrivalCityEdi = '';
  260. this.arrivalList = [];
  261. $('#route-edi').modal('hide')
  262. },
  263. addArrivalDom: function (option) {
  264. // dom = {
  265. // "arrivalProvince": region[0].name,
  266. // "arrivalCity": region[0].child[0].name,
  267. // "arrivalCityOption": region[0].child,
  268. // }
  269. //1.没有目的地的时候
  270. let arrivalProvince = this.departureProvince;
  271. let arrivalCity = this.departureCity;
  272. let childIndexValue = this.departureProvince;
  273. if (option == "edi") {
  274. arrivalProvince = this.departureProvinceEdi;
  275. arrivalCity = this.departureCityEdi;
  276. childIndexValue = this.departureProvinceEdi;
  277. }
  278. if (this.arrivalList.length !== 0) {
  279. childIndexValue = this.arrivalList[this.arrivalList.length - 1].arrivalProvince
  280. arrivalProvince = childIndexValue;
  281. arrivalCity = this.arrivalList[this.arrivalList.length - 1].arrivalCity;
  282. }
  283. let index = 0;
  284. region.forEach((element, i) => {
  285. if (element.name === childIndexValue) {
  286. index = i;
  287. return;
  288. }
  289. });
  290. dom = {
  291. "arrivalProvince": arrivalProvince,
  292. "arrivalCity": arrivalCity,
  293. "arrivalCityOption": region[index].child,
  294. }
  295. this.arrivalList.push(dom);
  296. },
  297. delArrivalDom: function (index) {
  298. this.arrivalList.splice(index, 1)
  299. },
  300. changeArrivalLeve2: function (event, index) {
  301. this.regionOption.forEach(element => {
  302. if (element.name == event.target.value) {
  303. this.arrivalList[index].arrivalCityOption = element.child;
  304. this.arrivalList[index].arrivalCity = element.child[0].name;
  305. return
  306. }
  307. });
  308. },
  309. computeTraveItem: function (event) {
  310. this.traveItem.forEach((element, index) => {
  311. let sum = 0;
  312. // 每一列求和
  313. this.traveList.forEach(el => {
  314. el.tripList.forEach(elementlv2 => {
  315. elementlv2.tripItem.forEach(elementlv3 => {
  316. if (element.name == elementlv3.name) {
  317. sum += Number(elementlv3.price);
  318. }
  319. });
  320. });
  321. });
  322. this.traveItem[index].price = sum.toFixed(2);
  323. });
  324. // 每一个小目的地合计
  325. this.traveList.forEach((el, index) => {
  326. let total = 0;
  327. el.tripList.forEach((elementlv2, indexlv2) => {
  328. let sum = 0;
  329. elementlv2.tripItem.forEach(elementlv3 => {
  330. sum += Number(elementlv3.price);
  331. });
  332. total += sum
  333. this.traveList[index].tripList[indexlv2].subtotal = sum.toFixed(2);
  334. });
  335. this.traveList[index].total = total.toFixed(2);
  336. });
  337. },
  338. },
  339. template:
  340. `
  341. <div>
  342. <div class="seTable">
  343. <table class="table table-bordered table-condensed mb-0">
  344. <tbody>
  345. <tr>
  346. <th colspan="2" class="taC">差旅相关费用</th>
  347. </tr>
  348. <tr>
  349. <td colspan="2">
  350. <!--行程1-->
  351. <table v-for="(trave,index) in traveList" class="table table-bordered table-condensed table-hover"
  352. style="margin-bottom: 5px;">
  353. <tr>
  354. <th colspan="3" class="taC">行程{{ index+1 }}#
  355. {{ trave.tripTime }}
  356. <div class="fR ">
  357. <a href="javascript:void(0)" @click="deleteTrip(index)" class="text-danger" data-toggle="modal">删除</a>
  358. <a href="#route-edi" @click="openEdiTrip(index)" data-toggle="modal">编辑</a>
  359. </div>
  360. </th>
  361. </tr>
  362. <tbody v-for="(trip,i) in trave.tripList">
  363. <tr>
  364. <th colspan="3" class="ta"><i class="contactsMark icon-">P</i> {{trip.province}}-{{trip.city}}</th>
  365. </tr>
  366. <tr v-for="item in trip.tripItem" v-if="i!==trave.tripList.length-1" >
  367. <th width="90">{{item.name}}</th>
  368. <td class="taR" width="100">
  369. ¥<input type="number" v-model="item.price" @input="computeTraveItem" pattern="[0-9]" step="0.01" min="0" class="span1">
  370. </td>
  371. <th>
  372. <textarea required v-model="item.remark" rows="2" style="width: 99%; margin-bottom: 0" ></textarea>
  373. </th>
  374. </tr>
  375. </tbody>
  376. </table>
  377. </td>
  378. </tr>
  379. <tr>
  380. <th colspan="2" class="taC"><a href="#route-add" @click="openTrip" data-toggle="modal"
  381. class="button">添加新行程</a></th>
  382. </tr>
  383. <tr>
  384. <th colspan="2" class="taC">差旅相关费用合计</th>
  385. </tr>
  386. <tr v-for="item in traveItem" >
  387. <th>{{ item.name }}</th>
  388. <td class="taR" width="200">¥{{ item.price }}</td>
  389. </tr>
  390. <tr class="warning">
  391. <td class="taR"><b>差旅相关费用合计</b></td>
  392. <td class="colGreed taR"><b style="font-size: 24px">¥{{travePrice}}</b></td>
  393. </tr>
  394. <tr>
  395. <th colspan="2" class="taC">报销说明</th>
  396. </tr>
  397. <tr>
  398. <th colspan="2" v-for="item in traveExplain" >
  399. <textarea required rows="6" style="width: 99%" v-model="item.traveExplain" placeholder="差旅相关费用额外说明"></textarea>
  400. </th>
  401. </tr>
  402. </tbody>
  403. </table>
  404. </div>
  405. <div class="seCensor receipt-censor">
  406. <div class="title">报销单填写说明</div>
  407. <div class="detail">
  408. <p>1
  409. 请按先后发生顺序填写报销明细,交通费(市内交通费及往来交通费)、邮寄费需在批注明注明费用明细(例:珠海-广州70元-佛山20元);</p>
  410. <p>2 出差补助30元/天,不需提供发票,只需在报销单上填写清楚;</p>
  411. <p>
  412. 3 <b>产生费用所在办事处</b> 默认使用您所在的第一个办事处。
  413. </p>
  414. </div>
  415. <div class="itinerary">
  416. <h2 class="itineraryTitle">总行程单</h2>
  417. <div class="itineraryCon">
  418. <ul v-for="(trave,index) in traveList" >
  419. <li class="sub-title">行程{{ index+1 }}# {{ trave.tripTime }}</li>
  420. <li v-for="(trip,i) in trave.tripList" >
  421. <div class="itineraryList">
  422. <div class="addressName">
  423. <i class="contactsMark icon-">P</i> <b>{{trip.city}}</b>
  424. </div>
  425. <div class="pointLine " v-if="i!==trave.tripList.length-1" >
  426. <div class="timeList">
  427. <div class="priceList">
  428. <span class="priceTitle">小计</span>
  429. <span class="price">¥{{ trip.subtotal }}</span>
  430. </div>
  431. </div>
  432. </div>
  433. </div>
  434. </li>
  435. <li class="sub-title">行程{{ index+1 }}# 合计:{{ trave.total }}</li>
  436. </ul>
  437. </div>
  438. </div>
  439. </div>
  440. <!--弹出 编辑行程 -->
  441. <div class="modal hide fade" id="route-edi">
  442. <div class="modal-dialog">
  443. <div class="modal-content">
  444. <div class="modal-header">
  445. <h3>编辑行程</h3>
  446. </div>
  447. <div class="modal-body saeaList">
  448. <table class="table table-bordered table-condensed">
  449. <tr>
  450. <th class="taC" colspan="2">行程</th>
  451. </tr>
  452. <tr>
  453. <th>出发/结束日期</th>
  454. <td><input class="datepicker-here span3" placeholder="按时间筛选" type="text" data-range="true"
  455. data-multiple-dates-separator=" - " data-language="zh" @blur.prevent="changeCount" v-model="tripTimeEdi" >
  456. &nbsp;&nbsp;旅程合计:<b class="colRed">{{ traveDay }}</b>天
  457. </td>
  458. </tr>
  459. <tr>
  460. <th><span>┌</span> 出发地</th>
  461. <td>
  462. <select v-model="departureProvinceEdi" @change="changeRegionLeve2($event,'departureCity')" >
  463. <option v-for="option in regionOption" :value="option.name" >{{option.name}}</option>
  464. </select>
  465. <select v-model="departureCityEdi" @change="changeArrivalCity($event)">
  466. <option v-for="option in regionLeve2Option">{{option.name}}</option>
  467. </select>
  468. <a href="javascript:void(0)" @click="addArrivalDom('edi')" >+添加目的地</a>
  469. </td>
  470. </tr>
  471. <tr v-for="(item,index) in arrivalList" >
  472. <th><span class="">├</span> 目的地</th>
  473. <td>
  474. <select v-model="item.arrivalProvince" @change="changeArrivalLeve2($event,index)" >
  475. <option v-for="option in regionOption" :value="option.name" >{{option.name}}</option>
  476. </select>
  477. <select v-model="item.arrivalCity">
  478. <option v-for="option in item.arrivalCityOption">{{option.name}}</option>
  479. </select> <a href="javascript:void(0)" @click="delArrivalDom(index)">-移除</a>
  480. </td>
  481. </tr>
  482. <tr>
  483. <th><span class="">└</span> 结束</th>
  484. <td>
  485. <select v-model="arrivalProvinceEdi" @change="changeRegionLeve2($event,'arrivalCity')" >
  486. <option v-for="option in regionOption" :value="option.name" >{{option.name}}</option>
  487. </select>
  488. <select v-model="arrivalCityEdi">
  489. <option v-for="option in arrivalLeve2Option">{{option.name}}</option>
  490. </select>
  491. </td>
  492. </tr>
  493. </table>
  494. </div>
  495. <div class="modal-footer">
  496. <a href="javascript:void(0)" class="button" @click="ediTrip" >确认</a>
  497. <a href="javascript:void(0)" class="button btn-gray" data-dismiss="modal" aria-hidden="true">关闭</a>
  498. </div>
  499. </div>
  500. </div>
  501. </div>
  502. <!--弹出 添加行程 -->
  503. <div class="modal hide fade" id="route-add">
  504. <div class="modal-dialog">
  505. <div class="modal-content">
  506. <div class="modal-header">
  507. <h3>添加行程</h3>
  508. </div>
  509. <div class="modal-body saeaList">
  510. <table class="table table-bordered table-condensed">
  511. <tr>
  512. <th class="taC" colspan="2">行程</th>
  513. </tr>
  514. <tr>
  515. <th>出发/结束日期</th>
  516. <td><input class="datepicker-here span3" placeholder="按时间筛选" type="text" data-range="true"
  517. data-multiple-dates-separator=" - " data-language="zh" @blur.prevent="changeCount" v-model="tripTime" >
  518. &nbsp;&nbsp;旅程合计:<b class="colRed">{{ traveDay }}</b>天
  519. </td>
  520. </tr>
  521. <tr>
  522. <th><span>┌</span> 出发地</th>
  523. <td>
  524. <select v-model="departureProvince" @change="changeRegionLeve2($event,'departureCity')" >
  525. <option v-for="option in regionOption" :value="option.name" >{{option.name}}</option>
  526. </select>
  527. <select v-model="departureCity" @change="changeArrivalCity($event)">
  528. <option v-for="option in regionLeve2Option">{{option.name}}</option>
  529. </select>
  530. <a href="javascript:void(0)" @click="addArrivalDom" >+添加目的地</a>
  531. </td>
  532. </tr>
  533. <tr v-for="(item,index) in arrivalList" >
  534. <th><span class="">├</span> 目的地</th>
  535. <td>
  536. <select v-model="item.arrivalProvince" @change="changeArrivalLeve2($event,index)" >
  537. <option v-for="option in regionOption" :value="option.name" >{{option.name}}</option>
  538. </select>
  539. <select v-model="item.arrivalCity">
  540. <option v-for="option in item.arrivalCityOption">{{option.name}}</option>
  541. </select> <a href="javascript:void(0)" @click="delArrivalDom(index)">-移除</a>
  542. </td>
  543. </tr>
  544. <tr>
  545. <th><span class="">└</span> 结束</th>
  546. <td>
  547. <select v-model="arrivalProvince" @change="changeRegionLeve2($event,'arrivalCity')" >
  548. <option v-for="option in regionOption" :value="option.name" >{{option.name}}</option>
  549. </select>
  550. <select v-model="arrivalCity">
  551. <option v-for="option in arrivalLeve2Option">{{option.name}}</option>
  552. </select>
  553. </td>
  554. </tr>
  555. </table>
  556. </div>
  557. <div class="modal-footer">
  558. <a href="javascript:void(0)" class="button" @click="addTrip" >确认</a>
  559. <a href="javascript:void(0)" class="button btn-gray" data-dismiss="modal" aria-hidden="true">关闭</a>
  560. </div>
  561. </div>
  562. </div>
  563. </div>
  564. <!--结束 弹出 添加行程 -->
  565. </div>
  566. `
  567. })