| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684 |
- <template>
- <view class="page inspection">
- <uni-nav-bar dark :fixed="true" :border="false" background-color="#004098" status-bar left-icon="left" :title="$t('inspection.editWorkOrder')" @clickLeft="navigatorBack()" />
- <template v-if="details.length > 0">
- <view class="page-top">
- <view class="top-content flex-row justify-between align-center">
- <view class="align-end">
- {{ details[currentTab].deviceName }}
- </view>
- <view class="align-end">
- <!-- 当前设备tab·所有步骤列表·当前步骤·indexId -->
- <span class="align-end" style="font-size: 24px">
- {{ details[currentTab].allStepsList[details[currentTab].currentStep].indexId }}
- </span>
- <span class="align-end">/{{ details[currentTab].allStepsList.length }}</span>
- </view>
- </view>
- </view>
- <view class="page-content">
- <scroll-view class="tabs-container" :scroll-x="true" :scroll-left="tabScrollLeft" scroll-with-animation ref="scrollContainerRef">
- <uv-tabs ref="tabsRef" :current="currentTab" :list="tabs" :line-color="'#0082CC'" :active-style="{ color: '#004098', fontWeight: '600' }" @click="onClickItem"></uv-tabs>
- <uni-segmented-control
- ref="segmentedControlRef"
- class="justify-start"
- :current="currentTab"
- :values="tabs"
- :style-type="'text'"
- :active-color="'#0082CC'"
- @clickItem="onClickItem"
- v-if="false"
- ></uni-segmented-control>
- </scroll-view>
- <swiper class="swiper-container" :current="currentTab" duration="100" @change="onSwiperChanged($event)">
- <swiper-item v-for="detail in details">
- <view class="step-section">
- <!-- 点击查看巡检项目 -->
- <view class="step-all" @click="allStepShow">
- {{ $t('inspection.clickView') }}
- {{ detail.deviceName }}
- {{ $t('inspection.proj') }}
- <view class="border"></view>
- </view>
- <!-- 巡检项 -->
- <view class="step-form">
- <view class="step-title">
- {{ currentStepInfo.item }}
- <view class="border"></view>
- </view>
- <!-- 巡检标准 -->
- <view class="step-standard">
- <span>{{ $t('inspection.standard') }}:</span>
- {{ currentStepInfo.standard }}
- </view>
- <!-- 巡检标准文件 -->
- <view class="step-standard file" v-if="currentStepInfo.urls">
- <view class="file-title">
- {{ $t('inspection.standardFile') }}
- </view>
- <view class="file-media">
- <video class="video" id="myVideo" :src="currentStepInfo.urls" controls v-if="currentStepInfo.urls && currentStepInfo.urls.includes('mp4')"></video>
- <uni-file-picker
- class="pic"
- file-mediatype="image"
- mode="grid"
- :auto-upload="false"
- :limit="1"
- :imageStyles="{ border: false }"
- v-model="currentStepInfo.urlsList"
- readonly
- v-if="currentStepInfo.urls && (currentStepInfo.urls.includes('jpg') || currentStepInfo.urls.includes('png'))"
- >
- <template #default>
- <view class="flex-col align-center justify-center" style="width: 60px; height: 60px; background-color: #f4f4f4">
- <uni-icons type="plusempty" color="#ACACAC" size="12" />
- </view>
- </template>
- </uni-file-picker>
- </view>
- </view>
- <view class="step-form-item">
- <!-- 是否异常 -->
- <view class="form-title">
- {{ $t('inspection.isAbnormal') }}
- </view>
- <view class="form-btns flex-row justify-center">
- <button type="default" class="abnormal-btn" :class="{ active: currentStepInfo.ifNormal == true }" @click="() => (currentStepInfo.ifNormal = true)">
- {{ $t('inspection.normal') }}
- <uni-icons type="checkmarkempty" color="#004098" v-if="currentStepInfo.ifNormal == true"></uni-icons>
- </button>
- <button type="default" class="abnormal-btn" :class="{ active: currentStepInfo.ifNormal == false }" @click="() => (currentStepInfo.ifNormal = false)">
- {{ $t('inspection.abnormal') }}
- <uni-icons type="checkmarkempty" color="#004098" v-if="currentStepInfo.ifNormal == false"></uni-icons>
- </button>
- </view>
- <!-- 异常描述 -->
- <view class="form-remark flex-row justify-between align-center">
- <view class="form-title align-center">
- <span v-if="currentStepInfo.ifNormal == false" style="color: #ff3b36">*</span>
- {{ $t('inspection.abnormalDesc') }}
- </view>
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- v-model="currentStepInfo.description"
- :placeholder="$t('operation.PleaseFillIn')"
- />
- </view>
- <!-- 图片 -->
- <view class="flex-row">
- <view class="form-title">
- {{ $t('general.picture') }}
- </view>
- <uni-file-picker
- file-mediatype="image"
- mode="grid"
- :auto-upload="false"
- :limit="1"
- :imageStyles="{ border: false }"
- v-model="currentStepInfo.picUrlList"
- @select="upload($event)"
- >
- <template #default>
- <view class="flex-col align-center justify-center" style="width: 60px; height: 60px; background-color: #f4f4f4">
- <uni-icons type="plusempty" color="#ACACAC" size="12" />
- </view>
- </template>
- </uni-file-picker>
- </view>
- </view>
- </view>
- <view class="step-btns flex-row justify-end align-center">
- <button type="primary" :plain="true" @click="onFault" v-if="currentStepInfo.ifNormal == false">
- {{ $t('home.faultReporting') }}
- </button>
- <!-- 上一步 -->
- <button type="primary" :plain="true" v-if="currentStepInfo.indexId > 1" @click="onLast">
- {{ $t('inspection.last') }}
- </button>
- <!-- 下一步 -->
- <button type="primary" :plain="false" v-if="currentStepInfo.indexId != detail.allStepsList.length" @click="onNext()">{{ $t('inspection.next') }}</button>
- <button type="primary" :plain="false" v-if="currentStepInfo.indexId == detail.allStepsList.length" @click="onNext('finished')">
- {{ $t('inspection.finish') }}
- </button>
- </view>
- </view>
- </swiper-item>
- </swiper>
- </view>
- </template>
- </view>
- <!-- 所有步骤弹窗 -->
- <uni-popup ref="allStepPopRef" background-color="#fff" type="top" borderRadius="0 0 10px 10px">
- <view class="popup-content flex-col">
- <view class="step-route-desc" v-if="details[currentTab].routeDesc">
- <view class="popup-step-title">
- <uni-section class="desc-section" :title="details[currentTab].routeName" type="line"></uni-section>
- </view>
- <view class="route-desc-content">
- {{ details[currentTab].routeDesc }}
- </view>
- <view class="step-border"></view>
- </view>
- <view class="step-all-content" :class="{ 'has-route': details[currentTab].routeDesc }">
- <view class="popup-step-title">
- <uni-section title="巡检项" type="line"></uni-section>
- </view>
- <uni-steps
- :options="details[currentTab].allStepsList"
- active-color="#004098"
- active-icon="smallcircle-filled"
- :active="details[currentTab].currentStep"
- direction="column"
- />
- </view>
- </view>
- </uni-popup>
- </template>
- <script setup>
- import { ref, reactive, onMounted, computed, getCurrentInstance, nextTick } from 'vue';
- import { onLoad, onReady } from '@dcloudio/uni-app';
- import { getInspectOrderGet, getInspectOrderGetDetails, inspectOrderWrite } from '@/api/inspection.js';
- import { useDataDictStore } from '@/store/modules/dataDict';
- import { reloginByUserId } from '@/utils/auth';
- import { uploadFile } from '@/api';
- // 引用全局变量$t
- const { appContext } = getCurrentInstance();
- const t = appContext.config.globalProperties.$t;
- // 巡检工单id
- const workOrderId = ref('');
- // 巡检工单tab列表
- const tabs = ref([]);
- // 巡检工单详情
- const details = ref([]);
- // 巡检工单详情原始数据
- const originalDetails = ref([]);
- // 获取巡检工单详情
- const getData = async () => {
- await getInspectOrderGetDetails({
- id: workOrderId.value
- }).then((res) => {
- console.log('getInspectOrderGetDetails', res);
- // 遍历res.data数组中orderDetails数组
- res.data.map((item) => {
- console.log('🚀 ~ getData ~ item:', item);
- // 存放所有路径
- // 存放所有步骤
- item.allStepsList = [];
- // 默认当前步骤为0
- item.currentStep = 0;
- const ifNormalArr = [];
- item.orderDetails.map((detail) => {
- // 将picUrl和urls字段组成数组
- detail.picUrlList = [];
- detail.urlsList = [];
- if (detail.picUrl) {
- detail.picUrlList.push({
- url: detail.picUrl
- });
- }
- if (detail.urls) {
- detail.urlsList.push({
- url: detail.urls
- });
- }
- // 存放所有步骤
- item.allStepsList.push({
- title: detail.item,
- indexId: detail.indexId
- });
- // 存放是否异常
- ifNormalArr.push(detail.ifNormal);
- });
- // 判断所有步骤是否异常是否全部选择
- if (ifNormalArr.every((item) => item != null)) {
- // 全部选择 - 将当前步骤设置为最后一步
- item.currentStep = ifNormalArr.length - 1;
- } else {
- // 未全部选择 - 将当前步骤设置为未选择异常的步骤
- item.currentStep = ifNormalArr.findIndex((item) => item == null);
- }
- });
- details.value = res.data;
- console.log('details.value', details.value);
- // 备份原始数据
- originalDetails.value = JSON.parse(JSON.stringify(res.data));
- // 根据原始数据生成tabs选项卡数据,避免填报时数据变化影响tab状态
- const tabsData = originalDetails.value.map((item) => {
- // 判断Tab是否已完成
- const isCompleted = isTabCompleted(item);
- return {
- name: item.deviceName, // 必备字段,展示的tab名称
- textStyle: isCompleted ? '' : { color: '#e96900' } //手动修改组件添加的字段,用于控制文字颜色
- };
- });
- tabs.value = tabsData;
- console.log('🚀 ~ getData ~ tabs.value:', tabs.value);
- });
- };
- // 当前巡检步骤信息
- const currentStepInfo = computed(() => details.value[currentTab.value].orderDetails[details.value[currentTab.value].currentStep]);
- // --------- 巡检工单tab ---------
- // 当前巡检tab
- const currentTab = ref(0);
- // 巡检工单tab滚动容器
- const scrollContainerRef = ref(null);
- // 巡检工单tab segmented-control
- const segmentedControlRef = ref(null);
- // 巡检工单tab滚动容器 scroll位置
- const tabScrollLeft = ref(0);
- const tabsRef = ref(null);
- // 判断Tab是否已完成的方法
- const isTabCompleted = (item) => {
- // 根据实际业务逻辑判断,这里假设当前Tab索引小于当前步骤则视为已完成
- const { allStepsList, currentStep, orderDetails } = item;
- if (currentStep < allStepsList.length - 1) return false; // 如果当前步骤小于总步骤数,则说明未完成
- // 如果当前步骤等于总步骤数,且最后一步的ifNormal字段不为null,则说明已完成
- const lastStep = orderDetails[orderDetails.length - 1];
- return lastStep.ifNormal !== null;
- };
- // 点击切换tab
- const onClickItem = async (e) => {
- // console.log("🚀 ~ onClickItem ~ e:", e);
- if (currentTab.value !== e.index) {
- currentTab.value = e.index;
- }
- };
- // Swiper滑动切换Tab时,同步滚动Tab到中心
- const onSwiperChanged = async (e) => {
- // console.log("🚀 ~ onSwiperChanged ~ e:", e);
- const newTabIndex = e.detail.current;
- currentTab.value = newTabIndex;
- };
- // -------------------所有步骤弹窗-------------------
- const allStepPopRef = ref(null);
- const allStepShow = () => {
- allStepPopRef.value.open();
- };
- // 故障上报
- const onFault = () => {
- uni.navigateTo({
- url: '/pages/fault/create',
- success() {
- const data = {
- id: currentStepInfo.value.deviceId,
- deptId: currentStepInfo.value.deptId,
- deviceCode: details.value[currentTab.value].deviceCode,
- deviceName: details.value[currentTab.value].deviceName
- };
- setTimeout(() => {
- uni.$emit('inspection-falut', data);
- }, 300);
- }
- });
- };
- // 上一步
- const onLast = () => {
- details.value[currentTab.value].currentStep -= 1;
- console.log('🚀 ~ onLast ~ details.value[currentTab.value].:', details.value[currentTab.value]);
- };
- // 下一步
- const onNext = (finished) => {
- // 判断当前步骤是否异常
- if (currentStepInfo.value.ifNormal == null) {
- uni.showToast({
- title: t('operation.PleaseSelect') + t('inspection.isAbnormal'),
- icon: 'none'
- });
- return;
- }
- // 判断当前步骤是否填写异常描述
- console.log('🚀 ~ onNext ~ currentStepInfo.value:', currentStepInfo.value);
- if (currentStepInfo.value.ifNormal == false && (currentStepInfo.value.description == '' || currentStepInfo.value.description == null)) {
- uni.showToast({
- title: t('operation.PleaseFillIn') + t('inspection.abnormalDesc'),
- icon: 'none'
- });
- return;
- }
- inspectOrderWrite(workOrderId.value, {
- description: currentStepInfo.value.description,
- deviceId: currentStepInfo.value.deviceId,
- ifNormal: currentStepInfo.value.ifNormal,
- indexId: currentStepInfo.value.indexId,
- picUrl: currentStepInfo.value.picUrl
- }).then((res) => {
- if (res.code == 0) {
- if (finished) {
- uni.showToast({ title: t('general.submitSuccess'), icon: 'none' });
- // navigatorBack();
- } else {
- details.value[currentTab.value].currentStep += 1;
- }
- } else {
- uni.showToast({ title: res.msg, icon: 'none' });
- }
- });
- };
- const getDataInfo = async () => {
- await getInspectOrderGet({
- id: workOrderId.value
- }).then((res) => {
- // 将res.data.details数组中的deviceCode赋值给details.value数组中的对应deviceId 的 deviceCode
- res.data.details.map((item) => {
- const device = details.value.find((detail) => detail.deviceId == item.deviceId);
- if (device) {
- device.deviceCode = item.deviceCode;
- }
- });
- console.log('details.value', details.value);
- });
- };
- // 上传图片
- const upload = async (event) => {
- for (const path of event.tempFilePaths) {
- currentStepInfo.value.picUrl = (await uploadFile(path)).data;
- currentStepInfo.value.picUrlList.push({
- url: currentStepInfo.value.picUrl
- });
- }
- };
- const navigatorBack = () => {
- uni.navigateBack();
- };
- onLoad(async (option) => {
- console.log('🚀 ~ inspection edit ~ onLoad:');
- await reloginByUserId(option.reloginUserId);
- workOrderId.value = option.id;
- await getData();
- await getDataInfo();
- console.log('🚀 onLoad ~ tabs.value:', tabs.value);
- });
- onReady(async () => {
- console.log('🚀 ~ inspection edit ~ onReady:');
- });
- onMounted(() => {
- console.log('🚀 ~ inspection edit ~ onMounted:');
- });
- </script>
- <style lang="scss" scoped>
- @import '@/style/work-order-detail.scss';
- // 补充自定义Tab项样式,确保宽度正常(避免Tab过窄或过宽)
- :deep(.uni-segmented-control__item) {
- .tab-item {
- width: max-content;
- padding: 0 16px; // 增加Tab内边距,避免文字拥挤
- height: 36px; // 固定Tab高度,确保对齐
- line-height: 36px; // 垂直居中
- }
- }
- :deep(.custom-finish-tab) {
- .uv-tabs__wrapper__nav__item__text {
- // color: #79C278 !important;
- }
- }
- .page {
- padding: 0;
- position: relative;
- }
- .page-top {
- background: #004098;
- width: 100%;
- box-sizing: border-box;
- padding: 10px 20px;
- }
- .top-content {
- padding-bottom: 30px;
- box-sizing: border-box;
- width: 100%;
- min-height: 70px;
- font-weight: bold;
- font-size: 16px;
- color: #ffffff;
- line-height: 28px;
- }
- .page-content {
- width: 100%;
- height: calc(100% - 100px);
- margin-top: -30px;
- background: #fff;
- background: #ffffff;
- border-radius: 20px 20px 0px 0px;
- // z-index: 1;
- }
- .tabs-container {
- position: relative;
- width: 100%;
- white-space: nowrap;
- padding: 20px;
- box-sizing: border-box;
- }
- :deep(.segmented-control) {
- overflow: unset;
- }
- :deep(.segmented-control__item) {
- uni-view {
- width: max-content;
- padding: 10px;
- }
- }
- .swiper-container {
- position: relative;
- width: 100%;
- height: calc(100% - 110px);
- padding: 0 20px;
- box-sizing: border-box;
- }
- .step-section {
- // font-weight: 600;
- width: 100%;
- height: 100%;
- font-size: 14px;
- color: #333333;
- position: relative;
- }
- .step-form {
- height: calc(100% - 50px - 30px - 10px - var(--status-bar-height));
- margin-bottom: 60px;
- overflow-y: auto;
- }
- .step-all {
- font-weight: 600;
- font-size: 14px;
- color: #004098;
- position: relative;
- padding-left: 10px;
- margin-bottom: 10px;
- }
- .step-title {
- position: relative;
- font-weight: 600;
- padding-left: 10px;
- margin-bottom: 10px;
- }
- .border {
- width: 2px;
- height: 14px;
- background-color: #004098;
- position: absolute;
- left: 0;
- top: 3px;
- }
- .step-standard {
- padding-left: 10px;
- margin-bottom: 10px;
- span {
- font-weight: 600;
- }
- }
- .file-media {
- margin: 10px 0;
- .pic,
- .video {
- width: 100px !important;
- height: 100px !important;
- }
- :deep(.file-picker__box) {
- width: 100px !important;
- height: 100px !important;
- }
- }
- .abnormal-btn {
- width: 45%;
- height: 35px;
- line-height: 35px;
- margin-top: 10px;
- font-weight: 600;
- font-size: 14px;
- color: #666666;
- background: #f3f5f9;
- border-radius: 4px;
- position: relative;
- &.active {
- background: #e4effe;
- color: #004098;
- }
- .uni-icons {
- position: absolute;
- right: 20px;
- }
- }
- .form-title {
- margin-right: 15px;
- }
- .form-remark {
- height: 50px;
- border-bottom: 1px dashed #cacccf;
- margin-bottom: 20px;
- margin-top: 10px;
- }
- :deep(.uni-easyinput__content-textarea) {
- min-height: inherit;
- margin: 10px;
- }
- .step-btns {
- // margin: 10px;
- height: 50px;
- width: 100%;
- background: #ffffff;
- position: fixed;
- bottom: 0;
- left: 0;
- z-index: 2;
- padding-bottom: var(--status-bar-height);
- uni-button {
- width: calc(33.3% - 20px);
- font-size: 14px;
- height: 32px;
- line-height: 32px;
- }
- }
- .popup-content {
- width: 100%;
- min-height: 300px;
- max-height: 500px;
- overflow-y: auto;
- position: relative;
- box-sizing: border-box;
- padding: 20px;
- margin-top: var(--status-bar-height);
- }
- .step-route-desc {
- position: fixed;
- top: 0px;
- left: 0px;
- padding: 10px 20px;
- padding-bottom: 0;
- background: #f2f4f8;
- color: #004098;
- font-size: 14px;
- z-index: 2;
- box-shadow: 0px -2px 10px 0px rgba(0, 0, 0, 0.1);
- // max-height: 130px;
- overflow: hidden;
- }
- .route-desc-content {
- width: 100%;
- max-height: 100px;
- overflow-y: auto;
- }
- .step-border {
- border-bottom: 1px dashed #cacccf;
- padding-top: 10px;
- width: 100%;
- }
- .step-all-content {
- &.has-route {
- margin-top: 150px;
- }
- }
- .popup-step-title {
- :deep(.uni-section) {
- padding: 10px 0;
- }
- :deep(.uni-section__content-title) {
- font-weight: 600;
- }
- .desc-section {
- background: #f2f4f8;
- }
- }
- :deep(.uni-steps__column-text) {
- height: 38px;
- font-weight: 600;
- font-size: 14px;
- color: #666666;
- line-height: 30px;
- display: flex;
- // justify-content: center;
- border: none;
- }
- :deep(.uni-steps__column-title) {
- color: #666666;
- }
- :deep(.uni-steps__column-line-item) {
- color: #666666;
- height: 50px !important;
- }
- :deep(.uni-steps__column-circle) {
- color: #666666;
- height: 10px;
- width: 10px;
- }
- </style>
|