Browse Source

调试隐患审核页面

master
DU 4 weeks ago
parent
commit
afd6dbff0b
  1. 18
      src/api/hazard/audit.js
  2. 2
      src/api/hazard/ledger.js
  3. 7
      src/components/SelectTree/index.vue
  4. 83
      src/views/hazard/audit/components/AuditActionForm.vue
  5. 24
      src/views/hazard/audit/components/HazardReportPanel.vue
  6. 63
      src/views/hazard/audit/index.vue
  7. 2
      src/views/hazard/ledger/index.vue

18
src/api/hazard/audit.js

@ -8,6 +8,15 @@ export function getHazardAuditDetail(id) { @@ -8,6 +8,15 @@ export function getHazardAuditDetail(id) {
})
}
// 根据流程实例 ID 获取流程详情,用于补齐当前待办任务 taskId
export function getHazardProcessDetail(flowInstanceId) {
return request({
url: '/flowable/busiInfo/getProcessDetail',
method: 'get',
params: { id: flowInstanceId }
})
}
// 查询隐患附件
export function listHazardAttachments(reportId) {
return request({
@ -16,17 +25,18 @@ export function listHazardAttachments(reportId) { @@ -16,17 +25,18 @@ export function listHazardAttachments(reportId) {
})
}
// 上传隐患附件,接口定义为二进制文件流
// 上传隐患附件,后端要求 multipart/form-data
export function uploadHazardAttachment(file, attachmentType) {
const formData = new FormData()
formData.append('files', file, file.name || 'hazard-attachment')
return request({
url: '/flowable/hazard/uploadAttachment',
url: '/business/hazard/uploadAttachment',
method: 'post',
params: { attachmentType },
headers: {
'Content-Type': file.type || 'application/octet-stream',
repeatSubmit: false
},
data: file
data: formData
})
}

2
src/api/hazard/ledger.js

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import request from '@/utils/request'
export function listHazardLedger(query) { return request({ url: '/business/hazard/getListByPage', method: 'get', params: query }) }
export function listHazardLedger(query) { return request({ url: '/flowable/hazard/todoList', method: 'get', params: query }) }
export function getHazardLedgerDetail(id) { return request({ url: '/business/hazard/info/' + id, method: 'get' }) }
export function listHazardLedgerAttachments(reportId) { return request({ url: '/business/hazard/attachment/' + reportId, method: 'get' }) }
export function exportHazardLedger(data) { return request({ url: '/business/hazard/export', method: 'post', data, responseType: 'blob' }) }

7
src/components/SelectTree/index.vue

@ -102,6 +102,9 @@ export default { @@ -102,6 +102,9 @@ export default {
if (val) {
this.orgdata_bm_list = this.formatData(val);
}
if (val && val.length && this.echoBack) {
this.setDefault(this.echoBack);
}
},
immediate: true,
deep: true,
@ -236,7 +239,7 @@ export default { @@ -236,7 +239,7 @@ export default {
},
findNodeById(tree, id) {
for (let node of tree) {
if (node.id === id) {
if (String(node.id) === String(id)) {
return node;
} else if (node.children && node.children.length > 0) {
let result = this.findNodeById(node.children, id);
@ -330,4 +333,4 @@ export default { @@ -330,4 +333,4 @@ export default {
::v-deep .el-input__suffix {
// display: none;
}
</style>
</style>

83
src/views/hazard/audit/components/AuditActionForm.vue

@ -46,9 +46,7 @@ @@ -46,9 +46,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="管理级别" prop="hazardLevel">
<el-select v-model="form.hazardLevel" placeholder="请选择管理级别" style="width:100%" @change="syncHazardLevelName">
<el-option v-for="item in levelOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<dict-select v-model="form.hazardLevel" :options="dict.type.hazard_management_level" placeholder="请选择管理级别" @change="syncDictName('hazardLevel', 'hazardLevelName', 'hazard_management_level')" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -132,9 +130,35 @@ @@ -132,9 +130,35 @@
</el-upload>
</div>
<div v-if="uploadedAttachments.length" class="uploaded-list">
<el-tag v-for="item in uploadedAttachments" :key="item.id || item.filePath" closable size="mini" @close="removeUploaded(item)">
{{ item.fileName || '新附件' }}
</el-tag>
<div
v-for="item in uploadedAttachments"
:key="item.id || item.filePath || item.fileUrl || item.fileName"
:class="['uploaded-file', { 'image-file': isUploadedImage(item) }]"
>
<el-image
v-if="isUploadedImage(item)"
:src="attachmentUrl(item)"
:preview-src-list="uploadedPreviewUrls"
:initial-index="uploadedImageIndex(item)"
fit="cover"
class="uploaded-image"
>
<div slot="error" class="uploaded-image-error">
<i class="el-icon-picture-outline" />
</div>
</el-image>
<a
v-else
:href="attachmentUrl(item) || undefined"
:target="attachmentUrl(item) ? '_blank' : undefined"
rel="noopener noreferrer"
class="uploaded-doc"
>
<i class="el-icon-document" />
<span>{{ item.fileName || '新附件' }}</span>
</a>
<i class="el-icon-close uploaded-remove" title="移除附件" @click.stop="removeUploaded(item)" />
</div>
</div>
<div class="security-tip">严禁处理或传输国家秘密、商业秘密及敏感信息;最多 8 个附件。</div>
</el-form-item>
@ -148,7 +172,7 @@ @@ -148,7 +172,7 @@
<el-button :disabled="!canApprove" :loading="submitting" @click="openReject">驳回</el-button>
<el-button type="warning" :disabled="!canApprove" :loading="submitting" @click="openSwitch">重新评估等级</el-button>
</div>
<div v-if="!canApprove" class="disabled-tip">当前记录不可审批,请确认 `canApprove` 和待办任务状态。</div>
<div v-if="!canApprove" class="disabled-tip">{{ disabledTip }}</div>
<el-dialog title="通过审核" :visible.sync="passVisible" width="460px" append-to-body>
<div class="confirm-content">
@ -202,6 +226,7 @@ @@ -202,6 +226,7 @@
</template>
<script>
/* global MyConfig */
import SelectTree from '@/components/SelectTree'
const DictSelect = {
@ -235,11 +260,11 @@ const DictSelect = { @@ -235,11 +260,11 @@ const DictSelect = {
export default {
name: 'AuditActionForm',
components: { SelectTree, DictSelect },
dicts: ['tree_dept', 'tree_person', 'hazard_major', 'hazard_category', 'hazard_source', 'hazard_type', 'hazard_governance_type', 'hazard_funds_source'],
dicts: ['tree_dept', 'tree_person', 'hazard_major', 'hazard_category', 'hazard_management_level', 'hazard_source', 'hazard_type', 'hazard_governance_type', 'hazard_funds_source'],
props: {
report: { type: Object, required: true },
attachments: { type: Array, default: () => [] },
taskId: { type: String, required: true },
taskId: { type: String, default: '' },
submitting: Boolean
},
data() {
@ -281,22 +306,32 @@ export default { @@ -281,22 +306,32 @@ export default {
canApprove() {
return (this.report.canApprove === true || String(this.report.canApprove) === 'true') && Boolean(this.taskId)
},
disabledTip() {
if (!this.taskId) return '未获取到当前待办任务 ID,无法执行审批。'
return '当前记录不可审批,请确认 canApprove 和待办任务状态。'
},
attachmentCount() {
return this.attachments.length + this.uploadedAttachments.length
},
uploadedImageAttachments() {
return this.uploadedAttachments.filter(item => this.isUploadedImage(item))
},
uploadedPreviewUrls() {
return this.uploadedImageAttachments.map(item => this.attachmentUrl(item)).filter(Boolean)
},
pointsSuffix() {
if (this.report.pointsAwarded === undefined || this.report.pointsAwarded === null || this.report.pointsAwarded === '') return ''
const points = Number(this.report.pointsAwarded)
return ` · ${points > 0 ? '+' : ''}${this.report.pointsAwarded} 积分`
},
normalizedCurrentLevel() {
const value = this.report.currentFlowLevel || this.report.hazardLevel || ''
const value = this.report.currentFlowLevel || this.report.hazardCategory || ''
const nameMap = { 一般: 'general', 一般隐患: 'general', 较大: 'major', 较大隐患: 'major', 重大: 'critical', 重大隐患: 'critical' }
return nameMap[value] || value
},
currentLevelName() {
const item = this.levelOptions.find(option => option.value === this.normalizedCurrentLevel)
return this.report.hazardLevelName || (item && item.label) || this.normalizedCurrentLevel || '—'
return (item && item.label) || this.normalizedCurrentLevel || '—'
}
},
watch: {
@ -305,7 +340,6 @@ export default { @@ -305,7 +340,6 @@ export default {
deep: true,
handler(value) {
this.form = JSON.parse(JSON.stringify(value || {}))
if (!this.form.hazardLevel && this.form.currentFlowLevel) this.form.hazardLevel = this.form.currentFlowLevel
this.auditComment = this.form.auditRemark || ''
this.uploadedAttachments = []
}
@ -328,11 +362,6 @@ export default { @@ -328,11 +362,6 @@ export default {
const item = (this.dict.type[dictType] || []).find(option => String(option.value) === String(this.form[valueField]))
this.$set(this.form, nameField, item ? item.label : '')
},
syncHazardLevelName(value) {
const item = this.levelOptions.find(option => option.value === value)
this.$set(this.form, 'hazardLevelName', item ? item.label : '')
this.$set(this.form, 'currentFlowLevel', value)
},
beforeUpload(file) {
if (this.attachmentCount >= 8) {
this.$modal.msgError('附件数量不能超过 8 个')
@ -359,6 +388,17 @@ export default { @@ -359,6 +388,17 @@ export default {
}
})
},
isUploadedImage(item) {
return item.attachmentType === 'IMAGE' || /^image\//i.test(item.fileType || '') || /\.(png|jpe?g|gif|webp|bmp)$/i.test(item.fileName || item.filePath || item.fileUrl || '')
},
attachmentUrl(item) {
const path = item.fileUrl || item.url || item.downloadUrl || item.filePath || ''
if (!path || /^https?:\/\//i.test(path) || /^data:image\//i.test(path)) return path
return MyConfig.BASE_API.replace(/\/$/, '') + '/' + path.replace(/^\//, '')
},
uploadedImageIndex(item) {
return this.uploadedPreviewUrls.indexOf(this.attachmentUrl(item))
},
removeUploaded(item) {
this.uploadedAttachments = this.uploadedAttachments.filter(current => current !== item)
},
@ -431,6 +471,15 @@ export default { @@ -431,6 +471,15 @@ export default {
.readonly-value { display: flex; align-items: center; min-height: 32px; }
.attachment-summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 32px; }
.uploaded-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.uploaded-file { position: relative; display: flex; align-items: center; width: 132px; height: 34px; border: 1px solid #e4e7ed; border-radius: 6px; background: #f7f9fc; overflow: hidden; }
.uploaded-file.image-file { width: 132px; height: 86px; }
.uploaded-image { width: 100%; height: 100%; cursor: zoom-in; }
.uploaded-image-error { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: #909399; background: #f7f9fc; }
.uploaded-doc { display: flex; align-items: center; gap: 5px; width: 100%; height: 100%; padding: 0 24px 0 8px; color: #606266; font-size: 11px; text-decoration: none; overflow: hidden; }
.uploaded-doc i { flex: none; color: #909399; }
.uploaded-doc span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uploaded-remove { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); color: #c0c4cc; font-size: 13px; cursor: pointer; z-index: 1; }
.uploaded-remove:hover { color: #f56c6c; }
.security-tip, .disabled-tip { margin-top: 6px; color: #f56c6c; font-size: 11px; line-height: 1.6; }
.action-buttons { display: grid; grid-template-columns: minmax(180px, 1fr) auto auto; gap: 8px; }
.reject-options { display: flex; flex-direction: column; gap: 12px; }

24
src/views/hazard/audit/components/HazardReportPanel.vue

@ -37,8 +37,8 @@ @@ -37,8 +37,8 @@
<section-title title="二、隐患信息" />
<div class="info-grid">
<info-item label="隐患状态" :value="report.statusName || report.status" tag />
<info-item label="隐患分类" :value="report.hazardCategoryName || report.hazardCategory" tag />
<info-item label="隐患状态" :value="report.statusName || report.status" tag tag-type="warning" />
<info-item label="隐患分类" :value="report.hazardCategoryName || report.hazardCategory" tag :tag-type="hazardCategoryTagType" />
<info-item label="管理级别" :value="report.hazardLevelName || report.currentFlowLevel || report.hazardLevel" />
<info-item label="资金来源" :value="report.fundsSourceName || report.fundsSource" optional />
<info-item label="隐患来源" :value="report.sourceTypeName || report.sourceType" />
@ -48,6 +48,9 @@ @@ -48,6 +48,9 @@
<info-item label="整改负责人" :value="report.chargePersonName" :extra="report.chargePersonUsername" />
<info-item label="专业" :value="report.majorName || report.major" />
</div>
<div class="classification-row">
<info-item label="分类标准" :value="classificationStandard" block />
</div>
<section-title title="三、隐患描述" />
<div class="description-list">
@ -84,6 +87,7 @@ const InfoItem = { @@ -84,6 +87,7 @@ const InfoItem = {
value: [String, Number],
extra: [String, Number],
tag: Boolean,
tagType: { type: String, default: 'warning' },
optional: Boolean,
block: Boolean
},
@ -92,7 +96,7 @@ const InfoItem = { @@ -92,7 +96,7 @@ const InfoItem = {
const empty = props.value === undefined || props.value === null || props.value === ''
const text = empty ? (props.optional ? '非必填项' : '—') : String(props.value)
const valueNode = props.tag && !empty
? h('el-tag', { props: { size: 'mini', type: 'warning' }}, text)
? h('el-tag', { props: { size: 'mini', type: props.tagType }}, text)
: h('strong', { class: { optional: empty && props.optional }}, [
text,
props.extra ? h('small', ` / ${props.extra}`) : null
@ -126,6 +130,18 @@ export default { @@ -126,6 +130,18 @@ export default {
},
previewUrls() {
return this.imageAttachments.map(item => this.attachmentUrl(item)).filter(Boolean)
},
classificationStandard() {
const category = String(this.report.hazardCategory || this.report.hazardCategoryName || '').toLowerCase()
if (category === 'general' || this.report.hazardCategoryName === '一般') return '-'
return this.report.hazardClassificationStandard || this.report.criteriaNames || this.report.hazardClassificationStandardLabel || '-'
},
hazardCategoryTagType() {
const code = String(this.report.hazardCategory || '').toLowerCase()
const name = String(this.report.hazardCategoryName || '')
if (code === 'major' || name === '较大' || name === '较大隐患') return 'warning'
if (code === 'critical' || name === '重大' || name === '重大隐患') return 'danger'
return 'primary'
}
},
methods: {
@ -156,11 +172,13 @@ export default { @@ -156,11 +172,13 @@ export default {
.section-title { margin: 16px 0 8px; color: #606266; font-size: 12px; font-weight: 600; }
.info-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 14px; }
.description-list { display: grid; gap: 9px; }
.classification-row { margin-top: 8px; }
::v-deep .info-item { display: grid; grid-template-columns: 92px minmax(0, 1fr); align-items: start; gap: 7px; min-width: 0; font-size: 12px; line-height: 1.55; }
::v-deep .info-label { color: #909399; }
::v-deep .info-item strong { min-width: 0; color: #303133; font-weight: 600; word-break: break-word; }
::v-deep .info-item strong.optional { color: #c0c4cc; font-weight: 400; }
::v-deep .info-item small { color: #606266; font-weight: 400; }
::v-deep .info-item .el-tag { justify-self: start; width: fit-content; max-width: 100%; }
::v-deep .el-empty { padding: 8px 0; }
@media (max-width: 1500px) { .info-grid { grid-template-columns: 1fr; } }
</style>

63
src/views/hazard/audit/index.vue

@ -24,6 +24,15 @@ @@ -24,6 +24,15 @@
</el-alert>
<template v-else-if="loaded">
<el-alert
v-if="!taskId"
title="当前未获取到任务 ID,仅可查看详情,无法执行审批。"
type="warning"
:closable="false"
show-icon
class="route-alert"
style="grid-column: 1 / -1;"
/>
<hazard-report-panel :report="report" :attachments="attachments" />
<audit-action-form
:report="report"
@ -47,6 +56,7 @@ import FlowSyncPanel from './components/FlowSyncPanel' @@ -47,6 +56,7 @@ import FlowSyncPanel from './components/FlowSyncPanel'
import {
completeHazardAudit,
getHazardAuditDetail,
getHazardProcessDetail,
listHazardAttachments,
switchHazardLevel,
updateHazardReport,
@ -63,6 +73,7 @@ export default { @@ -63,6 +73,7 @@ export default {
loaded: false,
loadError: '',
report: {},
taskId: '',
attachments: []
}
},
@ -70,13 +81,8 @@ export default { @@ -70,13 +81,8 @@ export default {
reportId() {
return String(this.$route.query.id || '')
},
taskId() {
return String(this.$route.query.taskId || '')
},
routeError() {
if (!this.reportId && !this.taskId) return '缺少隐患 ID 和任务 ID,请从待办任务的“办理”入口进入。'
if (!this.reportId) return '缺少隐患 ID,无法加载审核详情。'
if (!this.taskId) return '缺少任务 ID,无法执行审批;请从待办任务入口重新进入。'
return ''
}
},
@ -99,6 +105,7 @@ export default { @@ -99,6 +105,7 @@ export default {
this.loaded = false
this.loadError = ''
this.report = {}
this.taskId = ''
this.attachments = []
},
async loadPage() {
@ -112,6 +119,12 @@ export default { @@ -112,6 +119,12 @@ export default {
])
this.report = results[0].data || {}
this.attachments = Array.isArray(results[1].data) ? results[1].data : []
const routeFlowInstanceId = String(this.$route.query.flowInstanceId || '')
if (routeFlowInstanceId && !this.report.flowInstanceId) this.$set(this.report, 'flowInstanceId', routeFlowInstanceId)
if (this.$route.query.canApprove === '1' && this.report.canApprove !== true && String(this.report.canApprove) !== 'true') {
this.$set(this.report, 'canApprove', true)
}
await this.resolveCurrentTask()
this.loaded = true
} catch (error) {
this.loadError = '隐患详情或附件加载失败,请稍后重试。'
@ -119,6 +132,42 @@ export default { @@ -119,6 +132,42 @@ export default {
this.loading = false
}
},
async resolveCurrentTask() {
this.taskId = String(this.$route.query.taskId || '')
const canApprove = this.report.canApprove === true || String(this.report.canApprove) === 'true'
if (this.taskId || !canApprove || !this.report.flowInstanceId) return
try {
const response = await getHazardProcessDetail(this.report.flowInstanceId)
const currentTask = this.findCurrentTask(response.data)
this.taskId = currentTask ? String(currentTask.taskId || '') : ''
} catch (error) {
this.taskId = ''
}
},
findCurrentTask(data) {
const tasks = this.normalizeTaskList(data)
if (!tasks.length) return null
return tasks.find(task => task.taskId && !task.endTime && !task.finishTime) ||
tasks.find(task => task.taskId) ||
null
},
normalizeTaskList(data) {
const tasks = []
const visit = value => {
if (Array.isArray(value)) {
value.forEach(visit)
return
}
if (!value || typeof value !== 'object') return
if (Object.prototype.hasOwnProperty.call(value, 'taskId')) tasks.push(value)
Object.keys(value).forEach(key => {
if (key !== 'taskId') visit(value[key])
})
}
visit(data)
return tasks
},
handleAttachmentUpload(payload) {
uploadHazardAttachment(payload.file, payload.attachmentType).then(response => {
const data = response.data
@ -135,6 +184,10 @@ export default { @@ -135,6 +184,10 @@ export default {
})
},
async handleAuditSubmit(payload) {
if (!this.taskId) {
this.$modal.msgWarning('当前未获取到任务 ID,无法执行审批;请从待办任务入口进入。')
return
}
this.submitting = true
try {
await updateHazardReport(payload.saveData)

2
src/views/hazard/ledger/index.vue

@ -198,7 +198,7 @@ export default { @@ -198,7 +198,7 @@ export default {
getUnits() { deptTreeSelect().then(response => { this.unitOptions = this.flattenTree(response.data || []) }).catch(() => { this.unitOptions = [] }) }, flattenTree(nodes, result = []) { nodes.forEach(node => { result.push({ id: node.id, label: node.label || node.deptName }); if (node.children) this.flattenTree(node.children, result) }); return result },
handleQuery() { this.queryParams.pageNum = 1; this.getList() }, resetQuery() { this.$refs.queryForm.resetFields(); this.queryParams.pageNum = 1; this.getList() },
openDetail(row) { this.detailVisible = true; this.detail = null; this.attachments = []; this.detailLoading = true; Promise.all([getHazardLedgerDetail(row.id), listHazardLedgerAttachments(row.id)]).then(results => { this.detail = results[0].data || results[0]; const data = results[1].data || results[1]; this.attachments = Array.isArray(data) ? data : [] }).catch(() => { this.$modal.msgError('隐患详情加载失败') }).finally(() => { this.detailLoading = false }) },
goAudit(row) { const taskId = row.taskId || row.taskID || row.todoTaskId; if (!taskId) { this.$modal.msgWarning('当前记录缺少任务 ID,无法进入审核'); return } this.detailVisible = false; this.$router.push({ path: '/hazard/audit/detail', query: { id: String(row.id), taskId: String(taskId) }}) },
goAudit(row) { const query = { id: String(row.id) }; if (row.canApprove === true || String(row.canApprove) === 'true') query.canApprove = '1'; if (row.flowInstanceId) query.flowInstanceId = String(row.flowInstanceId); this.detailVisible = false; this.$router.push({ path: '/hazard/audit/detail', query }) },
handleRetrySync(row) { this.$confirm('确认重试将该隐患同步到生产运营平台吗?', '重试同步', { type: 'warning' }).then(() => retryHazardSync(row.id)).then(() => { this.$modal.msgSuccess('同步重试成功'); this.getList() }).catch(error => { if (error !== 'cancel') this.$modal.msgError(error.message || '同步重试失败') }) },
statusKey(row) { const value = String(row.status || '').toLowerCase(); const name = row.statusName || ''; if (/待提交|未提交/.test(name) || value === 'draft' || value === '0') return 'draft'; if (/审核中|待审核/.test(name) || value === 'reviewing' || value === '1') return 'reviewing'; if (/整改中/.test(name) || value === 'rectifying' || value === '2') return 'rectifying'; if (/已通过|已闭环/.test(name) || value === 'approved' || value === '3') return 'approved'; if (/已驳回|驳回/.test(name) || value === 'rejected' || value === '4') return 'rejected'; return value }, isReviewing(row) { return this.statusKey(row) === 'reviewing' }, isSyncFailed(row) { return /失败|异常/.test(row.pushStatusName || row.pushStatus || '') }, levelLabel(row) { return row.hazardLevelName || ({ general: '一般', major: '较大', critical: '重大' }[row.hazardLevel] || row.hazardLevel || '—') }, statusLabel(row) { const key = this.statusKey(row); return ({ draft: '待提交', reviewing: '审核中', rectifying: '整改中', approved: '已通过', rejected: '已驳回' }[key] || row.statusName || row.status || '—') }, pointsLabel(row) { if (row.pointsStatusName) return row.pointsAwarded === undefined || row.pointsAwarded === null ? row.pointsStatusName : `${row.pointsAwarded > 0 ? '+' : ''}${row.pointsAwarded} ${row.pointsStatusName}`; return row.pointsAwarded === undefined || row.pointsAwarded === null ? '—' : `${row.pointsAwarded > 0 ? '+' : ''}${row.pointsAwarded} 分` }, pushLabel(row) { return row.pushStatusName || ({ SUCCESS: '已同步', FAIL: '同步失败', FAILED: '同步失败', WAIT: '待同步' }[String(row.pushStatus).toUpperCase()] || row.pushStatus || '—') }, statusTagType(row) { const value = this.statusKey(row); return value === 'approved' ? 'success' : value === 'rejected' ? 'danger' : value === 'rectifying' ? 'warning' : value === 'reviewing' ? 'primary' : 'info' }, levelTagType(row) { return String(row.hazardLevel || '').toLowerCase() === 'critical' ? 'danger' : String(row.hazardLevel || '').toLowerCase() === 'major' ? 'warning' : 'info' }, pointsTagType(row) { return row.pointsStatusName && /待|未/.test(row.pointsStatusName) ? 'info' : row.pointsAwarded === undefined || row.pointsAwarded === null ? 'info' : 'success' }, pushTagType(row) { return this.isSyncFailed(row) ? 'danger' : /待/.test(this.pushLabel(row)) ? 'info' : 'success' },
isImageAttachment(item) { return String(item.attachmentType || '').toUpperCase() === 'IMAGE' || /^image\//i.test(item.fileType || '') || /\.(png|jpe?g|gif|webp|bmp|svg)(?:\?.*)?$/i.test(item.fileName || item.filePath || item.fileUrl || '') },

Loading…
Cancel
Save