展品维保小程序前端代码接口
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

646 lines
17 KiB

  1. <template>
  2. <view class="repair-submit">
  3. <!-- 导航栏 -->
  4. <!-- <uv-navbar title="报修提交" :border="false" bg-color="#ffffff" title-color="#333333" /> -->
  5. <!-- 报修基本信息 -->
  6. <view class="repair-info">
  7. <view class="info-header">
  8. <view class="red-line"></view>
  9. <text class="info-title">报修基本信息</text>
  10. </view>
  11. <!-- 报修日期 -->
  12. <view class="form-item">
  13. <text class="label">报修日期</text>
  14. <text class="value">{{ repairDate }}</text>
  15. </view>
  16. <!-- 故障紧急程度 -->
  17. <view class="form-item " @click="showUrgencyPicker">
  18. <text class="label">故障紧急程度</text>
  19. <view class="select-area">
  20. <text class="value" :class="{ placeholder: !urgencyLevel }">{{ urgencyLevel || '请选择' }}</text>
  21. <uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
  22. </view>
  23. </view>
  24. <!-- 故障情况 -->
  25. <view class="form-item form-item-header">
  26. <text class="label active">故障情况</text>
  27. </view>
  28. <!-- 故障情况选择 -->
  29. <view class="form-item" @click="showFaultPicker">
  30. <text class="label">故障情况</text>
  31. <view class="select-area">
  32. <text class="value" :class="{ placeholder: !faultSituation }">{{ faultSituation || '请选择' }}</text>
  33. <uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
  34. </view>
  35. </view>
  36. <!-- 故障情况描述 -->
  37. <view class="form-item">
  38. <text class="label">故障情况描述</text>
  39. </view>
  40. <view class="textarea-container">
  41. <uv-textarea
  42. v-model="faultDescription"
  43. placeholder="请对故障情况进行描述"
  44. :maxlength="200"
  45. :show-confirm-bar="false"
  46. height="60"
  47. border="none"
  48. :custom-style="{ backgroundColor: '#f5f5f5' }"
  49. ></uv-textarea>
  50. </view>
  51. <!-- 故障图片 -->
  52. <view class="form-item">
  53. <text class="label">故障图片</text>
  54. </view>
  55. <view class="image-upload">
  56. <view v-for="(img, index) in imageList" :key="index" class="image-item">
  57. <image :src="img" mode="aspectFill" @click="previewImage(img)"></image>
  58. <view class="delete-btn" @click="deleteImage(index)">
  59. <uv-icon name="close" size="12" color="#fff"></uv-icon>
  60. </view>
  61. </view>
  62. <view class="upload-btn" @click="uploadImage">
  63. <uv-icon name="camera" size="34" color="#C70019"></uv-icon>
  64. </view>
  65. </view>
  66. <!-- 故障首次发生时间 -->
  67. <view class="form-item" @click="showTimePicker">
  68. <text class="label">故障首次发生时间</text>
  69. <view class="select-area">
  70. <text class="value" :class="{ placeholder: !firstOccurTime }">{{ firstOccurTime || '请选择' }}</text>
  71. <uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
  72. </view>
  73. </view>
  74. <!-- 发生频率 -->
  75. <view class="form-item">
  76. <text class="label">发生频率</text>
  77. <view class="radio-options">
  78. <view
  79. v-for="(item, index) in frequencyOptions"
  80. :key="index"
  81. class="radio-item"
  82. :class="{ active: frequency === item.value }"
  83. @click="selectFrequency(item.value)"
  84. >
  85. <view class="radio-dot" :class="{ active: frequency === item.value }"></view>
  86. <text :class="{ active: frequency === item.value }">{{ item.label }}</text>
  87. </view>
  88. </view>
  89. </view>
  90. <!-- 请描述与故障设备发生主要故障的具体条件 -->
  91. <!-- <view class="form-item">
  92. <text class="label">请描述与故障设备发生主要故障的具体条件</text>
  93. </view> -->
  94. <view class="textarea-container">
  95. <uv-textarea
  96. v-model="faultCondition"
  97. placeholder="请填写说明故障发生频率的触发条件"
  98. :maxlength="200"
  99. :show-confirm-bar="false"
  100. height="60"
  101. border="none"
  102. :custom-style="{ backgroundColor: '#f5f5f5' }"
  103. ></uv-textarea>
  104. </view>
  105. <!-- 是否影响使用 -->
  106. <view class="form-item" @click="showImpactPicker">
  107. <text class="label">是否影响使用</text>
  108. <view class="select-area">
  109. <text class="value" :class="{ placeholder: !impactUsage }">{{ impactUsage || '请选择' }}</text>
  110. <uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
  111. </view>
  112. </view>
  113. <!-- 采取的临时措施 -->
  114. <!-- 故障情况 -->
  115. <view class="form-item form-item-header">
  116. <text class="label active">采取的临时措施</text>
  117. </view>
  118. <!-- <view class="form-item">
  119. <text class="label">是否采取临时措施</text>
  120. </view>
  121. <view class="textarea-container">
  122. <uv-textarea
  123. v-model="temporaryMeasures"
  124. placeholder="如有采取临时措施请填写措施说明"
  125. :maxlength="200"
  126. :show-confirm-bar="false"
  127. height="60"
  128. border="none"
  129. :custom-style="{ backgroundColor: '#f5f5f5' }"
  130. ></uv-textarea>
  131. </view> -->
  132. <!-- 是否采取的对措施 -->
  133. <view class="form-item">
  134. <text class="label">是否采取的对措施</text>
  135. <view class="radio-options">
  136. <view
  137. class="radio-item"
  138. :class="{ active: hasTakenMeasures === true }"
  139. @click="selectMeasures(true)"
  140. >
  141. <view class="radio-dot" :class="{ active: hasTakenMeasures === true }"></view>
  142. <text :class="{ active: hasTakenMeasures === true }"></text>
  143. </view>
  144. <view
  145. class="radio-item"
  146. :class="{ active: hasTakenMeasures === false }"
  147. @click="selectMeasures(false)"
  148. >
  149. <view class="radio-dot" :class="{ active: hasTakenMeasures === false }"></view>
  150. <text :class="{ active: hasTakenMeasures === false }"></text>
  151. </view>
  152. </view>
  153. </view>
  154. <view class="textarea-container">
  155. <uv-textarea
  156. v-model="temporaryMeasures"
  157. placeholder="如有采取临时措施请填写措施说明"
  158. :maxlength="200"
  159. :show-confirm-bar="false"
  160. height="60"
  161. border="none"
  162. :custom-style="{ backgroundColor: '#f5f5f5' }"
  163. ></uv-textarea>
  164. </view>
  165. <!-- 是否影响体验 -->
  166. <view class="form-item">
  167. <text class="label">是否影响体验</text>
  168. <view class="radio-options">
  169. <view
  170. class="radio-item"
  171. :class="{ active: impactExperience === true }"
  172. @click="selectExperience(true)"
  173. >
  174. <view class="radio-dot" :class="{ active: impactExperience === true }"></view>
  175. <text :class="{ active: impactExperience === true }"></text>
  176. </view>
  177. <view
  178. class="radio-item"
  179. :class="{ active: impactExperience === false }"
  180. @click="selectExperience(false)"
  181. >
  182. <view class="radio-dot" :class="{ active: impactExperience === false }"></view>
  183. <text :class="{ active: impactExperience === false }"></text>
  184. </view>
  185. </view>
  186. </view>
  187. <!-- 备注 -->
  188. <view class="form-item">
  189. <text class="label">备注</text>
  190. </view>
  191. <view class="textarea-container">
  192. <uv-textarea
  193. v-model="remark"
  194. placeholder="备注"
  195. :maxlength="200"
  196. :show-confirm-bar="false"
  197. height="60"
  198. border="none"
  199. :custom-style="{ backgroundColor: '#f5f5f5' }"
  200. ></uv-textarea>
  201. </view>
  202. </view>
  203. <!-- 提交按钮 -->
  204. <view class="submit-container">
  205. <uv-button
  206. type="primary"
  207. text="立即提交"
  208. :custom-style="{ backgroundColor: '#C70019', borderRadius: '25px' }"
  209. @click="submitRepair"
  210. ></uv-button>
  211. </view>
  212. <!-- 选择器 -->
  213. <uv-picker
  214. confirm-color="#C70019"
  215. ref="urgencyPicker"
  216. :columns="urgencyColumns"
  217. @confirm="confirmUrgency"
  218. @cancel="cancelUrgency"
  219. ></uv-picker>
  220. <uv-picker
  221. confirm-color="#C70019"
  222. ref="faultPicker"
  223. :columns="faultColumns"
  224. @confirm="confirmFault"
  225. @cancel="cancelFault"
  226. ></uv-picker>
  227. <uv-picker
  228. confirm-color="#C70019"
  229. ref="timePicker"
  230. :columns="timeColumns"
  231. @confirm="confirmTime"
  232. @cancel="cancelTime"
  233. ></uv-picker>
  234. <uv-picker
  235. confirm-color="#C70019"
  236. ref="impactPicker"
  237. :columns="impactColumns"
  238. @confirm="confirmImpact"
  239. @cancel="cancelImpact"
  240. ></uv-picker>
  241. </view>
  242. </template>
  243. <script>
  244. export default {
  245. data() {
  246. return {
  247. // 表单数据
  248. repairDate: '2025/03/31',
  249. urgencyLevel: '',
  250. faultSituation: '',
  251. faultDescription: '',
  252. imageList: [],
  253. firstOccurTime: '',
  254. frequency: '',
  255. faultCondition: '',
  256. impactUsage: '',
  257. temporaryMeasures: '',
  258. hasTakenMeasures: null,
  259. impactExperience: null,
  260. remark: '',
  261. // 选择器显示状态(保留用于其他可能的用途)
  262. // showUrgency: false,
  263. // showFault: false,
  264. // showTime: false,
  265. // showImpact: false,
  266. // 频率选项
  267. frequencyOptions: [
  268. { label: '持续性问题', value: 'continuous' },
  269. { label: '间歇性问题', value: 'intermittent' }
  270. ],
  271. // 选择器数据
  272. urgencyColumns: [['一般', '紧急', '非常紧急']],
  273. faultColumns: [['硬件故障', '软件故障', '网络故障', '其他']],
  274. timeColumns: [['今天', '昨天', '一周内', '一个月内', '更早']],
  275. impactColumns: [['是', '否']]
  276. }
  277. },
  278. methods: {
  279. // 显示紧急程度选择器
  280. showUrgencyPicker() {
  281. this.$refs.urgencyPicker.open()
  282. },
  283. // 确认紧急程度
  284. confirmUrgency(e) {
  285. this.urgencyLevel = e.value[0]
  286. },
  287. // 取消紧急程度选择
  288. cancelUrgency() {
  289. // 取消操作
  290. },
  291. // 显示故障情况选择器
  292. showFaultPicker() {
  293. this.$refs.faultPicker.open()
  294. },
  295. // 确认故障情况
  296. confirmFault(e) {
  297. this.faultSituation = e.value[0]
  298. },
  299. // 取消故障情况选择
  300. cancelFault() {
  301. // 取消操作
  302. },
  303. // 显示时间选择器
  304. showTimePicker() {
  305. this.$refs.timePicker.open()
  306. },
  307. // 确认时间
  308. confirmTime(e) {
  309. this.firstOccurTime = e.value[0]
  310. },
  311. // 取消时间选择
  312. cancelTime() {
  313. // 取消操作
  314. },
  315. // 显示影响使用选择器
  316. showImpactPicker() {
  317. this.$refs.impactPicker.open()
  318. },
  319. // 确认影响使用
  320. confirmImpact(e) {
  321. this.impactUsage = e.value[0]
  322. },
  323. // 取消影响使用选择
  324. cancelImpact() {
  325. // 取消操作
  326. },
  327. // 选择频率
  328. selectFrequency(value) {
  329. this.frequency = value
  330. },
  331. // 选择是否采取措施
  332. selectMeasures(value) {
  333. this.hasTakenMeasures = value
  334. },
  335. // 选择是否影响体验
  336. selectExperience(value) {
  337. this.impactExperience = value
  338. },
  339. // 上传图片
  340. async uploadImage() {
  341. try {
  342. const result = await this.$utils.chooseAndUpload()
  343. if (result && result.success) {
  344. console.log(result);
  345. this.imageList.push(result.url)
  346. }
  347. } catch (error) {
  348. console.error('头像上传失败:', error)
  349. uni.showToast({
  350. title: '头像上传失败',
  351. icon: 'error'
  352. })
  353. }
  354. },
  355. // 删除图片
  356. deleteImage(index) {
  357. this.imageList.splice(index, 1)
  358. },
  359. // 预览图片
  360. previewImage(url) {
  361. uni.previewImage({
  362. urls: this.imageList,
  363. current: url
  364. })
  365. },
  366. // 提交报修
  367. submitRepair() {
  368. // 表单验证
  369. if (!this.urgencyLevel) {
  370. uni.showToast({ title: '请选择故障紧急程度', icon: 'none' })
  371. return
  372. }
  373. if (!this.faultSituation) {
  374. uni.showToast({ title: '请选择故障情况', icon: 'none' })
  375. return
  376. }
  377. if (!this.faultDescription.trim()) {
  378. uni.showToast({ title: '请填写故障情况描述', icon: 'none' })
  379. return
  380. }
  381. // 提交数据
  382. const formData = {
  383. repairDate: this.repairDate,
  384. urgencyLevel: this.urgencyLevel,
  385. faultSituation: this.faultSituation,
  386. faultDescription: this.faultDescription,
  387. imageList: this.imageList,
  388. firstOccurTime: this.firstOccurTime,
  389. frequency: this.frequency,
  390. faultCondition: this.faultCondition,
  391. impactUsage: this.impactUsage,
  392. temporaryMeasures: this.temporaryMeasures,
  393. hasTakenMeasures: this.hasTakenMeasures,
  394. impactExperience: this.impactExperience,
  395. remark: this.remark
  396. }
  397. console.log('提交数据:', formData)
  398. uni.showToast({ title: '提交成功', icon: 'success' })
  399. // 返回上一页
  400. setTimeout(() => {
  401. uni.navigateBack()
  402. }, 1500)
  403. }
  404. }
  405. }
  406. </script>
  407. <style lang="scss" scoped>
  408. .repair-submit {
  409. min-height: 100vh;
  410. background-color: #f5f5f5;
  411. padding-bottom: 200rpx;
  412. }
  413. .repair-info {
  414. margin: 18rpx;
  415. background: #ffffff;
  416. border-radius: 15rpx;
  417. box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
  418. padding: 40rpx;
  419. .info-header {
  420. display: flex;
  421. align-items: center;
  422. margin-bottom: 40rpx;
  423. .red-line {
  424. width: 9rpx;
  425. height: 33rpx;
  426. background-color: $primary-color;
  427. margin-right: 7rpx;
  428. border-radius: 5rpx;
  429. }
  430. .info-title {
  431. font-size: 30rpx;
  432. font-weight: bold;
  433. color: $primary-text-color;
  434. }
  435. }
  436. .form-item-header {
  437. border-bottom: none;
  438. margin-top: 20rpx;
  439. }
  440. .form-item {
  441. display: flex;
  442. align-items: center;
  443. justify-content: space-between;
  444. padding: 24rpx 0;
  445. border-bottom: 2rpx solid #f0f0f0;
  446. &:last-child {
  447. border-bottom: none;
  448. }
  449. .label {
  450. font-size: 30rpx;
  451. color: $primary-text-color;
  452. flex-shrink: 0;
  453. &.active {
  454. font-weight: bold;
  455. }
  456. }
  457. .value {
  458. font-size: 30rpx;
  459. color: $secondary-text-color;
  460. &.placeholder {
  461. color: $secondary-text-color;
  462. }
  463. }
  464. .select-area {
  465. display: flex;
  466. align-items: center;
  467. gap: 16rpx;
  468. }
  469. }
  470. .textarea-container {
  471. // margin: 16rpx 0 32rpx 0;
  472. // background-color: #f5f5f5;
  473. border-radius: 8rpx;
  474. // padding: 16rpx;
  475. }
  476. .image-upload {
  477. display: flex;
  478. flex-wrap: wrap;
  479. gap: 24rpx;
  480. margin: 16rpx 0;
  481. .upload-btn {
  482. width: 160rpx;
  483. height: 160rpx;
  484. border: 2rpx dashed $primary-color;
  485. // border-radius: 8rpx;
  486. display: flex;
  487. align-items: center;
  488. justify-content: center;
  489. background-color: #fff;
  490. }
  491. .image-item {
  492. position: relative;
  493. width: 160rpx;
  494. height: 160rpx;
  495. image {
  496. width: 100%;
  497. height: 100%;
  498. border-radius: 8rpx;
  499. }
  500. .delete-btn {
  501. position: absolute;
  502. top: -12rpx;
  503. right: -12rpx;
  504. width: 40rpx;
  505. height: 40rpx;
  506. background-color: #ff4757;
  507. border-radius: 50%;
  508. display: flex;
  509. align-items: center;
  510. justify-content: center;
  511. }
  512. }
  513. }
  514. .hint-text {
  515. font-size: 24rpx;
  516. color: #999;
  517. margin-top: 16rpx;
  518. }
  519. .form-item .radio-options {
  520. display: flex;
  521. gap: 60rpx;
  522. .radio-item {
  523. display: flex;
  524. align-items: center;
  525. gap: 16rpx;
  526. .radio-dot {
  527. width: 32rpx;
  528. height: 32rpx;
  529. border: 4rpx solid #ddd;
  530. border-radius: 50%;
  531. position: relative;
  532. &.active {
  533. border-color: $primary-color;
  534. color: $primary-color;
  535. &::after {
  536. content: '';
  537. position: absolute;
  538. top: 50%;
  539. left: 50%;
  540. transform: translate(-50%, -50%);
  541. width: 16rpx;
  542. height: 16rpx;
  543. background-color: $primary-color;
  544. border-radius: 50%;
  545. }
  546. }
  547. }
  548. text {
  549. font-size: 30rpx;
  550. color: $secondary-text-color;
  551. &.active {
  552. color: $primary-color;
  553. }
  554. }
  555. }
  556. }
  557. }
  558. .submit-container {
  559. position: fixed;
  560. bottom: 0;
  561. left: 0;
  562. right: 0;
  563. padding: 32rpx;
  564. background-color: #fff;
  565. border-top: 2rpx solid #f0f0f0;
  566. }
  567. </style>