PatrolWorkOrderForm.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. <template>
  2. <view>
  3. <cu-custom :backUrl="'/pages/index/index?id=apps'" :isBack="true" bgColor="bg-gradual-blue" v-if="!nodeFlag">
  4. <block slot="content">建筑垃圾巡视</block>
  5. </cu-custom>
  6. <!-- First Section: 巡视工单 to 联系方式 -->
  7. <view class="form-section">
  8. <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="!nodeFlag">
  9. <u-form-item label="巡视工单" prop="no">
  10. <u--input v-model="inputForm.no" :disabled="true" placeholder="工单编号" clearable></u--input>
  11. </u-form-item>
  12. <u-form-item label="处理单位" borderBottom prop="processingUnit" :required="true" v-if="!disFlag">
  13. <jp-picker v-model="inputForm.processingUnit" rangeKey="label" rangeValue="value" :range="processingUnits" @input="getOfficeOnHamlet"></jp-picker>
  14. </u-form-item>
  15. <u-form-item label="处理单位" borderBottom prop="processingUnitName" :required="true" v-else-if="disFlag">
  16. <u--input v-model="inputForm.processingUnitName" :disabled="true" placeholder="处理单位" clearable></u--input>
  17. </u-form-item>
  18. <u-form-item label="村负责人" prop="clearUserName">
  19. <u--input v-model="inputForm.clearUserName" :disabled="true" placeholder="村负责人" clearable></u--input>
  20. </u-form-item>
  21. <u-form-item label="联系方式" prop="clearUserMobile">
  22. <u--input v-model="inputForm.clearUserMobile" :disabled="true" placeholder="联系方式" clearable></u--input>
  23. </u-form-item>
  24. </u--form>
  25. <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="nodeFlag">
  26. <u-form-item label="巡视工单" prop="no">
  27. <u--input v-model="inputForm.no" :disabled="true" placeholder="工单编号" clearable></u--input>
  28. </u-form-item>
  29. <u-form-item label="处理单位" borderBottom prop="processingUnit" :required="true" v-if="!disFlag">
  30. <jp-picker v-model="inputForm.processingUnit" rangeKey="label" rangeValue="value" :range="processingUnits" @input="getOfficeOnHamlet"></jp-picker>
  31. </u-form-item>
  32. <u-form-item label="处理单位" borderBottom prop="processingUnitName" :required="true" v-else-if="disFlag">
  33. <u--input v-model="inputForm.processingUnitName" :disabled="true" placeholder="处理单位" clearable></u--input>
  34. </u-form-item>
  35. <u-form-item label="村负责人" prop="clearUserName">
  36. <u--input v-model="inputForm.clearUserName" :disabled="true" placeholder="村负责人" clearable></u--input>
  37. </u-form-item>
  38. <u-form-item label="联系方式" prop="clearUserMobile">
  39. <u--input v-model="inputForm.clearUserMobile" :disabled="true" placeholder="联系方式" clearable></u--input>
  40. </u-form-item>
  41. </u--form>
  42. </view>
  43. <!-- Second Section: 上传图片 -->
  44. <view class="form-section" v-if="!nodeFlag">
  45. <text class="u-demo-block__title">现场照片</text>
  46. <view class="u-page__upload-item">
  47. <u-upload
  48. :fileList="fileList1"
  49. @afterRead="afterRead"
  50. @delete="deletePic"
  51. name="1"
  52. multiple
  53. :maxCount="10"
  54. ></u-upload>
  55. </view>
  56. </view>
  57. <!-- Second Section: 上传图片 -->
  58. <view class="form-section" v-if="nodeFlag">
  59. <text class="u-demo-block__title">清理前照片</text>
  60. <view class="u-page__upload-item">
  61. <u-upload
  62. :disabled="true"
  63. :fileList="fileList1"
  64. name="1"
  65. multiple
  66. :maxCount="10"
  67. ></u-upload>
  68. </view>
  69. </view>
  70. <!-- Second Section: 上传图片 -->
  71. <view class="form-section" v-if="nodeFlag">
  72. <text class="u-demo-block__title">清理中照片</text>
  73. <view class="u-page__upload-item" v-if="showFlag">
  74. <u-upload
  75. :disabled="true"
  76. :fileList="fileList2"
  77. name="2"
  78. multiple
  79. :maxCount="10"
  80. ></u-upload>
  81. </view>
  82. <view class="u-page__upload-item" v-else>
  83. <u-upload
  84. :fileList="fileList2"
  85. @afterRead="afterRead"
  86. @delete="deletePic"
  87. name="2"
  88. multiple
  89. :maxCount="10"
  90. ></u-upload>
  91. </view>
  92. </view>
  93. <!-- Second Section: 上传图片 -->
  94. <view class="form-section" v-if="nodeFlag">
  95. <text class="u-demo-block__title">清理后照片</text>
  96. <view class="u-page__upload-item" v-if="showFlag">
  97. <u-upload
  98. :disabled="true"
  99. :fileList="fileList3"
  100. name="3"
  101. multiple
  102. :maxCount="10"
  103. ></u-upload>
  104. </view>
  105. <view class="u-page__upload-item" v-else>
  106. <u-upload
  107. :fileList="fileList3"
  108. @afterRead="afterRead"
  109. @delete="deletePic"
  110. name="3"
  111. multiple
  112. :maxCount="10"
  113. ></u-upload>
  114. </view>
  115. </view>
  116. <!-- Third Section: 备注 -->
  117. <view class="form-section">
  118. <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="!nodeFlag">
  119. <u-form-item label="备注" borderBottom prop="remarks">
  120. <u--textarea placeholder='请填写备注' :maxlength="500" v-model="inputForm.remarks"></u--textarea>
  121. </u-form-item>
  122. <!--<view class="button-container">
  123. <u-button
  124. text="提交"
  125. size="large"
  126. type="primary"
  127. @click="saveForm"
  128. ></u-button>
  129. </view>-->
  130. <!-- 遮罩层 -->
  131. <view v-if="isProcessing" class="mask"></view>
  132. </u--form>
  133. <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="nodeFlag">
  134. <u-form-item label="备注" borderBottom prop="remarks">
  135. <u--textarea placeholder='请填写备注' :maxlength="500" :disabled="true" v-model="inputForm.remarks"></u--textarea>
  136. </u-form-item>
  137. <view class="button-container" v-if="!showFlag">
  138. <u-button
  139. text="确认"
  140. size="large"
  141. type="primary"
  142. @click="savePhoto"
  143. ></u-button>
  144. </view>
  145. </u--form>
  146. </view>
  147. </view>
  148. </template>
  149. <script>
  150. import overService from '@/api/garbageClearance/overService'
  151. import {mapState, mapMutations, mapActions} from 'vuex'
  152. import * as $auth from "../../common/auth";
  153. import { EventBus } from '@/store/eventBus.js';
  154. export default {
  155. components: {
  156. },
  157. computed: mapState({
  158. userInfo: (state) => state.user.userInfo,
  159. avatar: (state) => state.user.avatar
  160. }),
  161. data () {
  162. return {
  163. disFlag: true, // 启用动态获取处理单位则设置为false
  164. showFlag: false,
  165. isProcessing: false, // 遮罩层
  166. uploadFlag: true, // 上传判定值
  167. processingUnits: [],
  168. fileList1: [],
  169. fileList2: [],
  170. fileList3: [],
  171. nodeFlag: false,
  172. inputForm: {
  173. id: '',
  174. no: '',
  175. processingUnit: '',
  176. processingUnitName: '',
  177. clearUserId: '',
  178. clearUserName: '',
  179. clearUserMobile: '',
  180. remarks: '',
  181. },
  182. rules: {
  183. 'processingUnit': [
  184. {
  185. required: true,
  186. message: '处理单位不能为空',
  187. trigger: ['blur', 'change']
  188. }
  189. ],
  190. }
  191. }
  192. },
  193. // 页面加载时执行
  194. async created() {
  195. if('乡镇巡查员' === this.userInfo.roleNames){
  196. this.disFlag = false
  197. // 不动态获取 根据当前登录人去查
  198. await overService.getOfficeOnHamlet()
  199. .then(data => {
  200. this.processingUnits = []
  201. for (const value of data) {
  202. this.processingUnits.push({
  203. label: value.officeName,
  204. value: value.officeId
  205. });
  206. }
  207. })
  208. .catch(e => {
  209. throw e;
  210. });
  211. }
  212. if(!this.nodeFlag){
  213. let data = await overService.getMaxNo();
  214. this.inputForm.no = data;
  215. /*if (data) {
  216. let newNo = parseInt(data, 10) + 1;
  217. this.inputForm.no = 'XS-J' + newNo;
  218. } else {
  219. // 获取当前年份
  220. let nowY = new Date().getFullYear();
  221. this.inputForm.no = 'XS-J' + nowY + '0001';
  222. }*/
  223. // 如果要使用动态获取处理单位则设置为true
  224. if (false) {
  225. let units = await overService.getProcessingUnit();
  226. let childs = units[0].children;
  227. if (childs) {
  228. this.processingUnits = []; // 初始化数组
  229. for (let i = 0; i < childs.length; i++) {
  230. this.processingUnits.push({
  231. label: childs[i].name,
  232. value: childs[i].id
  233. });
  234. }
  235. }
  236. }
  237. this.inputForm.processingUnit = this.userInfo.officeDTO.id
  238. this.inputForm.processingUnitName = this.userInfo.officeDTO.name
  239. // 不动态获取 根据当前登录人去查
  240. await overService.getUserInfoByOffId(this.userInfo.officeDTO.id)
  241. .then(data => {
  242. this.inputForm.clearUserId = data.id
  243. this.inputForm.clearUserName = data.name
  244. this.inputForm.clearUserMobile = data.mobile
  245. })
  246. .catch(e => {
  247. throw e;
  248. });
  249. }
  250. },
  251. props: {
  252. businessId: {
  253. type: String,
  254. default: ''
  255. },
  256. formReadOnly: {
  257. type: Boolean,
  258. default: false
  259. },
  260. status: {
  261. type: String,
  262. default: ''
  263. }
  264. },
  265. watch: {
  266. 'businessId': {
  267. handler (newVal) {
  268. if (this.businessId) {
  269. this.init(this.businessId)
  270. } else {
  271. this.$nextTick(() => {
  272. // this.$refs.inputForm.reset()
  273. })
  274. }
  275. },
  276. immediate: true,
  277. deep: false
  278. },
  279. },
  280. onLoad(options) {
  281. // 从 options 中获取 id 参数
  282. this.showFlag = options.showFlag;
  283. this.id = options.id;
  284. // 这里可以调用初始化方法
  285. this.init(this.id);
  286. },
  287. methods: {
  288. async init (id) {
  289. if(id){
  290. this.nodeFlag = true
  291. this.inputForm.id = id
  292. if (id) {
  293. await overService.queryById(id).then((data) => {
  294. this.inputForm = this.recover(this.inputForm, data)
  295. if (data.beforeFileList) {
  296. this.fileList1 = []
  297. data.beforeFileList.forEach(
  298. (item) => {
  299. const newItem = {
  300. attachmentName: item.name,
  301. fileSize: item.size,
  302. url: item.temporaryUrl,
  303. type: item.type, // 如果不需要,可以不写
  304. };
  305. this.fileList1.push(newItem);
  306. }
  307. );
  308. }
  309. if (data.betweenFileList) {
  310. this.fileList2 = []
  311. data.betweenFileList.forEach(
  312. (item) => {
  313. const newItem = {
  314. attachmentName: item.name,
  315. fileSize: item.size,
  316. url: item.temporaryUrl,
  317. type: item.type, // 如果不需要,可以不写
  318. };
  319. this.fileList2.push(newItem);
  320. }
  321. );
  322. }
  323. if (data.afterFileList) {
  324. this.fileList3 = []
  325. data.afterFileList.forEach(
  326. (item) => {
  327. const newItem = {
  328. attachmentName: item.name,
  329. fileSize: item.size,
  330. url: item.temporaryUrl,
  331. type: item.type, // 如果不需要,可以不写
  332. };
  333. this.fileList3.push(newItem);
  334. }
  335. );
  336. }
  337. })
  338. }
  339. }
  340. },
  341. formatDate(date) {
  342. const dateNew = new Date(date); // 将日期字符串转换为 Date 对象
  343. const year = dateNew.getFullYear();
  344. const month = (dateNew.getMonth() + 1).toString().padStart(2, '0');
  345. const day = dateNew.getDate().toString().padStart(2, '0');
  346. return `${year}-${month}-${day}`;
  347. },
  348. isEmpty(value) {
  349. let result = false;
  350. if (value == null || value == undefined) {
  351. result = true;
  352. }
  353. if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
  354. result = true;
  355. }
  356. if (typeof value == "object" && value instanceof Array && value.length === 0) {
  357. result = true;
  358. }
  359. return result;
  360. },
  361. isNotEmpty (value) {
  362. return !this.isEmpty(value)
  363. },
  364. /**
  365. * 判断是否为空
  366. */
  367. isNull(val) {
  368. if (val instanceof Array) {
  369. if (val.length === 0) return true;
  370. } else if (val instanceof Object) {
  371. if (JSON.stringify(val) === "{}") return true;
  372. } else {
  373. if (
  374. val === "null" ||
  375. val == null ||
  376. val === "undefined" ||
  377. val === undefined ||
  378. val === ""
  379. )
  380. return true;
  381. return false;
  382. }
  383. return false;
  384. },
  385. formatDateNew(date) {
  386. const year = date.getFullYear();
  387. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  388. const day = date.getDate().toString().padStart(2, '0');
  389. const hours = date.getHours().toString().padStart(2, '0');
  390. const minutes = date.getMinutes().toString().padStart(2, '0');
  391. const seconds = date.getSeconds().toString().padStart(2, '0');
  392. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  393. },
  394. saveForm(callback) {
  395. this.isProcessing = true; // 显示遮罩层
  396. return new Promise((resolve, reject) => {
  397. // 表单规则验证
  398. // ...
  399. let errors = [];
  400. if(!this.uploadFlag){
  401. errors.push("图片未上传完成,请等待上传完后在提交")
  402. }
  403. if (this.fileList1 && this.fileList1.length > 0) {
  404. // 将 fileList1 中的每个文件对象的属性名调整为新的属性名
  405. this.inputForm.fileList1 = this.fileList1.map(file => {
  406. return {
  407. attachmentName: file.name,
  408. fileSize: file.size,
  409. url: file.url,
  410. type: file.type, // 如果不需要,可以不写
  411. attachmentFlag: 'before', // 如果不需要,可以不写
  412. };
  413. });
  414. }
  415. if (errors.length > 0) {
  416. // 存在错误,显示提示信息
  417. errors.forEach(error => {
  418. uni.showToast({
  419. title: error,
  420. icon: 'none',
  421. duration: 2000
  422. });
  423. });
  424. this.isProcessing = false;
  425. reject('Form validation failed');
  426. } else {
  427. // 所有验证通过,执行保存操作
  428. this.$refs.inputForm.validate().then(() => {
  429. uni.showLoading();
  430. this.inputForm.status = '2'
  431. overService.save(this.inputForm).then(data => {
  432. uni.showToast({
  433. title: "提交成功",
  434. icon: "success",
  435. duration: 1000 // 提示持续时间为1秒(1000毫秒)
  436. });
  437. // 延迟1秒后再跳转到上一页
  438. setTimeout(() => {
  439. this.isProcessing = false; // 显示遮罩层
  440. this.inputForm.assignee = this.inputForm.clearUserId
  441. callback(data.businessTable, data.businessId,this.inputForm);
  442. resolve('Form saved successfully');
  443. uni.navigateBack({
  444. delta: 1
  445. });
  446. }, 1000);
  447. }).catch(error => {
  448. reject('Save operation failed');
  449. });
  450. }).catch(() => {
  451. reject('Form validation failed');
  452. });
  453. }
  454. });
  455. },
  456. savePhoto() {
  457. return new Promise((resolve, reject) => {
  458. let errors = [];
  459. if(!this.uploadFlag){
  460. errors.push("图片未上传完成,请等待上传完后在提交")
  461. }
  462. if (this.fileList2 && this.fileList2.length > 0) {
  463. // 将 fileList1 中的每个文件对象的属性名调整为新的属性名
  464. this.inputForm.fileList2 = this.fileList2.map(file => {
  465. return {
  466. attachmentName: file.name,
  467. fileSize: file.size,
  468. url: file.url,
  469. type: file.type, // 如果不需要,可以不写
  470. attachmentFlag: 'between', // 如果不需要,可以不写
  471. };
  472. });
  473. }
  474. if (this.fileList3 && this.fileList3.length > 0) {
  475. // 将 fileList1 中的每个文件对象的属性名调整为新的属性名
  476. this.inputForm.fileList3 = this.fileList3.map(file => {
  477. return {
  478. attachmentName: file.name,
  479. fileSize: file.size,
  480. url: file.url,
  481. type: file.type, // 如果不需要,可以不写
  482. attachmentFlag: 'after', // 如果不需要,可以不写
  483. };
  484. });
  485. }
  486. if (errors.length > 0) {
  487. // 存在错误,显示提示信息
  488. errors.forEach(error => {
  489. uni.showToast({
  490. title: error,
  491. icon: 'none',
  492. duration: 2000
  493. });
  494. });
  495. this.isProcessing = false;
  496. reject('Form validation failed');
  497. } else {
  498. //数据保存
  499. this.$refs.inputForm.validate().then(() => {
  500. uni.showLoading();
  501. overService.savePhoto(this.inputForm).then(data => {
  502. EventBus.$emit('refreshPhoto');
  503. uni.showToast({
  504. title: "提交成功",
  505. icon: "success",
  506. duration: 1000 // 提示持续时间为1秒(1000毫秒)
  507. });
  508. // 延迟1秒后再跳转到上一页
  509. setTimeout(() => {
  510. this.isProcessing = false; // 显示遮罩层
  511. resolve('Form saved successfully');
  512. uni.navigateBack({
  513. delta: 1
  514. });
  515. }, 1000);
  516. }).catch(error => {
  517. reject('Save operation failed');
  518. });
  519. }).catch(() => {
  520. reject('Form validation failed');
  521. });
  522. }
  523. });
  524. },
  525. // 删除图片
  526. deletePic(event) {
  527. this[`fileList${event.name}`].splice(event.index, 1)
  528. },
  529. // 新增图片
  530. async afterRead(event) {
  531. try {
  532. this.uploadFlag = false
  533. // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
  534. let lists = [].concat(event.file)
  535. let fileListLen = this[`fileList${event.name}`].length
  536. lists.map((item) => {
  537. this[`fileList${event.name}`].push({
  538. ...item,
  539. status: 'uploading',
  540. message: '上传中'
  541. })
  542. })
  543. for (let i = 0; i < lists.length; i++) {
  544. const result = await this.uploadFilePromise(lists[i].url, fileListLen)
  545. let item = this[`fileList${event.name}`][fileListLen]
  546. this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
  547. status: 'success',
  548. message: '',
  549. url: result
  550. }))
  551. fileListLen++
  552. }
  553. this.uploadFlag = true
  554. } catch (error) {
  555. console.error('上传失败:', error);
  556. } finally {
  557. this.uploadFlag = true
  558. }
  559. },
  560. uploadFilePromise(url, index) {
  561. return new Promise((resolve, reject) => {
  562. let a = uni.uploadFile({
  563. url: 'http://dttz.xgccpm.cn/api/app/file/webUpload/fileUpload', // 仅为示例,非真实的接口地址
  564. filePath: url,
  565. name: 'file',
  566. formData: {
  567. user: this.$store.state.user.userInfo
  568. },
  569. header: {
  570. 'token': $auth.getUserToken(),
  571. },
  572. success: (res) => {
  573. // this.fileList1[index].url = url
  574. setTimeout(() => {
  575. const dataObj = JSON.parse(res.data);
  576. const url = dataObj.url;
  577. resolve(url);
  578. }, 1000);
  579. },
  580. fail: (err) => {
  581. console.error('Upload failed:', err);
  582. }
  583. });
  584. })
  585. },
  586. getOfficeOnHamlet(value){
  587. // 根据组织ID 获取 该村的 村支书
  588. overService.getUserInfoByOffId(value)
  589. .then(data => {
  590. this.inputForm.clearUserId = data.id
  591. this.inputForm.clearUserName = data.name
  592. this.inputForm.clearUserMobile = data.mobile
  593. })
  594. .catch(e => {
  595. throw e;
  596. });
  597. }
  598. }
  599. }
  600. </script>
  601. <style>
  602. .form-section {
  603. padding: 10px 15px;
  604. margin-bottom: 10px;
  605. background-color: #ffffff;
  606. border-radius: 5px;
  607. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  608. }
  609. .u-page__upload-item {
  610. margin-top: 10px;
  611. }
  612. .button-container {
  613. margin-top: 20px;
  614. text-align: center;
  615. }
  616. .cu-form-group .title {
  617. min-width: 100px;
  618. }
  619. /* 遮罩层样式 */
  620. .mask {
  621. position: fixed;
  622. top: 0;
  623. left: 0;
  624. width: 100%;
  625. height: 100%;
  626. background-color: rgba(0, 0, 0, 0.05); /* 半透明遮罩 */
  627. z-index: 9999; /* 确保遮罩层在最顶层 */
  628. }
  629. </style>