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

651 lines
19 KiB

  1. <template>
  2. <view class="container">
  3. <view class="header">
  4. <!-- 大Tab维修记录/保养记录 -->
  5. <view class="main-tabs">
  6. <view
  7. class="tab-item"
  8. :class="{ active: activeMainTab === 'repair' }"
  9. @click="switchMainTab('repair')"
  10. >
  11. <text class="tab-text">维修记录</text>
  12. <view class="tab-underline" v-if="activeMainTab === 'repair'"></view>
  13. </view>
  14. <view
  15. class="tab-item"
  16. :class="{ active: activeMainTab === 'maintain' }"
  17. @click="switchMainTab('maintain')"
  18. >
  19. <text class="tab-text">保养记录</text>
  20. <view class="tab-underline" v-if="activeMainTab === 'maintain'"></view>
  21. </view>
  22. </view>
  23. <!-- 筛选按钮区域 -->
  24. <view class="picker-buttons">
  25. <view class="picker-btn" :class="{ active: selectedTime }" @click="showTimePicker" >
  26. <text class="btn-text">{{ selectedTime || '时间' }}</text>
  27. <text class="arrow-icon"></text>
  28. </view>
  29. <view class="picker-btn" :class="{ active: selectedPerson }" @click="showPersonPicker" >
  30. <text class="btn-text">{{ selectedPerson || '人员' }}</text>
  31. <text class="arrow-icon"></text>
  32. </view>
  33. </view>
  34. </view>
  35. <!-- 时间选择器 -->
  36. <uv-picker
  37. ref="timePicker"
  38. :columns="timeColumns"
  39. @confirm="onTimeConfirm"
  40. @cancel="onTimeCancel"
  41. title="选择时间范围"
  42. confirmColor="#C70019"
  43. ></uv-picker>
  44. <!-- 人员选择器 -->
  45. <uv-picker
  46. ref="personPicker"
  47. :columns="personColumns"
  48. @confirm="onPersonConfirm"
  49. @cancel="onPersonCancel"
  50. title="选择人员"
  51. confirmColor="#C70019"
  52. ></uv-picker>
  53. <!-- 内容区域 -->
  54. <view class="content-area">
  55. <!-- 记录item -->
  56. <view class="record-item" v-for="(record, index) in list" :key="index">
  57. <!-- 维修记录 -->
  58. <template v-if="activeMainTab === 'repair'">
  59. <!-- 基本信息 -->
  60. <view class="info-row">
  61. <text class="label">维修人</text>
  62. <text class="value">{{ record.repairPerson }}</text>
  63. </view>
  64. <view class="info-row">
  65. <text class="label">联系方式</text>
  66. <text class="value">{{ record.contactPhone }}</text>
  67. </view>
  68. <view class="info-row">
  69. <text class="label">维修日期</text>
  70. <text class="value">{{ record.repairDate }}</text>
  71. </view>
  72. <view class="info-row">
  73. <text class="label">处理内容</text>
  74. </view>
  75. <!-- 处理内容文本区域 -->
  76. <view class="content-text">
  77. <text>{{ record.processContent }}</text>
  78. </view>
  79. <!-- 上传图片 -->
  80. <view class="info-row" v-if="!record.isCollapsed">
  81. <text class="label">上传图片</text>
  82. </view>
  83. <view class="image-container" v-if="!record.isCollapsed">
  84. <image class="uploaded-image" :src="record.uploadImage" mode="aspectFill"></image>
  85. </view>
  86. <!-- 是否产生费用 -->
  87. <view class="info-row">
  88. <text class="label">是否产生费用</text>
  89. <text class="value red-text">{{ record.hasCost }}</text>
  90. </view>
  91. </template>
  92. <!-- 保养记录 -->
  93. <template v-else>
  94. <!-- 基本信息 -->
  95. <view class="info-row">
  96. <text class="label">保养人</text>
  97. <text class="value">{{ record.maintainPerson }}</text>
  98. </view>
  99. <view class="info-row">
  100. <text class="label">保养日期</text>
  101. <text class="value">{{ record.maintainDate }}</text>
  102. </view>
  103. <view class="info-row">
  104. <text class="label">保养前状态</text>
  105. </view>
  106. <!-- 保养前状态文本区域 -->
  107. <view class="content-text">
  108. <text>{{ record.beforeStatus }}</text>
  109. </view>
  110. <!-- 保养前图片 -->
  111. <view class="image-container" v-if="!record.isCollapsed">
  112. <image
  113. class="uploaded-image"
  114. v-for="(img, imgIndex) in record.beforeImages"
  115. :key="imgIndex"
  116. :src="img"
  117. mode="aspectFill"
  118. ></image>
  119. </view>
  120. <view class="info-row" v-if="!record.isCollapsed">
  121. <text class="label">保养后状态</text>
  122. </view>
  123. <!-- 保养后状态文本区域 -->
  124. <view class="content-text" v-if="!record.isCollapsed">
  125. <text>{{ record.afterStatus }}</text>
  126. </view>
  127. <!-- 保养后图片 -->
  128. <view class="image-container" v-if="!record.isCollapsed">
  129. <image
  130. class="uploaded-image"
  131. v-for="(img, imgIndex) in record.afterImages"
  132. :key="'after-' + imgIndex"
  133. :src="img"
  134. mode="aspectFill"
  135. ></image>
  136. </view>
  137. <!-- 是否产生费用 -->
  138. <view class="info-row" v-if="!record.isCollapsed">
  139. <text class="label">是否产生费用</text>
  140. <text class="value red-text">{{ record.hasCost }}</text>
  141. </view>
  142. </template>
  143. <!-- 查看全部按钮收起状态时显示 -->
  144. <!-- <view class="view-all-btn" v-if="record.isCollapsed" @click="toggleCollapse(index)">
  145. <text class="view-all-text">查看全部</text>
  146. <text class="view-all-icon"></text>
  147. </view> -->
  148. <!-- 产生费用 -->
  149. <view class="info-row" v-if="!record.isCollapsed">
  150. <text class="label">产生费用</text>
  151. <text class="value red-text">{{ record.totalCost }}</text>
  152. </view>
  153. <!-- 费用详情表格 -->
  154. <view class="cost-table" v-if="!record.isCollapsed">
  155. <view class="table-header">
  156. <text class="header-cell">费用名称</text>
  157. <text class="header-cell">数量</text>
  158. <text class="header-cell">金额</text>
  159. </view>
  160. <view class="table-row" v-for="(item, index) in record.costDetails" :key="index">
  161. <text class="cell">{{ item.name }}</text>
  162. <text class="cell">{{ item.quantity }}</text>
  163. <text class="cell">{{ item.amount }}</text>
  164. </view>
  165. </view>
  166. <!-- 维修记录特有字段 -->
  167. <template v-if="activeMainTab === 'repair'">
  168. <!-- 问题是否解决 -->
  169. <view class="info-row" v-if="!record.isCollapsed">
  170. <text class="label">问题是否解决</text>
  171. <text class="value red-text">{{ record.isResolved }}</text>
  172. </view>
  173. <!-- 备注 -->
  174. <view class="info-row" v-if="!record.isCollapsed">
  175. <text class="label">备注</text>
  176. </view>
  177. <!-- 备注文本区域 -->
  178. <view class="content-text" v-if="!record.isCollapsed">
  179. <text>{{ record.remark }}</text>
  180. </view>
  181. </template>
  182. <!-- 保养记录特有字段 -->
  183. <template v-else>
  184. <!-- 附件信息 -->
  185. <view class="info-row" v-if="!record.isCollapsed">
  186. <text class="label">附件信息</text>
  187. </view>
  188. <!-- 附件信息文本区域 -->
  189. <view class="content-text" v-if="!record.isCollapsed">
  190. <text>{{ record.attachmentInfo }}</text>
  191. </view>
  192. <!-- 附件图片 -->
  193. <view class="image-container" v-if="!record.isCollapsed">
  194. <image class="uploaded-image" :src="record.attachmentImage" mode="aspectFill"></image>
  195. </view>
  196. <!-- 保养备注 -->
  197. <view class="info-row" v-if="!record.isCollapsed">
  198. <text class="label">备注</text>
  199. </view>
  200. <!-- 保养备注文本区域 -->
  201. <view class="content-text" v-if="!record.isCollapsed">
  202. <text>{{ record.maintainRemark }}</text>
  203. </view>
  204. </template>
  205. <!-- 收起按钮 -->
  206. <view class="collapse-btn" @click="toggleCollapse(index)">
  207. <text class="collapse-text">{{ record.isCollapsed ? '查看全部' : '收起' }}</text>
  208. <text class="collapse-icon">{{ record.isCollapsed ? '▼' : '▲' }}</text>
  209. </view>
  210. </view>
  211. </view>
  212. </view>
  213. </template>
  214. <script>
  215. import ListMixin from '@/mixins/list'
  216. export default {
  217. mixins: [ListMixin],
  218. data() {
  219. return {
  220. showpieceId: '',
  221. mixinListApi: 'exhibit.queryRepairList',
  222. activeMainTab: 'repair', // 当前激活的主Tab
  223. activeFilter: 0, // 当前激活的筛选器
  224. filterOptions: [
  225. { name: '时间' },
  226. { name: '人员' }
  227. ],
  228. selectedTime: '', // 选中的时间
  229. selectedPerson: '', // 选中的人员
  230. timeColumns: [
  231. ['今天', '昨天', '本周', '本月', '上月', '自定义']
  232. ],
  233. personColumns: [
  234. ['张三', '李四', '王五', '赵六', '钱七', '孙八']
  235. ],
  236. // 维修记录数据
  237. repairData: [
  238. {
  239. repairPerson: '李华',
  240. contactPhone: '15845623255',
  241. repairDate: '2025-08-14',
  242. processContent: '文字内容文字内容文字内容',
  243. uploadImage: '/static/商城_商品2.png',
  244. hasCost: '是',
  245. totalCost: '300.00',
  246. costDetails: [
  247. { name: '天然粘胶剂', quantity: '2', amount: '100.00' },
  248. { name: '达玛树脂', quantity: '1', amount: '200.00' }
  249. ],
  250. isResolved: '是',
  251. remark: '文字内容',
  252. isCollapsed: true // 控制收起状态
  253. },
  254. {
  255. repairPerson: '李华',
  256. contactPhone: '15845623255',
  257. repairDate: '2025-08-14',
  258. processContent: '文字内容文字内容文字内容',
  259. uploadImage: '/static/商城_商品2.png',
  260. hasCost: '是',
  261. totalCost: '300.00',
  262. costDetails: [
  263. { name: '天然粘胶剂', quantity: '2', amount: '100.00' },
  264. { name: '达玛树脂', quantity: '1', amount: '200.00' }
  265. ],
  266. isResolved: '是',
  267. remark: '文字内容',
  268. isCollapsed: true // 控制收起状态
  269. },
  270. ],
  271. // 保养记录数据
  272. maintainData: [
  273. {
  274. maintainPerson: '李华',
  275. maintainDate: '2025-08-19',
  276. beforeStatus: '文字内容文字内容文字内容',
  277. beforeImages: ['/static/商城_商品2.png', '/static/商城_商品2.png'],
  278. afterStatus: '文字内容文字内容文字内容',
  279. afterImages: ['/static/商城_商品2.png', '/static/商城_商品2.png'],
  280. hasCost: '是',
  281. totalCost: '300.00',
  282. costDetails: [
  283. { name: '天然粘胶剂', quantity: '2', amount: '100.00' },
  284. { name: '达玛树脂', quantity: '1', amount: '200.00' }
  285. ],
  286. attachmentInfo: '附件信息',
  287. maintainRemark: '文字内容',
  288. attachmentImage: '/static/商城_商品2.png',
  289. isCollapsed: true // 控制收起状态
  290. },
  291. {
  292. maintainPerson: '李华',
  293. maintainDate: '2025-08-19',
  294. beforeStatus: '文字内容文字内容文字内容',
  295. beforeImages: ['/static/商城_商品2.png', '/static/商城_商品2.png'],
  296. afterStatus: '文字内容文字内容文字内容',
  297. afterImages: ['/static/商城_商品2.png', '/static/商城_商品2.png'],
  298. hasCost: '是',
  299. totalCost: '300.00',
  300. costDetails: [
  301. { name: '天然粘胶剂', quantity: '2', amount: '100.00' },
  302. { name: '达玛树脂', quantity: '1', amount: '200.00' }
  303. ],
  304. attachmentInfo: '附件信息',
  305. maintainRemark: '文字内容',
  306. attachmentImage: '/static/商城_商品2.png',
  307. isCollapsed: true // 控制收起状态
  308. }
  309. ]
  310. }
  311. },
  312. computed: {
  313. // list() {
  314. // return this.activeMainTab === 'repair' ? this.repairData : this.maintainData
  315. // },
  316. contentText() {
  317. const tabText = this.activeMainTab === 'repair' ? '维修' : '保养'
  318. const filterText = this.filterOptions[this.activeFilter].name
  319. let selectedText = ''
  320. if (this.activeFilter === 0 && this.selectedTime) {
  321. selectedText = ` - ${this.selectedTime}`
  322. } else if (this.activeFilter === 1 && this.selectedPerson) {
  323. selectedText = ` - ${this.selectedPerson}`
  324. }
  325. return `${tabText}记录 - 按${filterText}筛选${selectedText}`
  326. }
  327. },
  328. methods: {
  329. mixinSetParams() {
  330. return {
  331. showpieceId: this.showpieceId
  332. }
  333. },
  334. switchMainTab(tab) {
  335. this.activeMainTab = tab
  336. },
  337. onFilterChange(index) {
  338. this.activeFilter = index
  339. // 切换筛选器时清空选择
  340. this.selectedTime = ''
  341. this.selectedPerson = ''
  342. },
  343. showTimePicker() {
  344. this.$refs.timePicker.open()
  345. },
  346. showPersonPicker() {
  347. this.$refs.personPicker.open()
  348. },
  349. onTimeConfirm(value) {
  350. this.selectedTime = value.value[0]
  351. console.log('选择的时间:', value)
  352. },
  353. onTimeCancel() {
  354. console.log('取消选择时间')
  355. },
  356. onPersonConfirm(value) {
  357. this.selectedPerson = value.value[0]
  358. console.log('选择的人员:', value)
  359. },
  360. onPersonCancel() {
  361. console.log('取消选择人员')
  362. },
  363. toggleCollapse(index) {
  364. if (this.activeMainTab === 'repair') {
  365. this.repairData[index].isCollapsed = !this.repairData[index].isCollapsed
  366. console.log('收起/展开费用详情', this.repairData[index].isCollapsed)
  367. } else {
  368. this.maintainData[index].isCollapsed = !this.maintainData[index].isCollapsed
  369. console.log('收起/展开费用详情', this.maintainData[index].isCollapsed)
  370. }
  371. }
  372. },
  373. onLoad(args){{
  374. this.showpieceId = args.id
  375. }}
  376. }
  377. </script>
  378. <style lang="scss" scoped>
  379. .container {
  380. background-color: #f5f5f5;
  381. min-height: 100vh;
  382. }
  383. .header{
  384. padding: 16rpx 39rpx 23rpx;
  385. background: #fff;
  386. }
  387. .main-tabs {
  388. display: flex;
  389. margin-bottom: 48rpx;
  390. // border-bottom: 2rpx solid #f0f0f0;
  391. .tab-item {
  392. flex: 1;
  393. position: relative;
  394. padding: 13rpx 0;
  395. text-align: center;
  396. .tab-text {
  397. font-size: 28rpx;
  398. color: $secondary-text-color;
  399. font-weight: 400;
  400. transition: all 0.3s ease;
  401. }
  402. &.active {
  403. .tab-text {
  404. color: $primary-color;
  405. // font-weight: 600;
  406. }
  407. }
  408. .tab-underline {
  409. position: absolute;
  410. bottom: 0;
  411. left: 50%;
  412. transform: translateX(-50%);
  413. width: 60rpx;
  414. height: 4rpx;
  415. background-color: $primary-color;
  416. border-radius: 2rpx;
  417. }
  418. }
  419. }
  420. .filter-section {
  421. margin-bottom: 32rpx;
  422. }
  423. .picker-buttons {
  424. // margin-bottom: 32rpx;
  425. display: flex;
  426. gap: 55rpx;
  427. .picker-btn {
  428. display: flex;
  429. align-items: center;
  430. justify-content: flex-start;
  431. padding: 0;
  432. background-color: transparent;
  433. color: $primary-text-color;
  434. &.active {
  435. color: $primary-color;
  436. }
  437. .btn-text {
  438. font-size: 28rpx;
  439. // color: $primary-color;
  440. margin-right: 10rpx;
  441. }
  442. .arrow-icon {
  443. font-size: 20rpx;
  444. // color: $primary-color;
  445. }
  446. }
  447. }
  448. .content-area {
  449. padding: 22rpx 29rpx;
  450. .record-item {
  451. background: #fff;
  452. border-radius: 16rpx;
  453. padding: 29rpx;
  454. margin-bottom: 37rpx;
  455. border-radius: 15rpx;
  456. box-shadow: 0 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
  457. .info-row {
  458. display: flex;
  459. justify-content: space-between;
  460. align-items: flex-start;
  461. margin-bottom: 38rpx;
  462. .label {
  463. font-size: 28rpx;
  464. color: $primary-text-color;
  465. // font-weight: 400;
  466. flex-shrink: 0;
  467. }
  468. .value {
  469. font-size: 28rpx;
  470. color: $primary-text-color;
  471. text-align: right;
  472. flex: 1;
  473. margin-left: 32rpx;
  474. &.red-text {
  475. color: $primary-color;
  476. }
  477. }
  478. }
  479. .content-text {
  480. background: #f5f5f5;
  481. border-radius: 15rpx;
  482. padding: 24rpx;
  483. margin-bottom: 24rpx;
  484. min-height: 120rpx;
  485. text {
  486. font-size: 28rpx;
  487. color: $primary-text-color;
  488. line-height: 1.5;
  489. }
  490. }
  491. .image-container {
  492. margin-bottom: 29rpx;
  493. .uploaded-image {
  494. width: 157rpx;
  495. height: 157rpx;
  496. // border-radius: 8rpx;
  497. }
  498. }
  499. .cost-table {
  500. margin-bottom: 24rpx;
  501. .table-header {
  502. display: flex;
  503. // background: #f8f8f8;
  504. // border-radius: 8rpx 8rpx 0 0;
  505. padding: 30rpx 0;
  506. justify-content: space-between;
  507. .header-cell {
  508. flex: 1;
  509. font-size: 30rpx;
  510. color: $secondary-text-color;
  511. &:nth-child(1) {
  512. text-align: left;
  513. }
  514. &:nth-child(2) {
  515. text-align: center;
  516. }
  517. &:nth-child(3) {
  518. text-align: right;
  519. }
  520. // font-weight: 500;
  521. }
  522. }
  523. .table-row {
  524. display: flex;
  525. border-bottom: 1rpx solid #f0f0f0;
  526. padding: 30rpx 0;
  527. // justify-content: space-between;
  528. .cell {
  529. flex: 1;
  530. font-size: 30rpx;
  531. color: $primary-text-color;
  532. &:nth-child(1) {
  533. text-align: left;
  534. }
  535. &:nth-child(2) {
  536. text-align: center;
  537. }
  538. &:nth-child(3) {
  539. text-align: right;
  540. }
  541. }
  542. // .cell:first-child {
  543. // text-align: center;
  544. // }
  545. }
  546. }
  547. .view-all-btn {
  548. display: flex;
  549. justify-content: center;
  550. align-items: center;
  551. padding: 16rpx 0;
  552. margin-top: 16rpx;
  553. .view-all-text {
  554. font-size: 26rpx;
  555. color: $primary-color;
  556. margin-right: 8rpx;
  557. }
  558. .view-all-icon {
  559. font-size: 20rpx;
  560. color: $primary-color;
  561. }
  562. }
  563. .collapse-btn {
  564. display: flex;
  565. justify-content: center;
  566. align-items: center;
  567. padding: 16rpx 0;
  568. margin-top: 16rpx;
  569. .collapse-text {
  570. font-size: 26rpx;
  571. color: $primary-color;
  572. margin-right: 8rpx;
  573. }
  574. .collapse-icon {
  575. font-size: 20rpx;
  576. color: $primary-color;
  577. }
  578. }
  579. }
  580. }
  581. </style>