repairRecord.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. <template>
  2. <view class="container">
  3. <view class="title">维修日期</view>
  4. <uni-datetime-picker placeholder="请选择日期" type="date" v-model="repairDate" />
  5. <view class="title">维修内容</view>
  6. <view class="textarea">
  7. <textarea placeholder-style="color:#CCCCCC" placeholder="请输入维修内容" v-model="repairContent"></textarea>
  8. </view>
  9. <view class="title">维修结果</view>
  10. <!-- 录音区域 -->
  11. <view class="voice">
  12. <view class="voice_box" v-if="!recordingPath" @click="handleRecording">
  13. <img src="../../static/images/repairsImg/voice.png" />
  14. </view>
  15. <view v-if="!recordingPath" @click="handleRecording">点击录音</view>
  16. <view class="item_recording" v-if="recordingPath" @click="handlePlayRecording">
  17. <img :src="recordingImg" />
  18. {{ recordingTime }}″
  19. </view>
  20. <view class="recording_icon" v-if="recordingPath" @click="handleDeleteRecording">×</view>
  21. </view>
  22. <!-- 录音弹窗区域 -->
  23. <uni-popup :safe-area="true" background-color="#fff" ref="popup_recording">
  24. <view class="popup_recording">
  25. <recording @getTempFilePath="getTempFilePath" />
  26. </view>
  27. </uni-popup>
  28. <view class="title">关联耗材</view>
  29. <!-- 每一个耗材盒子区域 -->
  30. <!-- <view class="detail_box">
  31. <view class="detail_box_item">
  32. <view class="item_key">耗材名称</view>
  33. <view class="item_value">螺丝钉</view>
  34. </view>
  35. <view class="detail_box_item">
  36. <view class="item_key">耗材数量</view>
  37. <view class="item_value">
  38. <uni-number-box v-model="count" :min="0" @change="bindChange"></uni-number-box>
  39. </view>
  40. </view>
  41. <view class="detail_box_item">
  42. <view class="item_key">耗材单价</view>
  43. <view class="item_value">0.5</view>
  44. </view>
  45. </view> -->
  46. <!-- 每一个耗材盒子区域 -->
  47. <view class="detail_box" v-for="(item, index) in goodList" :key="index">
  48. <view class="detail_box_item">
  49. <view class="item_key">耗材名称</view>
  50. <view class="item_value">{{ item.name }}</view>
  51. </view>
  52. <view class="detail_box_item">
  53. <view class="item_key">耗材数量</view>
  54. <view class="item_value">
  55. <uni-number-box v-model="item.num" :min="0" @change="bindChange($event, index)"></uni-number-box>
  56. </view>
  57. </view>
  58. <view class="detail_box_item">
  59. <view class="item_key">耗材单价</view>
  60. <view class="item_value">
  61. <input type="number" placeholder="请输入耗材单价" v-model="item.price" @blur="handleChangePrice($event, item)" />
  62. </view>
  63. </view>
  64. </view>
  65. <!-- 添加耗材区域 -->
  66. <view class="add" @click="handleAdd">
  67. <text>+</text>
  68. 添加耗材
  69. </view>
  70. <!-- 合计费用区域 -->
  71. <view class="total">
  72. <view>合计费用</view>
  73. <view>{{ countMoney }}元</view>
  74. </view>
  75. <view class="title">维修师傅</view>
  76. <view class="box">
  77. <img src="../../static/images/repairsImg/people.png" />
  78. {{ worker }}
  79. </view>
  80. <view class="title">手机</view>
  81. <view class="box">
  82. <img src="../../static/images/repairsImg/phone2.png" />
  83. {{ phone }}
  84. </view>
  85. <view class="title">现场拍照</view>
  86. <uni-file-picker
  87. ref="filePicker"
  88. limit="3"
  89. v-model="imgList"
  90. fileMediatype="image"
  91. :image-styles="imageStyles"
  92. mode="grid"
  93. @select="select"
  94. @delete="handleDelete"
  95. ></uni-file-picker>
  96. <view class="btn" @click="handleSub">确认提交</view>
  97. <!-- 用于图片压缩的canvas画布 -->
  98. <canvas
  99. :style="{
  100. width: cw + 'px',
  101. height: cw + 'px',
  102. position: 'absolute',
  103. zIndex: -1,
  104. left: '-10000rpx',
  105. top: '-10000rpx'
  106. }"
  107. canvas-id="zipCanvas"
  108. ></canvas>
  109. <!--画布结束-->
  110. </view>
  111. </template>
  112. <script>
  113. import recording from '../components/recording.vue'
  114. const innerAudioContext = uni.createInnerAudioContext()
  115. export default {
  116. components: {
  117. recording
  118. },
  119. data() {
  120. return {
  121. // 维修日期
  122. repairDate: '',
  123. // 维修内容
  124. repairContent: '',
  125. // 维修师傅
  126. worker: '张三',
  127. // 手机号码
  128. phone: '13659854589',
  129. // 耗材列表
  130. goodList: [],
  131. count: 6,
  132. // 显示的图片数据
  133. imgList: [],
  134. // 上传的图片数据
  135. subImgList: [],
  136. // 图片上传框的样式
  137. imageStyles: {
  138. width: 60,
  139. height: 60,
  140. border: {
  141. color: '#ccc',
  142. width: 1,
  143. style: 'dashed',
  144. radius: '9px'
  145. }
  146. },
  147. //画板边长默认是屏幕宽度,正方形画布
  148. cw: uni.getSystemInfoSync().windowWidth,
  149. // 录音文件路径
  150. recordingPath: '',
  151. // 录音图片地址
  152. recordingImg: '../../static/images/repairsImg/recording.jpg',
  153. // 录音时长
  154. recordingTime: 0,
  155. // 播放状态
  156. playStatus: false,
  157. // 定时器标识
  158. timer: null
  159. }
  160. },
  161. computed: {
  162. // 合计费用
  163. countMoney() {
  164. let countMoney = 0
  165. this.goodList.forEach((ele) => {
  166. countMoney += Number(ele.num) * Number(ele.price)
  167. })
  168. if (countMoney) {
  169. return countMoney
  170. } else {
  171. return 0
  172. }
  173. }
  174. },
  175. mounted() {
  176. //在ios下静音时播放没有声音,默认为true,改为false就好了。
  177. uni.setInnerAudioOption({
  178. obeyMuteSwitch: false
  179. })
  180. uni.$on('addConsumable', this.addConsumable)
  181. },
  182. methods: {
  183. // 单价输入框输入回调
  184. handleChangePrice(e, item) {
  185. // 验证输入单价格式 只能是数字,小数点最多两位
  186. const reg = /(^[1-9]\d*(\.\d{1,2})?$)|(^0(\.\d{1,2})?$)/
  187. if (!reg.test(e.detail.value)) {
  188. uni.showToast({
  189. title: '请确定单价为数字,并且只能保留两位小数点',
  190. icon: 'none'
  191. })
  192. item.price = 0
  193. }
  194. },
  195. // 全局自定义事件
  196. addConsumable(e) {
  197. // console.log(e)
  198. // 判断是否存在相同的耗材
  199. let flag = this.goodList.some((ele) => {
  200. return ele.name === e.data
  201. })
  202. if (!flag) {
  203. this.goodList.push({
  204. name: e.data,
  205. num: 1,
  206. price: ''
  207. })
  208. }
  209. },
  210. // 确认提交按钮回调
  211. handleSub() {
  212. if (!this.goodList.length) {
  213. uni.showToast({
  214. title: '请添加耗材',
  215. icon: 'none'
  216. })
  217. return
  218. }
  219. if (this.countMoney <= 0) {
  220. uni.showToast({
  221. title: '合计费用不能小于0元',
  222. icon: 'none'
  223. })
  224. return
  225. }
  226. uni.showModal({
  227. title: '提示',
  228. content: '确认提交吗?',
  229. success: (res) => {
  230. if (res.confirm) {
  231. console.log(this.repairDate)
  232. console.log(this.repairContent)
  233. console.log(this.recordingPath)
  234. console.log(this.goodList)
  235. console.log(this.countMoney)
  236. console.log(this.worker)
  237. console.log(this.phone)
  238. console.log(this.subImgList)
  239. uni.showToast({
  240. title: '提交成功',
  241. icon: 'success'
  242. })
  243. setTimeout(() => {
  244. uni.reLaunch({
  245. url: '/pagesRepairs/box/box'
  246. })
  247. }, 1500)
  248. }
  249. }
  250. })
  251. },
  252. // 耗材数量计数器改变回调
  253. bindChange(e, index) {
  254. // console.log(e)
  255. // console.log(index)
  256. if (e === 0) {
  257. this.goodList.splice(index, 1)
  258. }
  259. },
  260. // 添加耗材按钮回调
  261. handleAdd() {
  262. uni.navigateTo({
  263. url: '/pagesRepairs/addGoods/addGoods'
  264. })
  265. },
  266. // 选择图片回调
  267. select(e) {
  268. console.log(e)
  269. e.tempFiles.forEach((item) => {
  270. //这里的id和页面中写的html代码的canvas的id要一致
  271. let canvasId = 'zipCanvas'
  272. //原图的路径
  273. let imagePath = item.path
  274. //大小限制1024kb
  275. let limitSize = 1024
  276. //初始绘画区域是画布自身的宽度也就是屏幕宽度
  277. let drawWidth = uni.getSystemInfoSync().windowWidth
  278. getLessLimitSizeImage(canvasId, imagePath, limitSize, drawWidth, (resPath) => {
  279. uni.showLoading({
  280. title: '上传中'
  281. })
  282. uni.uploadFile({
  283. url: `https://jiangxih3cpartner.com/reporting/file/fileUpDown`,
  284. filePath: resPath,
  285. name: 'file',
  286. success: (uploadFileRes) => {
  287. this.subImgList.push(JSON.parse(uploadFileRes.data).data.join())
  288. this.imgList.push({
  289. url: item.path,
  290. name: ''
  291. })
  292. uni.hideLoading()
  293. },
  294. fail: () => {
  295. uni.showToast({
  296. title: '上传失败',
  297. icon: 'error'
  298. })
  299. }
  300. })
  301. })
  302. })
  303. },
  304. // 删除图片回调
  305. handleDelete(e) {
  306. // console.log(e);
  307. const num = this.imgList.findIndex((v) => v.url === e.tempFilePath)
  308. this.subImgList.splice(num, 1)
  309. this.imgList.splice(num, 1)
  310. },
  311. // 点击录音按钮回调
  312. handleRecording() {
  313. uni.getSetting({
  314. success: (res) => {
  315. if (!res.authSetting['scope.record']) {
  316. uni.authorize({
  317. scope: 'scope.record',
  318. success(res) {
  319. // 授权成功
  320. uni.showToast({
  321. title: '授权成功',
  322. icon: 'none'
  323. })
  324. },
  325. fail() {
  326. uni.showModal({
  327. content: '检测到您没打开麦克风权限,是否去设置打开?',
  328. confirmText: '确认',
  329. cancelText: '取消',
  330. success: (res) => {
  331. if (res.confirm) {
  332. uni.openSetting({
  333. success: (res) => {}
  334. })
  335. } else {
  336. uni.showToast({
  337. title: '获取麦克风权限失败',
  338. icon: 'none'
  339. })
  340. }
  341. }
  342. })
  343. }
  344. })
  345. } else {
  346. this.$refs.popup_recording.open('bottom')
  347. }
  348. },
  349. fail() {
  350. uni.showToast({
  351. title: '获取麦克风权限失败',
  352. icon: 'none'
  353. })
  354. }
  355. })
  356. },
  357. // 点击录音播放回调
  358. handlePlayRecording() {
  359. innerAudioContext.src = this.recordingPath
  360. if (!this.playStatus) {
  361. this.playStatus = true
  362. innerAudioContext.play()
  363. this.timer = setInterval(() => {
  364. if (this.recordingImg == '../../static/images/repairsImg/recording.jpg') {
  365. this.recordingImg = '../../static/images/repairsImg/recording2.jpg'
  366. } else if (this.recordingImg == '../../static/images/repairsImg/recording2.jpg') {
  367. this.recordingImg = '../../static/images/repairsImg/recording3.jpg'
  368. } else if (this.recordingImg == '../../static/images/repairsImg/recording3.jpg') {
  369. this.recordingImg = '../../static/images/repairsImg/recording.jpg'
  370. }
  371. }, 300)
  372. //播放结束
  373. innerAudioContext.onEnded(() => {
  374. clearInterval(this.timer)
  375. this.timer = null
  376. this.recordingImg = '../../static/images/repairsImg/recording.jpg'
  377. this.playStatus = false
  378. })
  379. } else {
  380. clearInterval(this.timer)
  381. this.recordingImg = '../../static/images/repairsImg/recording.jpg'
  382. this.playStatus = false
  383. innerAudioContext.stop()
  384. }
  385. },
  386. // 删除录音回调
  387. handleDeleteRecording() {
  388. if (this.playStatus) {
  389. uni.showToast({
  390. title: '播放中不能删除',
  391. icon: 'none',
  392. mask: true
  393. })
  394. } else {
  395. uni.showModal({
  396. title: '提示',
  397. content: '确定删除录音吗?',
  398. success: (res) => {
  399. if (res.confirm) {
  400. this.recordingPath = ''
  401. this.recordingTime = 0
  402. }
  403. }
  404. })
  405. }
  406. },
  407. // 自定义事件回调,获取录音文件路径
  408. getTempFilePath(path, time) {
  409. this.recordingPath = path
  410. this.recordingTime = time
  411. this.$refs.popup_recording.close()
  412. }
  413. }
  414. }
  415. </script>
  416. <style lang="scss" scoped>
  417. .container {
  418. box-sizing: border-box;
  419. padding: 0 30rpx;
  420. width: 100%;
  421. height: 100vh;
  422. overflow-y: auto;
  423. .title {
  424. display: flex;
  425. align-items: center;
  426. height: 107rpx;
  427. font-size: 36rpx;
  428. font-weight: bold;
  429. }
  430. .textarea {
  431. height: 310rpx;
  432. border-radius: 10rpx;
  433. border: 1rpx solid #cccccc;
  434. textarea {
  435. box-sizing: border-box;
  436. padding: 25rpx 35rpx;
  437. width: 100%;
  438. font-size: 32rpx;
  439. }
  440. }
  441. .voice {
  442. display: flex;
  443. align-items: center;
  444. height: 94rpx;
  445. font-size: 32rpx;
  446. color: #cccccc;
  447. border-radius: 10rpx;
  448. border: 1rpx solid #cccccc;
  449. .voice_box {
  450. display: flex;
  451. justify-content: center;
  452. align-items: center;
  453. margin: 0 38rpx 0 33rpx;
  454. width: 101rpx;
  455. height: 47rpx;
  456. border-radius: 33rpx;
  457. box-shadow: 0px 0px 4rpx rgba(0, 0, 0, 0.25);
  458. img {
  459. width: 33rpx;
  460. height: 33rpx;
  461. }
  462. }
  463. .item_recording {
  464. margin-left: 35rpx;
  465. display: flex;
  466. align-items: center;
  467. width: 230rpx;
  468. height: 65rpx;
  469. color: #000;
  470. border-radius: 100rpx;
  471. border: 1rpx solid #cccccc;
  472. img {
  473. margin: 0 12rpx;
  474. width: 40rpx;
  475. height: 40rpx;
  476. }
  477. }
  478. .recording_icon {
  479. margin-left: auto;
  480. margin-right: 35rpx;
  481. font-size: 40rpx;
  482. }
  483. }
  484. .popup_recording {
  485. width: 100%;
  486. height: 460rpx;
  487. background-color: #fff;
  488. }
  489. .detail_box {
  490. box-sizing: border-box;
  491. margin-bottom: 46rpx;
  492. padding: 5rpx 30rpx 0;
  493. width: 690rpx;
  494. height: 284rpx;
  495. border-radius: 9rpx;
  496. box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
  497. .detail_box_item {
  498. display: flex;
  499. justify-content: space-between;
  500. align-items: center;
  501. height: 92rpx;
  502. font-size: 32rpx;
  503. border-bottom: 1rpx solid #e5e5e5;
  504. .item_key {
  505. width: 150rpx;
  506. color: #808080;
  507. }
  508. .item_value {
  509. font-weight: bold;
  510. input {
  511. text-align: right;
  512. }
  513. }
  514. }
  515. }
  516. .add {
  517. display: flex;
  518. justify-content: center;
  519. align-items: center;
  520. width: 690rpx;
  521. height: 90rpx;
  522. color: #6fb6b8;
  523. font-size: 32rpx;
  524. border-radius: 9rpx;
  525. background-color: #ebf2f2;
  526. text {
  527. margin-right: 10rpx;
  528. font-size: 48rpx;
  529. }
  530. }
  531. .total {
  532. display: flex;
  533. justify-content: space-between;
  534. align-items: center;
  535. margin: auto;
  536. width: 622rpx;
  537. height: 100rpx;
  538. font-size: 32rpx;
  539. font-weight: bold;
  540. border-bottom: 1rpx solid #e5e5e5;
  541. }
  542. .box {
  543. display: flex;
  544. align-items: center;
  545. height: 94rpx;
  546. font-size: 32rpx;
  547. border-radius: 10rpx;
  548. border: 1rpx solid #cccccc;
  549. img {
  550. margin: 0 14rpx 0 30rpx;
  551. width: 40rpx;
  552. height: 40rpx;
  553. }
  554. }
  555. .btn {
  556. display: flex;
  557. justify-content: center;
  558. align-items: center;
  559. margin: 65rpx 0 60rpx;
  560. height: 100rpx;
  561. color: #fff;
  562. font-size: 32rpx;
  563. border-radius: 12rpx;
  564. background-color: #6fb6b8;
  565. }
  566. }
  567. </style>