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

676 lines
20 KiB

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