first commit
This commit is contained in:
244
src/views/iot/check/Execute.vue
Normal file
244
src/views/iot/check/Execute.vue
Normal file
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<el-dialog v-model="visibleInner" :title="dialogTitle" width="820px" :close-on-click-modal="false">
|
||||
<div class="sub mb-10px">分类:{{ categoryName || '-' }}</div>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header flex items-center justify-between">
|
||||
<span>检查项目</span>
|
||||
<div class="flex items-center gap-8px">
|
||||
<el-button size="small" type="primary" plain @click="addItem">新增项目</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="localItems.length === 0" class="text-gray-500">暂无项目,点击"新增项目"添加</div>
|
||||
<div v-for="(item, idx) in localItems" :key="item.code" class="item-row">
|
||||
<div class="item-left">
|
||||
<div class="item-name flex items-center">
|
||||
<span class="mr-8px">{{ idx + 1 }}.</span>
|
||||
<el-input v-model="item.name" placeholder="检查项名称" size="small" style="width: 240px; margin-right: 12px;" />
|
||||
<el-input v-model="item.desc" placeholder="检查项说明(可选)" size="small" style="width: 480px;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-right">
|
||||
<el-radio-group v-model="item.result" @change="onResultChange(item)">
|
||||
<el-radio label="ok">正常</el-radio>
|
||||
<el-radio label="bad">异常</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="inline-actions ml-12px">
|
||||
<el-button size="small" text @click="moveUp(idx)" :disabled="idx === 0">上移</el-button>
|
||||
<el-button size="small" text @click="moveDown(idx)" :disabled="idx === localItems.length - 1">下移</el-button>
|
||||
<el-button size="small" text type="danger" @click="removeItem(idx)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item.result === 'bad'" class="issue-area">
|
||||
<el-input v-model="item.issueDesc" type="textarea" :rows="2" placeholder="请描述异常" />
|
||||
<el-upload
|
||||
class="mt-8px"
|
||||
action=""
|
||||
:http-request="handleUpload"
|
||||
list-type="picture-card"
|
||||
:file-list="item.photos"
|
||||
:on-remove="(file, list) => onRemove(file, list, item)"
|
||||
:on-preview="(file) => onPreview(file)"
|
||||
:limit="10"
|
||||
multiple
|
||||
accept="image/*">
|
||||
<el-icon>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="close">取消</el-button>
|
||||
<el-button type="primary" @click="save">保存</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 图片预览对话框 -->
|
||||
<el-dialog v-model="previewVisible" title="图片预览" width="80%" center>
|
||||
<img :src="previewImageUrl" style="width: 100%; max-height: 70vh; object-fit: contain;" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { CheckLogApi } from '@/api/iot/check/log'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: boolean
|
||||
categoryName?: string
|
||||
items?: Array<{ name: string; desc?: string }>
|
||||
title?: string
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue', 'save'])
|
||||
const visibleInner = computed({
|
||||
get: () => !!props.modelValue,
|
||||
set: (v: boolean) => emit('update:modelValue', v)
|
||||
})
|
||||
const dialogTitle = computed(() => props.title || '新增模板')
|
||||
|
||||
interface ExecItem {
|
||||
code: string
|
||||
name: string
|
||||
desc?: string
|
||||
result?: 'ok' | 'bad'
|
||||
issueDesc?: string
|
||||
photos: any[]
|
||||
}
|
||||
|
||||
const localItems = ref<ExecItem[]>([])
|
||||
|
||||
// 图片预览相关
|
||||
const previewVisible = ref(false)
|
||||
const previewImageUrl = ref('')
|
||||
|
||||
// 初始化本地数据
|
||||
const initLocalItems = () => {
|
||||
const defs = (props.items || []).length ? props.items! : []
|
||||
localItems.value = defs.map((def, idx) => ({
|
||||
code: `CHK-${String(idx + 1).padStart(3, '0')}`,
|
||||
name: def.name,
|
||||
desc: def.desc,
|
||||
result: 'ok',
|
||||
issueDesc: '',
|
||||
photos: []
|
||||
}))
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initLocalItems()
|
||||
})
|
||||
|
||||
// 监听props.items变化,用于编辑时回显数据
|
||||
watch(() => props.items, () => {
|
||||
initLocalItems()
|
||||
}, { deep: true })
|
||||
|
||||
function addItem() {
|
||||
const nextIndex = localItems.value.length + 1
|
||||
localItems.value.push({
|
||||
code: `CHK-${String(nextIndex).padStart(3, '0')}`,
|
||||
name: '',
|
||||
desc: '',
|
||||
result: 'ok',
|
||||
issueDesc: '',
|
||||
photos: []
|
||||
})
|
||||
}
|
||||
|
||||
function removeItem(idx: number) {
|
||||
localItems.value.splice(idx, 1)
|
||||
// 重排 code
|
||||
localItems.value.forEach((it, i) => (it.code = `CHK-${String(i + 1).padStart(3, '0')}`))
|
||||
}
|
||||
|
||||
function moveUp(i: number) {
|
||||
if (i <= 0) return
|
||||
const t = localItems.value[i - 1]
|
||||
localItems.value[i - 1] = localItems.value[i]
|
||||
localItems.value[i] = t
|
||||
}
|
||||
function moveDown(i: number) {
|
||||
if (i >= localItems.value.length - 1) return
|
||||
const t = localItems.value[i + 1]
|
||||
localItems.value[i + 1] = localItems.value[i]
|
||||
localItems.value[i] = t
|
||||
}
|
||||
|
||||
function onResultChange(item: ExecItem) {
|
||||
if (item.result !== 'bad') {
|
||||
item.issueDesc = ''
|
||||
item.photos = []
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUpload(options: any) {
|
||||
const { file, onSuccess, onError } = options
|
||||
try {
|
||||
const res = await CheckLogApi.uploadImage(file as File)
|
||||
onSuccess({ url: res.url, name: res.name })
|
||||
} catch (e) {
|
||||
onError(e)
|
||||
}
|
||||
}
|
||||
|
||||
function onRemove(_: any, list: any[], item: ExecItem) {
|
||||
item.photos = list
|
||||
}
|
||||
|
||||
// 图片预览
|
||||
function onPreview(file: any) {
|
||||
previewImageUrl.value = file.url || file.response?.url
|
||||
previewVisible.value = true
|
||||
}
|
||||
|
||||
function save() {
|
||||
const payload = localItems.value.map(it => ({ name: (it.name || '').trim(), desc: (it.desc || '').trim() }))
|
||||
if (!payload.length) {
|
||||
ElMessage.warning('请至少新增一个检查项')
|
||||
return
|
||||
}
|
||||
emit('save', payload)
|
||||
visibleInner.value = false
|
||||
}
|
||||
function close() {
|
||||
visibleInner.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sub {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.item-left {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.issue-area {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.hint {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mt-8px {
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user