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

1015 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. async uploadImage() {
  449. try {
  450. const result = await this.$utils.chooseAndUpload()
  451. if (result && result.success) {
  452. console.log(result);
  453. this.processData.imageList.push(result.url)
  454. }
  455. } catch (error) {
  456. console.error('图片上传失败:', error)
  457. uni.showToast({
  458. title: '图片上传失败',
  459. icon: 'error'
  460. })
  461. }
  462. },
  463. // 删除图片
  464. deleteImage(index) {
  465. this.processData.imageList.splice(index, 1)
  466. },
  467. // 选择是否产生费用
  468. selectCost(value) {
  469. this.processData.hasCost = value
  470. if (!value) {
  471. this.processData.totalCost = ''
  472. this.processData.costDetails = [{ name: '', quantity: '', amount: '' }]
  473. }
  474. },
  475. // 添加费用项
  476. addCostItem() {
  477. this.processData.costDetails.push({ name: '', quantity: '', amount: '' })
  478. },
  479. // 删除费用项
  480. deleteCostItem(index) {
  481. this.processData.costDetails.splice(index, 1)
  482. },
  483. // 选择问题是否解决
  484. selectResolved(value) {
  485. this.processData.isResolved = value
  486. },
  487. // 显示状态选择器
  488. showStatusPicker() {
  489. uni.showActionSheet({
  490. itemList: ['故障中', '维修中', '已完成', '暂停维修'],
  491. success: (res) => {
  492. const statusList = ['故障中', '维修中', '已完成', '暂停维修']
  493. this.selectedStatus = statusList[res.tapIndex]
  494. }
  495. })
  496. },
  497. // 立即维修
  498. startRepair() {
  499. // 验证必填项
  500. if (!this.processData.repairPerson) {
  501. uni.showToast({
  502. title: '请输入维修人',
  503. icon: 'none'
  504. })
  505. return
  506. }
  507. if (!this.processData.contactPhone) {
  508. uni.showToast({
  509. title: '请输入联系方式',
  510. icon: 'none'
  511. })
  512. return
  513. }
  514. if (!this.processData.repairDate) {
  515. uni.showToast({
  516. title: '请选择维修日期',
  517. icon: 'none'
  518. })
  519. return
  520. }
  521. if (!this.processData.processContent) {
  522. uni.showToast({
  523. title: '请输入处理内容',
  524. icon: 'none'
  525. })
  526. return
  527. }
  528. if (this.processData.isResolved === null) {
  529. uni.showToast({
  530. title: '请选择问题是否解决',
  531. icon: 'none'
  532. })
  533. return
  534. }
  535. // 提交数据
  536. uni.showLoading({
  537. title: '提交中...'
  538. })
  539. // 模拟提交
  540. setTimeout(() => {
  541. uni.hideLoading()
  542. uni.showToast({
  543. title: '提交成功',
  544. icon: 'success'
  545. })
  546. setTimeout(() => {
  547. uni.navigateBack()
  548. }, 1500)
  549. }, 2000)
  550. }
  551. }
  552. }
  553. </script>
  554. <style lang="scss" scoped>
  555. .maintain-submit {
  556. min-height: 100vh;
  557. background-color: #f5f5f5;
  558. padding-bottom: 200rpx;
  559. }
  560. // 修改状态
  561. .status-item {
  562. margin: 18rpx;
  563. background: #ffffff;
  564. border-radius: 15rpx;
  565. box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
  566. padding: 20rpx 40rpx;
  567. .status-row {
  568. display: flex;
  569. align-items: center;
  570. justify-content: space-between;
  571. margin-bottom: 24rpx;
  572. .status-label {
  573. font-size: 30rpx;
  574. color: $primary-text-color;
  575. // font-weight: bold;
  576. }
  577. .status-select {
  578. display: flex;
  579. align-items: center;
  580. gap: 23rpx;
  581. padding: 12rpx 24rpx;
  582. // background-color: #f5f5f5;
  583. border-radius: 8rpx;
  584. // min-width: 200rpx;
  585. justify-content: space-between;
  586. .status-value {
  587. font-size: 28rpx;
  588. color: $primary-text-color;
  589. &.placeholder {
  590. color: $secondary-text-color;
  591. }
  592. }
  593. }
  594. }
  595. .status-btn {
  596. display: flex;
  597. align-items: center;
  598. justify-content: center;
  599. // padding: 16rpx 32rpx;
  600. // border: 2rpx solid #ddd;
  601. border-radius: full;
  602. background-color: #fff;
  603. width: 419rpx;
  604. height: 78rpx;
  605. border-radius: 39rpx;
  606. &.active {
  607. border-color: $primary-color;
  608. background-color: $primary-color;
  609. .status-text {
  610. color: #fff;
  611. }
  612. }
  613. .status-text {
  614. font-size: 30rpx;
  615. color: $secondary-text-color;
  616. }
  617. }
  618. }
  619. // 报修基本信息和处理内容通用样式
  620. .repair-info, .process-content {
  621. margin: 18rpx;
  622. background: #ffffff;
  623. border-radius: 15rpx;
  624. box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
  625. padding: 30rpx;
  626. .info-header {
  627. display: flex;
  628. align-items: center;
  629. margin-bottom: 40rpx;
  630. .red-line {
  631. width: 9rpx;
  632. height: 33rpx;
  633. background-color: $primary-color;
  634. margin-right: 7rpx;
  635. border-radius: 5rpx;
  636. }
  637. .info-title {
  638. font-size: 30rpx;
  639. font-weight: bold;
  640. color: $primary-text-color;
  641. }
  642. }
  643. .form-item {
  644. display: flex;
  645. align-items: center;
  646. justify-content: space-between;
  647. padding: 18rpx 0;
  648. border-bottom: 2rpx solid #f0f0f0;
  649. &:last-child {
  650. border-bottom: none;
  651. }
  652. .input-area {
  653. flex: 1;
  654. // background-color: #f5f5f5;
  655. border-radius: 8rpx;
  656. padding: 2rpx 24rpx;
  657. margin-left: 24rpx;
  658. .input-field {
  659. width: 100%;
  660. font-size: 30rpx;
  661. color: $primary-text-color;
  662. background: transparent;
  663. border: none;
  664. outline: none;
  665. text-align: right;
  666. &::placeholder {
  667. color: $secondary-text-color;
  668. }
  669. }
  670. }
  671. .label {
  672. font-size: 30rpx;
  673. color: $primary-text-color;
  674. flex-shrink: 0;
  675. &.active {
  676. font-weight: bold;
  677. }
  678. }
  679. .value {
  680. font-size: 30rpx;
  681. color: $primary-text-color;
  682. &.placeholder {
  683. color: $secondary-text-color;
  684. }
  685. &.red-text {
  686. color: $primary-color;
  687. }
  688. }
  689. .select-area {
  690. display: flex;
  691. align-items: center;
  692. gap: 16rpx;
  693. }
  694. }
  695. .content-text {
  696. // padding: 16rpx 0;
  697. margin-bottom: 16rpx;
  698. text {
  699. font-size: 30rpx;
  700. color: $secondary-text-color;
  701. line-height: 1.5;
  702. }
  703. }
  704. .image-container {
  705. display: flex;
  706. flex-wrap: wrap;
  707. gap: 24rpx;
  708. margin: 16rpx 0;
  709. .uploaded-image {
  710. width: 160rpx;
  711. height: 160rpx;
  712. // border-radius: 8rpx;
  713. }
  714. }
  715. .collapse-btn {
  716. display: flex;
  717. align-items: center;
  718. justify-content: center;
  719. gap: 16rpx;
  720. padding: 30rpx 0 0;
  721. margin-top: 16rpx;
  722. border-top: 2rpx solid #f0f0f0;
  723. .collapse-text {
  724. font-size: 28rpx;
  725. color: $primary-color;
  726. }
  727. .collapse-icon {
  728. font-size: 24rpx;
  729. color: $primary-color;
  730. }
  731. }
  732. }
  733. // 处理内容特有样式
  734. .process-content {
  735. .textarea-container {
  736. margin: 16rpx 0;
  737. background-color: #f5f5f5;
  738. border-radius: 8rpx;
  739. padding: 8rpx 16rpx;
  740. }
  741. .image-upload {
  742. display: flex;
  743. flex-wrap: wrap;
  744. gap: 24rpx;
  745. margin: 16rpx 0;
  746. .upload-btn {
  747. width: 160rpx;
  748. height: 160rpx;
  749. border: 2rpx dashed $primary-color;
  750. display: flex;
  751. align-items: center;
  752. justify-content: center;
  753. background-color: #fff;
  754. border-radius: 8rpx;
  755. }
  756. .image-item {
  757. position: relative;
  758. width: 160rpx;
  759. height: 160rpx;
  760. image {
  761. width: 100%;
  762. height: 100%;
  763. border-radius: 8rpx;
  764. }
  765. .delete-btn {
  766. position: absolute;
  767. top: -12rpx;
  768. right: -12rpx;
  769. width: 40rpx;
  770. height: 40rpx;
  771. background-color: #ff4757;
  772. border-radius: 50%;
  773. display: flex;
  774. align-items: center;
  775. justify-content: center;
  776. }
  777. }
  778. }
  779. .radio-options {
  780. display: flex;
  781. gap: 80rpx;
  782. .radio-item {
  783. display: flex;
  784. align-items: center;
  785. gap: 16rpx;
  786. .radio-dot {
  787. width: 32rpx;
  788. height: 32rpx;
  789. border: 4rpx solid #ddd;
  790. border-radius: 50%;
  791. position: relative;
  792. &.active {
  793. border-color: $primary-color;
  794. &::after {
  795. content: '';
  796. position: absolute;
  797. top: 50%;
  798. left: 50%;
  799. transform: translate(-50%, -50%);
  800. width: 16rpx;
  801. height: 16rpx;
  802. background-color: $primary-color;
  803. border-radius: 50%;
  804. }
  805. }
  806. }
  807. text {
  808. font-size: 30rpx;
  809. color: $secondary-text-color;
  810. &.active {
  811. color: $primary-color;
  812. }
  813. }
  814. }
  815. }
  816. // 费用表格样式
  817. .cost-table {
  818. margin: 16rpx 0;
  819. border: 2rpx solid #f0f0f0;
  820. border-radius: 8rpx;
  821. overflow: hidden;
  822. .table-header {
  823. display: flex;
  824. background-color: #f8f8f8;
  825. .header-cell {
  826. flex: 1;
  827. padding: 24rpx 16rpx;
  828. font-size: 28rpx;
  829. font-weight: bold;
  830. color: $primary-text-color;
  831. text-align: left;
  832. border-right: 2rpx solid #f0f0f0;
  833. &:first-child {
  834. flex: 2;
  835. text-align: left;
  836. }
  837. &:last-child {
  838. border-right: none;
  839. }
  840. }
  841. }
  842. .table-row {
  843. display: flex;
  844. border-top: 2rpx solid #f0f0f0;
  845. .cell-input {
  846. flex: 1;
  847. padding: 8rpx;
  848. border-right: 2rpx solid #f0f0f0;
  849. &:first-child {
  850. flex: 2;
  851. }
  852. &:last-child {
  853. border-right: none;
  854. }
  855. }
  856. .cell-action {
  857. width: 120rpx;
  858. display: flex;
  859. align-items: center;
  860. justify-content: center;
  861. gap: 8rpx;
  862. padding: 8rpx;
  863. .action-btn {
  864. width: 36rpx;
  865. height: 36rpx;
  866. padding: 4rpx;
  867. border-radius: 50%;
  868. display: flex;
  869. align-items: center;
  870. justify-content: center;
  871. &.add-btn {
  872. background-color: #1a9c10;
  873. }
  874. &.delete-btn {
  875. background-color: $primary-color;
  876. }
  877. }
  878. }
  879. }
  880. }
  881. // 立即维修按钮
  882. .repair-btn-container {
  883. margin-top: 40rpx;
  884. padding-top: 32rpx;
  885. border-top: 2rpx solid #f0f0f0;
  886. }
  887. }
  888. </style>