index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. <template>
  2. <view>
  3. <view class="warpbox">
  4. <view class="fllow_form">
  5. <view class="label key">{{i18n['工单编号']}}<span>*</span></view>
  6. <view class="form_right">
  7. <view :class="workorder_number ? 'valueActive' : '' " class="righttext">
  8. {{workorder_number ?workorder_number : ''}}</view>
  9. </view>
  10. </view>
  11. <view class="fllow_form">
  12. <view class="label key">{{i18n['工单标题']}}<span>*</span></view>
  13. <view class="form_right">
  14. <input type="text" :class="title ? 'valueActive' : '' " class="righttext" v-model="title"
  15. :placeholder="i18n['请填写工单标题']" />
  16. </view>
  17. </view>
  18. <view class="inp_warp">
  19. <view class="inp_title key">关联设备<span>*</span></view>
  20. <view class="add_in" @click="seProduct">
  21. <view class="iconfont icon-jiahaocu"></view>
  22. 添加设备
  23. </view>
  24. </view>
  25. <view class="prolist" v-if="productList.length != 0">
  26. <view class="probox">
  27. <view class="proli" v-for="(item,index) in productList" :key="index">
  28. <view class="iconfont icon-jian" @click="delProduct(index)"></view>
  29. <view class="protext" style="text-align: center;width:160rpx">{{item.name}}
  30. </view>
  31. <view class="protext">{{item.unit}}</view>
  32. </view>
  33. </view>
  34. </view>
  35. <view class="fllow_area">
  36. <view class="area_head key">{{i18n['情况说明']}}<span>*</span></view>
  37. <textarea v-model="desc" class="textself" :placeholder="i18n['情况说明']" placeholder-style="color:#999" />
  38. </view>
  39. <!-- <view class="fllow_form">
  40. <view class="label key">{{i18n['预约时间']}}<span>*</span></view>
  41. <picker @change="changeTime" mode="multiSelector" :range="dateTimeArray" :value="dateTime"
  42. @columnchange="changeColumn">
  43. <view class="form_right">
  44. <view :class="appointment_time ? 'valueActive' : '' " class="righttext">
  45. {{appointment_time ? appointment_time : i18n['预约时间']}}</view>
  46. <view class="iconfont icon-you"></view>
  47. </view>
  48. </picker>
  49. </view>
  50. <view class="fllow_form">
  51. <view class="label key">{{i18n['紧急程度']}}</view>
  52. <picker @change="changePriori" :range="priarr" :value="priIndex">
  53. <view class="form_right">
  54. <view :class="priarr[priIndex] ? 'valueActive' : '' " class="righttext">
  55. {{priarr[priIndex] ? priarr[priIndex] : i18n['紧急程度']}}</view>
  56. <view class="iconfont icon-you"></view>
  57. </view>
  58. </picker>
  59. </view> -->
  60. <view class="inp_warp" style="margin-top:0;">
  61. <view class="inp_title key">{{i18n['附件']}}<span>*</span></view>
  62. <view class="form_right" @click="uploadFiles">
  63. <view class="righttext">{{i18n['上传图片']}}</view>
  64. <view class="iconfont icon-arrows_right"></view>
  65. </view>
  66. </view>
  67. <view class="imglist" v-if="imgList.length != 0">
  68. <view class="imgbox" v-for="(item,index) in imgList" :key="index">
  69. <image src="/static/img/close.png" class="delimg" @click="delImg(index)" ></image>
  70. <image :src="item.url" class="selfimg" @click.stop="toPrevie(index)"></image>
  71. </view>
  72. </view>
  73. <view class="fllow_form">
  74. <view class="label key">报修人<span>*</span></view>
  75. <view class="form_right">
  76. <input type="text" :class="linkman ? 'valueActive' : '' " class="righttext" v-model="linkman"
  77. :placeholder="i18n['请填写联系人']" />
  78. </view>
  79. </view>
  80. <view class="fllow_form" style="border-bottom:0;">
  81. <view class="label key">{{i18n['手机号']}}<span>*</span></view>
  82. <view class="form_right">
  83. <input type="text" :class="linkfun ? 'valueActive' : '' " class="righttext" v-model="linkfun"
  84. :placeholder="i18n['手机号']" />
  85. </view>
  86. </view>
  87. <view class="inp_warp" style="margin-top:0;">
  88. <view class="inp_title key">报修位置<span>*</span></view>
  89. <view class="form_right" @click="openmap">
  90. <view class="righttext">{{address}}</view>
  91. <view class="iconfont icon-arrows_right"></view>
  92. </view>
  93. </view>
  94. </view>
  95. <view class="button" @click="$noMultipleClicks(submitWorkOrder)">{{i18n['提交']}}</view>
  96. <!-- 选择产品 -->
  97. <select-work-product ref="workProduct" :showProduct="showProduct" @close="closePop"
  98. @selectList="selectProduct"></select-work-product>
  99. </view>
  100. </template>
  101. <script>
  102. import {
  103. netWorkOrderNumber,
  104. netAddWorkorder,
  105. uploadUrl
  106. } from '@/api/api.js'
  107. import selectWorkProduct from '@/components/selectWorkProduct/index.vue'
  108. import {
  109. dateTimePicker,
  110. getMonthDay
  111. } from '@/util/dateTimePicker.js'
  112. import {
  113. BASE_URL,
  114. SIGN_NO
  115. } from '@/api/http.js'
  116. export default {
  117. components: {
  118. selectWorkProduct
  119. },
  120. data() {
  121. return {
  122. noClick: true, //防止 重复点击
  123. workorder_number: '', //工单编号 自动生成
  124. title: '', //工单标题
  125. linkman: '', //联系人
  126. linkfun: '', //联系人手机号
  127. customer_product_id: '', //客户产品id 1,2,3,4
  128. desc: '', //情况说明
  129. files: '', //附件列表
  130. owner_staff_id: '', //指派员工
  131. address:'请选择位置',
  132. latitude:'',
  133. longitude:'',
  134. addr_name:'',
  135. imgList: [], //附件
  136. appointment_time: '', //预约时间
  137. priarr: [], //紧急情况
  138. priIndex: 0,
  139. showProduct: false,
  140. productList: [],
  141. dateTimeArray: [],
  142. dateArr: [],
  143. dateTime: [],
  144. }
  145. },
  146. computed: {
  147. i18n() {
  148. return this.$t("server")
  149. }
  150. },
  151. onLoad(options) {
  152. this.priarr = this.i18n['priarr']
  153. //获取工单编号
  154. this.getNumber()
  155. this.initTime()
  156. },
  157. onShow() {
  158. uni.setNavigationBarTitle({
  159. title: this.i18n['提交服务']
  160. })
  161. },
  162. onUnload() {
  163. },
  164. methods: {
  165. openmap(){
  166. let self=this;
  167. uni.chooseLocation({
  168. success: function (res) {
  169. self.addr_name=res.name;
  170. self.address=res.address;
  171. self.latitude=res.latitude;
  172. self.longitude=res.longitude;
  173. console.log('位置名称:' + res.name);
  174. console.log('详细地址:' + res.address);
  175. console.log('纬度:' + res.latitude);
  176. console.log('经度:' + res.longitude);
  177. }
  178. });
  179. },
  180. withData(param) {
  181. return param < 10 ? '0' + param : '' + param;
  182. },
  183. initTime() {
  184. let date = new Date()
  185. let endYear = date.getFullYear()
  186. let mont = this.withData(date.getMonth() + 1)
  187. let day = this.withData(date.getDate())
  188. let hour = this.withData(date.getHours())
  189. let minu = this.withData(date.getMinutes())
  190. let seco = this.withData(date.getSeconds())
  191. // 获取完整的年月日 时分秒,以及默认显示的数组
  192. let obj = dateTimePicker()
  193. // 精确到分的处理,将数组的秒去掉
  194. let lastArray = obj.dateTimeArray.pop();
  195. let lastTime = obj.dateTime.pop();
  196. let lastDate = obj.dateArray.pop()
  197. this.dateTimeArray = obj.dateTimeArray
  198. this.dateArr = obj.dateArray
  199. this.dateTime = obj.dateTime
  200. },
  201. changeColumn(e) {
  202. let index = e.detail.column
  203. let value = e.detail.value
  204. if (index == 1) {
  205. let month = this.dateArr[index][value]
  206. let date = new Date();
  207. let endYear = date.getFullYear();
  208. let str = endYear + '-' + month + '-' + '01' + ' ' + '00' + ':' + '00' + ':' + '00'
  209. let obj = dateTimePicker()
  210. // 精确到分的处理,将数组的秒去掉
  211. let lastArray = obj.dateTimeArray.pop();
  212. let lastTime = obj.dateTime.pop();
  213. let lastDate = obj.dateArray.pop()
  214. this.dateTimeArray = obj.dateTimeArray
  215. this.dateArr = obj.dateArray
  216. this.dateTime = obj.dateTime
  217. }
  218. },
  219. //下次联系时间
  220. changeTime(e) {
  221. let arr = e.detail.value
  222. if (arr.includes(-1)) {
  223. uni.showToast({
  224. title: '请选择正确的时间',
  225. icon: 'none'
  226. })
  227. return
  228. }
  229. let str = this.handleTime(arr)
  230. this.appointment_time = str
  231. },
  232. handleTime(arr) {
  233. let year = this.dateArr[0][arr[0]]
  234. let month = this.dateArr[1][arr[1]]
  235. let day = this.dateArr[2][arr[2]]
  236. let hour = this.dateArr[3][arr[3]]
  237. let minu = this.dateArr[4][arr[4]]
  238. let str = year + '-' + month + '-' + day + ' ' + hour + ':' + minu
  239. return str
  240. },
  241. getNumber() {
  242. netWorkOrderNumber().then(res => {
  243. this.workorder_number = res.data.number
  244. })
  245. },
  246. //获取 客户 地址
  247. getCustomerInfo() {
  248. netCustomerAddress({
  249. customer_id: this.customerObj.id
  250. }).then(res => {
  251. this.address = res.data.address
  252. this.address_detail = res.data.address_detail
  253. this.lat = res.data.lat
  254. this.lng = res.data.lng
  255. })
  256. },
  257. //去选择客户 地址
  258. chooseAddress() {
  259. uni.setClipboardData({
  260. data: this.address + this.address_detail,
  261. success: (res) => {
  262. if (this.address_detail) {
  263. uni.showToast({
  264. title: '详细地址已复制,请粘贴搜索',
  265. icon: 'none'
  266. })
  267. } else {
  268. uni.showToast({
  269. title: '正在打开地图',
  270. icon: 'none'
  271. })
  272. }
  273. setTimeout(() => {
  274. uni.chooseLocation({
  275. success: res => {
  276. console.log(res, '地址选择成功')
  277. this.lat = res.latitude
  278. this.lng = res.longitude
  279. this.address = res.address
  280. this.address_detail = res.name
  281. },
  282. fail: err => {
  283. if (err.errMsg == 'chooseLocation:fail auth deny') {
  284. uni.showToast({
  285. title: '请允许使用位置信息',
  286. icon: 'none'
  287. })
  288. }
  289. }
  290. })
  291. }, 2000)
  292. }
  293. })
  294. },
  295. //选择 产品
  296. seProduct() {
  297. this.showProduct = true
  298. this.$refs.workProduct.init()
  299. },
  300. closePop() {
  301. this.showProduct = false
  302. },
  303. selectProduct(arr) {
  304. this.showProduct = false
  305. let data = arr.concat(this.productList)
  306. this.productList = this.deWeight(data)
  307. },
  308. // 去重
  309. deWeight(arr) {
  310. for (var i = 0; i < arr.length - 1; i++) {
  311. for (var j = i + 1; j < arr.length; j++) {
  312. if (arr[i].id == arr[j].id) {
  313. arr.splice(j, 1);
  314. j--;
  315. }
  316. }
  317. }
  318. return arr;
  319. },
  320. delProduct(index) {
  321. this.productList.splice(index, 1)
  322. },
  323. //紧急程度
  324. changePriori(e) {
  325. this.priIndex = e.detail.value
  326. },
  327. //上传图片
  328. uploadFiles() {
  329. uni.chooseImage({
  330. count: 9,
  331. sizeType:['compressed'],
  332. success: (res) => {
  333. let file = res.tempFilePaths
  334. file.forEach(ele => {
  335. this.toUpload(ele)
  336. })
  337. }
  338. })
  339. },
  340. toUpload(file) {
  341. uni.uploadFile({
  342. url: uploadUrl,
  343. name: 'file',
  344. header: {
  345. 'token': uni.getStorageSync('token'),
  346. 'sign-no': SIGN_NO
  347. },
  348. filePath: file,
  349. success: (res) => {
  350. let data = JSON.parse(res.data)
  351. if (data.code == 1) {
  352. this.imgList.push(data.data)
  353. } else {
  354. uni.showToast({
  355. title: '上传失败',
  356. icon: 'none'
  357. })
  358. }
  359. },
  360. fail: (err) => {
  361. console.log(err)
  362. }
  363. })
  364. },
  365. delImg(index) {
  366. this.imgList.splice(index, 1)
  367. },
  368. //预览图片
  369. toPrevie(index) {
  370. let arr = []
  371. this.imgList.forEach(ele=>{
  372. arr.push(ele.url)
  373. })
  374. uni.previewImage({
  375. current:index,
  376. urls:arr
  377. })
  378. },
  379. //去选择 指派员工
  380. toSelectStaff() {
  381. uni.navigateTo({
  382. url: '/pages/template/relation_staff'
  383. })
  384. },
  385. //提交
  386. submitWorkOrder() {
  387. let {
  388. workorder_number, //工单编号 自动生成
  389. title, //工单标题
  390. desc, //情况说明
  391. imgList,
  392. appointment_time, //预约时间
  393. priarr,
  394. priIndex,
  395. productList,
  396. linkman,
  397. linkfun
  398. } = this
  399. if (!title) {
  400. uni.showToast({
  401. title: '请填写工单标题',
  402. icon: 'none'
  403. })
  404. return
  405. }
  406. if (productList.length == 0) {
  407. uni.showToast({
  408. title: '请选择设备',
  409. icon: 'none'
  410. })
  411. return
  412. }
  413. if (!desc) {
  414. uni.showToast({
  415. title: '请填写情况说明',
  416. icon: 'none'
  417. })
  418. return
  419. }
  420. // if (!appointment_time) {
  421. // uni.showToast({
  422. // title: '请选择预约时间',
  423. // icon: 'none'
  424. // })
  425. // return
  426. // }
  427. if (imgList.length == 0) {
  428. uni.showToast({
  429. title: '请上传附件',
  430. icon: 'none'
  431. })
  432. return
  433. }
  434. if (!linkman) {
  435. uni.showToast({
  436. title: '请填写报修人',
  437. icon: 'none'
  438. })
  439. return
  440. }
  441. if (!linkfun) {
  442. uni.showToast({
  443. title: '请填写联系人手机号',
  444. icon: 'none'
  445. })
  446. return
  447. }
  448. //图片
  449. let arr = []
  450. imgList.forEach(ele => {
  451. arr.push(ele.id)
  452. })
  453. //产品
  454. let proarr = []
  455. productList.forEach((ele) => {
  456. proarr.push(ele.id)
  457. })
  458. let params = {
  459. title,
  460. workorder_number,
  461. desc,
  462. file_ids: arr.join(','),
  463. customer_product_id: proarr.join(','), //无用字段
  464. priority: priarr[priIndex],
  465. appointment_time,
  466. linkman,
  467. linkfun,
  468. lng:this.longitude,
  469. lat:this.latitude,
  470. address:this.addr_name,
  471. address_detail:this.address,
  472. }
  473. netAddWorkorder(params).then(res => {
  474. uni.showToast({
  475. title: res.msg,
  476. icon: 'none'
  477. })
  478. setTimeout(() => {
  479. uni.navigateBack({
  480. delta: 1
  481. })
  482. }, 2000)
  483. })
  484. }
  485. }
  486. }
  487. </script>
  488. <style lang="scss" scoped>
  489. .warpbox {
  490. width: 690rpx;
  491. margin: 30rpx auto;
  492. border-radius: 20rpx;
  493. background: #fff;
  494. }
  495. .inp_warp {
  496. padding: 24rpx;
  497. display: flex;
  498. justify-content: space-between;
  499. align-items: center;
  500. border-bottom: 1rpx solid #EDEDED;
  501. .inp_title {
  502. font-size: 26rpx;
  503. color: #000;
  504. text {
  505. color: #F00;
  506. }
  507. }
  508. .add_in {
  509. display: flex;
  510. justify-content: flex-end;
  511. align-items: center;
  512. font-size: 26rpx;
  513. color: #FF8A00;
  514. .icon-jiahaocu {
  515. font-size: 28rpx;
  516. color: #FF8A00;
  517. margin-right: 5rpx;
  518. }
  519. }
  520. }
  521. .fllow_form {
  522. display: flex;
  523. justify-content: space-between;
  524. border-bottom: 1rpx solid #EDEDED;
  525. padding: 24rpx;
  526. .label {
  527. font-size: 24rpx;
  528. color:#666;
  529. text {
  530. color: red;
  531. }
  532. }
  533. }
  534. .form_right {
  535. display: flex;
  536. justify-content: flex-end;
  537. align-items: center;
  538. color: #999;
  539. min-width: 450rpx;
  540. text-align: right;
  541. .righttext {
  542. font-size: 24rpx;
  543. }
  544. }
  545. .prolist {
  546. background-color: #fff;
  547. border-bottom: 1rpx solid #EDEDED;
  548. padding: 24rpx;
  549. .ptotitle {
  550. font-size: 24rpx;
  551. color: #333;
  552. }
  553. .probox {
  554. padding: 0 24rpx;
  555. .proli {
  556. padding: 24rpx 0;
  557. border-bottom: 1rpx dashed #f5f5f5;
  558. display: flex;
  559. justify-content: space-between;
  560. align-items: center;
  561. &:last-child {
  562. border-bottom: 0;
  563. }
  564. .icon-jian {
  565. font-size: 42rpx;
  566. color: #ff7800;
  567. }
  568. .protext {
  569. font-size: 24rpx;
  570. color: #333;
  571. margin-bottom: 15rpx;
  572. }
  573. }
  574. }
  575. }
  576. .fllow_area {
  577. background-color: #fff;
  578. padding: 24rpx;
  579. border-bottom: 1rpx solid #EAEAEA;
  580. .area_head {
  581. font-size: 24rpx;
  582. margin-bottom:15rpx;
  583. text {
  584. color: #f00;
  585. }
  586. }
  587. .textself {
  588. width: 600rpx;
  589. height: 230rpx;
  590. background: rgba(202, 202, 202, 0.2);
  591. box-sizing: border-box;
  592. padding: 24rpx;
  593. font-size: 24rpx;
  594. margin: 0 auto;
  595. border-radius: 20rpx;
  596. }
  597. }
  598. .imglist {
  599. padding: 24rpx 34rpx;
  600. background: #fff;
  601. border-bottom: 1rpx solid #EAEAEA;
  602. display: flex;
  603. justify-content: flex-start;
  604. align-items: center;
  605. flex-wrap: wrap;
  606. .imgbox {
  607. width: 160rpx;
  608. height: 160rpx;
  609. margin-right: 14rpx;
  610. position: relative;
  611. margin-bottom: 24rpx;
  612. border: 1rpx solid #EAEAEA;
  613. &:nth-child(4n) {
  614. margin-right: 0;
  615. }
  616. .delimg {
  617. width: 32rpx;
  618. height: 32rpx;
  619. border-radius: 50%;
  620. position: absolute;
  621. right: -16rpx;
  622. top: -16rpx;
  623. background: rgba(0, 0, 0, 0.5);
  624. z-index: 2;
  625. }
  626. .selfimg {
  627. width: 160rpx;
  628. height: 160rpx;
  629. }
  630. }
  631. }
  632. </style>