baoxiudj.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. const app = getApp();
  2. Page({
  3. data: {
  4. address: app.globalData.currentAccountInfo.address,
  5. contact: '',
  6. phone: '',
  7. repairType: '',
  8. repairTypeValue: '',
  9. repairTypeMap: [
  10. {name: '换表', value: '1'},
  11. {name: '换前阀', value: '2'},
  12. {name: '换后阀', value: '3'},
  13. {name: '换前后阀', value: '4'},
  14. {name: '其他', value: '5'}
  15. ],
  16. description: '',
  17. imageList: [],
  18. showNotification: true,
  19. countDown: 3,
  20. isFormValid: false,
  21. isPreviewMode: false,
  22. replyTime: '',
  23. replyContent: '',
  24. id: '',
  25. mode: '',
  26. isReplied: false,
  27. formSubmitted: false,
  28. isSubmitting: false, // 新增保存标志位
  29. lastSubmitTime: 0, // 上次提交时间(通过防抖(Debounce)技术,限制用户在一定时间内只能提交一次。)
  30. },
  31. onLoad: function (options) {
  32. const isReplied = options.isReplied === 'true';
  33. // 更新地址信息,确保是最新的户号地址
  34. this.setData({
  35. address: app.globalData.currentAccountInfo.address
  36. });
  37. if (options.mode === 'preview') {
  38. this.setData({
  39. isPreviewMode: true,
  40. showNotification: false,
  41. id: options.id,
  42. mode: options.mode,
  43. isReplied: isReplied
  44. });
  45. this.loadPreviewData(options.id);
  46. } else {
  47. this.startCountDown();
  48. this.setData({
  49. id: options.id || '',
  50. mode: options.mode || '',
  51. isReplied: isReplied
  52. });
  53. }
  54. },
  55. startCountDown: function () {
  56. let that = this;
  57. let timer = setInterval(function () {
  58. if (that.data.countDown > 0) {
  59. that.setData({
  60. countDown: that.data.countDown - 1
  61. });
  62. } else {
  63. clearInterval(timer);
  64. }
  65. }, 1000);
  66. },
  67. closeNotification: function () {
  68. if (this.data.countDown <= 0) {
  69. this.setData({
  70. showNotification: false
  71. });
  72. }
  73. },
  74. goBack: function () {
  75. wx.navigateBack();
  76. },
  77. inputContact: function (e) {
  78. this.setData({
  79. contact: e.detail.value
  80. });
  81. this.checkFormValidity();
  82. },
  83. inputPhone: function (e) {
  84. const value = e.detail.value;
  85. const phoneNumber = value.replace(/\D/g, '');
  86. this.setData({
  87. phone: phoneNumber
  88. });
  89. this.checkFormValidity();
  90. },
  91. validatePhone: function (phone) {
  92. const phoneReg = /^1[3-9]\d{9}$/;
  93. return phoneReg.test(phone);
  94. },
  95. showRepairTypeSelector: function () {
  96. let that = this;
  97. // 只显示名称列表
  98. const typeNames = this.data.repairTypeMap.map(item => item.name);
  99. wx.showActionSheet({
  100. itemList: typeNames,
  101. success: function (res) {
  102. const selectedType = that.data.repairTypeMap[res.tapIndex];
  103. that.setData({
  104. repairType: selectedType.name,
  105. repairTypeValue: selectedType.value
  106. });
  107. that.checkFormValidity();
  108. }
  109. });
  110. },
  111. inputDescription: function (e) {
  112. this.setData({
  113. description: e.detail.value
  114. });
  115. this.checkFormValidity();
  116. },
  117. chooseImage: function () {
  118. let that = this;
  119. if (that.data.imageList.length >= 10) {
  120. wx.showToast({
  121. title: '最多只能上传10张图片',
  122. icon: 'none'
  123. });
  124. return;
  125. }
  126. wx.chooseMedia({
  127. count: 10 - that.data.imageList.length,
  128. mediaType: ['image'],
  129. sourceType: ['album', 'camera'],
  130. sizeType: ['compressed'],
  131. success: function (res) {
  132. let tempFiles = res.tempFiles;
  133. let validFiles = [];
  134. for (let i = 0; i < tempFiles.length; i++) {
  135. const file = tempFiles[i];
  136. if (file.size <= 10 * 1024 * 1024) {
  137. validFiles.push(file);
  138. } else {
  139. wx.showToast({
  140. title: '图片大小不能超过10M',
  141. icon: 'none'
  142. });
  143. }
  144. }
  145. if (validFiles.length > 0) {
  146. wx.showLoading({
  147. title: '图片压缩中...',
  148. mask: true
  149. });
  150. let processedFiles = new Array(validFiles.length);
  151. let processCount = 0;
  152. // 处理每个图片
  153. validFiles.forEach((file, index) => {
  154. that.compressImage(file.tempFilePath).then(compressedPath => {
  155. processCount++;
  156. // 获取压缩后图片的信息
  157. wx.getFileInfo({
  158. filePath: compressedPath,
  159. success: (fileInfo) => {
  160. console.log('原始大小:', file.size / 1024, 'KB');
  161. console.log('压缩后大小:', fileInfo.size / 1024, 'KB');
  162. // 在对应位置添加压缩后的图片路径
  163. processedFiles[index] = {
  164. tempFilePath: compressedPath,
  165. size: fileInfo.size
  166. };
  167. // 检查是否所有图片都已处理完成
  168. if (processCount === validFiles.length) {
  169. // 过滤掉可能的空值,并按顺序合并
  170. let newImageList = that.data.imageList.concat(processedFiles.filter(item => item));
  171. that.setData({
  172. imageList: newImageList
  173. });
  174. wx.hideLoading();
  175. }
  176. },
  177. fail: (err) => {
  178. console.error('获取文件信息失败:', err);
  179. processCount++;
  180. // 如果失败,也要检查是否处理完所有图片
  181. if (processCount === validFiles.length) {
  182. wx.hideLoading();
  183. }
  184. }
  185. });
  186. }).catch(err => {
  187. console.error('图片压缩失败:', err);
  188. processCount++;
  189. if (processCount === validFiles.length) {
  190. wx.hideLoading();
  191. }
  192. });
  193. });
  194. }
  195. }
  196. });
  197. },
  198. // 使用canvas进行图片压缩
  199. compressImage: function(imagePath) {
  200. return new Promise((resolve, reject) => {
  201. // 获取图片信息
  202. wx.getImageInfo({
  203. src: imagePath,
  204. success: (res) => {
  205. // 先获取原图大小,单位KB
  206. wx.getFileInfo({
  207. filePath: imagePath,
  208. success: (fileInfo) => {
  209. const originalSize = fileInfo.size / 1024; // 原始大小,单位KB
  210. // 根据原图大小确定压缩质量
  211. let targetQuality = 0.8; // 默认压缩质量
  212. if (originalSize <= 500) {
  213. // 如果原图已经小于500KB,保持较高质量
  214. targetQuality = 0.9;
  215. } else if (originalSize <= 1024) {
  216. // 1MB以下,适当压缩
  217. targetQuality = 0.7;
  218. } else if (originalSize <= 2048) {
  219. // 2MB以下,中等压缩
  220. targetQuality = 0.5;
  221. } else if (originalSize <= 5120) {
  222. // 5MB以下,较大压缩
  223. targetQuality = 0.3;
  224. } else {
  225. // 超过5MB,大幅压缩
  226. targetQuality = 0.2;
  227. }
  228. wx.createSelectorQuery()
  229. .select('#compressCanvas')
  230. .fields({ node: true, size: true })
  231. .exec((canvasRes) => {
  232. if (!canvasRes || !canvasRes[0] || !canvasRes[0].node) {
  233. // 如果找不到canvas节点,则返回原图
  234. resolve(imagePath);
  235. return;
  236. }
  237. const canvas = canvasRes[0].node;
  238. const ctx = canvas.getContext('2d');
  239. const image = canvas.createImage();
  240. image.onload = () => {
  241. // 计算要缩放的尺寸,保持宽高比
  242. let ratio = 1;
  243. // 根据原图大小调整尺寸
  244. if (originalSize > 5120) { // 5MB以上
  245. ratio = Math.min(1, 1200 / res.width, 1200 / res.height);
  246. } else if (originalSize > 2048) { // 2MB以上
  247. ratio = Math.min(1, 1500 / res.width, 1500 / res.height);
  248. } else if (originalSize > 1024) { // 1MB以上
  249. ratio = Math.min(1, 1800 / res.width, 1800 / res.height);
  250. } else {
  251. ratio = Math.min(1, 2000 / res.width, 2000 / res.height);
  252. }
  253. const targetWidth = Math.round(res.width * ratio);
  254. const targetHeight = Math.round(res.height * ratio);
  255. // 设置canvas尺寸
  256. canvas.width = targetWidth;
  257. canvas.height = targetHeight;
  258. // 清除画布
  259. ctx.clearRect(0, 0, targetWidth, targetHeight);
  260. // 绘制图片
  261. ctx.drawImage(image, 0, 0, targetWidth, targetHeight);
  262. // 压缩参数
  263. const compressOptions = {
  264. canvas: canvas,
  265. width: targetWidth,
  266. height: targetHeight,
  267. destWidth: targetWidth,
  268. destHeight: targetHeight,
  269. fileType: 'jpg',
  270. quality: targetQuality
  271. };
  272. // 第一次尝试压缩
  273. const tryCompress = (quality, attempt = 1) => {
  274. compressOptions.quality = quality;
  275. wx.canvasToTempFilePath({
  276. ...compressOptions,
  277. success: (result) => {
  278. // 检查压缩后的大小
  279. wx.getFileInfo({
  280. filePath: result.tempFilePath,
  281. success: (compressedInfo) => {
  282. const compressedSize = compressedInfo.size / 1024; // 压缩后大小,单位KB
  283. console.log(`压缩后大小 (质量:${quality})`, compressedSize, 'KB');
  284. // 如果压缩后大小仍大于500KB且尝试次数未达上限,继续压缩
  285. if (compressedSize > 500 && attempt < 3) {
  286. // 递减质量
  287. const newQuality = Math.max(0.1, quality - 0.2);
  288. console.log(`尝试重新压缩,质量降低至${newQuality}`);
  289. tryCompress(newQuality, attempt + 1);
  290. }
  291. // 如果压缩后小于200KB且质量非最高,尝试提高质量
  292. else if (compressedSize < 200 && quality < 0.9 && attempt < 3) {
  293. // 递增质量
  294. const newQuality = Math.min(0.9, quality + 0.2);
  295. console.log(`尝试重新压缩,质量提高至${newQuality}`);
  296. tryCompress(newQuality, attempt + 1);
  297. }
  298. else {
  299. // 返回压缩后的图片
  300. resolve(result.tempFilePath);
  301. }
  302. },
  303. fail: (error) => {
  304. console.error('获取压缩后图片信息失败:', error);
  305. resolve(result.tempFilePath);
  306. }
  307. });
  308. },
  309. fail: (error) => {
  310. console.error('Canvas转图片失败:', error);
  311. // 如果转换失败则返回原图
  312. resolve(imagePath);
  313. }
  314. });
  315. };
  316. // 开始尝试压缩
  317. tryCompress(targetQuality);
  318. };
  319. image.onerror = () => {
  320. console.error('图片加载失败');
  321. resolve(imagePath);
  322. };
  323. image.src = imagePath;
  324. });
  325. },
  326. fail: (error) => {
  327. console.error('获取原始图片信息失败:', error);
  328. resolve(imagePath);
  329. }
  330. });
  331. },
  332. fail: (error) => {
  333. console.error('获取图片信息失败:', error);
  334. resolve(imagePath);
  335. }
  336. });
  337. });
  338. },
  339. previewImage: function (e) {
  340. let index = e.currentTarget.dataset.index;
  341. wx.previewImage({
  342. current: this.data.imageList[index],
  343. urls: this.data.imageList
  344. });
  345. },
  346. deleteImage: function (e) {
  347. let index = e.currentTarget.dataset.index;
  348. let imageList = this.data.imageList;
  349. imageList.splice(index, 1);
  350. this.setData({
  351. imageList: imageList
  352. });
  353. },
  354. checkFormValidity: function () {
  355. const {
  356. contact,
  357. phone,
  358. address,
  359. repairType,
  360. repairTypeValue,
  361. description
  362. } = this.data;
  363. const hasAddress = address && address.trim() !== '';
  364. const hasContact = contact && contact.trim() !== '';
  365. const hasPhone = phone && phone.trim() !== '';
  366. const hasValidPhone = this.validatePhone(phone);
  367. const hasRepairType = repairType && repairType.trim() !== '';
  368. const hasRepairTypeValue = repairTypeValue && repairTypeValue.trim() !== '';
  369. const hasDescription = description && description.trim() !== '';
  370. const isValid = hasAddress && hasContact && hasPhone && hasValidPhone && hasRepairType && hasRepairTypeValue && hasDescription;
  371. this.setData({
  372. isFormValid: isValid
  373. });
  374. return isValid;
  375. },
  376. onInputChange: function (e) {
  377. const {
  378. field
  379. } = e.currentTarget.dataset;
  380. const {
  381. value
  382. } = e.detail;
  383. this.setData({
  384. [field]: value
  385. });
  386. this.checkFormValidity();
  387. },
  388. bindPickerChange: function (e) {
  389. this.checkFormValidity();
  390. },
  391. submitRepair: function () {
  392. if (!this.checkFormValidity()) {
  393. wx.showToast({
  394. title: '请填写完整信息',
  395. icon: 'none'
  396. });
  397. return;
  398. }
  399. if (!this.validatePhone(this.data.phone)) {
  400. wx.showToast({
  401. title: '请输入正确的手机号',
  402. icon: 'none'
  403. });
  404. return;
  405. }
  406. const submitData = {
  407. address: this.data.address,
  408. contact: this.data.contact,
  409. phone: this.data.phone,
  410. repairType: this.data.repairType,
  411. repairTypeValue: this.data.repairTypeValue,
  412. description: this.data.description,
  413. images: this.data.imageList
  414. };
  415. console.log('提交的数据:', submitData);
  416. wx.showLoading({
  417. title: '提交中...',
  418. });
  419. setTimeout(() => {
  420. wx.hideLoading();
  421. wx.showToast({
  422. icon: 'success',
  423. duration: 2000,
  424. success: function () {
  425. setTimeout(() => {
  426. wx.navigateTo({
  427. url: '/pages/baoxiuSuccess/baoxiuSuccess',
  428. });
  429. }, 2000);
  430. }
  431. });
  432. }, 1500);
  433. },
  434. loadPreviewData: function (id) {
  435. wx.showLoading({
  436. title: '加载中...',
  437. });
  438. // 从上一个页面获取数据
  439. const pages = getCurrentPages();
  440. const prevPage = pages[pages.length - 2]; // 获取上一个页面
  441. if (prevPage && prevPage.data && prevPage.data.noticeList) {
  442. // 根据id查找对应的报修项
  443. const item = prevPage.data.noticeList.find(item => item.id == id);
  444. debugger
  445. if (item) {
  446. // 找到对应的报修类型名称
  447. let repairTypeName = '';
  448. const repairTypeValue = item.repairtype || '';
  449. const repairTypeItem = this.data.repairTypeMap.find(type => type.name === repairTypeValue);
  450. if (repairTypeItem) {
  451. repairTypeName = repairTypeItem.name;
  452. }
  453. // 格式化时间
  454. const formatTime = (timeString) => {
  455. if (!timeString) return ''; // 如果时间为空,返回空字符串
  456. const date = new Date(timeString);
  457. const year = date.getFullYear();
  458. const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份补零
  459. const day = String(date.getDate()).padStart(2, '0'); // 日期补零
  460. return `${year}-${month}-${day}`;
  461. };
  462. this.setData({
  463. address: item.address || '',
  464. contact: item.contact || '',
  465. phone: item.contactnumber || '',
  466. repairType: repairTypeName,
  467. repairTypeValue: repairTypeValue,
  468. description: item.faultdescription || '',
  469. imageList: item.attachments || [],
  470. replyTime: item.isReplied ? formatTime(item.repairtime) : '',
  471. replyContent: item.isReplied ? item.remark : ''
  472. });
  473. }
  474. }
  475. wx.hideLoading();
  476. },
  477. submitForm: function () {
  478. // 如果正在提交中,直接返回
  479. if (this.data.isSubmitting) {
  480. return;
  481. }
  482. if (!this.data.address || this.data.address.trim() === '') {
  483. wx.showToast({
  484. title: '请填写地址',
  485. icon: 'none'
  486. });
  487. this.setData({
  488. isSubmitting: false
  489. });
  490. return;
  491. }
  492. if (!this.data.contact || this.data.contact.trim() === '') {
  493. wx.showToast({
  494. title: '请填写联系人',
  495. icon: 'none'
  496. });
  497. this.setData({
  498. isSubmitting: false
  499. });
  500. return;
  501. }
  502. if (!this.data.phone || this.data.phone.trim() === '') {
  503. wx.showToast({
  504. title: '请填写联系电话',
  505. icon: 'none'
  506. });
  507. this.setData({
  508. isSubmitting: false
  509. });
  510. return;
  511. }
  512. if (!this.validatePhone(this.data.phone)) {
  513. wx.showToast({
  514. title: '请输入正确的手机号',
  515. icon: 'none'
  516. });
  517. this.setData({
  518. isSubmitting: false
  519. });
  520. return;
  521. }
  522. if (!this.data.repairType || this.data.repairType.trim() === '') {
  523. wx.showToast({
  524. title: '请选择报修类型',
  525. icon: 'none'
  526. });
  527. this.setData({
  528. isSubmitting: false
  529. });
  530. return;
  531. }
  532. if (!this.data.repairTypeValue || this.data.repairTypeValue.trim() === '') {
  533. wx.showToast({
  534. title: '请选择报修类型',
  535. icon: 'none'
  536. });
  537. this.setData({
  538. isSubmitting: false
  539. });
  540. return;
  541. }
  542. if (!this.data.description || this.data.description.trim() === '') {
  543. wx.showToast({
  544. title: '请填写故障说明',
  545. icon: 'none'
  546. });
  547. this.setData({
  548. isSubmitting: false
  549. });
  550. return;
  551. }
  552. const now = Date.now();
  553. const lastSubmitTime = this.data.lastSubmitTime;
  554. // 如果距离上次提交时间小于 2 秒,直接返回
  555. if (now - lastSubmitTime < 2000) {
  556. // wx.showToast({
  557. // title: '请勿重复提交',
  558. // icon: 'none',
  559. // });
  560. return;
  561. }
  562. // 更新上次提交时间
  563. this.setData({
  564. lastSubmitTime: now,
  565. });
  566. const fileManager = wx.getFileSystemManager();
  567. this.data.imageList.map(imgInfo => {
  568. const base64 = fileManager.readFileSync(imgInfo.tempFilePath, 'base64');
  569. imgInfo.base64 = base64;
  570. return imgInfo;
  571. })
  572. const submitData = {
  573. address: this.data.address,
  574. contact: this.data.contact,
  575. phone: this.data.phone,
  576. repairType: this.data.repairTypeValue,
  577. description: this.data.description,
  578. images: this.data.imageList,
  579. userName: app.globalData.currentAccountInfo.username,
  580. userNum: app.globalData.currentAccountInfo.usernumber
  581. };
  582. // 设置正在提交中 防止重复点击提交按钮
  583. this.setData({
  584. isSubmitting: true,
  585. });
  586. console.log('提交的数据:', submitData);
  587. wx.showLoading({
  588. title: '提交中...',
  589. mask: true
  590. });
  591. const that = this;
  592. wx.request({
  593. url: app.globalData.interfaceUrls.repairRegistration,
  594. method: 'POST',
  595. header: {
  596. 'content-type': 'application/json', // 默认值
  597. 'token': app.globalData.userWxInfo.token,
  598. 'source': "wc",
  599. '!SAAS_LOGIN_TOKEN_!': app.globalData.currentAccountInfo.dsKey
  600. },
  601. data: submitData,
  602. success(res) {
  603. wx.hideLoading();
  604. if (res.data.code == '200') {
  605. wx.navigateTo({
  606. url: '/pages/baoxiuSuccess/baoxiuSuccess',
  607. });
  608. }
  609. that.setData({
  610. isSubmitting: false
  611. });
  612. },
  613. fail(error) {
  614. wx.hideLoading();
  615. wx.showToast({
  616. title: '登记失败,请稍后再试',
  617. icon: 'none'
  618. });
  619. that.setData({
  620. isSubmitting: false
  621. });
  622. },
  623. complete: () => {
  624. this.setData({
  625. isSubmitting: false, // 提交完成,重置标志位,可继续提交
  626. formSubmitted: true // 在提交成功后设置标记,返回将重置表单
  627. });
  628. },
  629. })
  630. },
  631. inputAddress: function (e) {
  632. this.setData({
  633. address: e.detail.value
  634. });
  635. },
  636. onShow: function () {
  637. // 检查是否是从成功页面返回
  638. if (this.data.formSubmitted) {
  639. // 重置表单数据
  640. this.resetForm();
  641. // 重置提交状态标记
  642. this.setData({
  643. formSubmitted: false
  644. });
  645. } else if (!this.data.isPreviewMode) {
  646. // 非预览模式下,更新地址信息
  647. this.setData({
  648. address: app.globalData.currentAccountInfo.address
  649. });
  650. }
  651. },
  652. // 添加重置表单的方法
  653. resetForm: function () {
  654. this.setData({
  655. contact: '',
  656. phone: '',
  657. repairType: '',
  658. repairTypeValue: '',
  659. description: '',
  660. imageList: []
  661. });
  662. },
  663. });