展品维保小程序前端代码接口
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.

1009 lines
26 KiB

  1. <template>
  2. <view class="maintain-submit">
  3. <!-- 修改状态 -->
  4. <view class="status-item">
  5. <!-- 维修状态和状态选择 -->
  6. <view class="status-row">
  7. <text class="status-label">维修状态</text>
  8. <view class="status-select" @click="showStatusPicker">
  9. <text class="status-value" :class="{ placeholder: !selectedStatus }">{{ selectedStatus || '故障中' }}</text>
  10. <uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
  11. </view>
  12. </view>
  13. <!-- 修改状态按钮 -->
  14. <button class="status-btn" :class="{ active: statusType === 'modify' }" @click="statusType = 'modify'">
  15. <text class="status-text">修改状态</text>
  16. </button>
  17. </view>
  18. <!-- 保修基本信息 -->
  19. <view class="repair-info">
  20. <view class="info-header">
  21. <view class="red-line"></view>
  22. <text class="info-title">报修基本信息</text>
  23. </view>
  24. <!-- 报修日期 -->
  25. <view class="form-item">
  26. <text class="label">报修日期</text>
  27. <text class="value">{{ repairData.repairDate }}</text>
  28. </view>
  29. <!-- 故障紧急程度 -->
  30. <view class="form-item">
  31. <text class="label">故障紧急程度</text>
  32. <text class="value">{{ repairData.urgencyLevel }}</text>
  33. </view>
  34. <!-- 故障情况描述 -->
  35. <view class="form-item">
  36. <text class="label">故障情况描述</text>
  37. </view>
  38. <!-- 故障情况描述文本区域 -->
  39. <view class="content-text">
  40. <!-- <text>{{ repairData.faultDescription }}</text> -->
  41. <uv-textarea
  42. v-model="repairData.faultDescription"
  43. placeholder="展品故障描述"
  44. :maxlength="200"
  45. :show-confirm-bar="false"
  46. height="60"
  47. border="none"
  48. disabled
  49. :textStyle="{ color: '#000' }"
  50. :custom-style="{ backgroundColor: '#f5f5f5' }"
  51. ></uv-textarea>
  52. </view>
  53. <!-- 故障图片 -->
  54. <view class="form-item" v-if="!isCollapsed">
  55. <text class="label">故障图片</text>
  56. </view>
  57. <view class="image-container" v-if="!isCollapsed">
  58. <image
  59. class="uploaded-image"
  60. v-for="(img, index) in repairData.imageList"
  61. :key="index"
  62. :src="img"
  63. mode="aspectFill"
  64. @click="previewImage(img)"
  65. ></image>
  66. </view>
  67. <!-- 故障首次发生时间 -->
  68. <view class="form-item" v-if="!isCollapsed">
  69. <text class="label">故障首次发生时间</text>
  70. <text class="value">{{ repairData.firstOccurTime }}</text>
  71. </view>
  72. <!-- 发生频率 -->
  73. <view class="form-item" v-if="!isCollapsed">
  74. <text class="label">发生频率</text>
  75. <text class="value red-text">{{ repairData.frequency }}</text>
  76. </view>
  77. <!-- 故障发生频率的触发条件 -->
  78. <view class="content-text" v-if="!isCollapsed">
  79. <uv-textarea
  80. v-model="repairData.faultCondition"
  81. placeholder="故障发生频率的触发条件"
  82. :maxlength="200"
  83. :show-confirm-bar="false"
  84. height="60"
  85. border="none"
  86. disabled
  87. :textStyle="{ color: '#000' }"
  88. :custom-style="{ backgroundColor: '#f5f5f5' }"
  89. ></uv-textarea>
  90. </view>
  91. <!-- <view class="content-text" v-if="!isCollapsed">
  92. <text>{{ repairData.faultCondition }}</text>
  93. </view> -->
  94. <!-- 是否影响使用 -->
  95. <view class="form-item" v-if="!isCollapsed">
  96. <text class="label">是否影响使用</text>
  97. <text class="value red-text">{{ repairData.impactUsage }}</text>
  98. </view>
  99. <!-- 是否采取临时措施 -->
  100. <view class="form-item" v-if="!isCollapsed">
  101. <text class="label">是否采取临时措施</text>
  102. <text class="value red-text">{{ repairData.hasTakenMeasures ? '是' : '否' }}</text>
  103. </view>
  104. <!-- 如有采取临时措施请填写措施说明 -->
  105. <view class="content-text" v-if="!isCollapsed">
  106. <!-- <text>{{ repairData.faultDescription }}</text> -->
  107. <uv-textarea
  108. v-model="repairData.temporaryMeasures"
  109. placeholder="如果有采取临时措施请填写措施说明"
  110. :maxlength="200"
  111. :show-confirm-bar="false"
  112. height="60"
  113. border="none"
  114. disabled
  115. :textStyle="{ color: '#000' }"
  116. :custom-style="{ backgroundColor: '#f5f5f5' }"
  117. ></uv-textarea>
  118. </view>
  119. <!-- <view class="content-text" v-if="!isCollapsed && repairData.hasTakenMeasures">
  120. <text>{{ repairData.temporaryMeasures }}</text>
  121. </view> -->
  122. <!-- 是否影响体验 -->
  123. <view class="form-item" v-if="!isCollapsed">
  124. <text class="label">是否影响体验</text>
  125. <text class="value red-text">{{ repairData.impactExperience ? '是' : '否' }}</text>
  126. </view>
  127. <view class="form-item" v-if="!isCollapsed">
  128. <text class="label">备注</text>
  129. </view>
  130. <!-- 备注 -->
  131. <view class="content-text" v-if="!isCollapsed">
  132. <!-- <text>{{ repairData.faultDescription }}</text> -->
  133. <uv-textarea
  134. v-model="repairData.remark"
  135. placeholder="备注"
  136. :maxlength="200"
  137. :show-confirm-bar="false"
  138. height="60"
  139. border="none"
  140. disabled
  141. :textStyle="{ color: '#000' }"
  142. :custom-style="{ backgroundColor: '#f5f5f5' }"
  143. ></uv-textarea>
  144. </view>
  145. <!-- 查看全部/收起按钮 -->
  146. <view class="collapse-btn" @click="toggleCollapse">
  147. <text class="collapse-text">{{ isCollapsed ? '查看全部' : '收起' }}</text>
  148. <text class="collapse-icon">{{ isCollapsed ? '▼' : '▲' }}</text>
  149. </view>
  150. </view>
  151. <!-- 处理内容 -->
  152. <view class="process-content">
  153. <view class="info-header">
  154. <view class="red-line"></view>
  155. <text class="info-title">处理内容</text>
  156. </view>
  157. <!-- 维修人 -->
  158. <view class="form-item">
  159. <text class="label">维修人</text>
  160. <view class="input-area" >
  161. <input
  162. v-model="processData.repairPerson"
  163. placeholder="请填写"
  164. class="input-field"
  165. ref="maintainerInput"
  166. />
  167. </view>
  168. </view>
  169. <!-- 联系方式 -->
  170. <view class="form-item">
  171. <text class="label">联系方式</text>
  172. <view class="input-area" >
  173. <input
  174. v-model="processData.contactPhone"
  175. placeholder="请填写"
  176. class="input-field"
  177. ref="maintainerInput"
  178. />
  179. </view>
  180. </view>
  181. <!-- 维修日期 -->
  182. <view class="form-item" @click="showDatePicker">
  183. <text class="label">维修日期</text>
  184. <view class="select-area">
  185. <text class="value" :class="{ placeholder: !processData.repairDate }">{{ processData.repairDate || '请选择' }}</text>
  186. <uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
  187. </view>
  188. </view>
  189. <!-- 处理内容 -->
  190. <view class="form-item">
  191. <text class="label">处理内容</text>
  192. </view>
  193. <view class="textarea-container">
  194. <uv-textarea
  195. v-model="processData.processContent"
  196. placeholder="请输入处理内容"
  197. :maxlength="200"
  198. :show-confirm-bar="false"
  199. height="60"
  200. border="none"
  201. disabled
  202. :textStyle="{ color: '#000' }"
  203. :custom-style="{ backgroundColor: '#f5f5f5' }"
  204. ></uv-textarea>
  205. </view>
  206. <!-- 上传图片 -->
  207. <view class="form-item">
  208. <text class="label">上传图片</text>
  209. </view>
  210. <view class="image-upload">
  211. <view v-for="(img, index) in processData.imageList" :key="index" class="image-item">
  212. <image :src="img" mode="aspectFill" @click="previewImage(img)"></image>
  213. <view class="delete-btn" @click="deleteImage(index)">
  214. <uv-icon name="close" size="12" color="#fff"></uv-icon>
  215. </view>
  216. </view>
  217. <view class="upload-btn" @click="uploadImage">
  218. <uv-icon name="camera" size="34" color="#C70019"></uv-icon>
  219. </view>
  220. </view>
  221. <!-- 是否产生费用 -->
  222. <view class="form-item">
  223. <text class="label">是否产生费用</text>
  224. <view class="radio-options">
  225. <view
  226. class="radio-item"
  227. :class="{ active: processData.hasCost === true }"
  228. @click="selectCost(true)"
  229. >
  230. <view class="radio-dot" :class="{ active: processData.hasCost === true }"></view>
  231. <text :class="{ active: processData.hasCost === true }"></text>
  232. </view>
  233. <view
  234. class="radio-item"
  235. :class="{ active: processData.hasCost === false }"
  236. @click="selectCost(false)"
  237. >
  238. <view class="radio-dot" :class="{ active: processData.hasCost === false }"></view>
  239. <text :class="{ active: processData.hasCost === false }"></text>
  240. </view>
  241. </view>
  242. </view>
  243. <!-- 产生费用 -->
  244. <view class="form-item" v-if="processData.hasCost">
  245. <text class="label">产生费用</text>
  246. <view class="input-area" >
  247. <input
  248. v-model="processData.totalCost"
  249. placeholder="请输入费用"
  250. class="input-field"
  251. ref="maintainerInput"
  252. />
  253. </view>
  254. </view>
  255. <!-- 费用详情表格 -->
  256. <view class="cost-table" v-if="processData.hasCost">
  257. <view class="table-header">
  258. <text class="header-cell">费用名称</text>
  259. <text class="header-cell">数量</text>
  260. <text class="header-cell">金额</text>
  261. <text class="header-cell"></text>
  262. </view>
  263. <view class="table-row" v-for="(item, index) in processData.costDetails" :key="index">
  264. <view class="cell-input">
  265. <uv-input
  266. v-model="item.name"
  267. placeholder="费用名称"
  268. border="none"
  269. :custom-style="{ backgroundColor: 'transparent', fontSize: '28rpx' }"
  270. ></uv-input>
  271. </view>
  272. <view class="cell-input">
  273. <uv-input
  274. v-model="item.quantity"
  275. placeholder="数量"
  276. border="none"
  277. :custom-style="{ backgroundColor: 'transparent', fontSize: '28rpx' }"
  278. ></uv-input>
  279. </view>
  280. <view class="cell-input">
  281. <uv-input
  282. v-model="item.amount"
  283. placeholder="金额"
  284. border="none"
  285. :custom-style="{ backgroundColor: 'transparent', fontSize: '28rpx' }"
  286. ></uv-input>
  287. </view>
  288. <view class="cell-action">
  289. <view class="action-btn delete-btn" @click="deleteCostItem(index)" v-if="processData.costDetails.length > 1">
  290. <uv-icon name="close" size="14" color="#fff"></uv-icon>
  291. </view>
  292. <view class="action-btn add-btn" @click="addCostItem" v-if="index === processData.costDetails.length - 1">
  293. <uv-icon name="plus" size="14" color="#fff"></uv-icon>
  294. </view>
  295. </view>
  296. </view>
  297. </view>
  298. <!-- 问题是否解决 -->
  299. <view class="form-item">
  300. <text class="label">问题是否解决</text>
  301. <view class="radio-options">
  302. <view
  303. class="radio-item"
  304. :class="{ active: processData.isResolved === true }"
  305. @click="selectResolved(true)"
  306. >
  307. <view class="radio-dot" :class="{ active: processData.isResolved === true }"></view>
  308. <text :class="{ active: processData.isResolved === true }"></text>
  309. </view>
  310. <view
  311. class="radio-item"
  312. :class="{ active: processData.isResolved === false }"
  313. @click="selectResolved(false)"
  314. >
  315. <view class="radio-dot" :class="{ active: processData.isResolved === false }"></view>
  316. <text :class="{ active: processData.isResolved === false }"></text>
  317. </view>
  318. </view>
  319. </view>
  320. <!-- 备注 -->
  321. <view class="form-item">
  322. <text class="label">备注</text>
  323. </view>
  324. <view class="textarea-container">
  325. <uv-textarea
  326. v-model="processData.remark"
  327. placeholder="备注"
  328. :maxlength="200"
  329. :show-confirm-bar="false"
  330. height="60"
  331. border="none"
  332. :custom-style="{ backgroundColor: '#f5f5f5' }"
  333. ></uv-textarea>
  334. </view>
  335. <!-- 立即维修按钮 -->
  336. <view class="repair-btn-container">
  337. <uv-button
  338. type="primary"
  339. text="立即维修"
  340. :custom-style="{ backgroundColor: '#C70019', borderRadius: '25px' }"
  341. @click="startRepair"
  342. ></uv-button>
  343. </view>
  344. </view>
  345. <!-- 日期选择器 -->
  346. <uv-picker
  347. confirm-color="#C70019"
  348. ref="datePicker"
  349. :columns="dateColumns"
  350. @confirm="confirmDate"
  351. @cancel="cancelDate"
  352. ></uv-picker>
  353. </view>
  354. </template>
  355. <script>
  356. export default {
  357. data() {
  358. return {
  359. statusType: 'modify',
  360. selectedStatus: '故障中',
  361. isCollapsed: true,
  362. // 报修基本信息(只读)
  363. repairData: {
  364. repairDate: '2025/03/31',
  365. urgencyLevel: '一般',
  366. faultDescription: '展品故障情况',
  367. imageList: [
  368. '/static/商城_商品2.png',
  369. '/static/商城_商品2.png'
  370. ],
  371. firstOccurTime: '2025/03/31',
  372. frequency: '持续性问题',
  373. faultCondition: '故障发生频率的触发条件说明',
  374. impactUsage: '是',
  375. hasTakenMeasures: true,
  376. temporaryMeasures: '已采取临时措施说明',
  377. impactExperience: true,
  378. remark: '备注信息'
  379. },
  380. // 处理内容(可编辑)
  381. processData: {
  382. repairPerson: '',
  383. contactPhone: '',
  384. repairDate: '',
  385. processContent: '',
  386. imageList: [],
  387. hasCost: null,
  388. totalCost: '',
  389. costDetails: [
  390. { name: '', quantity: '', amount: '' }
  391. ],
  392. isResolved: null,
  393. remark: ''
  394. },
  395. // 日期选择器数据
  396. dateColumns: []
  397. }
  398. },
  399. onLoad() {
  400. this.initDatePicker()
  401. },
  402. methods: {
  403. // 切换折叠状态
  404. toggleCollapse() {
  405. this.isCollapsed = !this.isCollapsed
  406. },
  407. // 预览图片
  408. previewImage(img) {
  409. uni.previewImage({
  410. urls: [img],
  411. current: img
  412. })
  413. },
  414. // 显示日期选择器
  415. showDatePicker() {
  416. this.$refs.datePicker.open()
  417. },
  418. // 确认日期
  419. confirmDate(e) {
  420. const { indexs, value } = e
  421. this.processData.repairDate = value.join('/')
  422. },
  423. // 取消日期选择
  424. cancelDate() {
  425. // 取消选择
  426. },
  427. // 初始化日期选择器
  428. initDatePicker() {
  429. const currentYear = new Date().getFullYear()
  430. const years = []
  431. const months = []
  432. const days = []
  433. // 生成年份
  434. for (let i = currentYear - 10; i <= currentYear + 10; i++) {
  435. years.push(i + '年')
  436. }
  437. // 生成月份
  438. for (let i = 1; i <= 12; i++) {
  439. months.push(i.toString().padStart(2, '0') + '月')
  440. }
  441. // 生成日期
  442. for (let i = 1; i <= 31; i++) {
  443. days.push(i.toString().padStart(2, '0') + '日')
  444. }
  445. this.dateColumns = [years, months, days]
  446. },
  447. // 上传图片
  448. uploadImage() {
  449. uni.chooseImage({
  450. count: 9 - this.processData.imageList.length,
  451. sizeType: ['original', 'compressed'],
  452. sourceType: ['album', 'camera'],
  453. success: (res) => {
  454. this.processData.imageList.push(...res.tempFilePaths)
  455. }
  456. })
  457. },
  458. // 删除图片
  459. deleteImage(index) {
  460. this.processData.imageList.splice(index, 1)
  461. },
  462. // 选择是否产生费用
  463. selectCost(value) {
  464. this.processData.hasCost = value
  465. if (!value) {
  466. this.processData.totalCost = ''
  467. this.processData.costDetails = [{ name: '', quantity: '', amount: '' }]
  468. }
  469. },
  470. // 添加费用项
  471. addCostItem() {
  472. this.processData.costDetails.push({ name: '', quantity: '', amount: '' })
  473. },
  474. // 删除费用项
  475. deleteCostItem(index) {
  476. this.processData.costDetails.splice(index, 1)
  477. },
  478. // 选择问题是否解决
  479. selectResolved(value) {
  480. this.processData.isResolved = value
  481. },
  482. // 显示状态选择器
  483. showStatusPicker() {
  484. uni.showActionSheet({
  485. itemList: ['故障中', '维修中', '已完成', '暂停维修'],
  486. success: (res) => {
  487. const statusList = ['故障中', '维修中', '已完成', '暂停维修']
  488. this.selectedStatus = statusList[res.tapIndex]
  489. }
  490. })
  491. },
  492. // 立即维修
  493. startRepair() {
  494. // 验证必填项
  495. if (!this.processData.repairPerson) {
  496. uni.showToast({
  497. title: '请输入维修人',
  498. icon: 'none'
  499. })
  500. return
  501. }
  502. if (!this.processData.contactPhone) {
  503. uni.showToast({
  504. title: '请输入联系方式',
  505. icon: 'none'
  506. })
  507. return
  508. }
  509. if (!this.processData.repairDate) {
  510. uni.showToast({
  511. title: '请选择维修日期',
  512. icon: 'none'
  513. })
  514. return
  515. }
  516. if (!this.processData.processContent) {
  517. uni.showToast({
  518. title: '请输入处理内容',
  519. icon: 'none'
  520. })
  521. return
  522. }
  523. if (this.processData.isResolved === null) {
  524. uni.showToast({
  525. title: '请选择问题是否解决',
  526. icon: 'none'
  527. })
  528. return
  529. }
  530. // 提交数据
  531. uni.showLoading({
  532. title: '提交中...'
  533. })
  534. // 模拟提交
  535. setTimeout(() => {
  536. uni.hideLoading()
  537. uni.showToast({
  538. title: '提交成功',
  539. icon: 'success'
  540. })
  541. setTimeout(() => {
  542. uni.navigateBack()
  543. }, 1500)
  544. }, 2000)
  545. }
  546. }
  547. }
  548. </script>
  549. <style lang="scss" scoped>
  550. .maintain-submit {
  551. min-height: 100vh;
  552. background-color: #f5f5f5;
  553. padding-bottom: 200rpx;
  554. }
  555. // 修改状态
  556. .status-item {
  557. margin: 18rpx;
  558. background: #ffffff;
  559. border-radius: 15rpx;
  560. box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
  561. padding: 20rpx 40rpx;
  562. .status-row {
  563. display: flex;
  564. align-items: center;
  565. justify-content: space-between;
  566. margin-bottom: 24rpx;
  567. .status-label {
  568. font-size: 30rpx;
  569. color: $primary-text-color;
  570. // font-weight: bold;
  571. }
  572. .status-select {
  573. display: flex;
  574. align-items: center;
  575. gap: 23rpx;
  576. padding: 12rpx 24rpx;
  577. // background-color: #f5f5f5;
  578. border-radius: 8rpx;
  579. // min-width: 200rpx;
  580. justify-content: space-between;
  581. .status-value {
  582. font-size: 28rpx;
  583. color: $primary-text-color;
  584. &.placeholder {
  585. color: $secondary-text-color;
  586. }
  587. }
  588. }
  589. }
  590. .status-btn {
  591. display: flex;
  592. align-items: center;
  593. justify-content: center;
  594. // padding: 16rpx 32rpx;
  595. // border: 2rpx solid #ddd;
  596. border-radius: full;
  597. background-color: #fff;
  598. width: 419rpx;
  599. height: 78rpx;
  600. border-radius: 39rpx;
  601. &.active {
  602. border-color: $primary-color;
  603. background-color: $primary-color;
  604. .status-text {
  605. color: #fff;
  606. }
  607. }
  608. .status-text {
  609. font-size: 30rpx;
  610. color: $secondary-text-color;
  611. }
  612. }
  613. }
  614. // 报修基本信息和处理内容通用样式
  615. .repair-info, .process-content {
  616. margin: 18rpx;
  617. background: #ffffff;
  618. border-radius: 15rpx;
  619. box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
  620. padding: 30rpx;
  621. .info-header {
  622. display: flex;
  623. align-items: center;
  624. margin-bottom: 40rpx;
  625. .red-line {
  626. width: 9rpx;
  627. height: 33rpx;
  628. background-color: $primary-color;
  629. margin-right: 7rpx;
  630. border-radius: 5rpx;
  631. }
  632. .info-title {
  633. font-size: 30rpx;
  634. font-weight: bold;
  635. color: $primary-text-color;
  636. }
  637. }
  638. .form-item {
  639. display: flex;
  640. align-items: center;
  641. justify-content: space-between;
  642. padding: 18rpx 0;
  643. border-bottom: 2rpx solid #f0f0f0;
  644. &:last-child {
  645. border-bottom: none;
  646. }
  647. .input-area {
  648. flex: 1;
  649. // background-color: #f5f5f5;
  650. border-radius: 8rpx;
  651. padding: 2rpx 24rpx;
  652. margin-left: 24rpx;
  653. .input-field {
  654. width: 100%;
  655. font-size: 30rpx;
  656. color: $primary-text-color;
  657. background: transparent;
  658. border: none;
  659. outline: none;
  660. text-align: right;
  661. &::placeholder {
  662. color: $secondary-text-color;
  663. }
  664. }
  665. }
  666. .label {
  667. font-size: 30rpx;
  668. color: $primary-text-color;
  669. flex-shrink: 0;
  670. &.active {
  671. font-weight: bold;
  672. }
  673. }
  674. .value {
  675. font-size: 30rpx;
  676. color: $primary-text-color;
  677. &.placeholder {
  678. color: $secondary-text-color;
  679. }
  680. &.red-text {
  681. color: $primary-color;
  682. }
  683. }
  684. .select-area {
  685. display: flex;
  686. align-items: center;
  687. gap: 16rpx;
  688. }
  689. }
  690. .content-text {
  691. // padding: 16rpx 0;
  692. margin-bottom: 16rpx;
  693. text {
  694. font-size: 30rpx;
  695. color: $secondary-text-color;
  696. line-height: 1.5;
  697. }
  698. }
  699. .image-container {
  700. display: flex;
  701. flex-wrap: wrap;
  702. gap: 24rpx;
  703. margin: 16rpx 0;
  704. .uploaded-image {
  705. width: 160rpx;
  706. height: 160rpx;
  707. // border-radius: 8rpx;
  708. }
  709. }
  710. .collapse-btn {
  711. display: flex;
  712. align-items: center;
  713. justify-content: center;
  714. gap: 16rpx;
  715. padding: 30rpx 0 0;
  716. margin-top: 16rpx;
  717. border-top: 2rpx solid #f0f0f0;
  718. .collapse-text {
  719. font-size: 28rpx;
  720. color: $primary-color;
  721. }
  722. .collapse-icon {
  723. font-size: 24rpx;
  724. color: $primary-color;
  725. }
  726. }
  727. }
  728. // 处理内容特有样式
  729. .process-content {
  730. .textarea-container {
  731. margin: 16rpx 0;
  732. background-color: #f5f5f5;
  733. border-radius: 8rpx;
  734. padding: 8rpx 16rpx;
  735. }
  736. .image-upload {
  737. display: flex;
  738. flex-wrap: wrap;
  739. gap: 24rpx;
  740. margin: 16rpx 0;
  741. .upload-btn {
  742. width: 160rpx;
  743. height: 160rpx;
  744. border: 2rpx dashed $primary-color;
  745. display: flex;
  746. align-items: center;
  747. justify-content: center;
  748. background-color: #fff;
  749. border-radius: 8rpx;
  750. }
  751. .image-item {
  752. position: relative;
  753. width: 160rpx;
  754. height: 160rpx;
  755. image {
  756. width: 100%;
  757. height: 100%;
  758. border-radius: 8rpx;
  759. }
  760. .delete-btn {
  761. position: absolute;
  762. top: -12rpx;
  763. right: -12rpx;
  764. width: 40rpx;
  765. height: 40rpx;
  766. background-color: #ff4757;
  767. border-radius: 50%;
  768. display: flex;
  769. align-items: center;
  770. justify-content: center;
  771. }
  772. }
  773. }
  774. .radio-options {
  775. display: flex;
  776. gap: 80rpx;
  777. .radio-item {
  778. display: flex;
  779. align-items: center;
  780. gap: 16rpx;
  781. .radio-dot {
  782. width: 32rpx;
  783. height: 32rpx;
  784. border: 4rpx solid #ddd;
  785. border-radius: 50%;
  786. position: relative;
  787. &.active {
  788. border-color: $primary-color;
  789. &::after {
  790. content: '';
  791. position: absolute;
  792. top: 50%;
  793. left: 50%;
  794. transform: translate(-50%, -50%);
  795. width: 16rpx;
  796. height: 16rpx;
  797. background-color: $primary-color;
  798. border-radius: 50%;
  799. }
  800. }
  801. }
  802. text {
  803. font-size: 30rpx;
  804. color: $secondary-text-color;
  805. &.active {
  806. color: $primary-color;
  807. }
  808. }
  809. }
  810. }
  811. // 费用表格样式
  812. .cost-table {
  813. margin: 16rpx 0;
  814. border: 2rpx solid #f0f0f0;
  815. border-radius: 8rpx;
  816. overflow: hidden;
  817. .table-header {
  818. display: flex;
  819. background-color: #f8f8f8;
  820. .header-cell {
  821. flex: 1;
  822. padding: 24rpx 16rpx;
  823. font-size: 28rpx;
  824. font-weight: bold;
  825. color: $primary-text-color;
  826. text-align: left;
  827. border-right: 2rpx solid #f0f0f0;
  828. &:first-child {
  829. flex: 2;
  830. text-align: left;
  831. }
  832. &:last-child {
  833. border-right: none;
  834. }
  835. }
  836. }
  837. .table-row {
  838. display: flex;
  839. border-top: 2rpx solid #f0f0f0;
  840. .cell-input {
  841. flex: 1;
  842. padding: 8rpx;
  843. border-right: 2rpx solid #f0f0f0;
  844. &:first-child {
  845. flex: 2;
  846. }
  847. &:last-child {
  848. border-right: none;
  849. }
  850. }
  851. .cell-action {
  852. width: 120rpx;
  853. display: flex;
  854. align-items: center;
  855. justify-content: center;
  856. gap: 8rpx;
  857. padding: 8rpx;
  858. .action-btn {
  859. width: 36rpx;
  860. height: 36rpx;
  861. padding: 4rpx;
  862. border-radius: 50%;
  863. display: flex;
  864. align-items: center;
  865. justify-content: center;
  866. &.add-btn {
  867. background-color: #1a9c10;
  868. }
  869. &.delete-btn {
  870. background-color: $primary-color;
  871. }
  872. }
  873. }
  874. }
  875. }
  876. // 立即维修按钮
  877. .repair-btn-container {
  878. margin-top: 40rpx;
  879. padding-top: 32rpx;
  880. border-top: 2rpx solid #f0f0f0;
  881. }
  882. }
  883. </style>