This commit is contained in:
houjunxiang
2025-10-09 18:19:55 +08:00
parent f2ffc65094
commit 386f1e7466
1553 changed files with 284685 additions and 32820 deletions

View File

@@ -0,0 +1,105 @@
<template>
<uni-card style="height: 100%" spacing="0">
<view class="content">
<up-row class="flex-wrap">
<up-col :span="gridCol"
>使用部门
<text class="value">{{ acceptInfo.useDept }}</text>
</up-col>
<up-col :span="gridCol"
>到货日期
<text class="value">{{ acceptInfo.deviceCode }}</text>
</up-col>
<up-col :span="gridCol"
>安装调试
<text class="value">{{ acceptInfo.installStatus }}</text>
</up-col>
<up-col :span="gridCol"
>验收结果
<text class="value">{{ acceptInfo.acceptResult }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
</view>
</uni-card>
</template>
<script setup>
import { ref, reactive, onMounted, onBeforeMount } from 'vue'
import { acceptDetailList } from '@/nx/api/deviceInfo'
import { useGridCol } from '@/nx/hooks/useGridCol'
import nx from '@/nx'
const { gridCol } = useGridCol([700], [6, 4])
const acceptSchema = [
{
label: '使用部门',
field: 'useDept'
},
{
label: '到货日期',
field: 'arrivalDate'
},
{
label: '验收日期',
field: 'acceptDate'
},
{
label: '安装调试',
field: 'installStatus'
},
{
label: '验收结果',
field: 'acceptResult'
},
{
label: '验收状态',
field: 'acceptStatus'
},
{
label: '备注',
field: 'remark'
}
]
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
getDetailInfo(id)
})
let acceptInfo = ref({})
let commentWf = ref([])
async function getDetailInfo(id) {
const res = await acceptDetailList({
deviceBusInfoId: id
})
if (res.length > 0) {
let info = res[0]
acceptInfo.value = info
if (info.commentJson) {
try {
commentWf.value = JSON.parse(info.commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
color: #000;
.u-col {
padding: 10px;
}
.value {
color: #666;
font-size: 16px;
}
}
</style>

View File

@@ -0,0 +1,102 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="20px" type="line" title="设备借用单"> </uni-section>
<scroll-view scroll-y="true" class="content">
<up-row class="flex-wrap">
<up-col :span="gridCol"
>借用人
<text class="value">{{ detailInfo.borrowOper }}</text>
</up-col>
<up-col :span="gridCol"
>借用部门
<text class="value">{{ detailInfo.borrowDept }}</text>
</up-col>
<up-col :span="gridCol"
>借用日期
<text class="value">{{ detailInfo.borrowDate }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="6"
>计划归还日期
<text class="value">{{ detailInfo.planGivebackDate }}</text>
</up-col>
<up-col span="6"
>借用原因
<text class="value">{{ detailInfo.borrowReason }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>备注
<text class="value">{{ detailInfo.remark }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { useGridCol } from '@/nx/hooks/useGridCol'
const { gridCol } = useGridCol([700], [6, 4])
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
let commentWf = ref([])
function handleOpen() {
detailInfo.value = props.checkInfo
if (props.checkInfo.commentJson) {
try {
commentWf.value = JSON.parse(props.checkInfo.commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
height: 80vh;
width: 80vw;
padding: 20px;
.u-row {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.value {
color: #666;
font-size: 16;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

109
pages/lims/borrow/list.vue Normal file
View File

@@ -0,0 +1,109 @@
<template>
<view>
<uni-card spacing="0">
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<borrow-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import BorrowDetailPopup from './detail.vue'
import { borrowList } from '@/nx/api/deviceInfo'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
const column = reactive([
{
label: '借用人',
name: 'borrowOper',
width: 120
},
{
label: '借用部门',
name: 'borrowDept',
width: 140
},
{
label: '借用日期',
name: 'borrowDate',
width: 120
},
{
label: '借用原因',
name: 'borrowReason',
width: 180
},
{
label: '计划归还日期',
name: 'planGivebackDate',
width: 140
},
{
label: '备注',
name: 'remark',
width: 140
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceBusInfoId: deviceId.value,
borrowStatus: '已借出'
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: borrowList
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,9 @@
import request from '@/nx/request'
export function list(params) {
return request({
url: '/lims/bus/deviceBusCalibration/queryPageList',
method: 'GET',
params
})
}

View File

@@ -0,0 +1,144 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="20px" type="line" title="设备检定/校准信息"> </uni-section>
<scroll-view scroll-y="true" class="content">
<up-row class="flex-wrap">
<up-col :span="gridCol"
>仪器设备名称
<text class="value">{{ detailInfo.deviceName }}</text>
</up-col>
<up-col span="4"
>别名
<text class="value">{{ detailInfo.alias }}</text>
</up-col>
<up-col span="4"
>生产厂家
<text class="value">{{ detailInfo.manufacturer }}</text>
</up-col>
<up-col :span="gridCol"
>规格型号
<text class="value">{{ detailInfo.modelNo }}</text>
</up-col>
</up-row>
<up-row class="flex-wrap">
<up-col :span="gridCol"
>设备编号
<text class="value">{{ detailInfo.deviceCode }}</text>
</up-col>
<up-col :span="gridCol"
>统一编号
<text class="value">{{ detailInfo.deviceCode }}</text>
</up-col>
<up-col :span="gridCol"
>检定/校准单位
<text class="value">{{ detailInfo.agent }}</text>
</up-col>
</up-row>
<up-row class="flex-wrap">
<up-col :span="gridCol"
>检定/校准日期
<text class="value">{{ detailInfo.checkDate }}</text>
</up-col>
<up-col :span="gridCol"
>证书编号
<text class="value">{{ detailInfo.certificateCode }}</text>
</up-col>
<up-col :span="gridCol"
>确认结果
<text class="value">{{ detailInfo.checkResult }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>确认情况(理由)
<up-parse style="background: #f3f4f6" :content="processedContent"></up-parse>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>备注
<text class="value">{{ detailInfo.checkRemark }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { getImgBaseUrl } from '@/defaultBaseUrl'
import { useGridCol } from '@/nx/hooks/useGridCol'
const { gridCol } = useGridCol([700], [6, 4])
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
// / 处理富文本内容
const processedContent = computed(() => {
if (!detailInfo.value.checkContent) {
return ''
}
return detailInfo.value.checkContent.replace(
/<img([^>]+?)src="((?!http)[^"]*?)(file\/[^"]*)"/gi,
(match, attributes, prefix, filePath) => {
return `<img${attributes}src="${getImgBaseUrl()}/${filePath}"`
}
)
})
let commentWf = ref([])
function handleOpen() {
detailInfo.value = props.checkInfo
if (props.checkInfo.commentJson) {
try {
commentWf.value = JSON.parse(props.checkInfo.commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
height: 80vh;
width: 90vw;
padding: 10px;
.u-row {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.value {
color: #666;
font-size: 16px;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

View File

@@ -0,0 +1,101 @@
<template>
<view>
<uni-card spacing="0">
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<calibration-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import CalibrationDetailPopup from './detail.vue'
import { list } from './calibration.api'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
const column = reactive([
{
label: '检定/校准日期',
name: 'checkDate',
width: 140
},
{
label: '确认人',
name: 'checkPersonName',
width: 200
},
{
label: '检定/校准周期',
name: 'frequencyRemark',
width: 200
},
{
label: '检定/校准单位',
name: 'agent',
width: 200
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceId: deviceId.value,
effectiveFlag: '1',
wfStatus: 'finished'
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: list
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,32 @@
import { ref, reactive } from 'vue'
export const detailSchema = [
{ label: '设备名称', value: 'deviceName' },
{ label: '别名', value: 'alias' },
{ label: '设备型号', value: 'modelNo' },
{ label: '设备编码', value: 'deviceCode' },
{ label: '生产厂商', value: 'manufacturer' },
{ label: '使用班组', value: 'deptName' }
]
export const column = reactive([
{
label: '点检人',
name: 'checkUserName',
width: 160
},
{
label: '点检日期',
name: 'checkDate',
width: 180
},
{
label: '备注',
name: 'content',
width: 200
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])

View File

@@ -0,0 +1,138 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="18px" type="line" title="设备点检信息"> </uni-section>
<scroll-view scroll-y="true" style="height: 85vh; width: 90vw">
<view class="content">
<up-row class="flex-wrap p10" style="background-color: #f5f7fa">
<up-col class="mb10" :span="gridCol" v-for="(item, index) in detailSchema">
<view style="color: #666"
><span style="color: #333">{{ item.label }}</span>{{ detailInfo[item.value] }}</view
>
</up-col>
</up-row>
<view class="p5">
<view class="pt5"
>备注
<text style="color: #666">
{{ detailInfo.content }}
</text>
</view>
<up-row>
<up-col span="6">
<view class="pt5"
>点检人
<text style="color: #666">
{{ detailInfo.checkUserName }}
</text>
</view>
<view class="pt5"
>点检日期
<text style="color: #666">
{{ detailInfo.checkDate }}
</text>
</view>
</up-col>
<up-col span="6">
<up-album multiple-size="70" single-size="70" :urls="attachment" row-count="4"> </up-album>
</up-col>
</up-row>
</view>
<view>
<up-row class="font-bold" style="background-color: #f5f5f5">
<up-col span="5">点检项目</up-col>
<up-col span="3">检查标准</up-col>
<up-col span="2"> 频次</up-col>
<up-col span="2">是否正常</up-col>
</up-row>
<view class="pt10">
<up-row class="pb10" v-for="(item, index) in detailInfo.maintainItemList" :key="index">
<up-col span="5">
<view class="x-f">
<text class="pl10">
{{ item.itemName }}
</text>
</view>
</up-col>
<up-col span="3">{{ item.standard }}</up-col>
<up-col span="2">{{ item.frequencyRemark }}</up-col>
<up-col span="2">
<u-tag v-if="item.checkResult == '正常'" text="正常" size="mini" type="success" plain plainFill></u-tag>
<u-tag v-else text="不正常" type="error" size="mini" plain plainFill></u-tag>
</up-col>
</up-row>
</view>
<view class="p10"></view>
</view>
</view>
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { detailSchema } from './dailyCheck.data'
import dailyCheckApi from '@/nx/api/dailyCheck'
import { getImgBaseUrl } from '@/defaultBaseUrl'
import { useGridCol } from '@/nx/hooks/useGridCol'
const { gridCol } = useGridCol([700], [6, 4])
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
const attachment = ref([])
async function getDetailInfo(id) {
const res = await dailyCheckApi.queryById(id)
res.maintainItemList.forEach(item => {
if (item.checkResult == 'false' || !item.checkResult) {
item.checkResult = false
}
if (item.checkResult == 'true') {
item.checkResult = true
}
})
detailInfo.value = res
attachment.value = []
let files = res?.attachment?.split(',') || []
if (files.length > 0) {
attachment.value = files.map(item => getImgBaseUrl() + item)
}
}
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
function handleOpen() {
getDetailInfo(props.checkInfo.id)
}
</script>
<style lang="scss" scoped>
.content {
background-color: #fff;
height: 100%;
padding: 16px;
padding-top: 10px;
font-size: 16px;
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

View File

@@ -0,0 +1,293 @@
<template>
<view>
<up-sticky>
<navbar-back title="点检">
<up-button
v-if="detailInfo.id"
type="primary"
:plain="true"
icon="list"
size="small"
text="设备点检记录"
@click="handleCheckRecord"
></up-button>
</navbar-back>
</up-sticky>
<view class="container">
<n-scanTemp
v-if="!detailInfo.id"
title="请扫描设备条码进行点检"
icon="dailyCheck"
@deviceId="id => getDailyCheckRecord(id)"
/>
<view v-else class="content">
<view>
<uni-section titleFontSize="22px" type="line" title="设备点检信息">
<template v-slot:right>
<up-button
v-if="detailInfo.submitFlag == '1'"
type="success"
text="新建点检"
@click="handleCreateDailyCheck"
></up-button>
</template>
</uni-section>
<up-row class="flex-wrap p10" style="background-color: #f5f7fa">
<up-col class="mb10" :span="gridCol" v-for="(item, index) in detailSchema">
<view style="color: #666"
><span style="color: #333">{{ item.label }}</span>{{ detailInfo[item.value] }}</view
>
</up-col>
</up-row>
</view>
<view>
<uni-section titleFontSize="22px" type="line" title="检查项"> </uni-section>
<up-row class="p10 font-bold" style="background-color: #f5f5f5">
<up-col span="4">点检项目</up-col>
<up-col span="3">检查标准</up-col>
<up-col span="2"> 频次</up-col>
<up-col style="text-align: center" span="3">是否正常</up-col>
</up-row>
<view class="pt10">
<up-row class="pb12" v-for="(item, index) in detailInfo.maintainItemList" :key="index">
<up-col span="4">
<view class="x-f">
<u-badge type="warning " :value="index + 1"></u-badge>
<text class="pl10">
{{ item.itemName }}
</text>
</view>
</up-col>
<up-col span="3">{{ item.standard }}</up-col>
<up-col span="2">{{ item.frequencyRemark }}</up-col>
<up-col span="3">
<u-radio-group v-model="item.checkResult" placement="row">
<u-radio activeColor="green" label="正常" name="正常"></u-radio>
<u-radio activeColor="red" label="不正常" name="不正常"></u-radio>
</u-radio-group>
</up-col>
</up-row>
</view>
</view>
<view>
<uni-section titleFontSize="22px" type="line" title="备注"> </uni-section>
<up-textarea v-model="detailInfo.content" placeholder="请输入内容"></up-textarea>
<view class="p10">附件照片</view>
<n-upload v-model="detailInfo.attachment" />
<view class="p10">点检人</view>
<up-input v-model="detailInfo.checkUserName"></up-input>
<view v-if="detailInfo.submitFlag == '1'">
<view class="p10">点检日期</view>
<uni-datetime-picker type="datetime" v-model="detailInfo.checkDate" />
</view>
</view>
<view class="mt40 x-bc" v-if="detailInfo.submitFlag == '0'">
<up-button
style="width: 40%"
loadingText="保存中..."
type="warning"
text="暂存"
@click="handleSubmit('0')"
></up-button>
<up-button
style="width: 40%"
loadingText="提交中..."
type="primary"
text="提交"
@click="handleSubmit('1')"
></up-button>
</view>
</view>
</view>
<up-modal
:show="modalShow"
title="提示"
:content="modalText"
ref="uModal"
:asyncClose="true"
showCancelButton
@confirm="confirm"
@cancel="modalShow = false"
></up-modal>
<up-loading-page :loading="pageLoading"></up-loading-page>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, watch, toRefs, computed } from 'vue'
import { onShow, onLoad } from '@dcloudio/uni-app'
import dailyCheckApi from '@/nx/api/dailyCheck'
import { detailSchema } from './dailyCheck.data'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
import { useGridCol } from '@/nx/hooks/useGridCol'
import nx from '@/nx'
const { gridCol } = useGridCol([700], [6, 4])
const { lockOrientation } = useScreenOrientation()
const pageLoading = ref(false)
let detailInfo = ref({})
const { scanQRInfo } = toRefs(nx.$store('biz'))
watch(scanQRInfo, newVal => {
if (newVal && nx.$router.getCurrentPage().route == 'pages/lims/deviceBusDailyCheck/index') {
try {
const codeObj = JSON.parse(newVal)
if (!pageLoading.value) {
getDailyCheckRecord(codeObj.id)
}
scanQRInfo.value = ''
} catch (error) {
scanQRInfo.value = ''
uni.showToast({
title: '请扫描设备码',
icon: 'none'
})
}
}
})
const modalText = computed(() => {
return `确定${modalType.value == '0' ? '暂存' : '提交'}吗?${modalType.value == '0' ? '' : '提交后不能修改'} `
})
onShow(() => {
scanQRInfo.value = ''
})
let goBack = ref(false)
onLoad(options => {
if (options.deviceId) {
goBack.value = true
getDailyCheckRecord(options.deviceId)
}
})
async function getDailyCheckRecord(id) {
pageLoading.value = true
const res = await dailyCheckApi
.getCheckRecord({
deviceId: id,
dataType: 'dailyCheck'
})
.finally(() => {
pageLoading.value = false
})
if (!res.checkUserName) {
res.checkUserName = nx.$store('user').userInfo.realname
res.checkUserId = nx.$store('user').userInfo.id
}
detailInfo.value = res
modalType.value = res.submitFlag
lockOrientation('landscape')
}
const modalShow = ref(false)
const modalType = ref('')
// 是否有异常项
const hasAbnormal = computed(() => {
if (modalType.value == '1') {
const items = detailInfo.value.maintainItemList || []
for (let i = 0; i < items.length; i++) {
const checkResult = items[i].checkResult
if (checkResult == '不正常') {
return true
}
}
}
return false
})
function handleSubmit(type) {
// 新增维护保养项验证
if (type == '1') {
const items = detailInfo.value.maintainItemList || []
for (let i = 0; i < items.length; i++) {
const item = items[i]
const itemNumber = `${i + 1}`
if (!item.checkResult?.trim()) {
return uni.showToast({ title: `${itemNumber}设备检查状态未选择`, icon: 'none' })
}
}
}
if (!detailInfo.value.checkUserName) {
return uni.showToast({
title: '请输入点检人',
icon: 'none'
})
}
detailInfo.value.checkDate = nx.$dayjs().format('YYYY-MM-DD HH:mm:ss')
modalType.value = type
modalShow.value = true
console.log(detailInfo.value)
}
const submitLoading = ref(false)
async function confirm() {
if (submitLoading.value) return
submitLoading.value = true
await dailyCheckApi.submit({ ...detailInfo.value, submitFlag: modalType.value }).finally(() => {
submitLoading.value = false
modalShow.value = false
reset()
})
if (goBack.value && modalType.value == 1) {
uni.navigateBack()
}
}
function reset() {
detailInfo.value = {}
}
function handleCheckRecord() {
let deviceInfo = {
id: detailInfo.value.deviceId,
deviceName: detailInfo.value.deviceName
}
nx.$store('biz').deviceInfo = deviceInfo
nx.$router.go('/pages/lims/deviceBusDailyCheck/list')
}
// 新建点检
function handleCreateDailyCheck() {
uni.showModal({
title: '提示',
content: '确定新建点检吗?',
success: async function (res) {
if (res.confirm) {
const res = await dailyCheckApi.createDailyCheck({
deviceId: detailInfo.value.deviceId,
dataType: 'dailyCheck'
})
res.checkUserName = nx.$store('user').userInfo.realname
res.checkUserId = nx.$store('user').userInfo.id
res.checkDate = nx.$dayjs().format('YYYY-MM-DD HH:mm:ss')
detailInfo.value = res
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
.container {
.content {
background-color: #fff;
height: 100%;
padding: 16px;
padding-top: 10px;
font-size: 18px;
.title {
font-size: 22px;
font-weight: bold;
}
:deep(.u-checkbox) {
justify-content: center;
}
}
}
</style>

View File

@@ -0,0 +1,84 @@
<template>
<view>
<up-sticky v-if="!isComponent">
<navbar-back title="点检记录"> </navbar-back>
</up-sticky>
<uni-card spacing="0">
<uni-section v-if="!isComponent" titleFontSize="20px" type="line" :title="deviceText"> </uni-section>
<view :style="{ height: isComponent ? '70vh' : '72vh' }">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<daily-check-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import DailyCheckDetailPopup from './detail.vue'
import dailyCheckApi from '@/nx/api/dailyCheck'
import { useListData } from '@/nx/hooks/usePageListData'
import { column } from './dailyCheck.data'
import nx from '@/nx'
let props = defineProps({
isComponent: {
type: Boolean,
default: false
}
})
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
dataType: 'dailyCheck',
deviceId: deviceId.value
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: dailyCheckApi.list
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,86 @@
<template>
<view class="container">
<up-sticky>
<navbar-back :title="`${deviceText})设备信息`"></navbar-back>
</up-sticky>
<up-tabs lineWidth="30" :list="tabs" @click="tabClick"></up-tabs>
<scroll-view scroll-y="true" class="content">
<BaseInfoCard v-if="activeIndex == 0" @getDeviceInfo="getDeviceInfo" />
<AcceptDetail v-if="activeIndex == 1" />
<DailyCheckList v-if="activeIndex == 2" isComponent />
<MaintainList v-if="activeIndex == 3" isComponent />
<UseRecordList v-if="activeIndex == 4" isComponent />
<PeriodCheckList v-if="activeIndex == 5" />
<CalibrationList v-if="activeIndex == 6" />
<RepairList v-if="activeIndex == 7" />
<BorrowList v-if="activeIndex == 8" />
<GivebackList v-if="activeIndex == 9" />
<StopList v-if="activeIndex == 10" />
<DocumentList v-if="activeIndex == 11" />
<ScrapInfo v-if="activeIndex == 12 && scrapFlag == 1" />
</scroll-view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import nx from '@/nx'
import BaseInfoCard from '@/pages/lims/deviceBusInfo/baseInfoCard'
import AcceptDetail from '@/pages/lims/accept/detail'
import DailyCheckList from '@/pages/lims/deviceBusDailyCheck/list'
import MaintainList from '@/pages/lims/deviceBusMaintain/list'
import UseRecordList from '@/pages/lims/deviceBusUseRecord/list'
import PeriodCheckList from '@/pages/lims/periodCheckList/index'
import CalibrationList from '@/pages/lims/calibrationList/index'
import RepairList from '@/pages/lims/repair/list'
import BorrowList from '@/pages/lims/borrow/list'
import GivebackList from '@/pages/lims/giveback/list'
import StopList from '@/pages/lims/stop/list'
import DocumentList from '@/pages/lims/documentList/index'
import ScrapInfo from '@/pages/lims/scrap/detail'
import { tabList } from './deviceBusInfo.data'
let activeIndex = ref(0)
let deviceText = ref('')
const detailId = ref('')
const { id, deviceName, scrapFlag } = nx.$store('biz').deviceInfo
onMounted(() => {
detailId.value = id
})
const getDeviceInfo = info => {
deviceText.value = info.deviceName + (info.alias ? `[${info.alias}]` : '')
}
const tabs = computed(() => {
return tabList.filter((item, index) => {
if (scrapFlag != 1) {
return item.name != '报废信息'
} else {
return item
}
})
})
function tabClick(e) {
activeIndex.value = e.index
if (activeIndex.value == 0) {
getDeviceInfo()
}
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
.container {
background-color: #f0f2f5;
height: 100%;
.content {
height: 75vh;
}
}
:deep(.u-tabs__wrapper__nav__item__text) {
font-size: 18px;
}
</style>

View File

@@ -0,0 +1,119 @@
<template>
<uni-card spacing="0">
<view class="detail-content">
<up-row align="top">
<template v-for="item in deviceSchema">
<up-col :span="item.span ? item.span : 4">
<view class="x-f detail-item" :style="item.itemStyle">
<view class="detail-label" :style="item.labelStyle">{{ item.label }}</view>
<template v-if="item.field == 'photo'">
<view style="height: 50px">
<up-album multipleSize="50" singleSize="50" maxCount="2" :urls="imgs"></up-album>
</view>
</template>
<text v-else class="detail-value" :style="item.valueStyle">{{ detailInfo[item.field] }}</text>
</view>
</up-col>
</template>
</up-row>
</view>
</uni-card>
<up-loading-page :loading="pageLoading"></up-loading-page>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import nx from '@/nx'
import { getDeviceBusInfoById } from '@/nx/api/deviceInfo'
import { getImgBaseUrl } from '@/defaultBaseUrl'
import { deviceSchema } from './deviceBusInfo.data'
const detailId = ref('')
const pageLoading = ref(false)
const emit = defineEmits(['getDeviceInfo'])
onMounted(() => {
const { id } = nx.$store('biz').deviceInfo
detailId.value = id
getDeviceInfo()
})
let detailInfo = ref({})
let imgs = ref([])
// 获取设备详情
async function getDeviceInfo() {
pageLoading.value = true
const res = await getDeviceBusInfoById(detailId.value).finally(() => {
pageLoading.value = false
})
detailInfo.value = (data => {
const statuses = [
data.repairFlag == 1 && '维修',
data.demoteFlag == 1 && '降级',
data.scrapFlag == 1 && '报废',
data.disableFlag == 1 && '停用',
data.lendFlag == 1 && '外借'
].filter(Boolean) // 去掉 false 值
if (data.acceptFlag != 'finished') {
data.deviceStatus = '--'
data.inUseFlag = '--'
} else {
data.deviceStatus = statuses.length > 0 ? statuses.join('、') : '正常'
if (data.inUseFlag == '1') {
data.inUseFlag = '是'
} else {
data.inUseFlag = '否'
}
}
switch (data.acceptFlag) {
case '0':
data.acceptFlag = '待验收'
break
case 'running':
data.acceptFlag = '验收审批中'
break
case 'finished':
data.acceptFlag = '已验收'
break
default:
data.acceptFlag = '--'
}
return data
})(res)
imgs.value = getFileList(res.photo)
emit('getDeviceInfo', detailInfo.value)
}
function getFileList(photo) {
if (photo) {
let fileIds = photo.split(',').map(item => getImgBaseUrl() + item)
return fileIds
} else {
return []
}
}
</script>
<style scoped>
.detail-content {
border: 0.5px solid #f0f0f0;
width: 100%;
.detail-item {
display: flex;
align-items: center;
padding: 10px 6px;
box-sizing: border-box;
font-size: 16px;
border: 0.5px solid #f0f0f0;
.detail-label {
color: #000;
}
.detail-value {
font-size: 14px;
width: 72%;
overflow: auto;
}
}
}
:deep(.u-row) {
flex-wrap: wrap;
width: 100%;
}
</style>

View File

@@ -0,0 +1,104 @@
import { ref } from 'vue'
export function getColumn(isFold) {
return [
{
label: '设备名称',
name: 'deviceName',
width: isFold ? 200 : 130,
fixed: true
},
{
label: '别名',
name: 'alias',
width: isFold ? 120 : 90,
fixed: true
},
{
label: '设备状态',
name: 'stateShow',
width: isFold ? 120 : 90
},
{
label: '使用状态',
name: 'inUseFlag',
width: isFold ? 120 : 90
},
{
label: '规格型号',
name: 'modelNo',
width: isFold ? 160 : 130
},
{
label: '使用班组',
name: 'deptName',
width: isFold ? 140 : 100
},
{
label: '负责人',
name: 'managerUserName',
width: isFold ? 100 : 90
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '设备信息', func: 'detail' }]
}
]
}
export const tabList = [
{ name: '基础信息' },
{ name: '验收信息' },
{ name: '点检' },
{ name: '维护保养' },
{ name: '使用记录' },
{ name: '期间核查' },
{ name: '检定/校准' },
{ name: '维修记录' },
{ name: '借用记录' },
{ name: '归还记录' },
{ name: '停用记录' },
{ name: '设备文档' },
{ name: '报废信息' }
]
export const deviceSchema = [
{ label: '设备名称', field: 'deviceName' },
{ label: '别名', field: 'alias' },
{ label: '设备用途', field: 'deviceUse' },
{ label: '存放位置', field: 'position' },
{ label: '等级分类', field: 'gradeClassify' },
{ label: '设备状态', field: 'stateShow' },
{ label: '验收状态', field: 'acceptFlag' },
{ label: '使用状态', field: 'inUseFlag' },
{ label: '数量', field: 'deviceNum' },
{ label: '管理编号', field: 'deviceCode' },
{ label: '资产编号', field: 'assetCode' },
{ label: '出厂编号', field: 'factoryCode' },
{ label: '规格型号', field: 'modelNo' },
{ label: '购入价格', field: 'purchasePrice' },
{ label: '采购时间', field: 'purchaseDate' },
{ label: '出厂日期', field: 'productiveDate' },
{ label: '安装日期', field: 'deployDate' },
{ label: '安装人员', field: 'deployEngineer' },
{ label: '验收人员', field: 'acceptUserName' },
{ label: '负责人', field: 'managerUserName' },
{ label: '所属班组', field: 'deptName' },
{
label: '安装位置',
field: 'deployLocation'
},
{
label: '技术指标',
field: 'deviceParameters',
valueStyle: { fontSize: 12 + 'px', height: 50 + 'px' }
},
{
label: '设备图片',
field: 'photo'
}
]

View File

@@ -0,0 +1,213 @@
<template>
<view class="container">
<up-sticky>
<navbar-back title="设备查询" />
</up-sticky>
<view class="content">
<up-transition :show="!isFold" mode="slide-left">
<view class="con-left" v-show="!isFold">
<uni-card style="height: 100%; overflow: auto" title="分类和产品" padding="0" margin="0" spacing="0">
<DaTree
ref="DaTreeRef"
:data="roomTreeData"
labelField="name"
valueField="id"
appendField="modelNo"
:indent="10"
@change="handleTreeChange"
></DaTree>
</uni-card>
</view>
</up-transition>
<view class="con-right">
<uni-card padding="0" margin="10">
<view class="p10 x-f" style="width: 60%">
<image
class="mr15"
style="width: 30px; height: 30px"
:src="`/static/images/${isFold ? 'zhedie2' : 'zhedie1'}.png`"
@click="isFold = !isFold"
></image>
<up-search
v-model="keyword"
shape="square"
placeholder="请输入设备名称或者扫描设备二维码码查询"
actionText="重置"
:clearabled="false"
:showAction="true"
@change="handleInputSearch"
@custom="handleReset"
></up-search>
</view>
<view style="height: 73vh; width: 100%">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, watch, computed, toRefs } from 'vue'
import DaTree from '@/components/da-tree/index.vue'
import { onShow } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import { useListData } from '@/nx/hooks/usePageListData'
import { throttle } from '@/uview-plus'
import { getColumn } from './deviceBusInfo.data'
import { deviceList, treeData, getDeviceBusInfoById } from '@/nx/api/deviceInfo'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
import nx from '@/nx'
const column = computed(() => getColumn(isFold.value))
const isFold = ref(false)
const roomTreeData = ref([])
const { scanQRInfo } = toRefs(nx.$store('biz'))
watch(scanQRInfo, newVal => {
if (newVal && nx.$router.getCurrentPage().route == 'pages/lims/deviceBusInfo/index') {
try {
const codeObj = JSON.parse(newVal)
handleDetail({ id: codeObj.id })
scanQRInfo.value = ''
} catch (error) {
scanQRInfo.value = ''
uni.showToast({
title: '请扫描设备码',
icon: 'none'
})
}
}
})
onShow(() => {
scanQRInfo.value = ''
})
async function getTreeData() {
const res = await treeData()
roomTreeData.value = res
}
getTreeData()
const { lockOrientation } = useScreenOrientation()
onMounted(async () => {
lockOrientation('landscape')
await getInitData()
console.log('listData', listData.value)
})
const searchParams = computed(() => {
const params = {
deviceName: keyword.value
}
if (selectedNode.value) {
params.productId = selectedNode.value.key
}
return params
})
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: deviceList,
processData: data => {
return data.map(item => {
const statuses = [
item.repairFlag == 1 && '维修',
item.demoteFlag == 1 && '降级',
item.scrapFlag == 1 && '报废',
item.disableFlag == 1 && '停用',
item.lendFlag == 1 && '外借'
].filter(Boolean) // 去掉 false 值
if (item.acceptFlag != 'finished') {
item.deviceStatus = '--'
} else {
item.deviceStatus = statuses.length > 0 ? statuses.join('、') : '正常'
}
if (item.inUseFlag == '1') {
item.inUseFlag = '是'
} else {
item.inUseFlag = '否'
}
return item
})
}
})
let zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
let selectedNode = ref(null)
let DaTreeRef = ref()
function handleTreeChange(allCheckedKeys, currentItem) {
console.log(allCheckedKeys, currentItem)
selectedNode.value = currentItem
getInitData()
}
let keyword = ref('')
function handleInputSearch() {
if (!keyword.value) return
throttle(getInitData, 500)
}
function handleReset() {
keyword.value = ''
if (selectedNode.value) {
DaTreeRef.value.setCheckedKeys(selectedNode.value.key, false)
}
selectedNode.value = ''
getInitData()
}
async function handleDetail(row, index) {
nx.$store('biz').deviceInfo = row
await getDeviceBusInfoById(row.id)
nx.$router.go('/pages/lims/deviceBusInfo/baseInfo')
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
.container {
background-color: #f0f2f5;
height: 100%;
.content {
display: flex;
.con-left {
height: 83vh;
overflow: scroll;
margin-top: 10px;
margin-left: 10px;
flex: 2;
}
.con-right {
flex: 8;
overflow: auto;
}
}
}
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
:deep(.u-search__action--active) {
padding: 5px;
border-radius: 3px;
background: #0055a2;
color: #fff;
}
</style>

View File

@@ -0,0 +1,142 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="18px" type="line" title="设备维护保养信息"> </uni-section>
<scroll-view scroll-y="true" style="height: 85vh; width: 90vw">
<view class="content">
<up-row class="flex-wrap pt10 pl10" style="background-color: #f5f7fa">
<up-col class="mb8" :span="gridCol" v-for="(item, index) in detailSchema">
<view style="color: #666"
><span style="color: #333">{{ item.label }}</span>{{ detailInfo[item.value] }}</view
>
</up-col>
</up-row>
<view class="pt5">
<up-row>
<up-col span="6">
<view
>维护保养人
<text style="color: #666">
{{ detailInfo.checkUserName }}
</text>
</view>
<view class="pt5"
>维护保养日期
<text style="color: #666">
{{ detailInfo.checkDate }}
</text>
</view>
</up-col>
<up-col span="6">
<u-album multiple-size="70" single-size="70" :urls="attachment" row-count="4" />
</up-col>
</up-row>
</view>
<view>
<up-row class="p10 font-bold" style="background-color: #f5f5f5">
<up-col span="5">维护保养内容</up-col>
<up-col span="3"> 频次</up-col>
<up-col span="4">维护保养标准</up-col>
</up-row>
<view>
<view v-for="(item, index) in detailInfo.maintainItemList" :key="index">
<up-row class="p10">
<up-col span="5">
<view class="x-f">
<text>
{{ item.itemName }}
</text>
</view>
</up-col>
<up-col span="3">{{ item.frequencyRemark }}</up-col>
<up-col span="4">{{ item.standard }}</up-col>
</up-row>
<up-row class="fill-content">
<up-col span="12"
><view
>维护保养情况:
<text style="color: #666">
{{ item.checkRemark }}
</text>
</view>
</up-col>
</up-row>
</view>
<view class="p10"></view>
</view>
</view>
</view>
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { useGridCol } from '@/nx/hooks/useGridCol'
import dailyCheckApi from '@/nx/api/dailyCheck'
import { getImgBaseUrl } from '@/defaultBaseUrl'
const { gridCol } = useGridCol([700], [6, 4])
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const detailSchema = [
{ label: '设备名称', value: 'deviceName' },
{ label: '别名', value: 'alias' },
{ label: '设备型号', value: 'modelNo' },
{ label: '设备编码', value: 'deviceCode' },
{ label: '使用班组', value: 'deptName' }
]
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
const attachment = computed(() => {
let files = detailInfo.value?.attachment?.split(',') || []
if (files.length > 0) {
return files.map(item => getImgBaseUrl() + item)
} else {
return []
}
})
let detailInfo = ref({})
async function getDetailInfo(id) {
const res = await dailyCheckApi.queryById(id)
detailInfo.value = res
}
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
function handleOpen() {
getDetailInfo(props.checkInfo.id)
}
</script>
<style lang="scss" scoped>
.content {
background-color: #fff;
height: 100%;
padding: 10px;
font-size: 16px;
.fill-content {
font-size: 14px;
border-radius: 3px;
box-shadow: 2px 2px 8px 2px rgba(0, 0, 0, 0.2);
background-color: #fdf6ec;
padding: 10px;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

View File

@@ -0,0 +1,262 @@
<template>
<view>
<up-sticky>
<navbar-back title="维护保养">
<up-button
v-if="detailInfo.id"
type="primary"
:plain="true"
icon="list"
size="small"
text="设备维护保养记录"
@click="handleCheckRecord"
></up-button>
</navbar-back>
</up-sticky>
<view class="container">
<n-scanTemp
v-if="!detailInfo.id"
title="请扫描设备条码进行维护保养"
icon="maintain"
@deviceId="id => getDetailInfo(id)"
/>
<view v-else class="content">
<view>
<uni-section titleFontSize="22px" type="line" title="设备维护保养信息"> </uni-section>
<up-row class="flex-wrap p10" style="background-color: #f5f7fa">
<up-col class="mb10" :span="gridCol" v-for="(item, index) in detailSchema">
<view style="color: #666"
><span style="color: #333">{{ item.label }}</span>{{ detailInfo[item.value] }}</view
>
</up-col>
</up-row>
</view>
<view class="check-header">
<uni-section titleFontSize="22px" type="line" title="维护保养项"> </uni-section>
<up-row class="p10 font-bold border-b" style="background-color: #f5f5f5">
<up-col span="4">维护保养内容</up-col>
<up-col span="4"> 频次</up-col>
<up-col span="4">维护保养标准</up-col>
</up-row>
<view class="pt10">
<view v-for="(item, index) in detailInfo.maintainItemList" :key="index">
<up-row class="p20">
<up-col span="4">
<view class="x-f">
<u-badge type="warning " :value="index + 1"></u-badge>
<text class="pl10">
{{ item.itemName }}
</text>
</view>
</up-col>
<up-col span="4">{{ item.frequencyRemark }}</up-col>
<up-col span="4">{{ item.standard }}</up-col>
</up-row>
<up-row class="fill-content">
<up-col span="12" class="x-f"
><view class="p10"><text class="required-star">*</text>维护保养情况:</view>
<up-input class="bg-w" v-model="item.checkRemark" placeholder="请输入维护保养情况"></up-input
></up-col>
</up-row>
</view>
</view>
</view>
<view>
<view class="p10">附件照片</view>
<n-upload v-model="detailInfo.attachment" />
<view class="p10">维护保养人</view>
<up-input v-model="detailInfo.checkUserName"></up-input>
<view v-if="detailInfo.submitFlag == '1'">
<view class="p10">维护保养日期</view>
<uni-datetime-picker type="date" v-model="detailInfo.checkDate" />
</view>
</view>
<view class="mt40 x-bc" v-if="detailInfo.submitFlag == '0'">
<up-button
style="width: 40%"
loadingText="保存中..."
type="warning"
text="暂存"
@click="handleSubmit('0')"
></up-button>
<up-button
style="width: 40%"
loadingText="提交中..."
type="primary"
text="提交"
@click="handleSubmit('1')"
></up-button>
</view>
</view>
</view>
<up-modal
:show="modalShow"
title="提示"
:content="modalText"
ref="uModal"
:asyncClose="true"
showCancelButton
@confirm="confirm"
@cancel="modalShow = false"
></up-modal>
<up-loading-page :loading="pageLoading"></up-loading-page>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, computed, watch, toRefs } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import dailyCheckApi from '@/nx/api/dailyCheck'
import nx from '@/nx'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
import { useGridCol } from '@/nx/hooks/useGridCol'
const { gridCol } = useGridCol([700], [6, 4])
const { lockOrientation } = useScreenOrientation()
const pageLoading = ref(false)
const detailSchema = [
{ label: '设备名称', value: 'deviceName' },
{ label: '设备型号', value: 'modelNo' },
{ label: '设备编码', value: 'deviceCode' },
{ label: '使用班组', value: 'deptName' }
]
let detailInfo = ref({})
let checkList = ref([])
const { scanQRInfo } = toRefs(nx.$store('biz'))
watch(scanQRInfo, newVal => {
if (newVal && nx.$router.getCurrentPage().route == 'pages/lims/deviceBusMaintain/index') {
try {
const codeObj = JSON.parse(newVal)
if (!pageLoading.value) {
getDetailInfo(codeObj.id)
}
scanQRInfo.value = ''
} catch (error) {
scanQRInfo.value = ''
uni.showToast({
title: '请扫描设备码',
icon: 'none'
})
}
}
})
onShow(() => {
scanQRInfo.value = ''
})
const modalText = computed(() => {
return `确定${modalType.value == '0' ? '暂存' : '提交'}吗?${modalType.value == '0' ? '' : '提交后不能修改'} `
})
async function getDetailInfo(id) {
pageLoading.value = true
const res = await dailyCheckApi
.getCheckRecord({
deviceId: id,
dataType: 'maintain',
submitFlag: '0',
cancelFlag: '0'
})
.finally(() => {
pageLoading.value = false
})
if (!res.checkUserName) {
res.checkUserName = nx.$store('user').userInfo.realname
res.checkUserId = nx.$store('user').userInfo.id
}
if (!res.checkDate) {
res.checkDate = nx.$dayjs().format('YYYY-MM-DD 00:00:00')
}
detailInfo.value = res
modalType.value = res.submitFlag
lockOrientation('landscape')
}
const modalShow = ref(false)
const modalType = ref('')
function handleSubmit(type) {
if (!detailInfo.value.checkUserName) {
return uni.showToast({
title: '请输入维护保养人',
icon: 'none'
})
}
if (!detailInfo.value.checkDate) {
return uni.showToast({
title: '请选择维护保养日期',
icon: 'none'
})
}
if (type === '1') {
// 新增维护保养项验证
const items = detailInfo.value.maintainItemList || []
for (let i = 0; i < items.length; i++) {
const item = items[i]
const itemNumber = `${i + 1}`
if (!item.checkRemark?.trim()) {
return uni.showToast({ title: `${itemNumber}维护保养情况未填写`, icon: 'none' })
}
}
}
modalType.value = type
modalShow.value = true
console.log(detailInfo.value)
}
const submitLoading = ref(false)
async function confirm() {
if (submitLoading.value) return
submitLoading.value = true
await dailyCheckApi.submit({ ...detailInfo.value, submitFlag: modalType.value }).finally(() => {
submitLoading.value = false
modalShow.value = false
reset()
})
}
function reset() {
detailInfo.value = {}
}
function handleCheckRecord() {
let deviceInfo = {
id: detailInfo.value.deviceId,
deviceName: detailInfo.value.deviceName
}
nx.$store('biz').deviceInfo = deviceInfo
nx.$router.go('/pages/lims/deviceBusMaintain/list')
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
.container {
.required-star {
color: red;
margin-right: 4px;
}
.content {
background-color: #fff;
height: 100%;
padding: 16px;
padding-top: 10px;
font-size: 18px;
.title {
font-size: 22px;
font-weight: bold;
}
.check-header {
.u-sticky {
top: 70px !important;
}
}
.fill-content {
border-radius: 3px;
box-shadow: 2px 2px 8px 2px rgba(0, 0, 0, 0.2);
background-color: #fdf6ec;
padding: 10px;
box-sizing: border-box;
}
}
}
</style>

View File

@@ -0,0 +1,100 @@
<template>
<view>
<up-sticky v-if="!isComponent">
<navbar-back title="维护保养记录"> </navbar-back>
</up-sticky>
<uni-card spacing="0">
<uni-section v-if="!isComponent" titleFontSize="20px" type="line" :title="deviceText"> </uni-section>
<view :style="{ height: isComponent ? '70vh' : '72vh' }">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<maintain-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import MaintainDetailPopup from './detail.vue'
import dailyCheckApi from '@/nx/api/dailyCheck'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
let props = defineProps({
isComponent: {
type: Boolean,
default: false
}
})
const column = reactive([
{
label: '维护保养人',
name: 'checkUserName',
width: 160
},
{
label: '维护保养日期',
name: 'checkDate',
width: 300
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
dataType: 'maintain',
deviceId: deviceId.value
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: dailyCheckApi.list
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,104 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="20px" type="line" title="设备使用记录"> </uni-section>
<scroll-view scroll-y="true" class="content">
<up-row>
<up-col span="6"
>开始使用人
<text class="value">{{ detailInfo.userName }}</text>
</up-col>
<up-col span="6"
>开始时间
<text class="value">{{ detailInfo.useTimeStart }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="6"
>结束使用人
<text class="value">{{ detailInfo.userNameEnd }}</text>
</up-col>
<up-col span="6"
>结束时间
<text class="value">{{ detailInfo.useTimeEnd }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="4"
>使用前状态
<text class="value">{{ detailInfo.stateBefore }}</text>
</up-col>
<up-col span="4"
>使用后状态
<text class="value">{{ detailInfo.stateAfter }}</text>
</up-col>
<up-col span="4"
>温度()
<text class="value">{{ detailInfo.temperature }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="4"
>湿度(%RH)
<text class="value">{{ detailInfo.humidity }}</text>
</up-col>
<up-col span="6"
>样品类别/个数/任务
<text class="value">{{ detailInfo.useRemark }}</text>
</up-col>
</up-row>
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
function handleOpen() {
detailInfo.value = props.checkInfo
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
height: 80vh;
width: 80vw;
padding: 10px 20px;
.u-row {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.value {
color: #666;
font-size: 16px;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

View File

@@ -0,0 +1,330 @@
<template>
<view>
<up-sticky>
<navbar-back title="使用">
<up-button
v-if="detailInfo.id"
type="primary"
:plain="true"
icon="list"
size="small"
text="设备使用记录"
@click="handleUseRecord"
></up-button>
</navbar-back>
</up-sticky>
<view class="container">
<n-scanTemp v-if="!detailInfo.id" title="请扫描设备条码进行设备使用" @deviceId="id => handleTestAction(id)" />
<view v-else class="content">
<view>
<uni-section titleFontSize="20px" type="line" title="设备信息"> </uni-section>
<up-row class="flex-wrap p10" style="background-color: #f5f7fa">
<up-col class="mb10" :span="gridCol" v-for="(item, index) in detailSchema">
<view style="color: #666"
><span style="color: #333">{{ item.label }}</span>{{ detailInfo[item.value] }}</view
>
</up-col>
</up-row>
</view>
<view>
<up-row justify="space-around">
<up-col span="3.5">
<view class="p5">使用前状态</view>
<uni-data-select :disabled="useIng" v-model="formData.stateBefore" :localdata="ditData"></uni-data-select>
</up-col>
<up-col span="3.5">
<view class="p5">使用中状态</view>
<uni-data-select :disabled="!useIng" v-model="formData.stateRun" :localdata="ditData"></uni-data-select>
</up-col>
<up-col span="3.5">
<view class="p5">使用后状态</view>
<uni-data-select :disabled="!useIng" v-model="formData.stateAfter" :localdata="ditData"></uni-data-select>
</up-col>
</up-row>
<up-row justify="space-around">
<up-col span="3.5">
<view class="p5">温度</view>
<up-input v-model="formData.temperature"></up-input>
</up-col>
<up-col span="3.5">
<view class="p5">湿度%HR</view>
<up-input v-model="formData.humidity"></up-input>
</up-col>
<up-col span="3.5">
<view class="p5">样品类别/个数/任务</view>
<up-input v-model="formData.useRemark"></up-input>
</up-col>
</up-row>
<up-row justify="space-around">
<up-col span="11.5">
<view class="p5">{{ useIng ? '结束使用人' : '开始使用人' }}</view>
<up-input v-if="useIng" v-model="formData.userNameEnd"></up-input>
<up-input v-else v-model="formData.userName"></up-input>
</up-col>
</up-row>
<up-row justify="space-around">
<up-col span="11.5">
<view class="p5">备注</view>
<up-textarea v-model="formData.remark" placeholder="请输入内容" autoHeight></up-textarea>
</up-col>
</up-row>
</view>
<up-button
style="width: 90%"
class="mt40"
loadingText="提交中..."
type="primary"
:text="useIng ? '结束使用' : '开始使用'"
@click="handleValidate"
></up-button>
</view>
</view>
<up-modal
:show="modalShow"
title="提示"
content="确定提交吗?"
ref="uModal"
:asyncClose="true"
showCancelButton
@confirm="submitConfirm"
@cancel="modalShow = false"
></up-modal>
<up-loading-page :loading="pageLoading"></up-loading-page>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, watch, toRefs } from 'vue'
import { onShow, onLoad } from '@dcloudio/uni-app'
import { getDeviceBusInfoById } from '@/nx/api/deviceInfo'
import { getUseRecordById, addUseRecord, editUseRecord } from './useRecord.api'
import dailyCheckApi from '@/nx/api/dailyCheck'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
import { useGridCol } from '@/nx/hooks/useGridCol'
import nx from '@/nx'
const { gridCol } = useGridCol([700], [6, 4])
const { lockOrientation } = useScreenOrientation()
const ditData = ref([
{ value: '正常', text: '正常' },
{ value: '异常', text: '异常' }
])
const detailSchema = [
{ label: '设备名称', value: 'deviceName' },
{ label: '设备型号', value: 'modelNo' },
{ label: '设备编码', value: 'deviceCode' },
{ label: '使用班组', value: 'deptName' }
]
const pageLoading = ref(false)
const userId = nx.$store('user').userInfo['id']
const userName = nx.$store('user').userInfo['realname']
let detailInfo = ref({})
const { scanQRInfo } = toRefs(nx.$store('biz'))
watch(scanQRInfo, newVal => {
if (newVal && nx.$router.getCurrentPage().route == 'pages/lims/deviceBusUseRecord/index') {
try {
const codeObj = JSON.parse(newVal)
if (!pageLoading.value) {
getLastDailyCheckOfToday(codeObj.id)
}
scanQRInfo.value = ''
} catch (error) {
scanQRInfo.value = ''
uni.showToast({
title: '请扫描设备码',
icon: 'none'
})
}
}
})
onShow(() => {
scanQRInfo.value = ''
})
// 检查该设备在使用前是否已经点检过
function getLastDailyCheckOfToday(id) {
pageLoading.value = true
try {
dailyCheckApi.getLastDailyCheckOfToday({ deviceId: id }).then(async res => {
if (!res || res.submitFlag == '0') {
setTimeout(() => {
uni.showToast({
title: '设备使用前请先进行设备点检',
icon: 'none'
})
}, 100)
pageLoading.value = false
nx.$router.go('/pages/deviceBusDailyCheck/index', { deviceId: id })
} else {
getDeviceInfo(id)
await getUseIngRecord(id)
pageLoading.value = false
}
})
} catch (error) {
pageLoading.value = false
}
}
function handleTestAction(id) {
getLastDailyCheckOfToday(id)
}
// 获取设备详情
async function getDeviceInfo(id) {
const res = await getDeviceBusInfoById(id).finally(() => {})
detailInfo.value = res
lockOrientation('landscape')
}
const useIng = ref(false)
// 获取使用记录判断是否在使用中
async function getUseIngRecord(id) {
const res = await getUseRecordById(id)
if (res) {
useIng.value = true
formData.value = res
formData.value.userIdEnd = userId
formData.value.userNameEnd = userName
// checkUseStatusIsMySelf(res)
} else {
useIng.value = false
}
}
// 定义一个变量,用于标记当前是否有 modal 正在显示
let isModalShowing = false
// 如果设备在使用中,检查设备使用记录是否是所登录用户的
function checkUseStatusIsMySelf(useInfo) {
if (isModalShowing) {
return
}
if (useInfo.userId != userId) {
isModalShowing = true
uni.showModal({
title: '提示',
content: '该设备正在使用中,是否结束使用',
success: function (res) {
if (res.confirm) {
submitConfirm()
isModalShowing = false
} else if (res.cancel) {
console.log('用户点击取消')
isModalShowing = false
}
}
})
}
}
let formData = ref({
userName,
userId,
stateBefore: '正常'
})
const modalShow = ref(false)
function handleValidate() {
if (!useIng.value && !formData.value.stateBefore) {
return uni.showToast({
title: '请选择使用前状态',
icon: 'none'
})
}
if (useIng.value) {
if (!formData.value.stateRun) {
return uni.showToast({
title: '请选择使用中状态',
icon: 'none'
})
}
if (!formData.value.stateAfter) {
return uni.showToast({
title: '请选择使用后状态',
icon: 'none'
})
}
}
if (!formData.value.userName) {
return uni.showToast({
title: '请输入使用人',
icon: 'none'
})
}
if (!formData.value.useRemark) {
return uni.showToast({
title: '请输入样品类别/个数/任务',
icon: 'none'
})
}
modalShow.value = true
}
const submitLoading = ref(false)
async function submitConfirm() {
if (submitLoading.value) return
submitLoading.value = true
let submitParams = {
...formData.value,
deviceId: detailInfo.value.id,
temperature: formData.value.temperature || '/',
humidity: formData.value.humidity || '/'
}
// 如果在使用中加入使用结束参数
let currentTime = nx.$dayjs().format('YYYY-MM-DD HH:mm:ss')
let submitApi = useIng.value ? editUseRecord : addUseRecord
if (useIng.value) {
submitParams.useTimeEnd = currentTime
} else {
submitParams.useTimeStart = currentTime
}
await submitApi(submitParams)
.then(() => {
submitLoading.value = false
modalShow.value = false
reset()
})
.catch(() => {
modalShow.value = false
submitLoading.value = false
})
}
function reset() {
formData.value = {
userName: nx.$store('user').userInfo['realname']
}
detailInfo.value = {}
}
function handleUseRecord() {
nx.$store('biz').deviceInfo = detailInfo.value
nx.$router.go('/pages/lims/deviceBusUseRecord/list')
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
.container {
.content {
background-color: #fff;
height: 100%;
padding: 16px;
padding-top: 10px;
font-size: 16px;
.title {
font-size: 22px;
font-weight: bold;
}
.check-header {
.u-sticky {
top: 70px !important;
}
}
.fill-content {
border-radius: 3px;
box-shadow: 2px 2px 8px 2px rgba(0, 0, 0, 0.2);
background-color: #fdf6ec;
padding: 10px;
}
}
}
</style>

View File

@@ -0,0 +1,164 @@
<template>
<view>
<up-sticky v-if="!isComponent">
<navbar-back title="设备使用记录查看"> </navbar-back>
</up-sticky>
<uni-card spacing="0">
<uni-section v-if="!isComponent" titleFontSize="20px" type="line" :title="deviceText"> </uni-section>
<view class="p10" style="width: 50%">
<!-- <uni-datetime-picker v-model="startEndTime" type="daterange" @change="datetimeChange" /> -->
<up-search
v-model="keyword"
shape="square"
placeholder="请输入使用人"
actionText="重置"
:clearabled="false"
:showAction="true"
@change="handleInputSearch"
@custom="reset"
></up-search>
</view>
<view :style="{ height: isComponent ? '60vh' : '62vh' }">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<use-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import UseDetailPopup from './detail.vue'
import { getList } from './useRecord.api'
import { throttle } from '@/uview-plus'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
let props = defineProps({
isComponent: {
type: Boolean,
default: false
}
})
let startEndTime = ref([])
const column = reactive([
{
label: '开始使用人',
name: 'userName',
width: 100
},
{
label: '开始时间',
name: 'useTimeStart',
width: 170
},
{
label: '结束使用人',
name: 'userNameEnd',
width: 100
},
{
label: '结束时间',
name: 'useTimeEnd',
width: 170
},
{
label: '使用前状态',
name: 'stateBefore'
},
{
label: '使用后状态',
name: 'stateAfter'
},
{
label: '温度(℃)',
name: 'temperature'
},
{
label: '湿度(%RH)',
name: 'humidity'
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
let zbTableRef = ref(null)
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceId: deviceId.value,
userName: keyword.value
}))
const { listData, loadingData, getInitData, scrollToLower, loadStatus } = useListData({
searchParams,
api: getList
})
function pullUpLoadingAction(done) {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
let keyword = ref('')
function handleInputSearch() {
if (!keyword.value) return
throttle(getInitData, 500)
}
function reset() {
keyword.value = ''
getInitData()
}
function datetimeChange(e) {
startEndTime.value = [nx.$dayjs(e[0]).format('YYYY-MM-DD 00:00:00'), nx.$dayjs(e[1]).format('YYYY-MM-DD 23:59:59')]
getInitData()
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
background-color: #fff !important;
}
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
:deep(.u-search__action--active) {
padding: 5px;
border-radius: 3px;
background: #0055a2;
color: #fff;
}
</style>

View File

@@ -0,0 +1,36 @@
import request from '@/nx/request'
export function addUseRecord(data) {
return request({
url: '/lims/bus/device/use-record/create',
method: 'POST',
data,
custom: {
showSuccess: true
}
})
}
export function editUseRecord(data) {
return request({
url: '/lims/bus/device/use-record/edit',
method: 'POST',
data,
custom: {
showSuccess: true
}
})
}
export function getList(params) {
return request({
url: '/lims/bus/device/use-record/list',
method: 'GET',
params
})
}
export function getUseRecordById(id) {
return request({
url: '/lims/bus/device/use-record/queryLastUsingData',
method: 'GET',
params: { deviceId: id }
})
}

View File

@@ -0,0 +1,16 @@
import request from '@/nx/request'
export function getDeviceDocumentList(params) {
return request({
url: '/lims/document/device-relation/list',
method: 'GET',
params
})
}
export function getDocumentInfoById(id) {
return request({
url: '/lims/document/info/queryById',
method: 'GET',
params: { id }
})
}

View File

@@ -0,0 +1,117 @@
<template>
<view>
<uni-card spacing="0">
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<up-modal :show="fileShow" :title="fileInfo.documentName" confirmText="关闭" @confirm="fileShow = false">
<scroll-view scroll-y="true" style="max-height: 60vh">
<uni-card>
<up-parse :content="fileInfo.documentContent"></up-parse>
</uni-card>
</scroll-view>
</up-modal>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import { getDeviceDocumentList, getDocumentInfoById } from './document.api'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
const column = reactive([
{
label: '文档名称',
name: 'documentName',
width: 260
},
{
label: '文档描述',
name: 'documentAbstract',
width: 420
},
{
label: '文档类型',
name: 'documentType',
width: 120
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '查看', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceBusInfoId: deviceId.value,
searchRelationType: 'device'
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: getDeviceDocumentList,
processData: data => {
return data.map(item => {
return {
...item,
documentType: item.documentType === 'file' ? '文件' : '文本'
}
})
}
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const fileShow = ref(false)
const fileInfo = ref({})
async function handleDetail(row) {
console.log(row)
fileInfo.value = row
if (row.documentType === '文本') {
const { documentContent } = await getDocumentInfoById(row.documentBusInfoId)
fileInfo.value.documentContent = documentContent
fileShow.value = true
} else {
nx.$router.go('/pages/lims/documentList/preview', { documentUrl: row.documentUrl })
}
}
</script>
<style lang="scss" scoped>
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,32 @@
<template>
<view class="container">
<up-icon size="20" class="close-icon" @click="handleClose" name="close-circle"></up-icon>
<web-view :src="previewUrl"></web-view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import CryptoJS from 'crypto-js'
import { getImgBaseUrl } from '@/defaultBaseUrl'
import { onLoad } from '@dcloudio/uni-app'
let previewUrl = ref('')
onLoad(option => {
let url = encodeURIComponent(
CryptoJS.enc.Utf8.parse(getImgBaseUrl() + option.documentUrl).toString(CryptoJS.enc.Base64)
)
previewUrl.value = getImgBaseUrl() + '/preview/onlinePreview?url=' + url
})
</script>
<style lang="scss" scoped>
.container {
.close-icon {
position: absolute;
top: 20rpx;
right: 20rpx;
z-index: 999999;
}
}
</style>

View File

@@ -0,0 +1,93 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="20px" type="line" title="设备借用单"> </uni-section>
<scroll-view scroll-y="true" class="content">
<up-row class="flex-wrap">
<up-col :span="gridCol"
>归还人
<text class="value">{{ detailInfo.givebackOper }}</text>
</up-col>
<up-col :span="gridCol"
>归还日期
<text class="value">{{ detailInfo.givebackDate }}</text>
</up-col>
<up-col :span="gridCol"
>接收人
<text class="value">{{ detailInfo.givebackReceiveOper }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>备注
<text class="value">{{ detailInfo.remark }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { useGridCol } from '@/nx/hooks/useGridCol'
const { gridCol } = useGridCol([700], [6, 4])
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
let commentWf = ref([])
function handleOpen() {
detailInfo.value = props.checkInfo
if (props.checkInfo.commentJson) {
try {
commentWf.value = JSON.parse(props.checkInfo.commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
height: 80vh;
width: 75vw;
padding: 20px;
.u-row {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.value {
color: #666;
font-size: 16px;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

View File

@@ -0,0 +1,99 @@
<template>
<view>
<uni-card spacing="0">
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<giveback-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GivebackDetailPopup from './detail.vue'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import { givebackList } from '@/nx/api/deviceInfo'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
const column = reactive([
{
label: '归还人',
name: 'givebackOper',
width: 140
},
{
label: '归还日期',
name: 'givebackDate',
width: 140
},
{
label: '接收人',
name: 'givebackReceiveOper',
width: 140
},
{
label: '备注',
name: 'remark',
width: 140
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceBusInfoId: deviceId.value,
givebackStatus: '已归还'
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: givebackList
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,44 @@
<template>
<view>
<navbar-back title="设备管理系统" :autoBack="false" leftIcon="" :leftText="`您好!${userInfo.realname}`">
<u-icon @click="popupShow = true" size="28" color="#FFF" name="account-fill" />
</navbar-back>
<up-grid :border="false" :col="gridCol">
<up-grid-item
class="mb20 mt20"
v-for="(item, listIndex) in list"
:key="listIndex"
@click="nx.$router.go(item.url)"
>
<image style="width: 80px; height: 80px" :src="`/static/images/menus/${item.icon}.png`"></image>
<text class="grid-text">{{ item.name }}</text>
</up-grid-item>
</up-grid>
<mePopup v-model:show="popupShow" />
</view>
</template>
<script setup>
import { reactive, ref, computed } from 'vue'
import nx from '@/nx'
import { useGridCol } from '@/nx/hooks/useGridCol'
import mePopup from '@/pages/index/me-popup.vue'
const { gridCol } = useGridCol([400, 600], [2, 3, 4])
let popupShow = ref(false)
let list = reactive([
{ url: '/pages/lims/deviceBusDailyCheck/index', name: '点检', icon: 'dailyCheck' },
{ url: '/pages/lims/deviceBusMaintain/index', name: '维护保养', icon: 'maintain' },
{ url: '/pages/lims/deviceBusUseRecord/index', name: '使用', icon: 'useRecord' },
{ url: '/pages/lims/deviceBusInfo/index', name: '设备查询', icon: 'baseInfo' },
{ url: '/pages/lims/knowledge/index', name: '知识库查询', icon: 'knowledge' }
])
const roleMenus = computed(() => nx.$store('user').roleMenus)
const userInfo = computed(() => nx.$store('user').userInfo)
</script>
<style lang="scss" scoped>
.grid-text {
font-size: 24px;
}
</style>

View File

@@ -0,0 +1,148 @@
<template>
<view>
<up-sticky>
<navbar-back title="知识库查询"></navbar-back>
</up-sticky>
<uni-card spacing="0">
<view class="p10" style="width: 50%">
<!-- <uni-datetime-picker v-model="startEndTime" type="daterange" @change="datetimeChange" /> -->
<up-search
v-model="keyword"
shape="square"
placeholder="请输入文档名称"
actionText="重置"
:clearabled="false"
:showAction="true"
@change="handleInputSearch"
@custom="reset"
></up-search>
</view>
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<up-modal :show="fileShow" :title="fileInfo.documentName" confirmText="关闭" @confirm="fileShow = false">
<scroll-view scroll-y="true" style="max-height: 60vh">
<uni-card>
<up-parse :content="fileInfo.documentContent"></up-parse>
</uni-card>
</scroll-view>
</up-modal>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import { getDeviceDocumentList } from './knowledge.api'
import { getDocumentInfoById } from '../documentList/document.api'
import { useListData } from '@/nx/hooks/usePageListData'
import { throttle } from '@/uview-plus'
import nx from '@/nx'
const column = reactive([
{
label: '文档名称',
name: 'documentName',
width: 260
},
{
label: '文档描述',
name: 'documentAbstract',
width: 420
},
{
label: '文档类型',
name: 'documentType',
width: 120
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '查看', func: 'detail' }]
}
])
onMounted(() => {
getInitData()
})
const searchParams = computed(() => ({
documentName: keyword.value
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: getDeviceDocumentList,
processData: data => {
return data.map(item => {
return {
...item,
documentType: item.documentType === 'file' ? '文件' : '文本'
}
})
}
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
let keyword = ref('')
function handleInputSearch() {
if (!keyword.value) return
throttle(getInitData, 500)
}
function reset() {
keyword.value = ''
getInitData()
}
const fileShow = ref(false)
const fileInfo = ref({})
async function handleDetail(row) {
console.log(row)
fileInfo.value = row
if (row.documentType === '文本') {
const { documentContent } = await getDocumentInfoById(row.documentBusInfoId)
fileInfo.value.documentContent = documentContent
fileShow.value = true
} else {
nx.$router.go('/pages/lims/documentList/preview', { documentUrl: row.documentUrl })
}
}
</script>
<style lang="scss" scoped>
.u-sticky {
top: 0 !important;
}
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
:deep(.u-search__action--active) {
padding: 5px;
border-radius: 3px;
background: #0055a2;
color: #fff;
}
</style>

View File

@@ -0,0 +1,16 @@
import request from '@/nx/request'
export function getDeviceDocumentList(params) {
return request({
url: 'lims/knowledge/document-relation/list',
method: 'GET',
params
})
}
export function getDocumentInfoById(id) {
return request({
url: '/lims/knowledge/base/queryById',
method: 'GET',
params: { id }
})
}

View File

@@ -0,0 +1,118 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="20px" type="line" title="设备期间核查信息"> </uni-section>
<scroll-view scroll-y="true" class="content">
<up-row class="flex-wrap">
<up-col :span="gridCol"
>核查对象
<text class="value">{{ detailInfo.deviceName }}</text>
</up-col>
<up-col span="4"
>别名
<text class="value">{{ detailInfo.alias }}</text>
</up-col>
<up-col span="4"
>核查日期
<text class="value">{{ detailInfo.checkDate }}</text>
</up-col>
<up-col :span="gridCol"
>核查方法
<text class="value">{{ detailInfo.checkAccording }}</text>
</up-col>
</up-row>
<up-row class="flex-wrap">
<up-col span="12"
>核查方法描述
<text class="value">{{ detailInfo.checkAccordingRemark }}</text>
</up-col>
<up-col span="12"
>核查记录
<up-parse style="background: #f3f4f6" :content="processedContent"></up-parse>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>备注
<text class="value">{{ detailInfo.checkRemark }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { getImgBaseUrl } from '@/defaultBaseUrl'
import { useGridCol } from '@/nx/hooks/useGridCol'
const { gridCol } = useGridCol([700], [6, 4])
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
// / 处理富文本内容
const processedContent = computed(() => {
if (!detailInfo.value.checkContent) {
return ''
}
return detailInfo.value.checkContent.replace(
/<img([^>]+?)src="((?!http)[^"]*?)(file\/[^"]*)"/gi,
(match, attributes, prefix, filePath) => {
return `<img${attributes}src="${getImgBaseUrl()}/${filePath}"`
}
)
})
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
let commentWf = ref([])
function handleOpen() {
detailInfo.value = props.checkInfo
if (props.checkInfo.commentJson) {
try {
commentWf.value = JSON.parse(props.checkInfo.commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
height: 85vh;
width: 80vw;
padding: 10px;
.u-row {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.value {
color: #666;
font-size: 16px;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

View File

@@ -0,0 +1,101 @@
<template>
<view>
<uni-card spacing="0">
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<period-check-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import PeriodCheckDetailPopup from './detail.vue'
import { list } from './period.api'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
const column = reactive([
{
label: '核查日期',
name: 'checkDate',
width: 120
},
{
label: '核查人',
name: 'checkPersonName',
width: 120
},
{
label: '核查方法',
name: 'checkAccording',
width: 120
},
{
label: '期间核查频次',
name: 'frequencyRemark',
width: 200
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceId: deviceId.value,
effectiveFlag: '1',
wfStatus: 'finished',
cancelFlag: '0'
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: list
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,9 @@
import request from '@/nx/request'
export function list(params) {
return request({
url: '/lims/bus/deviceBusPeriodCheck/queryPageList',
method: 'GET',
params
})
}

View File

@@ -0,0 +1,130 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="20px" type="line" title="设备维修单"> </uni-section>
<scroll-view scroll-y="true" class="content">
<up-row class="flex-wrap">
<up-col :span="gridCol"
>设备名称
<text class="value">{{ detailInfo.deviceName }}</text>
</up-col>
<up-col span="4"
>别名
<text class="value">{{ detailInfo.alias }}</text>
</up-col>
<up-col span="4"
>设备编号
<text class="value">{{ detailInfo.deviceCode }}</text>
</up-col>
<up-col :span="gridCol"
>生产厂家
<text class="value">{{ detailInfo.manufacturer }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="6"
>使用部门
<text class="value">{{ detailInfo.deviceDeptName }}</text>
</up-col>
<up-col span="6"
>设备负责人
<text class="value">{{ detailInfo.deviceManagerUserName }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>故障分析及处理方案
<text class="value">{{ detailInfo.repairAnalysis }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>故障判定
<text class="value">{{ detailInfo.repairDetermine }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>维修事项及配件更换
<text class="value">{{ detailInfo.repairContent }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>维修后仪器设备状态
<text class="value">{{ detailInfo.repairResult }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>备注
<text class="value">{{ detailInfo.remark }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { useGridCol } from '@/nx/hooks/useGridCol'
const { gridCol } = useGridCol([700], [6, 4])
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
let commentWf = ref({})
function handleOpen() {
detailInfo.value = props.checkInfo
if (props.checkInfo.commentJson) {
try {
commentWf.value = JSON.parse(props.checkInfo.commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
height: 80vh;
width: 80vw;
padding: 20px;
.u-row {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.value {
color: #666;
font-size: 16px;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

104
pages/lims/repair/list.vue Normal file
View File

@@ -0,0 +1,104 @@
<template>
<view>
<uni-card spacing="0">
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import DetailPopup from './detail.vue'
import { repairList } from '@/nx/api/deviceInfo'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
const column = reactive([
{
label: '申请人',
name: 'applyUserName',
width: 140
},
{
label: '报修时间',
name: 'applyTime',
width: 120
},
{
label: '设备责任人',
name: 'deviceManagerUserName',
width: 120
},
{
label: '设备使用部门',
name: 'deviceDeptName',
width: 140
},
{
label: '故障判定',
name: 'repairDetermine',
width: 240
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceId: deviceId.value,
wfStatus: 'finished'
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: repairList
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>

View File

@@ -0,0 +1,72 @@
<template>
<uni-card style="height: 100%" spacing="0">
<scroll-view scroll-y="true" class="content">
<up-row>
<up-col span="6"
>报废类型
<text class="value">{{ scrapInfo.scrapType }}</text>
</up-col>
<up-col span="6"
>报废日期
<text class="value">{{ scrapInfo.scrapDate }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>报废原因
<text class="value">{{ scrapInfo.scrapReason }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
<view class="p20"></view>
</scroll-view>
</uni-card>
</template>
<script setup>
import { ref, reactive, onMounted, onBeforeMount } from 'vue'
import { scrapDetailList } from '@/nx/api/deviceInfo'
import nx from '@/nx'
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
getDetailInfo(id)
})
let scrapInfo = ref({})
let commentWf = ref([])
async function getDetailInfo(id) {
const records = await scrapDetailList({
deviceBusInfoId: id
})
if (records.length > 0) {
scrapInfo.value = records[0]
if (records[0].commentJson) {
try {
commentWf.value = JSON.parse(records[0].commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.content {
height: 80vh;
font-size: 18px;
color: #000;
padding: 10px;
.u-row {
border-bottom: 1px solid #eee;
}
.value {
color: #666;
font-size: 16px;
}
}
</style>

View File

@@ -0,0 +1,89 @@
<template>
<up-popup :show="visible" mode="right" closeable @close="handleClose" @open="handleOpen">
<uni-section titleFontSize="20px" type="line" title="设备借用单"> </uni-section>
<scroll-view scroll-y="true" class="content">
<up-row>
<up-col span="12"
>停用日期
<text class="value">{{ detailInfo.stopDate }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>借用原因
<text class="value">{{ detailInfo.stopReason }}</text>
</up-col>
</up-row>
<up-row>
<up-col span="12"
>备注
<text class="value">{{ detailInfo.remark }}</text>
</up-col>
</up-row>
<wf-comment :commentWf="commentWf" />
</scroll-view>
</up-popup>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
const props = defineProps({
show: {
type: Boolean,
default: false
},
checkInfo: {
type: Object
}
})
const visible = ref(props.show)
// 监听外部传入的show属性变化
watch(
() => props.show,
newVal => {
visible.value = newVal
}
)
let detailInfo = ref({})
const emit = defineEmits(['close', 'open'])
function handleClose() {
emit('close')
}
let commentWf = ref([])
function handleOpen() {
detailInfo.value = props.checkInfo
if (props.checkInfo.commentJson) {
try {
commentWf.value = JSON.parse(props.checkInfo.commentJson)
} catch (error) {
uni.showToast({
title: '解析数据错误',
icon: 'none'
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
font-size: 18px;
height: 80vh;
width: 75vw;
padding: 20px;
.u-row {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.value {
color: #666;
font-size: 16px;
}
}
:deep(.uicon-close) {
font-size: 22px !important;
}
</style>

94
pages/lims/stop/list.vue Normal file
View File

@@ -0,0 +1,94 @@
<template>
<view>
<uni-card spacing="0">
<view style="height: 72vh">
<zb-table
ref="zbTableRef"
isShowLoadMore
stripe
:fit="false"
:columns="column"
:cellStyle="setCellStyle"
:cellHeaderStyle="setCellHeaderStyle"
:data="listData"
@detail="handleDetail"
@pullUpLoading="pullUpLoadingAction"
></zb-table>
</view>
</uni-card>
<stop-detail-popup :show="detailShow" :checkInfo="checkInfo" @close="detailShow = false" />
</view>
</template>
<script setup>
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { setCellHeaderStyle, setCellStyle } from '@/nx/config/zbTable'
import { stopList } from '@/nx/api/deviceInfo'
import StopDetailPopup from './detail.vue'
import { useListData } from '@/nx/hooks/usePageListData'
import nx from '@/nx'
const column = reactive([
{
label: '停用日期',
name: 'stopDate',
width: 140
},
{
label: '停用原因',
name: 'stopReason',
width: 280
},
{
label: '备注',
name: 'remark',
width: 140
},
{
name: 'operation',
type: 'operation',
label: '操作',
renders: [{ name: '详情', func: 'detail' }]
}
])
const deviceId = ref('')
const deviceText = ref('')
onMounted(() => {
const { id, deviceName } = nx.$store('biz').deviceInfo
deviceId.value = id
deviceText.value = deviceName
getInitData()
})
const searchParams = computed(() => ({
deviceBusInfoId: deviceId.value,
stopListStatus: '已停用'
}))
const { listData, loadingData, scrollToLower, loadStatus, getInitData } = useListData({
searchParams,
api: stopList
})
const zbTableRef = ref()
function pullUpLoadingAction() {
if (loadingData.value) return
if (loadStatus.value === 'nomore') {
zbTableRef.value.pullUpCompleteLoading('ok')
} else {
scrollToLower()
}
}
const detailShow = ref(false)
const checkInfo = ref({})
function handleDetail(row) {
checkInfo.value = row
detailShow.value = true
}
</script>
<style lang="scss" scoped>
:deep(.zb-table uni-button[type='primary']) {
background-color: $uni-color-primary !important;
}
</style>