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

607 lines
17 KiB

<template>
<view class="container">
<view class="header">
<!-- 大Tab维修记录/保养记录 -->
<view class="main-tabs">
<view
class="tab-item"
:class="{ active: activeMainTab === 'repair' }"
@click="switchMainTab('repair')"
>
<text class="tab-text">维修记录</text>
<view class="tab-underline" v-if="activeMainTab === 'repair'"></view>
</view>
<view
class="tab-item"
:class="{ active: activeMainTab === 'maintain' }"
@click="switchMainTab('maintain')"
>
<text class="tab-text">保养记录</text>
<view class="tab-underline" v-if="activeMainTab === 'maintain'"></view>
</view>
</view>
<!-- 筛选按钮区域 -->
<view class="picker-buttons">
<view class="picker-btn" :class="{ active: selectedTime }" @click="showTimePicker" >
<text class="btn-text">{{ selectedTime || '时间' }}</text>
<text class="arrow-icon">▼</text>
</view>
<view class="picker-btn" :class="{ active: selectedPerson }" @click="showPersonPicker" >
<text class="btn-text">{{ selectedPerson.label || '人员' }}</text>
<text class="arrow-icon">▼</text>
</view>
</view>
</view>
<!-- 日期选择器 -->
<uv-datetime-picker
confirm-color="#C70019"
ref="timePicker"
mode="date"
@confirm="onTimeConfirm"
></uv-datetime-picker>
<!-- 人员选择器 -->
<uv-picker
ref="personPicker"
:columns="personColumns"
@confirm="onPersonConfirm"
@cancel="onPersonCancel"
keyName="label"
title="选择人员"
confirmColor="#C70019"
></uv-picker>
<!-- 内容区域 -->
<view class="content-area">
<!-- 记录item -->
<!-- 加载动画容器 -->
<view v-if="isLoading" class="loading-icon">
<uv-loading-icon mode="circle" size="48"></uv-loading-icon>
</view>
<view class="record-item" v-else-if="list.length" v-for="(record, index) in list" :key="index">
<!-- 维修记录 -->
<template v-if="activeMainTab === 'repair'">
<!-- 基本信息 -->
<view class="info-row">
<text class="label">维修人</text>
<text class="value">{{ record.repairName }}</text>
</view>
<view class="info-row">
<text class="label">联系方式</text>
<text class="value">{{ record.phone }}</text>
</view>
<view class="info-row">
<text class="label">维修日期</text>
<text class="value">{{ record.repairDate }}</text>
</view>
<view class="info-row">
<text class="label">处理内容</text>
</view>
<!-- 处理内容文本区域 -->
<view class="content-text">
<text>{{ record.content }}</text>
</view>
<!-- 上传图片 -->
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">上传图片</text>
</view>
<view class="image-container" v-if="!collapsedStates[index]">
<image class="uploaded-image" v-for="(value, index) in record.image.split(',')" :key="index" :src="value" mode="aspectFill"></image>
</view>
<!-- 是否产生费用 -->
<view class="info-row">
<text class="label">是否产生费用</text>
<text class="value red-text">{{ record.isExpend === '1' || record.isExpend === 1 ? '是' : '否' }}</text>
</view>
</template>
<!-- 保养记录 -->
<template v-else>
<!-- 基本信息 -->
<view class="info-row">
<text class="label">保养人</text>
<text class="value">{{ record.maintenanceName }}</text>
</view>
<view class="info-row">
<text class="label">保养日期</text>
<text class="value">{{ record.maintenanceDate }}</text>
</view>
<view class="info-row">
<text class="label">保养前状态</text>
</view>
<!-- 保养前状态文本区域 -->
<view class="content-text">
<text>{{ record.stateFrontText }}</text>
</view>
<!-- 保养前图片 -->
<view class="image-container" v-if="!collapsedStates[index]">
<image
class="uploaded-image"
v-for="(img, imgIndex) in record.stateFrontImage.split(',')"
:key="imgIndex"
:src="img"
mode="aspectFill"
></image>
</view>
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">保养后状态</text>
</view>
<!-- 保养后状态文本区域 -->
<view class="content-text" v-if="!collapsedStates[index]">
<text>{{ record.stateBackText }}</text>
</view>
<!-- 保养后图片 -->
<view class="image-container" v-if="!collapsedStates[index]">
<image
class="uploaded-image"
v-for="(img, imgIndex) in record.stateBackImage.split(',')"
:key="'after-' + imgIndex"
:src="img"
mode="aspectFill"
></image>
</view>
<!-- 是否产生费用 -->
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">是否产生费用</text>
<text class="value red-text">{{ record.isExpend === '1'||record.isExpend === 1 ? '是' : '否' }}</text>
</view>
</template>
<!-- 产生费用 -->
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">产生费用</text>
<text class="value red-text">{{ record.amount }}</text>
</view>
<!-- 费用详情表格 -->
<view class="cost-table" v-if="!collapsedStates[index]">
<view class="table-header">
<text class="header-cell">费用名称</text>
<text class="header-cell">数量</text>
<text class="header-cell">金额</text>
</view>
<view class="table-row" v-for="(item, costIndex) in record.exhibitMaintenanceExpenses" :key="costIndex">
<text class="cell">{{ item.title }}</text>
<text class="cell">{{ item.num }}</text>
<text class="cell">{{ item.amount }}</text>
</view>
<view class="table-row" v-for="(item, costIndex) in record.exhibitRepairExpenseList" :key="costIndex">
<text class="cell">{{ item.title }}</text>
<text class="cell">{{ item.num }}</text>
<text class="cell">{{ item.amount }}</text>
</view>
</view>
<!-- 维修记录特有字段 -->
<template v-if="activeMainTab === 'repair'">
<!-- 问题是否解决 -->
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">问题是否解决</text>
<text class="value red-text">{{ record.isResolved }}</text>
</view>
<!-- 备注 -->
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">备注</text>
</view>
<!-- 备注文本区域 -->
<view class="content-text" v-if="!collapsedStates[index]">
<text>{{ record.remark }}</text>
</view>
</template>
<!-- 保养记录特有字段 -->
<template v-else>
<!-- 附件信息 -->
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">附件信息</text>
</view>
<!-- 附件信息文本区域 -->
<view class="content-text" v-if="!collapsedStates[index]">
<text>{{ record.remarkText }}</text>
</view>
<!-- 附件图片 -->
<view class="image-container" v-if="!collapsedStates[index]">
<image class="uploaded-image" v-for="(value, index) in record.remarkImage.split(',')" :src="value" :key="index" mode="aspectFill"></image>
</view>
<!-- 保养备注 -->
<view class="info-row" v-if="!collapsedStates[index]">
<text class="label">备注</text>
</view>
<!-- 保养备注文本区域 -->
<view class="content-text" v-if="!collapsedStates[index]">
<text>{{ record.remark }}</text>
</view>
</template>
<!-- 收起按钮 -->
<view class="collapse-btn" @click="toggleCollapse(index)">
<text class="collapse-text">{{ collapsedStates[index] ? '查看全部' : '收起' }}</text>
<text class="collapse-icon">{{ collapsedStates[index] ? '' : '' }}</text>
</view>
</view>
<view v-else>
<uv-empty icon="/static/暂无搜索结果.png" />
</view>
</view>
</view>
</template>
<script>
import ListMixin from '@/mixins/list'
export default {
mixins: [ListMixin],
data() {
return {
showpieceId: '',
mixinListApi: 'exhibit.queryRepairList',
activeMainTab: 'repair', // 当前激活的主Tab
activeFilter: 0, // 当前激活的筛选器
collapsedStates: [], // 控制每个记录项的展开/收起状态
afterUpdateDataFn(list) {
this.collapsedStates = new Array(list.length).fill(true)
},
filterOptions: [
{ name: '时间' },
{ name: '人员' }
],
selectedTime: '', // 选中的时间
selectedPerson: '', // 选中的人员
timeColumns: [
['今天', '昨天', '本周', '本月', '上月', '自定义']
],
personColumns: [ ]
}
},
computed: {
contentText() {
const tabText = this.activeMainTab === 'repair' ? '维修' : '保养'
const filterText = this.filterOptions[this.activeFilter].name
let selectedText = ''
if (this.activeFilter === 0 && this.selectedTime) {
selectedText = ` - ${this.selectedTime}`
} else if (this.activeFilter === 1 && this.selectedPerson) {
selectedText = ` - ${this.selectedPerson}`
}
return `${tabText}记录 - 按${filterText}筛选${selectedText}`
}
},
methods: {
mixinSetParams() {
const params = { }
if (this.activeMainTab === 'repair' && this.selectedTime) {
params.repairDate = this.selectedTime
} else if (this.activeMainTab === 'maintain' && this.selectedTime) {
params.maintainDate = this.selectedTime
}
if (this.selectedPerson) {
params.id = this.selectedPerson.id
}
return {
showpieceId: this.showpieceId,
...params
}
},
async switchMainTab(tab) {
this.activeMainTab = tab
this.mixinListApi = this.activeMainTab === 'repair' ? 'exhibit.queryRepairList' : 'exhibit.queryMaintenanceList'
this.onFilterChange()
this.initPage()
this.getList(true)
// this.initCollapsedStates()
},
onFilterChange() {
// this.activeFilter = index
// 切换筛选器时清空选择
this.selectedTime = ''
this.selectedPerson = ''
},
showTimePicker() {
this.$refs.timePicker.open()
},
showPersonPicker() {
this.$refs.personPicker.open()
},
onTimeConfirm(e) {
this.selectedTime = this.$utils.formatTime(e.value)
this.initPage()
this.getList(true)
},
onTimeCancel() {
console.log('取消选择时间')
},
onPersonConfirm(value) {
this.selectedPerson = value.value[0]
console.log('选择的人员:', value)
this.initPage()
this.getList(true)
},
onPersonCancel() {
console.log('取消选择人员')
},
toggleCollapse(index) {
this.$set(this.collapsedStates, index, !this.collapsedStates[index])
console.log('收起/展开费用详情', this.collapsedStates[index])
}
},
async onLoad(args){{
this.showpieceId = args.id
const userRes = await this.$api.config.queryUserList()
this.personColumns = [[...userRes.result.records.map(item => ({
label: item.nickName,
id: item.id
}))]]
}}
}
</script>
<style lang="scss" scoped>
.container {
background-color: #f5f5f5;
min-height: 100vh;
}
.header{
padding: 16rpx 39rpx 23rpx;
background: #fff;
}
.main-tabs {
display: flex;
margin-bottom: 48rpx;
// border-bottom: 2rpx solid #f0f0f0;
.tab-item {
flex: 1;
position: relative;
padding: 13rpx 0;
text-align: center;
.tab-text {
font-size: 28rpx;
color: $secondary-text-color;
font-weight: 400;
transition: all 0.3s ease;
}
&.active {
.tab-text {
color: $primary-color;
// font-weight: 600;
}
}
.tab-underline {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: $primary-color;
border-radius: 2rpx;
}
}
}
.filter-section {
margin-bottom: 32rpx;
}
.picker-buttons {
// margin-bottom: 32rpx;
display: flex;
gap: 55rpx;
.picker-btn {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0;
background-color: transparent;
color: $primary-text-color;
&.active {
color: $primary-color;
}
.btn-text {
font-size: 28rpx;
// color: $primary-color;
margin-right: 10rpx;
}
.arrow-icon {
font-size: 20rpx;
// color: $primary-color;
}
}
}
.content-area {
padding: 22rpx 29rpx;
.loading-icon {
margin-top: 60rpx;
}
.record-item {
background: #fff;
border-radius: 16rpx;
padding: 29rpx;
margin-bottom: 37rpx;
border-radius: 15rpx;
box-shadow: 0 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
.info-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 38rpx;
.label {
font-size: 28rpx;
color: $primary-text-color;
// font-weight: 400;
flex-shrink: 0;
}
.value {
font-size: 28rpx;
color: $primary-text-color;
text-align: right;
flex: 1;
margin-left: 32rpx;
&.red-text {
color: $primary-color;
}
}
}
.content-text {
background: #f5f5f5;
border-radius: 15rpx;
padding: 24rpx;
margin-bottom: 24rpx;
min-height: 120rpx;
text {
font-size: 28rpx;
color: $primary-text-color;
line-height: 1.5;
}
}
.image-container {
margin-bottom: 29rpx;
.uploaded-image {
width: 157rpx;
height: 157rpx;
// border-radius: 8rpx;
}
}
.cost-table {
margin-bottom: 24rpx;
.table-header {
display: flex;
// background: #f8f8f8;
// border-radius: 8rpx 8rpx 0 0;
padding: 30rpx 0;
justify-content: space-between;
.header-cell {
flex: 1;
font-size: 30rpx;
color: $secondary-text-color;
&:nth-child(1) {
text-align: left;
}
&:nth-child(2) {
text-align: center;
}
&:nth-child(3) {
text-align: right;
}
// font-weight: 500;
}
}
.table-row {
display: flex;
border-bottom: 1rpx solid #f0f0f0;
padding: 30rpx 0;
// justify-content: space-between;
.cell {
flex: 1;
font-size: 30rpx;
color: $primary-text-color;
&:nth-child(1) {
text-align: left;
}
&:nth-child(2) {
text-align: center;
}
&:nth-child(3) {
text-align: right;
}
}
// .cell:first-child {
// text-align: center;
// }
}
}
.view-all-btn {
display: flex;
justify-content: center;
align-items: center;
padding: 16rpx 0;
margin-top: 16rpx;
.view-all-text {
font-size: 26rpx;
color: $primary-color;
margin-right: 8rpx;
}
.view-all-icon {
font-size: 20rpx;
color: $primary-color;
}
}
.collapse-btn {
display: flex;
justify-content: center;
align-items: center;
padding: 16rpx 0;
margin-top: 16rpx;
.collapse-text {
font-size: 26rpx;
color: $primary-color;
margin-right: 8rpx;
}
.collapse-icon {
font-size: 20rpx;
color: $primary-color;
}
}
}
}
</style>