|
|
|
@ -3,28 +3,37 @@
|
|
|
|
<NavBar :title="t('equipmentInspectionTasks.moduleName')" />
|
|
|
|
<NavBar :title="t('equipmentInspectionTasks.moduleName')" />
|
|
|
|
|
|
|
|
|
|
|
|
<view class="filter-bar">
|
|
|
|
<view class="filter-bar">
|
|
|
|
<view class="line-filter" @click="openLineCascader">
|
|
|
|
<view class="filter-row quick-row">
|
|
|
|
<text :class="['line-filter-text', selectedLineId === '' ? 'placeholder' : '']">{{ selectedLineLabel }}</text>
|
|
|
|
<view class="line-filter" @click="openLineCascader">
|
|
|
|
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
|
|
|
|
<text :class="['line-filter-text', selectedLineId === '' ? 'placeholder' : '']">{{ selectedLineLabel }}</text>
|
|
|
|
</view>
|
|
|
|
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
|
|
|
|
<view class="keyword-box">
|
|
|
|
</view>
|
|
|
|
<input
|
|
|
|
<picker mode="selector" :range="taskTypeLabels" :value="taskTypeIndex" @change="onTaskTypeChange">
|
|
|
|
id="equipment-inspection-tasks-keyword-input"
|
|
|
|
<view class="status-filter">
|
|
|
|
v-model="searchKeyword"
|
|
|
|
<text :class="['status-filter-text', selectedTaskType === '' ? 'placeholder' : '']">{{ currentTaskTypeLabel }}</text>
|
|
|
|
class="keyword-input"
|
|
|
|
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
|
|
|
|
:placeholder="t('equipmentInspectionTasks.searchPlaceholder')"
|
|
|
|
</view>
|
|
|
|
confirm-type="search"
|
|
|
|
</picker>
|
|
|
|
@input="handleKeywordInput"
|
|
|
|
|
|
|
|
@confirm="handleSearch"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<picker mode="selector" :range="taskTypeLabels" :value="taskTypeIndex" @change="onTaskTypeChange">
|
|
|
|
<view class="filter-row search-row">
|
|
|
|
<view class="status-box">
|
|
|
|
<view class="keyword-wrap">
|
|
|
|
<text class="status-box-text">{{ currentTaskTypeLabel }}</text>
|
|
|
|
<input
|
|
|
|
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
|
|
|
|
id="equipment-inspection-tasks-keyword-input"
|
|
|
|
|
|
|
|
v-model="searchKeyword"
|
|
|
|
|
|
|
|
class="keyword-input"
|
|
|
|
|
|
|
|
:placeholder="t('equipmentInspectionTasks.searchPlaceholder')"
|
|
|
|
|
|
|
|
confirm-type="search"
|
|
|
|
|
|
|
|
@input="handleKeywordInput"
|
|
|
|
|
|
|
|
@confirm="handleSearch"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="icon-filter-btn" @click="resetFilters">
|
|
|
|
|
|
|
|
<uni-icons type="refresh" size="24" color="#7b8491"></uni-icons>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="icon-filter-btn" @click="openFilterDrawer">
|
|
|
|
|
|
|
|
<uni-icons type="settings" size="24" color="#7b8491"></uni-icons>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</picker>
|
|
|
|
</view>
|
|
|
|
<view class="reset-filter-btn" @click="resetFilters">{{ t('functionCommon.reset') }}</view>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<scroll-view scroll-y class="list-scroll" :scroll-top="scrollTop" @scroll="onScroll" @scrolltolower="loadMore" :lower-threshold="80">
|
|
|
|
<scroll-view scroll-y class="list-scroll" :scroll-top="scrollTop" @scroll="onScroll" @scrolltolower="loadMore" :lower-threshold="80">
|
|
|
|
@ -63,6 +72,60 @@
|
|
|
|
<view v-if="showGoTop" class="go-top-btn" @click="goTop">
|
|
|
|
<view v-if="showGoTop" class="go-top-btn" @click="goTop">
|
|
|
|
<uni-icons type="arrow-up" size="20" color="#1a3a5c"></uni-icons>
|
|
|
|
<uni-icons type="arrow-up" size="20" color="#1a3a5c"></uni-icons>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<uni-popup
|
|
|
|
|
|
|
|
ref="filterPopupRef"
|
|
|
|
|
|
|
|
class="equipment-filter-popup"
|
|
|
|
|
|
|
|
type="right"
|
|
|
|
|
|
|
|
background-color="transparent"
|
|
|
|
|
|
|
|
:animation="false"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<view class="filter-drawer">
|
|
|
|
|
|
|
|
<view class="drawer-header">
|
|
|
|
|
|
|
|
<text class="drawer-title">{{ t('equipmentInspectionTasks.moreFilter') }}</text>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<scroll-view scroll-y class="drawer-body">
|
|
|
|
|
|
|
|
<view class="drawer-section">
|
|
|
|
|
|
|
|
<view class="drawer-section-head">
|
|
|
|
|
|
|
|
<text class="drawer-section-title">{{ t('equipmentInspectionTasks.filterScope') }}</text>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="drawer-field drawer-field-wide">
|
|
|
|
|
|
|
|
<text class="drawer-label">{{ t('equipmentInspectionTasks.projectFormName') }}</text>
|
|
|
|
|
|
|
|
<view class="drawer-picker" @click="togglePlanPanel">
|
|
|
|
|
|
|
|
<text :class="['drawer-picker-text', selectedPlanIds.length ? '' : 'placeholder']">{{ selectedPlanLabel }}</text>
|
|
|
|
|
|
|
|
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<scroll-view v-if="planPanelOpen" scroll-y class="drawer-option-panel">
|
|
|
|
|
|
|
|
<view v-for="option in drawerPlanOptions" :key="option.id" :class="['drawer-option-item', selectedPlanIds.includes(String(option.id)) ? 'active' : '']" @click="togglePlanOption(option)">
|
|
|
|
|
|
|
|
<text class="drawer-option-text">{{ option.name }}</text>
|
|
|
|
|
|
|
|
<uni-icons v-if="selectedPlanIds.includes(String(option.id))" type="checkmarkempty" size="18" color="#174b78"></uni-icons>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view v-if="!drawerPlanOptions.length" class="drawer-option-empty">{{ t('equipmentInspectionTasks.noPlanData') }}</view>
|
|
|
|
|
|
|
|
</scroll-view>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="drawer-field drawer-field-wide drawer-field-gap">
|
|
|
|
|
|
|
|
<text class="drawer-label">{{ t('equipmentInspectionTasks.deviceList') }}</text>
|
|
|
|
|
|
|
|
<view class="drawer-picker" @click="toggleDevicePanel">
|
|
|
|
|
|
|
|
<text :class="['drawer-picker-text', selectedDeviceIds.length ? '' : 'placeholder']">{{ selectedDeviceLabel }}</text>
|
|
|
|
|
|
|
|
<uni-icons type="bottom" size="14" color="#9ca3af"></uni-icons>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<scroll-view v-if="devicePanelOpen" scroll-y class="drawer-option-panel">
|
|
|
|
|
|
|
|
<view v-for="option in drawerDeviceOptions" :key="option.id" :class="['drawer-option-item', selectedDeviceIds.includes(String(option.id)) ? 'active' : '']" @click="toggleDeviceOption(option)">
|
|
|
|
|
|
|
|
<text class="drawer-option-text">{{ option.label }}</text>
|
|
|
|
|
|
|
|
<uni-icons v-if="selectedDeviceIds.includes(String(option.id))" type="checkmarkempty" size="18" color="#174b78"></uni-icons>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view v-if="!drawerDeviceOptions.length" class="drawer-option-empty">{{ t('equipmentInspectionTasks.noDeviceData') }}</view>
|
|
|
|
|
|
|
|
</scroll-view>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
</scroll-view>
|
|
|
|
|
|
|
|
<view class="drawer-actions">
|
|
|
|
|
|
|
|
<view class="drawer-action reset" @click="resetFilters">{{ t('functionCommon.reset') }}</view>
|
|
|
|
|
|
|
|
<view class="drawer-action confirm" @click="confirmFilterDrawer">{{ t('functionCommon.confirm') }}</view>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
</uni-popup>
|
|
|
|
|
|
|
|
|
|
|
|
<up-cascader
|
|
|
|
<up-cascader
|
|
|
|
:key="lineCascaderKey"
|
|
|
|
:key="lineCascaderKey"
|
|
|
|
v-model:show="lineCascaderShow"
|
|
|
|
v-model:show="lineCascaderShow"
|
|
|
|
@ -86,7 +149,7 @@ import { computed, nextTick, ref } from 'vue'
|
|
|
|
import { onLoad, onReachBottom, onReady, onShow, onUnload } from '@dcloudio/uni-app'
|
|
|
|
import { onLoad, onReachBottom, onReady, onShow, onUnload } from '@dcloudio/uni-app'
|
|
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import NavBar from '@/components/common/NavBar.vue'
|
|
|
|
import NavBar from '@/components/common/NavBar.vue'
|
|
|
|
import { getTaskManagementPage, createTaskManagementTicket } from '@/api/mes/taskManagement'
|
|
|
|
import { getTaskManagementPage, createTaskManagementTicket, getPlanMaintenancePage } from '@/api/mes/taskManagement'
|
|
|
|
import { getDeviceLineTree } from '@/api/mes/deviceLine'
|
|
|
|
import { getDeviceLineTree } from '@/api/mes/deviceLine'
|
|
|
|
import { getDeviceLedgerList } from '@/api/mes/deviceLedger'
|
|
|
|
import { getDeviceLedgerList } from '@/api/mes/deviceLedger'
|
|
|
|
|
|
|
|
|
|
|
|
@ -94,6 +157,12 @@ const { t } = useI18n()
|
|
|
|
|
|
|
|
|
|
|
|
const searchKeyword = ref('')
|
|
|
|
const searchKeyword = ref('')
|
|
|
|
const selectedTaskType = ref('')
|
|
|
|
const selectedTaskType = ref('')
|
|
|
|
|
|
|
|
const selectedPlanIds = ref([])
|
|
|
|
|
|
|
|
const selectedDeviceIds = ref([])
|
|
|
|
|
|
|
|
const planOptions = ref([])
|
|
|
|
|
|
|
|
const planPanelOpen = ref(false)
|
|
|
|
|
|
|
|
const devicePanelOpen = ref(false)
|
|
|
|
|
|
|
|
const filterPopupRef = ref(null)
|
|
|
|
const list = ref([])
|
|
|
|
const list = ref([])
|
|
|
|
const loading = ref(false)
|
|
|
|
const loading = ref(false)
|
|
|
|
const loadingMore = ref(false)
|
|
|
|
const loadingMore = ref(false)
|
|
|
|
@ -130,7 +199,6 @@ const lineOptions = computed(() => {
|
|
|
|
let searchTimer = null
|
|
|
|
let searchTimer = null
|
|
|
|
|
|
|
|
|
|
|
|
const taskTypeOptions = computed(() => [
|
|
|
|
const taskTypeOptions = computed(() => [
|
|
|
|
{ label: t('functionCommon.all'), value: '' },
|
|
|
|
|
|
|
|
{ label: t('equipmentInspectionTasks.taskTypeInspect'), value: '1' },
|
|
|
|
{ label: t('equipmentInspectionTasks.taskTypeInspect'), value: '1' },
|
|
|
|
{ label: t('equipmentInspectionTasks.taskTypeMaintain'), value: '2' }
|
|
|
|
{ label: t('equipmentInspectionTasks.taskTypeMaintain'), value: '2' }
|
|
|
|
])
|
|
|
|
])
|
|
|
|
@ -141,13 +209,28 @@ const taskTypeIndex = computed(() => {
|
|
|
|
return index >= 0 ? index : 0
|
|
|
|
return index >= 0 ? index : 0
|
|
|
|
})
|
|
|
|
})
|
|
|
|
const currentTaskTypeLabel = computed(() => {
|
|
|
|
const currentTaskTypeLabel = computed(() => {
|
|
|
|
|
|
|
|
if (selectedTaskType.value === '') return t('equipmentInspectionTasks.taskType')
|
|
|
|
const current = taskTypeOptions.value.find((item) => item.value === selectedTaskType.value)
|
|
|
|
const current = taskTypeOptions.value.find((item) => item.value === selectedTaskType.value)
|
|
|
|
return current ? current.label : t('functionCommon.all')
|
|
|
|
return current ? current.label : t('equipmentInspectionTasks.taskType')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const drawerPlanOptions = computed(() => planOptions.value.map((item) => ({
|
|
|
|
|
|
|
|
id: String(item.id),
|
|
|
|
|
|
|
|
name: item.planName || item.name || String(item.id || '')
|
|
|
|
|
|
|
|
})))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const drawerDeviceOptions = computed(() => deviceOptions.value.map((item) => ({
|
|
|
|
|
|
|
|
id: String(item.id),
|
|
|
|
|
|
|
|
label: item.label || item.deviceName || String(item.id || '')
|
|
|
|
|
|
|
|
})))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectedPlanLabel = computed(() => formatSelectedSummary(selectedPlanIds.value, drawerPlanOptions.value, 'name', t('equipmentInspectionTasks.placeholderProjectForm')))
|
|
|
|
|
|
|
|
const selectedDeviceLabel = computed(() => formatSelectedSummary(selectedDeviceIds.value, drawerDeviceOptions.value, 'label', t('equipmentInspectionTasks.placeholderDeviceList')))
|
|
|
|
|
|
|
|
|
|
|
|
onLoad(async () => {
|
|
|
|
onLoad(async () => {
|
|
|
|
activateKeywordFocus()
|
|
|
|
activateKeywordFocus()
|
|
|
|
await Promise.all([loadLineTree(), ensureDeviceOptionsLoaded(), fetchList(true)])
|
|
|
|
await Promise.all([loadLineTree(), ensurePlanOptionsLoaded(), ensureDeviceOptionsLoaded()])
|
|
|
|
|
|
|
|
await fetchList(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
onShow(() => {
|
|
|
|
onShow(() => {
|
|
|
|
@ -168,6 +251,17 @@ onReachBottom(() => {
|
|
|
|
loadMore()
|
|
|
|
loadMore()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function ensurePlanOptionsLoaded() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const res = await getPlanMaintenancePage({ pageNo: 1, pageSize: 100 })
|
|
|
|
|
|
|
|
const root = res && res.data !== undefined ? res.data : res
|
|
|
|
|
|
|
|
const data = Array.isArray(root) ? root : (root?.list || root?.data?.list || root?.records || [])
|
|
|
|
|
|
|
|
planOptions.value = (Array.isArray(data) ? data : []).filter((item) => item && item.id !== undefined && item.id !== null)
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
planOptions.value = []
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function ensureDeviceOptionsLoaded() {
|
|
|
|
async function ensureDeviceOptionsLoaded() {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const res = await getDeviceLedgerList()
|
|
|
|
const res = await getDeviceLedgerList()
|
|
|
|
@ -205,8 +299,9 @@ async function fetchList(reset) {
|
|
|
|
pageNo: pageNo.value,
|
|
|
|
pageNo: pageNo.value,
|
|
|
|
pageSize: pageSize.value,
|
|
|
|
pageSize: pageSize.value,
|
|
|
|
name: deviceId ? undefined : keyword || undefined,
|
|
|
|
name: deviceId ? undefined : keyword || undefined,
|
|
|
|
deviceIds: deviceId ? [deviceId] : undefined,
|
|
|
|
deviceIds: selectedDeviceIds.value.length ? selectedDeviceIds.value.join(',') : (deviceId ? [deviceId] : undefined),
|
|
|
|
taskType: selectedTaskType.value || undefined,
|
|
|
|
taskType: selectedTaskType.value || undefined,
|
|
|
|
|
|
|
|
projectForm: selectedPlanIds.value.length ? selectedPlanIds.value.join(',') : undefined,
|
|
|
|
deviceLineId: selectedLineId.value || undefined
|
|
|
|
deviceLineId: selectedLineId.value || undefined
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const res = await getTaskManagementPage(params)
|
|
|
|
const res = await getTaskManagementPage(params)
|
|
|
|
@ -307,6 +402,56 @@ function normalizePageData(res) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function openFilterDrawer() {
|
|
|
|
|
|
|
|
filterPopupRef.value?.open()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function closeFilterDrawer() {
|
|
|
|
|
|
|
|
filterPopupRef.value?.close()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function confirmFilterDrawer() {
|
|
|
|
|
|
|
|
planPanelOpen.value = false
|
|
|
|
|
|
|
|
devicePanelOpen.value = false
|
|
|
|
|
|
|
|
closeFilterDrawer()
|
|
|
|
|
|
|
|
await fetchList(true)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function togglePlanPanel() {
|
|
|
|
|
|
|
|
planPanelOpen.value = !planPanelOpen.value
|
|
|
|
|
|
|
|
devicePanelOpen.value = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toggleDevicePanel() {
|
|
|
|
|
|
|
|
devicePanelOpen.value = !devicePanelOpen.value
|
|
|
|
|
|
|
|
planPanelOpen.value = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function togglePlanOption(option) {
|
|
|
|
|
|
|
|
toggleStringSelection(selectedPlanIds, option?.id)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toggleDeviceOption(option) {
|
|
|
|
|
|
|
|
toggleStringSelection(selectedDeviceIds, option?.id)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toggleStringSelection(targetRef, value) {
|
|
|
|
|
|
|
|
const id = String(value ?? '')
|
|
|
|
|
|
|
|
if (!id) return
|
|
|
|
|
|
|
|
const current = targetRef.value.map((item) => String(item))
|
|
|
|
|
|
|
|
targetRef.value = current.includes(id) ? current.filter((item) => item !== id) : [...current, id]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function formatSelectedSummary(ids, options, labelKey, placeholder) {
|
|
|
|
|
|
|
|
const selected = Array.isArray(ids) ? ids : []
|
|
|
|
|
|
|
|
if (!selected.length) return placeholder
|
|
|
|
|
|
|
|
if (selected.length === 1) {
|
|
|
|
|
|
|
|
const found = options.find((item) => String(item.id) === String(selected[0]))
|
|
|
|
|
|
|
|
return found?.[labelKey] || placeholder
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return t('equipmentInspectionTasks.selectedCount', { count: selected.length })
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleSearch() {
|
|
|
|
function handleSearch() {
|
|
|
|
clearSearchTimer()
|
|
|
|
clearSearchTimer()
|
|
|
|
uni.hideKeyboard()
|
|
|
|
uni.hideKeyboard()
|
|
|
|
@ -324,6 +469,11 @@ async function resetFilters() {
|
|
|
|
clearSearchTimer()
|
|
|
|
clearSearchTimer()
|
|
|
|
searchKeyword.value = ''
|
|
|
|
searchKeyword.value = ''
|
|
|
|
selectedTaskType.value = ''
|
|
|
|
selectedTaskType.value = ''
|
|
|
|
|
|
|
|
selectedPlanIds.value = []
|
|
|
|
|
|
|
|
selectedDeviceIds.value = []
|
|
|
|
|
|
|
|
planPanelOpen.value = false
|
|
|
|
|
|
|
|
devicePanelOpen.value = false
|
|
|
|
|
|
|
|
closeFilterDrawer()
|
|
|
|
resetLineFilter()
|
|
|
|
resetLineFilter()
|
|
|
|
activateKeywordFocus()
|
|
|
|
activateKeywordFocus()
|
|
|
|
await nextTick()
|
|
|
|
await nextTick()
|
|
|
|
@ -355,15 +505,22 @@ function openDetail(item) {
|
|
|
|
|
|
|
|
|
|
|
|
async function handleCreateTicket(item) {
|
|
|
|
async function handleCreateTicket(item) {
|
|
|
|
if (!item?.id || ticketLoadingId.value) return
|
|
|
|
if (!item?.id || ticketLoadingId.value) return
|
|
|
|
ticketLoadingId.value = item.id
|
|
|
|
uni.showModal({
|
|
|
|
try {
|
|
|
|
title: t('functionCommon.confirmTitle'),
|
|
|
|
await createTaskManagementTicket(item.id)
|
|
|
|
content: t('equipmentInspectionTasks.confirmCreateTicketContent', { name: textValue(item.name) }),
|
|
|
|
uni.showToast({ title: t('equipmentInspectionTasks.createTicketSuccess'), icon: 'success' })
|
|
|
|
success: async (res) => {
|
|
|
|
} catch (error) {
|
|
|
|
if (!res.confirm) return
|
|
|
|
uni.showToast({ title: t('equipmentInspectionTasks.createTicketFail'), icon: 'none' })
|
|
|
|
ticketLoadingId.value = item.id
|
|
|
|
} finally {
|
|
|
|
try {
|
|
|
|
ticketLoadingId.value = null
|
|
|
|
await createTaskManagementTicket(item.id)
|
|
|
|
}
|
|
|
|
uni.showToast({ title: t('equipmentInspectionTasks.createTicketSuccess'), icon: 'success' })
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
uni.showToast({ title: t('equipmentInspectionTasks.createTicketFail'), icon: 'none' })
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
ticketLoadingId.value = null
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onScroll(event) {
|
|
|
|
function onScroll(event) {
|
|
|
|
@ -446,65 +603,50 @@ function formatDate(value) {
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.page-container { min-height: 100vh; background: #f4f5f7; }
|
|
|
|
.page-container { min-height: 100vh; background: #f4f5f7; }
|
|
|
|
.filter-bar {
|
|
|
|
.filter-bar { padding: 18rpx 14rpx 20rpx; background: #f4f5f7; }
|
|
|
|
display: grid;
|
|
|
|
.filter-row { display: flex; align-items: center; gap: 18rpx; }
|
|
|
|
grid-template-columns: minmax(0, 1fr) 150rpx 96rpx;
|
|
|
|
.search-row { margin-top: 18rpx; }
|
|
|
|
align-items: center;
|
|
|
|
.quick-row > picker { min-width: 0; flex: 1; }
|
|
|
|
gap: 14rpx;
|
|
|
|
.keyword-wrap,
|
|
|
|
padding: 18rpx 4rpx 0rpx;
|
|
|
|
.status-filter,
|
|
|
|
}
|
|
|
|
|
|
|
|
.line-filter,
|
|
|
|
.line-filter,
|
|
|
|
.keyword-box,
|
|
|
|
.icon-filter-btn { height: 66rpx; border: 1rpx solid #d9dde5; background: #ffffff; box-sizing: border-box; }
|
|
|
|
.status-box,
|
|
|
|
.keyword-wrap { min-width: 0; flex: 1; display: flex; align-items: center; }
|
|
|
|
.reset-filter-btn {
|
|
|
|
.keyword-input { width: 100%; height: 64rpx; padding: 0 20rpx; font-size: 26rpx; color: #374151; }
|
|
|
|
height: 66rpx;
|
|
|
|
.status-filter,
|
|
|
|
background: #ffffff;
|
|
|
|
.line-filter { min-width: 0; flex: 1; display: flex; align-items: center; justify-content: space-between; padding: 0 18rpx 0 26rpx; }
|
|
|
|
border: 1rpx solid #d9dde5;
|
|
|
|
.icon-filter-btn { width: 66rpx; flex: 0 0 66rpx; display: flex; align-items: center; justify-content: center; border-color: transparent; background: transparent; }
|
|
|
|
box-sizing: border-box;
|
|
|
|
.status-filter-text,
|
|
|
|
display: flex;
|
|
|
|
.line-filter-text { min-width: 0rpx; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #374151; }
|
|
|
|
align-items: center;
|
|
|
|
.status-filter-text.placeholder,
|
|
|
|
}
|
|
|
|
.line-filter-text.placeholder,
|
|
|
|
.line-filter {
|
|
|
|
.placeholder { color: #a8adb7; }
|
|
|
|
grid-column: 1 / -1;
|
|
|
|
.filter-drawer { width: 630rpx; height: calc(100vh - var(--status-bar-height)); margin-top: var(--status-bar-height); background: #f5f5f7; display: flex; flex-direction: column; overflow: hidden; border-radius: 28rpx 0 0 28rpx; }
|
|
|
|
justify-content: space-between;
|
|
|
|
:deep(.equipment-filter-popup.right .uni-popup__content-transition) { transform: none !important; }
|
|
|
|
padding: 0 28rpx;
|
|
|
|
.drawer-header { height: 104rpx; padding: 18rpx 34rpx 0; background: #ffffff; display: flex; align-items: center; box-sizing: border-box; }
|
|
|
|
border-radius: 8rpx;
|
|
|
|
.drawer-title { color: #1f2937; font-size: 34rpx; line-height: 1.3; font-weight: 700; }
|
|
|
|
}
|
|
|
|
.drawer-body { flex: 1; min-height: 0; padding-bottom: 40rpx; box-sizing: border-box; }
|
|
|
|
|
|
|
|
.drawer-section { margin-bottom: 18rpx; padding: 28rpx 28rpx 30rpx; border-radius: 24rpx; background: #ffffff; box-sizing: border-box; }
|
|
|
|
.line-filter-text {
|
|
|
|
.drawer-section-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24rpx; }
|
|
|
|
font-size: 26rpx;
|
|
|
|
.drawer-section-title { font-size: 32rpx; line-height: 1.3; color: #1f2937; font-weight: 700; }
|
|
|
|
color: #374151;
|
|
|
|
.drawer-field { min-width: 0; }
|
|
|
|
max-width: 85%;
|
|
|
|
.drawer-field-wide { grid-column: 1 / -1; }
|
|
|
|
overflow: hidden;
|
|
|
|
.drawer-field-gap { margin-top: 22rpx; }
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
.drawer-label { display: block; margin-bottom: 12rpx; font-size: 24rpx; line-height: 1.3; color: #4b5563; font-weight: 500; }
|
|
|
|
white-space: nowrap;
|
|
|
|
.drawer-picker { width: 100%; min-height: 74rpx; border: 0; border-radius: 8rpx; background: #f7f8fb; box-sizing: border-box; display: flex; align-items: center; justify-content: center; padding: 0 18rpx; gap: 8rpx; }
|
|
|
|
}
|
|
|
|
.drawer-picker-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #111827; text-align: center; }
|
|
|
|
|
|
|
|
.drawer-picker-text.placeholder { color: #9ca3af; }
|
|
|
|
.line-filter-text.placeholder {
|
|
|
|
.drawer-option-panel { max-height: 420rpx; margin-top: 12rpx; border-radius: 12rpx; background: #f7f8fb; overflow: hidden; }
|
|
|
|
color: #a8adb7;
|
|
|
|
.drawer-option-item { min-height: 72rpx; padding: 0 24rpx; display: flex; align-items: center; gap: 12rpx; border-bottom: 1rpx solid #eceff3; box-sizing: border-box; }
|
|
|
|
}
|
|
|
|
.drawer-option-item:last-child { border-bottom: 0; }
|
|
|
|
|
|
|
|
.drawer-option-item.active { background: rgba(23, 75, 120, 0.1); }
|
|
|
|
.keyword-box {
|
|
|
|
.drawer-option-item.active .drawer-option-text { color: #174b78; font-weight: 600; }
|
|
|
|
padding: 0 20rpx;
|
|
|
|
.drawer-option-text { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 26rpx; color: #1f2937; }
|
|
|
|
}
|
|
|
|
.drawer-option-empty { padding: 28rpx 0; text-align: center; font-size: 26rpx; color: #9ca3af; }
|
|
|
|
.keyword-input {
|
|
|
|
.drawer-actions { height: 126rpx; padding: 18rpx 28rpx 24rpx; box-sizing: border-box; display: flex; align-items: center; gap: 0; background: #ffffff; box-shadow: 0 -8rpx 24rpx rgba(17, 24, 39, 0.06); }
|
|
|
|
width: 100%;
|
|
|
|
.drawer-action { flex: 1; height: 72rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 600; border: 2rpx solid #174b78; box-sizing: border-box; }
|
|
|
|
font-size: 26rpx;
|
|
|
|
.drawer-action.reset { border-radius: 12rpx 0 0 12rpx; background: #ffffff; color: #174b78; }
|
|
|
|
color: #374151;
|
|
|
|
.drawer-action.confirm { border-radius: 0 12rpx 12rpx 0; background: #174b78; color: #ffffff; }
|
|
|
|
}
|
|
|
|
|
|
|
|
.status-box {
|
|
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
padding: 0 18rpx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.status-box-text {
|
|
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.reset-filter-btn {
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
|
|
color: #4b5563;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.list-scroll { height: calc(100vh - 194rpx); }
|
|
|
|
.list-scroll { height: calc(100vh - 194rpx); }
|
|
|
|
.list-wrap { padding: 0 4rpx 32rpx; }
|
|
|
|
.list-wrap { padding: 0 4rpx 32rpx; }
|
|
|
|
.task-card { position: relative; margin-top: 20rpx; padding: 28rpx; background: #fff; border-radius: 22rpx; box-shadow: 0 8rpx 28rpx rgba(15, 23, 42, 0.06); }
|
|
|
|
.task-card { position: relative; margin-top: 20rpx; padding: 28rpx; background: #fff; border-radius: 22rpx; box-shadow: 0 8rpx 28rpx rgba(15, 23, 42, 0.06); }
|
|
|
|
|