| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212 |
- <template>
- <uni-navbar-lite :showLeft="true" title="设备检查"></uni-navbar-lite>
- <scroll-view class="container" scroll-y="true">
- <view class="info-card">
- <view class="info-item">
- <text class="info-label">设备名称</text>
- <text class="info-value">{{ deviceInfo.machineryName ?? '' }}</text>
- </view>
- <view class="info-item">
- <text class="info-label">设备编号</text>
- <text class="info-value">{{ deviceInfo.machinerySpec ?? '' }}</text>
- </view>
- <view class="info-item">
- <text class="info-label">位置</text>
- <text class="info-value">{{ deviceInfo.machineryLocation ?? '' }}</text>
- </view>
- </view>
- <!-- 检查项目列表 -->
- <!-- <view class="section">
- <view class="section-header">
- <text class="section-title">检查项目</text>
- </view> -->
- <view class="check-items-list">
- <view class="check-item" v-for="(item, index) in checkItems" :key="index">
- <view class="item-container">
- <view class="item-header">
- <text class="item-title">{{ item.subjectName ?? '' }}</text>
- <view class="check-item-controls">
- <view class="form-picker" @click="showStatusPicker(item)">
- <view class="picker-display">
- <text v-if="item.status != null" class="selected-value">{{ getStatusText(item.status) }}</text>
- <text v-else class="placeholder">请选择状态</text>
- <text class="arrow">▼</text>
- </view>
- </view>
- <view class="expand-toggle" @click="toggleExpand(item)">
- <text class="expand-icon" :class="{'rotated': item.expanded}">▼</text>
- </view>
- </view>
- </view>
-
- <!-- 展开区域 -->
- <view class="expanded-content" v-if="!item.expanded">
- <!-- 图片和视频上传区域 -->
- <view class="check-item-media">
- <view class="media-section">
- <text class="media-title">上传图片</text>
- <view class="upload-wrapper" v-if="currentOpType != 'view'">
- <UploadImage
- :limit="6"
- :modelValue="item.photos ?? []"
- businessType="deviceCheck"
- @update:modelValue="(value: UTSArray<UploadResponse>) => updatePhotos(item, value)"
- />
- </view>
- <view class="image-container" v-else>
- <image
- v-for="(attachment, index) in getAttachmentList(item.photoUrl)"
- :key="index"
- :src="attachment"
- :alt="'附件图片' + (index + 1)"
- class="attachment-image"
- @click="previewImage(attachment)"
- />
- </view>
- </view>
-
- <!-- 视频上传区域 -->
- <view class="media-section">
- <text class="media-title">上传视频</text>
- <view class="upload-wrapper" v-if="currentOpType != 'view'">
- <UploadVideo
- :limit="3"
- :modelValue="item.videos ?? []"
- businessType="deviceCheck"
- @update:modelValue="(value: UTSArray<VideoItem>) => updateVideos(item, value)"
- />
- </view>
- <view class="image-container" v-else>
- <video
- v-for="(attachment, index) in getVideoList(item.videoUrl)"
- :key="index"
- :src="attachment"
- :alt="'附件视频' + (index + 1)"
- class="attachment-image"
- :controls="true"
- />
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- <!-- </view> -->
-
- <!-- 全局备注 -->
- <view class="section">
- <view class="section-header">
- <text class="section-title">备注</text>
- </view>
- <view class="remark-container">
- <textarea class="remark-textarea" v-model="deviceInfo.remark" placeholder="请输入备注信息" maxlength="500"></textarea>
- </view>
- </view>
- </scroll-view>
- <!-- 底部操作栏 -->
- <view class="bottom-actions" v-if="currentOpType != 'view'" >
- <!-- <button class="action-btn draft-btn" @click="saveDraft">保存草稿</button>
- <button
- v-if="showMaintenanceBtn"
- class="action-btn maintenance-btn"
- @click="submitMaintenance"
- >
- 提交维修
- </button> -->
- <button class="action-btn submit-btn" @click="submitCheck">提交检查</button>
- </view>
- <!-- 状态选择器弹窗 -->
- <view v-if="currentItem != null" class="picker-modal">
- <view class="modal-mask" @click="hideStatusPicker"></view>
- <view class="modal-content">
- <view class="modal-header">
- <text class="modal-title">选择状态</text>
- <text class="modal-close" @click="hideStatusPicker">取消</text>
- </view>
- <scroll-view class="modal-body" scroll-y="true">
- <view
- v-for="(option, index) in statusOptions"
- :key="index"
- class="picker-option"
- :class="{ 'selected': index == selectedStatusIndex }"
- @click="selectStatusManually(index)"
- >
- <text class="option-text">{{ option.label }}</text>
- <text v-if="index == selectedStatusIndex" class="option-check">✓</text>
- </view>
- </scroll-view>
- </view>
- </view>
- </template>
- <script setup lang="uts">
- import { ref, reactive, onMounted, computed} from 'vue'
- import UploadImage from '../../components/upload-image/upload-image.uvue'
- import UploadVideo from '../../components/upload-video/upload-video.uvue'
- import type { UploadResponse } from '../../types/workbench'
- import type { VideoItem } from '../../types/workbench'
- import type { SysDictData } from '../../types/dict'
- import { getDetailInfo, batchEditTaskDetail } from '../../api/task/detail.uts'
- import { getDictDataByType } from '../../api/dict/index'
- import { getBaseUrl } from '../../utils/request'
- // TaskDetailSubject类型定义(与后端保持一致,并添加前端需要的字段)
- type TaskDetailSubject = {
- id: Number | null
- taskDetailId: Number | null
- subjectName: string | null
- subjectValue: string | null
- photoUrl: string | null
- videoUrl: string | null
- remarks: string | null
- sortOrder: Number | null
- status: string | null
- // 前端扩展字段
- expanded: boolean // 控制展开收起
- photos?: UploadResponse[] // 前端临时存储图片上传的文件对象
- videos?: VideoItem[] // 前端临时存储视频上传的文件对象
- }
- // DvCheckTaskDetail类型定义
- type DvCheckTaskDetail = {
- detailId: Number | null
- taskId: Number | null
- machineryRecordId: Number | null
- machineryId: Number | null
- machineryTypeName: string | null
- machinerySpec: string | null
- machineryLocation: string | null
- machineryName: string | null
- subjectId: Number | null
- subjectCode: string | null
- subjectName: string | null
- locationRecordId: Number | null
- locationId: Number | null
- locationName: string | null
- locationCode: string | null
- sourceType: string | null
- orderNum: Number | null
- status: string | null
- taskStatus: string | null
- imagesUrl: string | null
- videosUrl: string | null
- resultValue: string | null
- resultDesc: string | null
- remark: string | null
- attr1: string | null
- attr2: string | null
- attr3: Number | null
- attr4: Number | null
- taskDetailSubjectList: TaskDetailSubject[] | null
- }
- // 设备信息
- const deviceInfo = ref<DvCheckTaskDetail>({
- detailId: null,
- taskId: null,
- machineryRecordId: null,
- machineryId: null,
- machineryTypeName: null,
- machinerySpec: null,
- machineryLocation: null,
- machineryName: null,
- subjectId: null,
- subjectCode: null,
- subjectName: null,
- locationRecordId: null,
- locationId: null,
- locationName: null,
- locationCode: null,
- sourceType: null,
- orderNum: null,
- status: null,
- taskStatus: null,
- imagesUrl: null,
- videosUrl: null,
- resultValue: null,
- resultDesc: null,
- remark: null,
- attr1: null,
- attr2: null,
- attr3: null,
- attr4: null,
- taskDetailSubjectList: null
- })
- // 当前任务明细ID
- const currentDetailId = ref<string>('')
- const currentOpType = ref<string>('')
- // 检查项目列表(直接使用TaskDetailSubject类型)
- const checkItems = ref<TaskDetailSubject[]>([])
- // 字典数据
- const subjectStatusDictList = ref<SysDictData[]>([]) // 检查项状态字典列表
- const dictLoaded = ref<boolean>(false) // 字典加载状态
- // 选择器选项类型
- type PickerOption = {
- label: string
- value: string
- }
- // 状态选项
- const statusOptions = ref<PickerOption[]>([])
- // 获取检查项状态字典列表
- const loadSubjectStatusDictList = async (): Promise<void> => {
- try {
- const result = await getDictDataByType('mes_subject_status')
- const resultObj = result as UTSJSONObject
- if (resultObj['code'] == 200) {
- const data = resultObj['data'] as any[]
- const dictData: SysDictData[] = []
- if (data.length > 0) {
- for (let i = 0; i < data.length; i++) {
- const item = data[i] as UTSJSONObject
- const dictItem: SysDictData = {
- dictValue: item['dictValue'] as string | null,
- dictLabel: item['dictLabel'] as string | null,
- dictCode: null,
- dictSort: null,
- dictType: null,
- cssClass: null,
- listClass: null,
- isDefault: null,
- status: null,
- default: null,
- createTime: null,
- remark: null
- }
- dictData.push(dictItem)
- }
- }
- subjectStatusDictList.value = dictData
- dictLoaded.value = true
-
- // 更新状态选项
- const newOptions: PickerOption[] = []
- for (let i = 0; i < dictData.length; i++) {
- const dict = dictData[i]
- if (dict.dictValue != null && dict.dictLabel != null) {
- newOptions.push({
- label: dict.dictLabel,
- value: dict.dictValue
- })
- }
- }
- statusOptions.value = newOptions
- }
- } catch (e: any) {
- console.error('获取检查项状态字典失败:', e.message)
- dictLoaded.value = true
- }
- }
- // 获取状态文本
- const getStatusText = (status: string | null): string => {
- if (status == null || status.length == 0) return ''
- if (dictLoaded.value != true) {
- return status
- }
- const dictItem = subjectStatusDictList.value.find((dict: SysDictData) => dict.dictValue == status)
- return dictItem != null && dictItem.dictLabel != null ? dictItem.dictLabel : status
- }
- // 当前选中的检查项
- const currentItem = ref<TaskDetailSubject | null>(null)
- // 选中的状态索引
- const selectedStatusIndex = ref<number>(-1)
- // 显示状态选择器
- const showStatusPicker = (item: TaskDetailSubject): void => {
- currentItem.value = item
- // 根据字典数据动态设置当前选中索引
- if (item.status != null && dictLoaded.value) {
- // 在字典选项中查找匹配的索引
- for (let i = 0; i < statusOptions.value.length; i++) {
- if (statusOptions.value[i].value == item.status) {
- selectedStatusIndex.value = i
- return
- }
- }
- }
- // 如果没找到匹配项或字典未加载,设置为-1
- selectedStatusIndex.value = -1
- }
- // 隐藏状态选择器
- const hideStatusPicker = (): void => {
- currentItem.value = null
- selectedStatusIndex.value = -1
- }
- // 手动选择状态
- const selectStatusManually = (index: number): void => {
- selectedStatusIndex.value = index
- if (currentItem.value != null && index >= 0 && index < statusOptions.value.length) {
- const selectedOption = statusOptions.value[index]
- currentItem.value.status = selectedOption.value
- }
- hideStatusPicker()
- }
- /* // 从弹窗处理状态更改
- const handleStatusChangeFromPopup = (item: TaskDetailSubject, value: string): void => {
- item.status = value
- // 隐藏弹窗
- hideStatusPicker();
- } */
- // 切换展开/收起
- const toggleExpand = (item: TaskDetailSubject): void => {
- item.expanded = !item.expanded
- }
- // 加载设备检查任务明细数据
- const loadDeviceDetail = async (): Promise<void> => {
- if (currentDetailId.value == null || currentDetailId.value.length == 0) {
- uni.showToast({
- title: '缺少任务明细ID参数',
- icon: 'none'
- })
- return
- }
-
- try {
- uni.showLoading({
- title: '加载中...'
- })
-
- const result = await getDetailInfo(currentDetailId.value)
- const resultObj = result as UTSJSONObject
- const code = resultObj['code'] as number
-
- if (code == 200) {
- const data = resultObj['data'] as UTSJSONObject
-
- // 转换设备信息
- const newDeviceInfo: DvCheckTaskDetail = {
- detailId: data['detailId'] != null ? (data['detailId'] as Number) : null,
- taskId: data['taskId'] != null ? (data['taskId'] as Number) : null,
- machineryRecordId: data['machineryRecordId'] != null ? (data['machineryRecordId'] as Number) : null,
- machineryId: data['machineryId'] != null ? (data['machineryId'] as Number) : null,
- machineryTypeName: data['machineryTypeName'] as string | null,
- machinerySpec: data['machinerySpec'] as string | null,
- machineryLocation: data['machineryLocation'] as string | null,
- machineryName: data['machineryName'] as string | null,
- subjectId: data['subjectId'] != null ? (data['subjectId'] as Number) : null,
- subjectCode: data['subjectCode'] as string | null,
- subjectName: data['subjectName'] as string | null,
- locationRecordId: data['locationRecordId'] != null ? (data['locationRecordId'] as Number) : null,
- locationId: data['locationId'] != null ? (data['locationId'] as Number) : null,
- locationName: data['locationName'] as string | null,
- locationCode: data['locationCode'] as string | null,
- sourceType: data['sourceType'] as string | null,
- orderNum: data['orderNum'] != null ? (data['orderNum'] as Number) : null,
- status: data['status'] as string | null,
- taskStatus: data['taskStatus'] as string | null,
- imagesUrl: data['imagesUrl'] as string | null,
- videosUrl: data['videosUrl'] as string | null,
- resultValue: data['resultValue'] as string | null,
- resultDesc: data['resultDesc'] as string | null,
- remark: data['remark'] as string | null,
- attr1: data['attr1'] as string | null,
- attr2: data['attr2'] as string | null,
- attr3: data['attr3'] != null ? (data['attr3'] as Number) : null,
- attr4: data['attr4'] != null ? (data['attr4'] as Number) : null,
- taskDetailSubjectList: null
- }
- deviceInfo.value = newDeviceInfo
-
- // 处理检查项目列表
- const subjectList = data['taskDetailSubjectList'] as any[] | null
- if (subjectList != null && subjectList.length > 0) {
- const newCheckItems: TaskDetailSubject[] = []
- for (let i = 0; i < subjectList.length; i++) {
- const subject = subjectList[i] as UTSJSONObject
- const checkItem: TaskDetailSubject = {
- id: subject['id'] != null ? (subject['id'] as Number) : null,
- taskDetailId: subject['taskDetailId'] != null ? (subject['taskDetailId'] as Number) : null,
- subjectName: subject['subjectName'] as string | null,
- subjectValue: subject['subjectValue'] as string | null,
- photoUrl: subject['photoUrl'] as string | null,
- videoUrl: subject['videoUrl'] as string | null,
- remarks: subject['remarks'] as string | null,
- sortOrder: subject['sortOrder'] != null ? (subject['sortOrder'] as Number) : null,
- //status: '0', // 默认状态为正常
- status: subject['status'] != null ? (subject['status'] as string) : null,
- // 前端扩展字段
- expanded: false,
- photos: [] as UploadResponse[],
- videos: [] as VideoItem[]
- }
- newCheckItems.push(checkItem)
- }
- checkItems.value = newCheckItems
- }
-
- uni.hideLoading()
- } else {
- const msg = resultObj['msg'] as string | null
- uni.hideLoading()
- uni.showToast({
- title: msg ?? '加载失败',
- icon: 'none'
- })
- }
- } catch (e: any) {
- uni.hideLoading()
- uni.showToast({
- title: e.message ?? '加载失败',
- icon: 'none'
- })
- console.error('加载设备检查任务明细失败:', e)
- }
- }
- // 更新图片
- const updatePhotos = (item: TaskDetailSubject, value: UTSArray<UploadResponse>): void => {
- item.photos = value;
- // 同步更新photoUrl字段
- if (value.length > 0) {
- /* const urls: string[] = [];
- for (let i = 0; i < value.length; i++) {
- urls.push(value[i].url);
- }
- item.photoUrl = urls.join(','); */
- const fileNames: string[] = [];
- for (let i = 0; i < value.length; i++) {
- fileNames.push(value[i].fileName);
- }
- item.photoUrl = fileNames.join(',');
- } else {
- item.photoUrl = null;
- }
- };
- // 更新视频
- const updateVideos = (item: TaskDetailSubject, value: UTSArray<VideoItem>): void => {
- item.videos = value;
- // 同步更新videoUrl字段
- if (value.length > 0) {
- /* const urls: string[] = [];
- for (let i = 0; i < value.length; i++) {
- urls.push(value[i].url);
- }
- item.videoUrl = urls.join(','); */
- const fileNames: string[] = [];
- for (let i = 0; i < value.length; i++) {
- fileNames.push(value[i].fileName);
- }
- item.videoUrl = fileNames.join(',');
- } else {
- item.videoUrl = null;
- }
- };
- // 异常项目列表
- const abnormalItems = computed((): TaskDetailSubject[] => {
- return checkItems.value.filter(item => item.status != null && item.status == 'ABNORMAL')
- })
- // 是否显示维修按钮
- const showMaintenanceBtn = computed((): boolean => {
- return abnormalItems.value.length > 0
- })
- // 保存草稿
- const saveDraft = (): void => {
- uni.showModal({
- title: '提示',
- content: '检查信息已保存为草稿',
- showCancel: false,
- success: (res) => {
- if (res.confirm) {
- // 这里可以将数据存储到本地缓存
- const draftData = {
- deviceInfo: deviceInfo.value,
- checkItems: checkItems.value,
- savedAt: new Date().toISOString()
- }
-
- uni.setStorageSync('deviceCheckDraft', JSON.stringify(draftData))
- uni.showToast({
- title: '已保存草稿',
- icon: 'success'
- })
- }
- }
- })
- }
- // 提交检查
- const submitCheck = (): void => {
- // 提交检查结果
-
- // 验证每个检查项的状态不能为空
- for (let i = 0; i < checkItems.value.length; i++) {
- const item = checkItems.value[i];
- if (item.status == null || item.status.length === 0) {
- uni.showToast({
- title: `检查项 "${item.subjectName}" 的状态不能为空`,
- icon: 'none'
- });
- return;
- }
-
- // 当状态为 ABNORMAL 时,验证 photoUrl 或 videoUrl 至少一个不能为空
- // 使用 includes 方法来判断是否包含 ABNORMAL,解决字符串比较问题
- if (item.status.includes('ABNORMAL')) {
- // 检查是否至少有一个媒体文件
- const hasPhotos = item.photoUrl != null && item.photoUrl.length > 0;
- const hasVideos = item.videoUrl != null && item.videoUrl.length > 0;
-
- if (!hasPhotos && !hasVideos) {
- uni.showToast({
- title: `检查项 "${item.subjectName}" 状态为异常时,必须上传图片或视频`,
- icon: 'none'
- });
- return;
- }
- }
- }
-
- const deviceNameStr = (deviceInfo.value.machineryName != null && deviceInfo.value.machineryName.length > 0) ? deviceInfo.value.machineryName : '';
- uni.showModal({
- title: '确认提交',
- //content: `确定提交设备检查结果?\n设备:${deviceNameStr}`,
- success: (res) => {
- if (res.confirm) {
- // 构造提交数据
- const submitData: UTSJSONObject = {
- 'detailId': deviceInfo.value.detailId,
- 'taskId': deviceInfo.value.taskId,
- 'machineryRecordId': deviceInfo.value.machineryRecordId,
- 'machineryId': deviceInfo.value.machineryId,
- 'machineryTypeName': deviceInfo.value.machineryTypeName,
- 'machinerySpec': deviceInfo.value.machinerySpec,
- 'machineryLocation': deviceInfo.value.machineryLocation,
- 'machineryName': deviceInfo.value.machineryName,
- 'subjectId': deviceInfo.value.subjectId,
- 'subjectCode': deviceInfo.value.subjectCode,
- 'subjectName': deviceInfo.value.subjectName,
- 'locationRecordId': deviceInfo.value.locationRecordId,
- 'locationId': deviceInfo.value.locationId,
- 'locationName': deviceInfo.value.locationName,
- 'locationCode': deviceInfo.value.locationCode,
- 'sourceType': deviceInfo.value.sourceType,
- 'orderNum': deviceInfo.value.orderNum,
- 'status': deviceInfo.value.status,
- 'taskStatus': deviceInfo.value.taskStatus,
- 'imagesUrl': deviceInfo.value.imagesUrl,
- 'videosUrl': deviceInfo.value.videosUrl,
- 'resultValue': deviceInfo.value.resultValue,
- 'resultDesc': deviceInfo.value.resultDesc,
- 'remark': deviceInfo.value.remark,
- 'attr1': deviceInfo.value.attr1,
- 'attr2': deviceInfo.value.attr2,
- 'attr3': deviceInfo.value.attr3,
- 'attr4': deviceInfo.value.attr4,
- 'taskDetailSubjectList': checkItems.value.map((item): UTSJSONObject => ({
- 'id': item.id,
- 'taskDetailId': item.taskDetailId,
- 'subjectName': item.subjectName,
- 'subjectValue': item.subjectValue,
- 'photoUrl': item.photoUrl,
- 'videoUrl': item.videoUrl,
- 'remarks': item.remarks,
- 'sortOrder': item.sortOrder,
- 'status': item.status
- }))
- } as UTSJSONObject;
- // 调用批量编辑接口
- uni.showLoading({
- title: '提交中...'
- });
- batchEditTaskDetail(submitData)
- .then((result: any) => {
- const resultObj = result as UTSJSONObject;
- const code = resultObj['code'] as number;
-
- uni.hideLoading();
-
- if (code == 200) {
- uni.showToast({
- title: '检查提交成功!',
- icon: 'success'
- });
- // 设置标记,通知上一个页面需要刷新数据
- uni.setStorageSync('needRefresh', true);
- // 返回上一页
- setTimeout(() => {
- uni.navigateBack();
- }, 1500);
- } else {
- uni.hideLoading(); // 确保在失败时也隐藏加载图标
- const msg = resultObj['msg'] as string | null;
- uni.showToast({
- title: msg ?? '提交失败',
- icon: 'none'
- });
- }
- })
- .catch((error) => {
- uni.hideLoading();
- uni.showToast({
- title: '提交失败',
- icon: 'none'
- });
- console.error('提交检查结果失败:', error);
- });
- }
- }
- });
- }
- // 提交维修申请
- const submitMaintenance = (): void => {
- uni.showModal({
- title: '提交维修申请',
- //content: `检测到设备存在异常,是否提交维修申请?\n设备:${deviceInfo.value.machineryName}\n异常项目数:${abnormalItems.value != null ? abnormalItems.value.length : 0}`,
- confirmText: '提交申请',
- cancelText: '暂不申请',
- success: (res) => {
- if (res.confirm) {
- // 模拟提交维修申请
- uni.showLoading({
- title: '提交中...'
- })
- setTimeout(() => {
- uni.hideLoading()
- uni.showToast({
- title: '维修申请已提交!',
- icon: 'success'
- })
- // 可以跳转到维修申请详情页或返回上一页
- /* setTimeout(() => {
- uni.navigateBack()
- }, 1500) */
- }, 1500)
- }
- }
- })
- }
- const getAttachmentList = (photoUrl: string | null): string[] => {
- if (photoUrl != null && photoUrl != '') {
- // 按逗号分割附件URL字符串,并加上基础URL
- const arr = photoUrl.split(',')
- .map((url: string) => {
- const trimmedUrl = url.trim();
- // 如果是相对路径,加上基础URL
- if (trimmedUrl.startsWith('/')) {
- return getBaseUrl() + trimmedUrl;
- }
- return trimmedUrl;
- })
- .filter((url: string) => url.length > 0);
- return arr;
- }
- return []
- }
-
- // 计算附件列表
- const getVideoList = (videoUrl: string | null): string[] => {
- if (videoUrl != null && videoUrl != '') {
- // 按逗号分割附件URL字符串,并加上基础URL
- const arr = videoUrl.split(',')
- .map((url: string) => {
- const trimmedUrl = url.trim();
- // 如果是相对路径,加上基础URL
- if (trimmedUrl.startsWith('/')) {
- return getBaseUrl() + trimmedUrl;
- }
- return trimmedUrl;
- })
- .filter((url: string) => url.length > 0);
- return arr;
- }
- return []
- }
-
- // 预览图片
- const previewImage = (url: string) => {
- if (url == '') return
-
- // 检查是否为图片文件
- const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
- const isImage = imageExtensions.some(ext => url.toLowerCase().endsWith(ext))
-
- if (isImage) {
- // 如果是图片,使用uni.previewImage预览
- uni.previewImage({
- urls: [url],
- current: 0
- })
- } else {
- // 对于非图片文件,显示提示
- uni.showToast({
- title: '不支持预览此文件类型',
- icon: 'none',
- duration: 2000
- })
- }
- }
- onLoad((options: any) => {
- const params = options as UTSJSONObject
- const detailId = params['detailId'] as string | null
- const opType = params.get('opType') as string | null
-
- if(opType != null){
- currentOpType.value = opType;
- }
- // 获取传递的任务明细ID
- if (detailId != null && detailId.length > 0) {
- currentDetailId.value = detailId
- // 并行加载字典数据和设备检查任务明细数据
- Promise.all([
- loadSubjectStatusDictList(),
- loadDeviceDetail()
- ]).catch(error => {
- console.error('加载数据失败:', error)
- })
- } else {
- uni.showToast({
- title: '缺少任务明细ID参数',
- icon: 'none'
- })
- }
- })
- </script>
- <style lang="scss">
- .container {
- flex: 1;
- background-color: #e8f0f9;
- padding: 20rpx;
- padding-bottom: 120rpx; // 为底部操作栏留出空间
- }
- .info-card {
- background-color: #fff;
- padding: 30rpx;
- border-radius: 16rpx;
- margin: 12rpx 10rpx;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- }
- .info-item {
- flex-direction: row;
- padding: 20rpx 0;
- border-bottom: 1rpx solid #f0f0f0;
- &:last-child {
- border-bottom: none;
- }
- .info-label {
- width: 240rpx;
- font-size: 28rpx;
- color: #666666;
- white-space: nowrap;
- }
- .info-value {
- flex: 1;
- font-size: 28rpx;
- color: #333333;
- text-align: right;
- }
- }
- .section {
- background-color: #ffffff;
- padding: 30rpx;
- border-radius: 16rpx;
- margin: 12rpx 10rpx;
- }
- .remark-container {
- margin-top: 20rpx;
- }
- .remark-textarea {
- width: 100%;
- min-height: 120rpx;
- padding: 20rpx;
- border: 1rpx solid #e0e0e0;
- border-radius: 8rpx;
- background-color: #fff;
- font-size: 28rpx;
- color: #333;
- box-sizing: border-box;
- }
- .section-header {
- margin-bottom: 20rpx;
- padding-bottom: 15rpx;
- border-bottom: 1rpx solid #eee;
- }
- .section-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
- .check-items-list {
- .check-item {
- margin: 12rpx 10rpx;
- background-color: #ffffff;
- border-radius: 16rpx;
- &:last-child {
- border-bottom: none;
- }
- }
-
- .item-container {
- padding: 30rpx;
- }
-
- .item-header {
- flex-direction: row;
- align-items: flex-start;
- margin-bottom: 16rpx;
- justify-content: space-between; /* 主轴两端对齐 */
- min-height: 55rpx;
-
- .item-title {
- font-size: 30rpx;
- color: #333333;
- font-weight: bold;
- flex-wrap: wrap;
- flex: 0 1 75%;
- min-width: 0;
- line-height: 40rpx;
- height: 40rpx;
- }
- }
- .check-item-controls {
- display: flex;
- flex-direction: row;
- align-items: center;
- }
-
- .expand-toggle {
- margin-left: 30rpx;
- padding: 8rpx;
- }
-
- .expand-icon {
- font-size: 24rpx;
- transition: transform 0.3s;
- }
-
- .expand-icon.rotated {
- transform: rotate(180deg);
- }
-
- .form-picker {
- flex: 1;
- }
-
- .picker-display {
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- min-height: 40rpx;
- padding: 12rpx 16rpx;
- border: 1rpx solid #e0e0e0;
- border-radius: 8rpx;
- background-color: #f8f9fa;
- }
-
- .selected-value {
- font-size: 28rpx;
- color: #333333;
- }
-
- .placeholder {
- font-size: 28rpx;
- color: #999999;
- }
-
- .arrow {
- font-size: 24rpx;
- color: #999999;
- margin-left: 12rpx;
- }
- .check-item-media {
- display: flex;
- flex-direction: column;
- gap: 20rpx;
- margin: 15rpx 0;
- }
- .media-section {
- margin-bottom: 15rpx;
- .image-container {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: flex-start; // 或 space-around
- // justify-content: space-around; /* 自动分配间距,避免挤压 */
- align-items: center;
- padding: 0 3rpx;
- .attachment-image {
- width: 280rpx; /* 一行显示两个图片,减去间距的一半 */
- height: 280rpx;
- // padding: 3rpx;
- margin: 3px;
- }
- }
- }
- .media-title {
- display: block;
- font-size: 26rpx;
- color: #666;
- margin-bottom: 10rpx;
- font-weight: 500;
- }
- .upload-wrapper {
- margin-top: 10rpx;
- }
- .image {
- &-list {
- flex-direction: row;
- flex-wrap: wrap;
- }
- &-item {
- background-color: #f5f7fa;
- border-radius: 8rpx;
- position: relative;
- width: 160rpx;
- height: 160rpx;
- margin-right: 20rpx;
- margin-bottom: 20rpx;
- }
- width: 160rpx;
- height: 160rpx;
- border-radius: 8rpx;
- &-delete {
- position: absolute;
- top: 2rpx;
- right: 2rpx;
- width: 44rpx;
- height: 44rpx;
- justify-content: center;
- align-items: center;
- }
- }
- .delete-icon {
- width: 32rpx;
- height: 32rpx;
- }
- .upload {
- &-box {
- background-color: #f5f7fa;
- border-radius: 8rpx;
- width: 160rpx;
- height: 160rpx;
- margin-right: 20rpx;
- margin-bottom: 20rpx;
- border: 2rpx dashed #d0d0d0;
- border-radius: 8rpx;
- justify-content: center;
- align-items: center;
- }
- &-icon {
- font-size: 60rpx;
- color: #999999;
- line-height: 60rpx;
- margin-bottom: 10rpx;
- }
- &-text {
- font-size: 24rpx;
- color: #999999;
- }
- }
- .video {
- &-list {
- flex-direction: row;
- flex-wrap: wrap;
- }
- &-item {
- background-color: #f5f7fa;
- border-radius: 8rpx;
- position: relative;
- width: 220rpx;
- height: 220rpx;
- margin-right: 20rpx;
- margin-bottom: 20rpx;
- }
- width: 220rpx;
- height: 220rpx;
- border-radius: 8rpx;
- &-delete {
- position: absolute;
- top: 2rpx;
- right: 2rpx;
- width: 44rpx;
- height: 44rpx;
- justify-content: center;
- align-items: center;
- }
- }
- }
- .expanded-content {
- margin-top: 15rpx;
- padding-top: 15rpx;
- border-top: 1rpx solid #eee;
- }
- .bottom-actions {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- display: flex;
- flex-direction: row;
- padding: 20rpx 30rpx;
- background-color: #fff;
- border-top: 1rpx solid #eee;
- box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
- }
- .action-btn {
- flex: 1;
- padding: 12rpx;
- border: none;
- border-radius: 6rpx;
- font-size: 26rpx;
- font-weight: bold;
- margin: 0 10rpx;
- min-width: 120rpx;
- }
- .draft-btn {
- background-color: #f0f0f0;
- color: #666;
- }
- .submit-btn {
- background-color: #165dff;
- color: #fff;
- }
- .maintenance-btn {
- background-color: #ff4d4f;
- color: #fff;
- }
- .picker-modal {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 1000;
- }
- .modal-mask {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- }
- .modal-content {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: #ffffff;
- border-top-left-radius: 16rpx;
- border-top-right-radius: 16rpx;
- min-height: 700rpx;
- }
- .modal-header {
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- padding: 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
- }
- .modal-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333333;
- }
- .modal-close {
- font-size: 28rpx;
- color: #007aff;
- }
- .modal-body {
- max-height: 600rpx;
- }
- .picker-option {
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- padding: 24rpx 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
- }
- .picker-option.selected {
- background-color: #f8f9fa;
- }
- .option-text {
- font-size: 28rpx;
- color: #333333;
- }
- .option-check {
- font-size: 28rpx;
- color: #007aff;
- }
- </style>
|