You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
besure_web/src/views/mes/zjschema/ZjSchemaForm.vue

736 lines
24 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="120px"
v-loading="formLoading"
>
<el-form-item :label="t('QualityManagement.ZjSchema.name')" prop="name">
<el-input
v-model="formData.name"
:placeholder="t('QualityManagement.ZjSchema.placeholderName')"
/>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjSchema.type')" prop="type">
<el-radio-group v-model="formData.type">
<el-radio v-for="dict in getDictOptions('mes_zj_schema_type')" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="isSampleType" :label="t('QualityManagement.ZjSchema.sampleMethod')" prop="sampleMethod">
<el-radio-group v-model="formData.sampleMethod">
<el-radio v-for="dict in getDictOptions('mes_zj_schema_sample_method')" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="isSampleType" :label="t('QualityManagement.ZjSchema.val')" prop="val">
<template v-if="isRateMethod">
<el-input-number v-model="rateVal" :min="0" class="!w-160px" />
<span class="ml-8px">%</span>
</template>
<template v-else-if="isGapMethod">
<span>{{ t('QualityManagement.ZjSchema.atIntervals') }}</span>
<el-input-number v-model="gapInterval" :min="1" class="!w-120px mx-8px" :controls="false" />
<span>{{ t('QualityManagement.ZjSchema.extraction') }}</span>
<el-input-number v-model="gapCount" :min="1" class="!w-120px mx-8px" :controls="false" />
</template>
<template v-else>
<el-input
v-model="formData.val"
:placeholder="t('QualityManagement.ZjSchema.placeholderVal')"
/>
</template>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjSchema.item')" prop="item">
<el-input :model-value="displayItemNames" readonly clearable class="device-ledger-selection-input"
:placeholder="t('QualityManagement.ZjSchema.placeholderItem')"
@click="openCriticalComponentDialog" @clear="clearBeijian" />
<!-- <el-row :gutter="8" class="w-full">
<el-col :span="22">
<el-input
:model-value="displayItemNames"
:placeholder="t('QualityManagement.ZjSchema.placeholderItem')"
readonly
/>
</el-col>
<el-col :span="2" class="text-right">
<el-button type="primary" @click="openItemDialog">
{{ t('action.select') }}
</el-button>
</el-col>
</el-row>-->
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjSchema.remark')" prop="remark">
<el-input
v-model="formData.remark"
:placeholder="t('QualityManagement.ZjSchema.placeholderRemark')"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">
{{ t('common.ok') }}
</el-button>
<el-button @click="dialogVisible = false">
{{ t('common.cancel') }}
</el-button>
</template>
</Dialog>
<el-dialog
v-model="itemDialogVisible"
:title="t('QualityManagement.ZjSchema.selectItemDialogTitle')"
width="1300px"
draggable
>
<!-- <div v-loading="itemLoading">
<div class="formula-config-picklist">
<div class="formula-config-panel">
<div class="formula-config-panel__header">
<div>{{ t('QualityManagement.ZjSchema.source') }}</div>
<div class="formula-config-panel__meta">{{ filteredSourceItems.length }}</div>
</div>
<div class="formula-config-panel__filter">
<el-input
v-model="sourceKeyword"
:placeholder="t('QualityManagement.ZjSchema.filterPlaceholder')"
clearable
/>
</div>
<el-table
class="formula-config-panel__table"
:data="filteredSourceItems"
height="440"
row-key="key"
@selection-change="handleSourceSelectionChange"
>
<el-table-column type="selection" width="44" />
<el-table-column :label="t('QualityManagement.ZjItem.name')" prop="name" sortable />
<el-table-column :label="t('QualityManagement.ZjItem.zjType')">
<template #default="scope">
{{ scope.row.zjTypeName }}
</template>
</el-table-column>
</el-table>
</div>
<div class="formula-config-actions">
<el-button type="primary" :disabled="!sourceCheckedKeys.length" @click="addToTarget">
&gt;&gt;
</el-button>
<el-button :disabled="!targetCheckedKeys.length" @click="removeFromTarget">
&lt;&lt;
</el-button>
</div>
<div class="formula-config-panel">
<div class="formula-config-panel__header">
<div>{{ t('QualityManagement.ZjSchema.target') }}</div>
<div class="formula-config-panel__meta">{{ filteredTargetItems.length }}</div>
</div>
<div class="formula-config-panel__filter">
<el-input
v-model="targetKeyword"
:placeholder="t('QualityManagement.ZjSchema.filterPlaceholder')"
clearable
/>
</div>
<el-table
class="formula-config-panel__table"
:data="filteredTargetItems"
height="440"
row-key="key"
@selection-change="handleTargetSelectionChange"
>
<el-table-column type="selection" width="44" />
<el-table-column :label="t('QualityManagement.ZjItem.name')" prop="name" sortable />
<el-table-column :label="t('QualityManagement.ZjItem.zjType')">
<template #default="scope">
{{ scope.row.zjTypeName }}
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>-->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" min-label-width="68px"
style="margin-bottom: 10px">
<el-form-item :label="t('QualityManagement.ZjItem.zjType')" prop="zjType">
<el-select
v-model="queryParams.zjType"
clearable
filterable
:placeholder="t('QualityManagement.ZjItem.placeholderZjType')"
class="!w-240px"
>
<el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjItem.name')" prop="name">
<el-input
v-model="queryParams.name"
:placeholder="t('QualityManagement.ZjItem.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjItem.remark')" prop="remark">
<el-input
v-model="queryParams.remark"
:placeholder="t('QualityManagement.ZjItem.placeholderRemark')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
<ContentWrap>
<el-table ref="multipleTableRef" v-loading="loading" :data="list" :stripe="true"
@selection-change="handleSelectionChange" @select="handleSelect" @select-all="handleSelectAll" :show-overflow-tooltip="true" row-key="id">
<el-table-column type="selection" width="55" :reserve-selection="true" />
<el-table-column :label="t('QualityManagement.ZjItem.name')" align="center" prop="name" sortable />
<el-table-column :label="t('QualityManagement.ZjItem.tool')" align="center" prop="tool" />
<el-table-column :label="t('QualityManagement.ZjItem.zjType')" align="center" prop="zjTypeName" sortable>
<template #default="scope">
<el-tag>{{ scope.row.zjTypeName }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('QualityManagement.ZjItem.standardVal')" align="center" prop="standardVal" />
<el-table-column :label="t('QualityManagement.ZjItem.upperVal')" align="center" prop="upperVal" />
<el-table-column :label="t('QualityManagement.ZjItem.lowerVal')" align="center" prop="lowerVal" />
<el-table-column :label="t('QualityManagement.ZjItem.unit')" align="center" prop="unitName" sortable />
<el-table-column :label="t('QualityManagement.ZjItem.remark')" align="center" prop="remark" />
</el-table>
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<template #footer>
<el-button @click="itemDialogVisible = false">
{{ t('common.cancel') }}
</el-button>
<el-button type="primary" @click="confirmSelectItems">
{{ t('common.ok') }}
</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { getDictOptions } from '@/utils/dict'
import { ZjSchemaApi, ZjSchemaVO } from '@/api/mes/zjschema'
import { ZjItemApi, ZjItemVO } from '@/api/mes/zjitem'
import {ref} from "vue";
import {ElTable} from "element-plus";
import {ZjTypeApi, ZjTypeVO} from "@/api/mes/zjtype";
/** */
defineOptions({ name: 'ZjSchemaForm' })
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
code: undefined as string | undefined,
name: undefined as string | undefined,
description: undefined as string | undefined,
remark: undefined as string | undefined,
createTime: [] as string[]
})
const typeList = ref<ZjTypeVO[]>([]) // 列表
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const loading = ref(true)
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const queryFormRef = ref()
const formData = ref({
type: 'All' as string | undefined,
name: undefined as string | undefined,
remark: undefined as string | undefined,
sampleMethod: undefined as string | undefined,
val: undefined as string | undefined,
item: undefined as string | undefined,
})
const rateVal = ref<number | undefined>(undefined)
const gapInterval = ref<number | undefined>(undefined)
const gapCount = ref<number | undefined>(undefined)
const itemDialogVisible = ref(false)
const itemLoading = ref(false)
const itemList = ref<ZjItemVO[]>([])
const selectedItemIds = ref<number[]>([])
const sourceKeyword = ref('')
const targetKeyword = ref('')
const sourceCheckedKeys = ref<number[]>([])
const targetCheckedKeys = ref<number[]>([])
const formRules = reactive({
name: [{ required: true, message: t('QualityManagement.ZjSchema.validatorNameRequired'), trigger: 'blur' }],
type: [{ required: true, message: t('QualityManagement.ZjSchema.validatorTypeRequired'), trigger: 'change' }],
sampleMethod: [
{ required: true, message: t('QualityManagement.ZjSchema.validatorSampleMethodRequired'), trigger: 'change' },
],
val: [{ validator: (_: any, __: any, callback: any) => validateVal(callback), trigger: 'blur' }],
})
const formRef = ref() // 表单 Ref
const list = ref<ZjItemVO[]>([])
const selectedRows = ref<any[]>([])
const total = ref(0)
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
const selectedIds = ref<number[]>([])
const isSampleType = computed(() => {
const type = formData.value.type
return type === 'Sample'
})
const isRateMethod = computed(() => formData.value.sampleMethod === 'Rate')
const isGapMethod = computed(() => formData.value.sampleMethod === 'Gap')
const displayItemNames = computed( () => {
if (!ids.value.length)return ''
if (!itemList.value.length) {
return formData.value.item ? String(formData.value.item) : ''
}
const map = new Map(itemList.value.map((item) => [item.id, item.name]))
const names = ids.value
.map((id) => map.get(id))
.filter((name) => name)
return names.join(',')
})
const allItems = computed(() =>
itemList.value.map((item) => {
const typeName = item.zjTypeName || ''
const name = item.name || ''
const label = typeName ? `${typeName}-${name}` : name
return {
...item,
key: item.id,
label,
}
})
)
const sourceItems = computed(() =>
allItems.value.filter((item) => !selectedItemIds.value.includes(item.id))
)
const targetItems = computed(() =>
allItems.value.filter((item) => selectedItemIds.value.includes(item.id))
)
const filteredSourceItems = computed(() => {
const keyword = sourceKeyword.value.trim()
if (!keyword) return sourceItems.value
return sourceItems.value.filter((item) => item.label?.includes(keyword))
})
const filteredTargetItems = computed(() => {
const keyword = targetKeyword.value.trim()
if (!keyword) return targetItems.value
return targetItems.value.filter((item) => item.label?.includes(keyword))
})
const validateVal = (callback: any) => {
if (!isSampleType.value) {
callback()
return
}
if (isRateMethod.value) {
if (rateVal.value === undefined || rateVal.value === null) {
callback(new Error(t('QualityManagement.ZjSchema.validatorValRequired')))
return
}
} else if (isGapMethod.value) {
if (!gapInterval.value || !gapCount.value) {
callback(new Error(t('QualityManagement.ZjSchema.validatorValRequired')))
return
}
} else if (!formData.value.val) {
callback(new Error(t('QualityManagement.ZjSchema.validatorValRequired')))
return
}
callback()
}
watch(
() => formData.value.type,
(val) => {
if (val === 'Sample') {
if (!formData.value.sampleMethod) {
const opts = getDictOptions('mes_zj_schema_sample_method')
if (opts && opts.length > 0) {
formData.value.sampleMethod = String(opts[0].value)
}
}
return
}
formData.value.sampleMethod = undefined
formData.value.val = undefined
rateVal.value = undefined
gapInterval.value = undefined
gapCount.value = undefined
formRef.value?.clearValidate?.(['sampleMethod', 'val'])
}
)
// 方法1直接监听 data
watch(list, (newData, oldData) => {
// 可以在这里执行相关操作
if (newData.length > 0) {
// 数据加载完成后的操作
setDefaultSelections()
}
}, { deep: true })
const openItemDialog = async () => {
itemDialogVisible.value = true
if (!itemList.value.length) {
itemLoading.value = true
try {
itemList.value = await ZjItemApi.getZjItemList()
} finally {
itemLoading.value = false
}
}
initSelectedItemIds()
sourceCheckedKeys.value = []
targetCheckedKeys.value = []
}
const initSelectedItemIds = () => {
if (!formData.value.item) {
ids.value = []
return
}
let s = formData.value.item.toString();
let allIds =formData.value.item!=undefined?formData.value.item.toString().split(','):[]
ids.value =allIds.map((id) => Number(id))
selectedItemIds.value = allIds.map((id) => Number(id))
}
const confirmSelectItems = () => {
formData.value.item = ids.value.join(',')
itemDialogVisible.value = false
}
const handleSourceSelectionChange = (rows: any[]) => {
sourceCheckedKeys.value = rows.map((row: any) => row.id)
}
const handleTargetSelectionChange = (rows: any[]) => {
targetCheckedKeys.value = rows.map((row: any) => row.id)
}
const addToTarget = () => {
if (!sourceCheckedKeys.value.length) return
const set = new Set(selectedItemIds.value)
sourceCheckedKeys.value.forEach((id) => set.add(id))
selectedItemIds.value = Array.from(set)
sourceCheckedKeys.value = []
}
const removeFromTarget = () => {
if (!targetCheckedKeys.value.length) return
const removeSet = new Set(targetCheckedKeys.value)
selectedItemIds.value = selectedItemIds.value.filter((id) => !removeSet.has(id))
targetCheckedKeys.value = []
}
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
initSelectedItems()
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
const data = await ZjSchemaApi.getZjSchema(id)
formData.value = data
initSelectedItemIds()
if (formData.value.type === 'Sample') {
if (formData.value.sampleMethod === 'Rate') {
const n = Number(formData.value.val)
rateVal.value = Number.isNaN(n) ? undefined : n
} else if (formData.value.sampleMethod === 'Gap' && typeof formData.value.val === 'string') {
const parts = formData.value.val.split(',').map((v: string) => v.trim())
const interval = Number(parts[0])
const count = Number(parts[1])
gapInterval.value = Number.isNaN(interval) ? undefined : interval
gapCount.value = Number.isNaN(count) ? undefined : count
}
}
} finally {
formLoading.value = false
}
}else{
ids.value=[]
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
// 校验表单
await formRef.value.validate()
if (isSampleType.value) {
if (isRateMethod.value) {
formData.value.val =
rateVal.value === undefined || rateVal.value === null ? undefined : String(rateVal.value)
} else if (isGapMethod.value) {
if (gapInterval.value && gapCount.value) {
formData.value.val = `${gapInterval.value},${gapCount.value}`
} else {
formData.value.val = undefined
}
}
} else {
formData.value.sampleMethod = ''
formData.value.val = ''
}
// 提交请求
formLoading.value = true
try {
const data = formData.value as unknown as ZjSchemaVO
if (formType.value === 'create') {
await ZjSchemaApi.createZjSchema(data)
message.success(t('common.createSuccess'))
} else {
await ZjSchemaApi.updateZjSchema(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
type: 'All',
name: undefined,
remark: undefined,
sampleMethod: undefined,
val: undefined,
item: undefined,
}
rateVal.value = undefined
gapInterval.value = undefined
gapCount.value = undefined
selectedItemIds.value = []
sourceKeyword.value = ''
targetKeyword.value = ''
sourceCheckedKeys.value = []
targetCheckedKeys.value = []
formRef.value?.resetFields()
}
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
const getList = async () => {
loading.value = true
try {
const data = await ZjItemApi.getZjItemPage(queryParams)
list.value = data.list
total.value = data.total
// 数据加载后,重新设置选中状态
nextTick(() => {
toggleSelection()
})
} finally {
loading.value = false
}
}
const initSelectedItems = async () => {
if (!itemList.value.length) {
itemLoading.value = true
try {
itemList.value = await ZjItemApi.getZjItemList()
} finally {
itemLoading.value = false
}
}
}
const ids = ref([])
const handleSelectionChange = (rows: ZjItemVO[]) => {
selectedIds.value = rows.map((r) => r.id).filter((id): id is number => typeof id === 'number')
// 获取当前页所有行的 id
const currentPageIds = rows.map(item => item.id)
// 从已选中的数组中移除当前页的数据
selectedRows.value = selectedRows.value.filter(
item => !currentPageIds.includes(item.id)
)
// 添加当前页新选中的数据
selectedRows.value.push(...rows)
let a=1;
}
// 存储当前已选中的行
const currentSelectedRows = ref([])
// select 事件row 是当前操作的行selected 是操作后的状态
const handleSelect = (selection, row) => {
// 判断是选中还是取消选中
const isSelected = selection.includes(row)
if (isSelected) {
// console.log(`✅ 行被选中: ID=${row.id}, Name=${row.name}`)
ids.value.push(row.id)
} else {
ids.value = ids.value.filter(
item => item !== row.id
)
// console.log(`❌ 行被取消选中: ID=${row.id}, Name=${row.name}`)
}
// 更新当前选中状态
currentSelectedRows.value = selection
}
const handleSelectAll = (selection) => {
let initIds=selection?.map((row) => row.id).filter((id) => id !== undefined) ?? []
ids.value =initIds.map((id) => Number(id))
}
const openCriticalComponentDialog = async () => {
itemDialogVisible.value = true
let initIds= formData.value.item!=undefined?formData.value.item.toString().split(","):[]
ids.value=initIds.map((id) => Number(id))
/* initSelectedItemIds()
sourceCheckedKeys.value = []
targetCheckedKeys.value = []*/
setDefaultSelections()
}
// 切换选中状态
const toggleSelection = () => {
if (!multipleTableRef.value || !selectedRows.value.length) return
// 遍历当前页的数据
list.value.forEach(row => {
// 检查这一行是否在已选中数组中
const isSelected = selectedRows.value.some(item => item.id === row.id)
if (isSelected) {
// 如果应该选中,就选中
multipleTableRef.value!.toggleRowSelection(row, true)
} else {
// 否则取消选中
multipleTableRef.value!.toggleRowSelection(row, false)
}
})
}
const clearBeijian = () => {
formData.value.item = ''
}
// 设置默认选中的行
const setDefaultSelections = () => {
// 等待DOM更新完成
nextTick(() => {
if (!multipleTableRef.value) return
multipleTableRef.value.clearSelection()
// const rawSubjectIds = toRaw(formData.value.item!=undefined?formData.value.item.toString().split(","):[])
let initIds= formData.value.item!=undefined?formData.value.item.toString().split(","):[]
const rawSubjectIds =initIds.map((id) => Number(id))
if (rawSubjectIds.length != 0) {
let row = {
id: undefined
}
multipleTableRef.value.toggleRowSelection(row, true)
}
// 遍历数据,找到需要选中的行
list.value.forEach(row => {
let id = row.id;
if (rawSubjectIds.includes(row.id)) {
multipleTableRef.value.toggleRowSelection(row, true)
}
})
})
}
/** 初始化 **/
onMounted(async () => {
typeList.value = await ZjTypeApi.getZjTypeList()
getList()
})
</script>
<style scoped>
.formula-config-picklist {
display: flex;
width: 100%;
}
.formula-config-panel {
width: calc((100% - 96px) / 2);
overflow: hidden;
background: var(--el-bg-color);
border: 1px solid var(--el-border-color);
border-radius: 4px;
}
.formula-config-panel__header {
display: flex;
padding: 10px 12px;
font-weight: 600;
border-bottom: 1px solid var(--el-border-color);
justify-content: space-between;
}
.formula-config-panel__meta {
font-weight: 400;
color: var(--el-text-color-secondary);
}
.formula-config-panel__filter {
padding: 10px 12px;
border-bottom: 1px solid var(--el-border-color);
}
.formula-config-panel__table {
width: 100%;
}
.formula-config-actions {
display: flex;
width: 96px;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 12px;
}
</style>