|
|
|
|
@ -4,35 +4,58 @@
|
|
|
|
|
|
|
|
|
|
<view class="filter-bar">
|
|
|
|
|
<view class="line-filter" @click="openLineCascader">
|
|
|
|
|
<text :class="['line-filter-text', selectedLineId === '' ? 'placeholder' : '']">{{ selectedLineLabel }}</text>
|
|
|
|
|
<text
|
|
|
|
|
:class="[
|
|
|
|
|
'line-filter-text',
|
|
|
|
|
selectedLineId === '' ? 'placeholder' : '',
|
|
|
|
|
]"
|
|
|
|
|
>{{ selectedLineLabel }}</text
|
|
|
|
|
>
|
|
|
|
|
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="keyword-wrap">
|
|
|
|
|
<input
|
|
|
|
|
id="equipment-ledger-keyword-input"
|
|
|
|
|
v-model="searchKeyword"
|
|
|
|
|
class="keyword-input"
|
|
|
|
|
type="text"
|
|
|
|
|
:placeholder="t('equipmentLedger.searchPlaceholder')"
|
|
|
|
|
:focus="keywordFocus"
|
|
|
|
|
confirm-type="search"
|
|
|
|
|
@blur="keywordFocus = false"
|
|
|
|
|
@confirm="handleSearch"
|
|
|
|
|
/>
|
|
|
|
|
</view>
|
|
|
|
|
<picker :range="statusPickerLabels" :value="statusPickerIndex" @change="onStatusFilterChange">
|
|
|
|
|
<picker
|
|
|
|
|
:range="statusPickerLabels"
|
|
|
|
|
:value="statusPickerIndex"
|
|
|
|
|
@change="onStatusFilterChange"
|
|
|
|
|
>
|
|
|
|
|
<view class="status-filter">
|
|
|
|
|
<text :class="['status-filter-text', selectedStatus === '' ? 'placeholder' : '']">{{ selectedStatusLabel }}</text>
|
|
|
|
|
<text
|
|
|
|
|
:class="[
|
|
|
|
|
'status-filter-text',
|
|
|
|
|
selectedStatus === '' ? 'placeholder' : '',
|
|
|
|
|
]"
|
|
|
|
|
>{{ selectedStatusLabel }}</text
|
|
|
|
|
>
|
|
|
|
|
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
|
|
|
|
|
</view>
|
|
|
|
|
</picker>
|
|
|
|
|
<view class="reset-filter-btn" @click="resetFilters">{{ resetFilterText }}</view>
|
|
|
|
|
<!-- <view class="scan-btn" @click="handleScan">
|
|
|
|
|
<view class="reset-filter-btn" @click="resetFilters">{{
|
|
|
|
|
resetFilterText
|
|
|
|
|
}}</view>
|
|
|
|
|
<!-- <view class="scan-btn" @click="handleScan">
|
|
|
|
|
<uni-icons type="scan" size="24" color="#1f2937"></uni-icons>
|
|
|
|
|
</view> -->
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="list-scroll">
|
|
|
|
|
<view class="list-wrap">
|
|
|
|
|
<view v-for="item in list" :key="item.id" class="ledger-card" @click="openDetail(item)">
|
|
|
|
|
<view
|
|
|
|
|
v-for="item in list"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
class="ledger-card"
|
|
|
|
|
@click="openDetail(item)"
|
|
|
|
|
>
|
|
|
|
|
<view class="card-top">
|
|
|
|
|
<text class="device-code">{{ textValue(item.deviceCode) }}</text>
|
|
|
|
|
<picker
|
|
|
|
|
@ -43,21 +66,36 @@
|
|
|
|
|
@change="(e) => onItemStatusChange(item, e)"
|
|
|
|
|
>
|
|
|
|
|
<view class="status-chip">
|
|
|
|
|
<view :class="['status-dot', getStatusClass(item.deviceStatus)]"></view>
|
|
|
|
|
<text :class="['status-text', getStatusClass(item.deviceStatus)]">{{ getStatusText(item.deviceStatus) }}</text>
|
|
|
|
|
<view
|
|
|
|
|
:class="['status-dot', getStatusClass(item.deviceStatus)]"
|
|
|
|
|
></view>
|
|
|
|
|
<text
|
|
|
|
|
:class="['status-text', getStatusClass(item.deviceStatus)]"
|
|
|
|
|
>{{ getStatusText(item.deviceStatus) }}</text
|
|
|
|
|
>
|
|
|
|
|
</view>
|
|
|
|
|
</picker>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="card-bottom">
|
|
|
|
|
<text class="device-name">{{ textValue(item.deviceName) }}</text>
|
|
|
|
|
<text class="date-text">{{ formatDateValue(item.createTime) }}</text>
|
|
|
|
|
<text class="date-text">{{
|
|
|
|
|
formatDateValue(item.createTime)
|
|
|
|
|
}}</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view v-if="loading && pageNo === 1" class="loading-text">{{ t('functionCommon.loading') }}</view>
|
|
|
|
|
<view v-else-if="!list.length" class="empty-text">{{ t('equipmentLedger.empty') }}</view>
|
|
|
|
|
<view v-else-if="loadingMore" class="loading-text">{{ t('functionCommon.loadingMore') }}</view>
|
|
|
|
|
<view v-else-if="finished" class="finished-text">{{ t('functionCommon.noMore') }}</view>
|
|
|
|
|
<view v-if="loading && pageNo === 1" class="loading-text">{{
|
|
|
|
|
t('functionCommon.loading')
|
|
|
|
|
}}</view>
|
|
|
|
|
<view v-else-if="!list.length" class="empty-text">{{
|
|
|
|
|
t('equipmentLedger.empty')
|
|
|
|
|
}}</view>
|
|
|
|
|
<view v-else-if="loadingMore" class="loading-text">{{
|
|
|
|
|
t('functionCommon.loadingMore')
|
|
|
|
|
}}</view>
|
|
|
|
|
<view v-else-if="finished" class="finished-text">{{
|
|
|
|
|
t('functionCommon.noMore')
|
|
|
|
|
}}</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
@ -78,237 +116,290 @@
|
|
|
|
|
:auto-close="false"
|
|
|
|
|
@confirm="onLineCascaderConfirm"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, computed, nextTick } from 'vue'
|
|
|
|
|
import { onLoad, onPageScroll, onReachBottom, onShow } from '@dcloudio/uni-app'
|
|
|
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
|
import NavBar from '@/components/common/NavBar.vue'
|
|
|
|
|
import { getDeviceLedgerPage, updateDeviceLedger } from '@/api/mes/deviceLedger'
|
|
|
|
|
import { getDeviceLineTree } from '@/api/mes/deviceLine'
|
|
|
|
|
import { DICT_TYPE, getDictLabel, initAllDict } from '@/utils/dict'
|
|
|
|
|
import useDictStore from '@/store/modules/dict'
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
const dictStore = useDictStore()
|
|
|
|
|
const resetFilterText = computed(() => t('functionCommon.reset'))
|
|
|
|
|
const searchKeyword = ref('')
|
|
|
|
|
const selectedStatus = ref('')
|
|
|
|
|
const selectedLineId = ref('')
|
|
|
|
|
const lineTree = ref([])
|
|
|
|
|
const lineCascaderShow = ref(false)
|
|
|
|
|
const lineCascaderValue = ref([])
|
|
|
|
|
const lineCascaderKey = ref(0)
|
|
|
|
|
const list = ref([])
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
const loadingMore = ref(false)
|
|
|
|
|
const finished = ref(false)
|
|
|
|
|
const pageNo = ref(1)
|
|
|
|
|
const pageSize = ref(10)
|
|
|
|
|
const total = ref(0)
|
|
|
|
|
const showGoTop = ref(false)
|
|
|
|
|
const statusUpdatingMap = ref({})
|
|
|
|
|
const keywordFocus = ref(false)
|
|
|
|
|
import { ref, computed, nextTick } from 'vue';
|
|
|
|
|
import { onLoad, onPageScroll, onReachBottom, onReady, onShow } from '@dcloudio/uni-app';
|
|
|
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
|
import NavBar from '@/components/common/NavBar.vue';
|
|
|
|
|
import {
|
|
|
|
|
getDeviceLedgerPage,
|
|
|
|
|
updateDeviceLedger,
|
|
|
|
|
} from '@/api/mes/deviceLedger';
|
|
|
|
|
import { getDeviceLineTree } from '@/api/mes/deviceLine';
|
|
|
|
|
import { DICT_TYPE, getDictLabel, initAllDict } from '@/utils/dict';
|
|
|
|
|
import useDictStore from '@/store/modules/dict';
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n();
|
|
|
|
|
const dictStore = useDictStore();
|
|
|
|
|
const resetFilterText = computed(() => t('functionCommon.reset'));
|
|
|
|
|
const searchKeyword = ref('');
|
|
|
|
|
const selectedStatus = ref('');
|
|
|
|
|
const selectedLineId = ref('');
|
|
|
|
|
const lineTree = ref([]);
|
|
|
|
|
const lineCascaderShow = ref(false);
|
|
|
|
|
const lineCascaderValue = ref([]);
|
|
|
|
|
const lineCascaderKey = ref(0);
|
|
|
|
|
const list = ref([]);
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
const loadingMore = ref(false);
|
|
|
|
|
const finished = ref(false);
|
|
|
|
|
const pageNo = ref(1);
|
|
|
|
|
const pageSize = ref(10);
|
|
|
|
|
const total = ref(0);
|
|
|
|
|
const showGoTop = ref(false);
|
|
|
|
|
const statusUpdatingMap = ref({});
|
|
|
|
|
const focusNoKeyboardRef = ref(null);
|
|
|
|
|
const keywordInputSelector = '#equipment-ledger-keyword-input input, input#equipment-ledger-keyword-input';
|
|
|
|
|
|
|
|
|
|
const statusOptions = computed(() => {
|
|
|
|
|
const dicts = dictStore.getDict(DICT_TYPE.MES_TZ_STATUS) || []
|
|
|
|
|
const dicts = dictStore.getDict(DICT_TYPE.MES_TZ_STATUS) || [];
|
|
|
|
|
return dicts
|
|
|
|
|
.filter(item => item?.value !== null && item?.value !== undefined && String(item.value) !== '')
|
|
|
|
|
.map(item => ({ label: item.label, value: item.value }))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const statusPickerLabels = computed(() => statusOptions.value.map(item => item.label))
|
|
|
|
|
const statusChangeLabels = computed(() => statusOptions.value.map(item => item.label))
|
|
|
|
|
.filter(
|
|
|
|
|
(item) =>
|
|
|
|
|
item?.value !== null &&
|
|
|
|
|
item?.value !== undefined &&
|
|
|
|
|
String(item.value) !== '',
|
|
|
|
|
)
|
|
|
|
|
.map((item) => ({ label: item.label, value: item.value }));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const statusPickerLabels = computed(() =>
|
|
|
|
|
statusOptions.value.map((item) => item.label),
|
|
|
|
|
);
|
|
|
|
|
const statusChangeLabels = computed(() =>
|
|
|
|
|
statusOptions.value.map((item) => item.label),
|
|
|
|
|
);
|
|
|
|
|
const statusPickerIndex = computed(() => {
|
|
|
|
|
const idx = statusOptions.value.findIndex(item => String(item.value) === String(selectedStatus.value))
|
|
|
|
|
return idx >= 0 ? idx : 0
|
|
|
|
|
})
|
|
|
|
|
const idx = statusOptions.value.findIndex(
|
|
|
|
|
(item) => String(item.value) === String(selectedStatus.value),
|
|
|
|
|
);
|
|
|
|
|
return idx >= 0 ? idx : 0;
|
|
|
|
|
});
|
|
|
|
|
const selectedStatusLabel = computed(() => {
|
|
|
|
|
if (selectedStatus.value === '') return t('equipmentLedger.deviceStatus')
|
|
|
|
|
const found = statusOptions.value.find(item => String(item.value) === String(selectedStatus.value))
|
|
|
|
|
return found?.label || t('equipmentLedger.deviceStatus')
|
|
|
|
|
})
|
|
|
|
|
const lineOptions = computed(() => flattenLineTree(lineTree.value))
|
|
|
|
|
if (selectedStatus.value === '') return t('equipmentLedger.deviceStatus');
|
|
|
|
|
const found = statusOptions.value.find(
|
|
|
|
|
(item) => String(item.value) === String(selectedStatus.value),
|
|
|
|
|
);
|
|
|
|
|
return found?.label || t('equipmentLedger.deviceStatus');
|
|
|
|
|
});
|
|
|
|
|
const lineOptions = computed(() => flattenLineTree(lineTree.value));
|
|
|
|
|
const lineCascaderOptions = computed(() => [
|
|
|
|
|
{ label: t('functionCommon.all'), value: '' },
|
|
|
|
|
...normalizeLineTreeForCascader(lineTree.value)
|
|
|
|
|
])
|
|
|
|
|
...normalizeLineTreeForCascader(lineTree.value),
|
|
|
|
|
]);
|
|
|
|
|
const selectedLineLabel = computed(() => {
|
|
|
|
|
if (selectedLineId.value === '') return t('equipmentLedger.lineFilter')
|
|
|
|
|
const found = lineOptions.value.find(item => String(item.id) === String(selectedLineId.value))
|
|
|
|
|
return found?.name || t('equipmentLedger.lineFilter')
|
|
|
|
|
})
|
|
|
|
|
if (selectedLineId.value === '') return t('equipmentLedger.lineFilter');
|
|
|
|
|
const found = lineOptions.value.find(
|
|
|
|
|
(item) => String(item.id) === String(selectedLineId.value),
|
|
|
|
|
);
|
|
|
|
|
return found?.name || t('equipmentLedger.lineFilter');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onLoad(async () => {
|
|
|
|
|
activateKeywordFocus()
|
|
|
|
|
await initAllDict()
|
|
|
|
|
await fetchLineTree()
|
|
|
|
|
await fetchList(true)
|
|
|
|
|
})
|
|
|
|
|
activateKeywordFocus();
|
|
|
|
|
await initAllDict();
|
|
|
|
|
await fetchLineTree();
|
|
|
|
|
await fetchList(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onShow(() => {
|
|
|
|
|
activateKeywordFocus()
|
|
|
|
|
})
|
|
|
|
|
activateKeywordFocus();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onReady(() => {
|
|
|
|
|
focusKeywordNoKeyboard();
|
|
|
|
|
setTimeout(focusKeywordNoKeyboard, 300);
|
|
|
|
|
setTimeout(focusKeywordNoKeyboard, 800);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onReachBottom(() => {
|
|
|
|
|
loadMore()
|
|
|
|
|
})
|
|
|
|
|
loadMore();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onPageScroll((e) => {
|
|
|
|
|
showGoTop.value = (e?.scrollTop || 0) > 600
|
|
|
|
|
})
|
|
|
|
|
showGoTop.value = (e?.scrollTop || 0) > 600;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
async function fetchLineTree() {
|
|
|
|
|
try {
|
|
|
|
|
const res = await getDeviceLineTree()
|
|
|
|
|
const root = res && res.data !== undefined ? res.data : res
|
|
|
|
|
const treeData = Array.isArray(root) ? root : (Array.isArray(root?.data) ? root.data : [])
|
|
|
|
|
lineTree.value = normalizeLineTree(treeData)
|
|
|
|
|
const res = await getDeviceLineTree();
|
|
|
|
|
const root = res && res.data !== undefined ? res.data : res;
|
|
|
|
|
const treeData = Array.isArray(root)
|
|
|
|
|
? root
|
|
|
|
|
: Array.isArray(root?.data)
|
|
|
|
|
? root.data
|
|
|
|
|
: [];
|
|
|
|
|
lineTree.value = normalizeLineTree(treeData);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
lineTree.value = []
|
|
|
|
|
lineTree.value = [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeLineTree(nodes) {
|
|
|
|
|
return (Array.isArray(nodes) ? nodes : []).map((node) => {
|
|
|
|
|
const children = normalizeLineTree(node.children)
|
|
|
|
|
const children = normalizeLineTree(node.children);
|
|
|
|
|
const item = {
|
|
|
|
|
...node,
|
|
|
|
|
id: String(node.id ?? ''),
|
|
|
|
|
name: node.name || node.label || String(node.id || '')
|
|
|
|
|
}
|
|
|
|
|
name: node.name || node.label || String(node.id || ''),
|
|
|
|
|
};
|
|
|
|
|
if (children.length) {
|
|
|
|
|
item.children = children
|
|
|
|
|
item.children = children;
|
|
|
|
|
} else {
|
|
|
|
|
delete item.children
|
|
|
|
|
delete item.children;
|
|
|
|
|
}
|
|
|
|
|
return item
|
|
|
|
|
})
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function flattenLineTree(nodes, level = 0) {
|
|
|
|
|
const result = []
|
|
|
|
|
;(Array.isArray(nodes) ? nodes : []).forEach((node) => {
|
|
|
|
|
const result = [];
|
|
|
|
|
(Array.isArray(nodes) ? nodes : []).forEach((node) => {
|
|
|
|
|
result.push({
|
|
|
|
|
id: node.id,
|
|
|
|
|
name: node.name || node.label || String(node.id || ''),
|
|
|
|
|
level
|
|
|
|
|
})
|
|
|
|
|
level,
|
|
|
|
|
});
|
|
|
|
|
if (Array.isArray(node.children) && node.children.length) {
|
|
|
|
|
result.push(...flattenLineTree(node.children, level + 1))
|
|
|
|
|
result.push(...flattenLineTree(node.children, level + 1));
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return result
|
|
|
|
|
});
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeLineTreeForCascader(nodes) {
|
|
|
|
|
return (Array.isArray(nodes) ? nodes : []).map((node) => {
|
|
|
|
|
const children = normalizeLineTreeForCascader(node.children)
|
|
|
|
|
const children = normalizeLineTreeForCascader(node.children);
|
|
|
|
|
const item = {
|
|
|
|
|
label: node.name || node.label || String(node.id || ''),
|
|
|
|
|
value: String(node.id ?? '')
|
|
|
|
|
}
|
|
|
|
|
if (children.length) item.children = children
|
|
|
|
|
return item
|
|
|
|
|
})
|
|
|
|
|
value: String(node.id ?? ''),
|
|
|
|
|
};
|
|
|
|
|
if (children.length) item.children = children;
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findLinePath(nodes, id, parents = []) {
|
|
|
|
|
const target = String(id)
|
|
|
|
|
const target = String(id);
|
|
|
|
|
for (const node of Array.isArray(nodes) ? nodes : []) {
|
|
|
|
|
const currentPath = [...parents, String(node.id ?? '')]
|
|
|
|
|
if (String(node.id) === target) return currentPath
|
|
|
|
|
const childPath = findLinePath(node.children, target, currentPath)
|
|
|
|
|
if (childPath.length) return childPath
|
|
|
|
|
const currentPath = [...parents, String(node.id ?? '')];
|
|
|
|
|
if (String(node.id) === target) return currentPath;
|
|
|
|
|
const childPath = findLinePath(node.children, target, currentPath);
|
|
|
|
|
if (childPath.length) return childPath;
|
|
|
|
|
}
|
|
|
|
|
return []
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function activateKeywordFocus() {
|
|
|
|
|
keywordFocus.value = false
|
|
|
|
|
focusKeywordNoKeyboard();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function focusKeywordNoKeyboard() {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
keywordFocus.value = true
|
|
|
|
|
})
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
focusNoKeyboardRef.value?.focus(keywordInputSelector);
|
|
|
|
|
}, 80);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function fetchList(reset) {
|
|
|
|
|
if (reset) {
|
|
|
|
|
pageNo.value = 1
|
|
|
|
|
finished.value = false
|
|
|
|
|
pageNo.value = 1;
|
|
|
|
|
finished.value = false;
|
|
|
|
|
}
|
|
|
|
|
if (pageNo.value === 1) {
|
|
|
|
|
loading.value = true
|
|
|
|
|
loading.value = true;
|
|
|
|
|
} else {
|
|
|
|
|
loadingMore.value = true
|
|
|
|
|
loadingMore.value = true;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
const keyword = searchKeyword.value.trim()
|
|
|
|
|
const keyword = searchKeyword.value.trim();
|
|
|
|
|
const params = {
|
|
|
|
|
pageNo: pageNo.value,
|
|
|
|
|
pageSize: pageSize.value,
|
|
|
|
|
deviceCode: keyword || undefined,
|
|
|
|
|
deviceName: keyword || undefined,
|
|
|
|
|
deviceStatus: selectedStatus.value === '' ? undefined : selectedStatus.value,
|
|
|
|
|
deviceLine: selectedLineId.value === '' ? undefined : selectedLineId.value
|
|
|
|
|
}
|
|
|
|
|
const res = await getDeviceLedgerPage(params)
|
|
|
|
|
const page = normalizePageData(res)
|
|
|
|
|
total.value = page.total
|
|
|
|
|
list.value = reset ? page.list : [...list.value, ...page.list]
|
|
|
|
|
finished.value = list.value.length >= total.value || page.list.length < pageSize.value
|
|
|
|
|
deviceStatus:
|
|
|
|
|
selectedStatus.value === '' ? undefined : selectedStatus.value,
|
|
|
|
|
deviceLine:
|
|
|
|
|
selectedLineId.value === '' ? undefined : selectedLineId.value,
|
|
|
|
|
};
|
|
|
|
|
const res = await getDeviceLedgerPage(params);
|
|
|
|
|
const page = normalizePageData(res);
|
|
|
|
|
total.value = page.total;
|
|
|
|
|
list.value = reset ? page.list : [...list.value, ...page.list];
|
|
|
|
|
finished.value =
|
|
|
|
|
list.value.length >= total.value || page.list.length < pageSize.value;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (!reset) pageNo.value = Math.max(1, pageNo.value - 1)
|
|
|
|
|
uni.showToast({ title: t('functionCommon.loadFailed'), icon: 'none' })
|
|
|
|
|
if (!reset) pageNo.value = Math.max(1, pageNo.value - 1);
|
|
|
|
|
uni.showToast({ title: t('functionCommon.loadFailed'), icon: 'none' });
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false
|
|
|
|
|
loadingMore.value = false
|
|
|
|
|
loading.value = false;
|
|
|
|
|
loadingMore.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizePageData(res) {
|
|
|
|
|
const root = res && res.data !== undefined ? res.data : res
|
|
|
|
|
const candidateList = root?.list || root?.rows || root?.records || root?.data?.list || root?.data?.rows || root?.data?.records || []
|
|
|
|
|
const candidateTotal = root?.total ?? root?.data?.total ?? (Array.isArray(candidateList) ? candidateList.length : 0)
|
|
|
|
|
return { list: Array.isArray(candidateList) ? candidateList : [], total: Number(candidateTotal || 0) }
|
|
|
|
|
const root = res && res.data !== undefined ? res.data : res;
|
|
|
|
|
const candidateList =
|
|
|
|
|
root?.list ||
|
|
|
|
|
root?.rows ||
|
|
|
|
|
root?.records ||
|
|
|
|
|
root?.data?.list ||
|
|
|
|
|
root?.data?.rows ||
|
|
|
|
|
root?.data?.records ||
|
|
|
|
|
[];
|
|
|
|
|
const candidateTotal =
|
|
|
|
|
root?.total ??
|
|
|
|
|
root?.data?.total ??
|
|
|
|
|
(Array.isArray(candidateList) ? candidateList.length : 0);
|
|
|
|
|
return {
|
|
|
|
|
list: Array.isArray(candidateList) ? candidateList : [],
|
|
|
|
|
total: Number(candidateTotal || 0),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onStatusFilterChange(e) {
|
|
|
|
|
const idx = Number(e?.detail?.value || 0)
|
|
|
|
|
selectedStatus.value = statusOptions.value[idx]?.value ?? ''
|
|
|
|
|
fetchList(true)
|
|
|
|
|
const idx = Number(e?.detail?.value || 0);
|
|
|
|
|
selectedStatus.value = statusOptions.value[idx]?.value ?? '';
|
|
|
|
|
fetchList(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openLineCascader() {
|
|
|
|
|
lineCascaderShow.value = true
|
|
|
|
|
lineCascaderShow.value = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onLineCascaderConfirm(values) {
|
|
|
|
|
const selectedValues = Array.isArray(values) ? values : []
|
|
|
|
|
const nextValue = selectedValues[selectedValues.length - 1] ?? ''
|
|
|
|
|
selectedLineId.value = nextValue === '' ? '' : String(nextValue)
|
|
|
|
|
lineCascaderValue.value = nextValue === '' ? [] : selectedValues.map(item => String(item))
|
|
|
|
|
fetchList(true)
|
|
|
|
|
const selectedValues = Array.isArray(values) ? values : [];
|
|
|
|
|
const nextValue = selectedValues[selectedValues.length - 1] ?? '';
|
|
|
|
|
selectedLineId.value = nextValue === '' ? '' : String(nextValue);
|
|
|
|
|
lineCascaderValue.value =
|
|
|
|
|
nextValue === '' ? [] : selectedValues.map((item) => String(item));
|
|
|
|
|
fetchList(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function resetFilters() {
|
|
|
|
|
searchKeyword.value = ''
|
|
|
|
|
selectedStatus.value = ''
|
|
|
|
|
selectedLineId.value = ''
|
|
|
|
|
lineCascaderValue.value = []
|
|
|
|
|
lineCascaderShow.value = false
|
|
|
|
|
lineCascaderKey.value += 1
|
|
|
|
|
activateKeywordFocus()
|
|
|
|
|
await fetchList(true)
|
|
|
|
|
searchKeyword.value = '';
|
|
|
|
|
selectedStatus.value = '';
|
|
|
|
|
selectedLineId.value = '';
|
|
|
|
|
lineCascaderValue.value = [];
|
|
|
|
|
lineCascaderShow.value = false;
|
|
|
|
|
lineCascaderKey.value += 1;
|
|
|
|
|
activateKeywordFocus();
|
|
|
|
|
await fetchList(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function resetLineFilter() {
|
|
|
|
|
await resetFilters()
|
|
|
|
|
await resetFilters();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleSearch() {
|
|
|
|
|
await fetchList(true)
|
|
|
|
|
await fetchList(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleScan() {
|
|
|
|
|
@ -316,125 +407,138 @@ function handleScan() {
|
|
|
|
|
onlyFromCamera: true,
|
|
|
|
|
scanType: ['qrCode', 'barCode'],
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
const scan = parseScanResult(res?.result)
|
|
|
|
|
const scan = parseScanResult(res?.result);
|
|
|
|
|
if (!scan.type || !scan.id) {
|
|
|
|
|
uni.showToast({ title: t('equipmentLedger.scanUnrecognized'), icon: 'none' })
|
|
|
|
|
return
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: t('equipmentLedger.scanUnrecognized'),
|
|
|
|
|
icon: 'none',
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (scan.type === 'DEVICE_LINE') {
|
|
|
|
|
selectedLineId.value = scan.id
|
|
|
|
|
lineCascaderValue.value = findLinePath(lineTree.value, scan.id)
|
|
|
|
|
await fetchList(true)
|
|
|
|
|
return
|
|
|
|
|
selectedLineId.value = scan.id;
|
|
|
|
|
lineCascaderValue.value = findLinePath(lineTree.value, scan.id);
|
|
|
|
|
await fetchList(true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (scan.type === 'EQUIPMENT') {
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: `/pages_function/pages/equipmentLedger/detail?id=${encodeURIComponent(String(scan.id))}`
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
url: `/pages_function/pages/equipmentLedger/detail?id=${encodeURIComponent(String(scan.id))}`,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uni.showToast({ title: t('equipmentLedger.scanTypeMismatch'), icon: 'none' })
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: t('equipmentLedger.scanTypeMismatch'),
|
|
|
|
|
icon: 'none',
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
const msg = String(err?.errMsg || '')
|
|
|
|
|
if (msg.includes('cancel')) return
|
|
|
|
|
uni.showToast({ title: t('equipmentLedger.scanFailed'), icon: 'none' })
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
const msg = String(err?.errMsg || '');
|
|
|
|
|
if (msg.includes('cancel')) return;
|
|
|
|
|
uni.showToast({ title: t('equipmentLedger.scanFailed'), icon: 'none' });
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parseScanResult(value) {
|
|
|
|
|
const text = String(value || '').trim()
|
|
|
|
|
const match = text.match(/^([A-Z_]+)-(\d+)$/i)
|
|
|
|
|
if (!match) return { type: '', id: '' }
|
|
|
|
|
const text = String(value || '').trim();
|
|
|
|
|
const match = text.match(/^([A-Z_]+)-(\d+)$/i);
|
|
|
|
|
if (!match) return { type: '', id: '' };
|
|
|
|
|
return {
|
|
|
|
|
type: match[1].toUpperCase(),
|
|
|
|
|
id: match[2]
|
|
|
|
|
}
|
|
|
|
|
id: match[2],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function goTop() {
|
|
|
|
|
uni.pageScrollTo({ scrollTop: 0, duration: 200 })
|
|
|
|
|
uni.pageScrollTo({ scrollTop: 0, duration: 200 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function loadMore() {
|
|
|
|
|
if (loading.value || loadingMore.value || finished.value) return
|
|
|
|
|
pageNo.value += 1
|
|
|
|
|
await fetchList(false)
|
|
|
|
|
if (loading.value || loadingMore.value || finished.value) return;
|
|
|
|
|
pageNo.value += 1;
|
|
|
|
|
await fetchList(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStatusText(status) {
|
|
|
|
|
return getDictLabel(DICT_TYPE.MES_TZ_STATUS, status, textValue(status))
|
|
|
|
|
return getDictLabel(DICT_TYPE.MES_TZ_STATUS, status, textValue(status));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStatusClass(status) {
|
|
|
|
|
const s = String(status)
|
|
|
|
|
if (s === '0') return 'status-enabled'
|
|
|
|
|
if (s === '1') return 'status-idle'
|
|
|
|
|
return 'status-danger'
|
|
|
|
|
const s = String(status);
|
|
|
|
|
if (s === '0') return 'status-enabled';
|
|
|
|
|
if (s === '1') return 'status-idle';
|
|
|
|
|
return 'status-danger';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStatusChangeIndex(status) {
|
|
|
|
|
const idx = statusOptions.value.findIndex(item => String(item.value) === String(status))
|
|
|
|
|
return idx >= 0 ? idx : 0
|
|
|
|
|
const idx = statusOptions.value.findIndex(
|
|
|
|
|
(item) => String(item.value) === String(status),
|
|
|
|
|
);
|
|
|
|
|
return idx >= 0 ? idx : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function onItemStatusChange(item, e) {
|
|
|
|
|
const id = item?.id
|
|
|
|
|
const id = item?.id;
|
|
|
|
|
if (id === undefined || id === null) {
|
|
|
|
|
uni.showToast({ title: t('equipmentLedger.noId'), icon: 'none' })
|
|
|
|
|
return
|
|
|
|
|
uni.showToast({ title: t('equipmentLedger.noId'), icon: 'none' });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const nextOption = statusOptions.value[Number(e?.detail?.value || 0)]
|
|
|
|
|
if (!nextOption || String(nextOption.value) === String(item.deviceStatus)) return
|
|
|
|
|
const nextOption = statusOptions.value[Number(e?.detail?.value || 0)];
|
|
|
|
|
if (!nextOption || String(nextOption.value) === String(item.deviceStatus))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const oldStatus = item.deviceStatus
|
|
|
|
|
item.deviceStatus = nextOption.value
|
|
|
|
|
statusUpdatingMap.value = { ...statusUpdatingMap.value, [id]: true }
|
|
|
|
|
const oldStatus = item.deviceStatus;
|
|
|
|
|
item.deviceStatus = nextOption.value;
|
|
|
|
|
statusUpdatingMap.value = { ...statusUpdatingMap.value, [id]: true };
|
|
|
|
|
try {
|
|
|
|
|
await updateDeviceLedger({ id, deviceStatus: nextOption.value })
|
|
|
|
|
uni.showToast({ title: t('functionCommon.updateSuccess'), icon: 'success' })
|
|
|
|
|
await updateDeviceLedger({ id, deviceStatus: nextOption.value });
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: t('functionCommon.updateSuccess'),
|
|
|
|
|
icon: 'success',
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
item.deviceStatus = oldStatus
|
|
|
|
|
uni.showToast({ title: t('functionCommon.saveFailed'), icon: 'none' })
|
|
|
|
|
item.deviceStatus = oldStatus;
|
|
|
|
|
uni.showToast({ title: t('functionCommon.saveFailed'), icon: 'none' });
|
|
|
|
|
} finally {
|
|
|
|
|
statusUpdatingMap.value = { ...statusUpdatingMap.value, [id]: false }
|
|
|
|
|
statusUpdatingMap.value = { ...statusUpdatingMap.value, [id]: false };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openDetail(item) {
|
|
|
|
|
const id = item?.id
|
|
|
|
|
if (!id && id !== 0) return
|
|
|
|
|
const id = item?.id;
|
|
|
|
|
if (!id && id !== 0) return;
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: `/pages_function/pages/equipmentLedger/detail?id=${encodeURIComponent(String(id))}`
|
|
|
|
|
})
|
|
|
|
|
url: `/pages_function/pages/equipmentLedger/detail?id=${encodeURIComponent(String(id))}`,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function textValue(value) {
|
|
|
|
|
if (value === 0) return '0'
|
|
|
|
|
if (value === false) return t('functionCommon.no')
|
|
|
|
|
if (value === true) return t('functionCommon.yes')
|
|
|
|
|
if (value === null || value === undefined) return '-'
|
|
|
|
|
const text = String(value).trim()
|
|
|
|
|
return text || '-'
|
|
|
|
|
if (value === 0) return '0';
|
|
|
|
|
if (value === false) return t('functionCommon.no');
|
|
|
|
|
if (value === true) return t('functionCommon.yes');
|
|
|
|
|
if (value === null || value === undefined) return '-';
|
|
|
|
|
const text = String(value).trim();
|
|
|
|
|
return text || '-';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatDateValue(value) {
|
|
|
|
|
if (!value) return '-'
|
|
|
|
|
const pad = (n) => String(n).padStart(2, '0')
|
|
|
|
|
const formatDate = (date) => `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
|
|
|
|
|
if (!value) return '-';
|
|
|
|
|
const pad = (n) => String(n).padStart(2, '0');
|
|
|
|
|
const formatDate = (date) =>
|
|
|
|
|
`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
|
|
|
if (Array.isArray(value) && value.length >= 3) {
|
|
|
|
|
const [y, m, d] = value
|
|
|
|
|
return `${y}-${pad(m)}-${pad(d)}`
|
|
|
|
|
const [y, m, d] = value;
|
|
|
|
|
return `${y}-${pad(m)}-${pad(d)}`;
|
|
|
|
|
}
|
|
|
|
|
const text = String(value).trim()
|
|
|
|
|
if (!text) return '-'
|
|
|
|
|
const text = String(value).trim();
|
|
|
|
|
if (!text) return '-';
|
|
|
|
|
if (/^\d{10,13}$/.test(text)) {
|
|
|
|
|
const timestamp = Number(text.length === 10 ? `${text}000` : text)
|
|
|
|
|
const date = new Date(timestamp)
|
|
|
|
|
if (!Number.isNaN(date.getTime())) return formatDate(date)
|
|
|
|
|
const timestamp = Number(text.length === 10 ? `${text}000` : text);
|
|
|
|
|
const date = new Date(timestamp);
|
|
|
|
|
if (!Number.isNaN(date.getTime())) return formatDate(date);
|
|
|
|
|
}
|
|
|
|
|
return text.split(' ')[0]
|
|
|
|
|
return text.split(' ')[0];
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
@ -532,9 +636,9 @@ function formatDateValue(value) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.reset-filter-btn {
|
|
|
|
|
min-width: 10rpx;
|
|
|
|
|
flex: 1;
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
min-width: 10rpx;
|
|
|
|
|
flex: 1;
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
@ -687,4 +791,3 @@ function formatDateValue(value) {
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|