Files
labmanager/desktop-ui/src/views/Standard.vue
2026-05-11 16:04:31 +08:00

263 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { ref, computed, onMounted } from "vue"
import { getCurrentInstance } from "vue"
import { ElMessage, ElMessageBox } from "element-plus"
const { $http } = getCurrentInstance().appContext.config.globalProperties
const isAdmin = localStorage.getItem('role') === 'admin'
function formatDate(date) {
if (!date) return "-"
const d = new Date(date)
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, "0")
const day = String(d.getDate()).padStart(2, "0")
return `${y}-${m}-${day}`
}
const data = ref([])
const dialogVisible = ref(false)
const editing = ref(false)
const form = ref({
batch: "",
im: "",
ass: "",
calibration_date: "",
expire_date: "",
location: "",
})
// 有效期筛查天数0=全部)
const filterDays = ref(0)
const filteredData = computed(() => {
if (!filterDays.value || filterDays.value <= 0) return data.value
const now = new Date()
const limit = new Date(now.getTime() + filterDays.value * 86400000)
return data.value.filter((item) => {
if (!item.expire_date) return false
const expire = new Date(item.expire_date)
return expire >= now && expire <= limit
})
})
function rowClass({ row }) {
if (!row.expire_date) return ""
const today = new Date()
today.setHours(0, 0, 0, 0)
const expire = new Date(row.expire_date)
expire.setHours(0, 0, 0, 0)
return expire < today ? "row-expired" : ""
}
function rowStyle({ row }) {
if (!row.expire_date) return {}
const today = new Date()
today.setHours(0, 0, 0, 0)
const expire = new Date(row.expire_date)
expire.setHours(0, 0, 0, 0)
if (expire < today) {
return { color: "#dc2626" }
}
return {}
}
async function refresh() {
try {
const res = await $http.get("/standard")
data.value = res.data || []
} catch {
data.value = []
}
}
function openCreate() {
editing.value = false
form.value = { batch: "", im: "", ass: "", calibration_date: "", expire_date: "", location: "" }
dialogVisible.value = true
}
function openEdit(row) {
editing.value = true
form.value = { ...row }
dialogVisible.value = true
}
async function save() {
if (!form.value.batch) {
ElMessage.error("批号不能为空")
return
}
try {
if (editing.value) {
await $http.patch(`/standard/${form.value._id}`, form.value)
ElMessage.success("更新成功")
} else {
await $http.post("/standard", form.value)
ElMessage.success("创建成功")
}
dialogVisible.value = false
await refresh()
} catch (error) {
ElMessage.error(error.response?.data?.message || "操作失败")
}
}
async function remove(row) {
try {
await ElMessageBox.confirm(`确定要删除批号为"${row.batch}"的对照品吗?`, "确认删除", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
await $http.delete(`/standard/${row._id}`)
ElMessage.success("删除成功")
await refresh()
} catch {
// cancelled
}
}
onMounted(refresh)
</script>
<template>
<div class="page-container">
<div class="actions-bar">
<div class="actions-left">
<el-button @click="refresh">刷新</el-button>
<el-button type="primary" @click="openCreate">新增对照品</el-button>
</div>
<div class="actions-right">
<span class="filter-label">有效期</span>
<el-input-number v-model="filterDays" :min="0" :max="365" :step="7" size="small"
controls-position="right" style="width: 100px" />
<span class="filter-unit">天内到期</span>
<el-tag v-if="filterDays > 0" type="warning" size="small" effect="plain">
显示 {{ filteredData.length }}
</el-tag>
<el-button v-if="filterDays > 0" size="small" text type="info" @click="filterDays = 0">
清除
</el-button>
</div>
</div>
<el-table :data="filteredData" stripe border style="width: 100%" :row-class-name="rowClass"
:row-style="rowStyle">
<el-table-column prop="batch" label="批号" min-width="180" />
<el-table-column prop="im" label="含量(%)" width="100" />
<el-table-column prop="ass" label="纯度(%)" width="100" />
<el-table-column prop="calibration_date" label="标定日期" width="120">
<template #default="{ row }">
{{ formatDate(row.calibration_date) }}
</template>
</el-table-column>
<el-table-column prop="expire_date" label="有效期" width="120">
<template #default="{ row }">
{{ formatDate(row.expire_date) }}
</template>
</el-table-column>
<el-table-column prop="location" label="存放位置" min-width="140" />
<el-table-column label="操作" width="180" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="openEdit(row)">编辑</el-button>
<el-button size="small" type="danger" :disabled="!isAdmin" @click="remove(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="dialogVisible" :title="editing ? '编辑对照品' : '新增对照品'" width="520px" align-center>
<el-form :model="form" label-position="top">
<el-form-item label="批号" required>
<el-input v-model="form.batch" />
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="含量(%)">
<el-input v-model="form.im" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="纯度(%)">
<el-input v-model="form.ass" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="标定日期">
<el-date-picker v-model="form.calibration_date" type="date" style="width: 100%"
value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效期">
<el-date-picker v-model="form.expire_date" type="date" style="width: 100%"
value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="存放位置">
<el-input v-model="form.location" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="save">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<style scoped>
.page-container {
padding: 24px;
}
.actions-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
flex-wrap: wrap;
gap: 8px;
}
.actions-left {
display: flex;
align-items: center;
gap: 8px;
}
.actions-right {
display: flex;
align-items: center;
gap: 6px;
}
.filter-label {
font-size: 13px;
color: #8896a8;
white-space: nowrap;
}
.filter-unit {
font-size: 13px;
color: #3d4a5c;
white-space: nowrap;
}
/* 过期行文字红色 */
:deep(.el-table .row-expired) {
color: #dc2626 !important;
font-weight: 500;
}
:deep(.row-expired:hover) {
background-color: #fee2e2 !important;
}
:deep(.row-expired .el-table__cell) {
color: #dc2626;
}
</style>