|
|
|
|
@ -1,42 +1,26 @@
|
|
|
|
|
<template>
|
|
|
|
|
<ContentWrap>
|
|
|
|
|
<el-form
|
|
|
|
|
class="-mb-15px"
|
|
|
|
|
:model="queryParams"
|
|
|
|
|
ref="queryFormRef"
|
|
|
|
|
:inline="true"
|
|
|
|
|
label-width="68px"
|
|
|
|
|
>
|
|
|
|
|
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
|
|
|
|
<el-form-item label="配方编码" prop="recipeCode">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="queryParams.recipeCode"
|
|
|
|
|
placeholder="请输入配方编码"
|
|
|
|
|
clearable
|
|
|
|
|
@keyup.enter="handleQuery"
|
|
|
|
|
class="!w-240px"
|
|
|
|
|
/>
|
|
|
|
|
v-model="queryParams.recipeCode" placeholder="请输入配方编码" clearable @keyup.enter="handleQuery"
|
|
|
|
|
class="!w-240px" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="配方名称" prop="recipeName">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="queryParams.recipeName"
|
|
|
|
|
placeholder="请输入配方名称"
|
|
|
|
|
clearable
|
|
|
|
|
@keyup.enter="handleQuery"
|
|
|
|
|
class="!w-240px"
|
|
|
|
|
/>
|
|
|
|
|
v-model="queryParams.recipeName" placeholder="请输入配方名称" clearable @keyup.enter="handleQuery"
|
|
|
|
|
class="!w-240px" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="产品名称" prop="productName">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="queryParams.productName"
|
|
|
|
|
placeholder="请输入产品名称"
|
|
|
|
|
clearable
|
|
|
|
|
@keyup.enter="handleQuery"
|
|
|
|
|
class="!w-240px"
|
|
|
|
|
/>
|
|
|
|
|
v-model="queryParams.productName" placeholder="请输入产品名称" clearable @keyup.enter="handleQuery"
|
|
|
|
|
class="!w-240px" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 查询</el-button>
|
|
|
|
|
<el-button @click="handleQuery">
|
|
|
|
|
<Icon icon="ep:search" class="mr-5px" /> 查询
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button type="primary" plain @click="openDialog('create')">
|
|
|
|
|
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
|
|
|
|
</el-button>
|
|
|
|
|
@ -49,78 +33,60 @@
|
|
|
|
|
|
|
|
|
|
<ContentWrap>
|
|
|
|
|
<el-table
|
|
|
|
|
ref="tableRef"
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
:data="list"
|
|
|
|
|
:stripe="true"
|
|
|
|
|
:show-overflow-tooltip="true"
|
|
|
|
|
row-key="id"
|
|
|
|
|
@selection-change="handleSelectionChange"
|
|
|
|
|
>
|
|
|
|
|
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
|
|
|
|
|
highlight-current-row @selection-change="handleSelectionChange" @row-click="handleRowClick">
|
|
|
|
|
<el-table-column type="selection" width="55" reserve-selection />
|
|
|
|
|
<el-table-column label="配方编码" align="center" prop="recipeCode" />
|
|
|
|
|
<el-table-column label="配方名称" align="center" prop="recipeName" />
|
|
|
|
|
<el-table-column label="配方类型" align="center" prop="recipeType" />
|
|
|
|
|
<el-table-column label="配方类型" align="center" prop="recipeType">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ getRecipeTypeLabel(scope.row.recipeType) }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="关联产品" align="center" prop="productName" />
|
|
|
|
|
<el-table-column label="关联设备" align="center" prop="deviceName" />
|
|
|
|
|
<el-table-column label="备注" align="center" prop="remark" />
|
|
|
|
|
<el-table-column label="操作" align="center" width="240px" fixed="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-button link type="primary" @click="openConfigDialog(scope.row)">配置</el-button>
|
|
|
|
|
<el-button link type="info" @click="openDetail(scope.row)">详情</el-button>
|
|
|
|
|
<el-button link type="warning" @click="openDialog('update', scope.row)">编辑</el-button>
|
|
|
|
|
<el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
|
|
|
|
|
<el-button link type="primary" @click.stop="openConfigDialog(scope.row)">配置</el-button>
|
|
|
|
|
<el-button link type="warning" @click.stop="openDialog('update', scope.row)">编辑</el-button>
|
|
|
|
|
<el-button link type="danger" @click.stop="handleDelete(scope.row)">删除</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<Pagination
|
|
|
|
|
:total="total"
|
|
|
|
|
v-model:page="queryParams.pageNo"
|
|
|
|
|
v-model:limit="queryParams.pageSize"
|
|
|
|
|
@pagination="handlePagination"
|
|
|
|
|
/>
|
|
|
|
|
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
|
|
|
|
@pagination="handlePagination" />
|
|
|
|
|
</ContentWrap>
|
|
|
|
|
|
|
|
|
|
<ContentWrap v-if="detailVisible">
|
|
|
|
|
<div class="flex items-center justify-between mb-12px">
|
|
|
|
|
<div class="text-14px">
|
|
|
|
|
详情:{{ detailMeta.recipeCode }} - {{ detailMeta.recipeName }}
|
|
|
|
|
</div>
|
|
|
|
|
<el-button link type="info" @click="closeDetail">收起</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table
|
|
|
|
|
v-loading="detailLoading"
|
|
|
|
|
:data="detailList"
|
|
|
|
|
:stripe="true"
|
|
|
|
|
:show-overflow-tooltip="true"
|
|
|
|
|
row-key="id"
|
|
|
|
|
>
|
|
|
|
|
<el-table-column label="序号" align="center" width="80">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ (detailQueryParams.pageNo - 1) * detailQueryParams.pageSize + scope.$index + 1 }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="点位名称" align="center" prop="pointName" />
|
|
|
|
|
<el-table-column label="点位类型" align="center" prop="pointType" />
|
|
|
|
|
<el-table-column label="数据类型" align="center" prop="dataType" />
|
|
|
|
|
<el-table-column label="单位" align="center" prop="dataUnit" />
|
|
|
|
|
</el-table>
|
|
|
|
|
<Pagination
|
|
|
|
|
:total="detailTotal"
|
|
|
|
|
v-model:page="detailQueryParams.pageNo"
|
|
|
|
|
v-model:limit="detailQueryParams.pageSize"
|
|
|
|
|
@pagination="handleDetailPagination"
|
|
|
|
|
/>
|
|
|
|
|
<el-tabs v-model="detailActiveTab" class="mb-12px">
|
|
|
|
|
<template #extra>
|
|
|
|
|
<el-button link type="info" @click="closeDetail">收起</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
<el-tab-pane :label="`详情:${detailMeta.recipeCode} - ${detailMeta.recipeName}`" name="detail">
|
|
|
|
|
<el-table
|
|
|
|
|
v-loading="detailLoading" :data="detailList" :stripe="true" :show-overflow-tooltip="true"
|
|
|
|
|
row-key="id">
|
|
|
|
|
<el-table-column label="序号" align="center" width="80">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ (detailQueryParams.pageNo - 1) * detailQueryParams.pageSize + scope.$index + 1 }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="点位名称" align="center" prop="pointName" />
|
|
|
|
|
<el-table-column label="点位类型" align="center" prop="pointType" />
|
|
|
|
|
<el-table-column label="数据类型" align="center" prop="dataType" />
|
|
|
|
|
<el-table-column label="单位" align="center" prop="dataUnit" />
|
|
|
|
|
</el-table>
|
|
|
|
|
<Pagination
|
|
|
|
|
:total="detailTotal" v-model:page="detailQueryParams.pageNo"
|
|
|
|
|
v-model:limit="detailQueryParams.pageSize" @pagination="handleDetailPagination" />
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
</el-tabs>
|
|
|
|
|
</ContentWrap>
|
|
|
|
|
|
|
|
|
|
<Dialog :title="dialogTitle" v-model="dialogVisible" width="720px">
|
|
|
|
|
<el-form
|
|
|
|
|
ref="dialogFormRef"
|
|
|
|
|
:model="dialogForm"
|
|
|
|
|
:rules="dialogRules"
|
|
|
|
|
label-width="100px"
|
|
|
|
|
v-loading="dialogLoading"
|
|
|
|
|
>
|
|
|
|
|
<el-form ref="dialogFormRef" :model="dialogForm" :rules="dialogRules" label-width="100px" v-loading="dialogLoading">
|
|
|
|
|
<el-form-item label="配方编码" prop="recipeCode">
|
|
|
|
|
<el-input v-model="dialogForm.recipeCode" placeholder="请输入配方编码" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
@ -128,40 +94,24 @@
|
|
|
|
|
<el-input v-model="dialogForm.recipeName" placeholder="请输入配方名称" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="配方类型" prop="recipeType">
|
|
|
|
|
<el-input v-model="dialogForm.recipeType" placeholder="请输入配方类型" clearable />
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="dialogForm.recipeType" placeholder="请选择配方类型" clearable filterable class="!w-full"
|
|
|
|
|
:loading="recipeTypeLoading">
|
|
|
|
|
<el-option v-for="item in recipeTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="关联产品" prop="productId">
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="dialogForm.productId"
|
|
|
|
|
placeholder="请选择关联产品"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
class="!w-full"
|
|
|
|
|
:loading="productLoading"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in productOptions"
|
|
|
|
|
:key="item.value"
|
|
|
|
|
:label="item.label"
|
|
|
|
|
:value="item.value"
|
|
|
|
|
/>
|
|
|
|
|
v-model="dialogForm.productId" placeholder="请选择关联产品" clearable filterable class="!w-full"
|
|
|
|
|
:loading="productLoading">
|
|
|
|
|
<el-option v-for="item in productOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="关联设备" prop="deviceId">
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="dialogForm.deviceId"
|
|
|
|
|
placeholder="请选择关联设备"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
class="!w-full"
|
|
|
|
|
:loading="deviceLoading"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in deviceOptions"
|
|
|
|
|
:key="item.value"
|
|
|
|
|
:label="item.label"
|
|
|
|
|
:value="item.value"
|
|
|
|
|
/>
|
|
|
|
|
v-model="dialogForm.deviceId" placeholder="请选择关联设备" clearable filterable class="!w-full"
|
|
|
|
|
:loading="deviceLoading">
|
|
|
|
|
<el-option v-for="item in deviceOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="备注" prop="remark">
|
|
|
|
|
@ -177,11 +127,8 @@
|
|
|
|
|
<Dialog title="配置" v-model="configVisible" width="920px">
|
|
|
|
|
<div v-loading="configLoading">
|
|
|
|
|
<el-transfer
|
|
|
|
|
v-model="configSelectedKeys"
|
|
|
|
|
:data="configCandidates"
|
|
|
|
|
filterable
|
|
|
|
|
:titles="['候选点位', '已选点位']"
|
|
|
|
|
/>
|
|
|
|
|
class="formula-config-transfer" v-model="configSelectedKeys" :data="configCandidates" filterable
|
|
|
|
|
:titles="['来源', '目标']" />
|
|
|
|
|
</div>
|
|
|
|
|
<template #footer>
|
|
|
|
|
<el-button @click="configVisible = false">取 消</el-button>
|
|
|
|
|
@ -194,6 +141,7 @@
|
|
|
|
|
import download from '@/utils/download'
|
|
|
|
|
import { ProductApi } from '@/api/erp/product/product'
|
|
|
|
|
import { DeviceApi } from '@/api/iot/device'
|
|
|
|
|
import { RecipeApi } from '@/api/iot/recipe'
|
|
|
|
|
import { RecipeConfigApi, RecipeConfigVO, RecipePointDetailVO } from '@/api/iot/recipeConfig'
|
|
|
|
|
|
|
|
|
|
type SelectOption = { label: string; value: number }
|
|
|
|
|
@ -204,8 +152,6 @@ const message = useMessage()
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
const tableRef = ref()
|
|
|
|
|
const queryFormRef = ref()
|
|
|
|
|
const queryParams = reactive({
|
|
|
|
|
pageNo: 1,
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
@ -278,13 +224,15 @@ const handleDelete = async (row: RecipeConfigVO) => {
|
|
|
|
|
await RecipeConfigApi.deleteRecipeConfig(row.id)
|
|
|
|
|
message.success(t('common.delSuccess'))
|
|
|
|
|
await getList()
|
|
|
|
|
} catch {}
|
|
|
|
|
} catch { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const productLoading = ref(false)
|
|
|
|
|
const productOptions = ref<SelectOption[]>([])
|
|
|
|
|
const deviceLoading = ref(false)
|
|
|
|
|
const deviceOptions = ref<SelectOption[]>([])
|
|
|
|
|
const recipeTypeLoading = ref(false)
|
|
|
|
|
const recipeTypeOptions = ref<SelectOption[]>([])
|
|
|
|
|
|
|
|
|
|
const productLabelMap = computed<Record<number, string>>(() => {
|
|
|
|
|
return productOptions.value.reduce((acc, cur) => {
|
|
|
|
|
@ -300,6 +248,19 @@ const deviceLabelMap = computed<Record<number, string>>(() => {
|
|
|
|
|
}, {} as Record<number, string>)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const recipeTypeLabelMap = computed<Record<number, string>>(() => {
|
|
|
|
|
return recipeTypeOptions.value.reduce((acc, cur) => {
|
|
|
|
|
acc[cur.value] = cur.label
|
|
|
|
|
return acc
|
|
|
|
|
}, {} as Record<number, string>)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const getRecipeTypeLabel = (value: unknown) => {
|
|
|
|
|
const num = Number(value)
|
|
|
|
|
if (!Number.isNaN(num) && recipeTypeLabelMap.value[num]) return recipeTypeLabelMap.value[num]
|
|
|
|
|
return (value as any) ?? ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getProductOptions = async () => {
|
|
|
|
|
productLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
@ -320,9 +281,23 @@ const getDeviceOptions = async () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getRecipeTypeOptions = async () => {
|
|
|
|
|
recipeTypeLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const data = await RecipeApi.getRecipePage(undefined)
|
|
|
|
|
recipeTypeOptions.value = (data?.list ?? []).map((item: any) => ({
|
|
|
|
|
label: item.name,
|
|
|
|
|
value: item.id
|
|
|
|
|
}))
|
|
|
|
|
} finally {
|
|
|
|
|
recipeTypeLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ensureOptionsLoaded = async () => {
|
|
|
|
|
if (!productOptions.value.length) await getProductOptions()
|
|
|
|
|
if (!deviceOptions.value.length) await getDeviceOptions()
|
|
|
|
|
if (!recipeTypeOptions.value.length) await getRecipeTypeOptions()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type DialogMode = 'create' | 'update'
|
|
|
|
|
@ -335,7 +310,7 @@ const dialogForm = reactive({
|
|
|
|
|
id: undefined as number | undefined,
|
|
|
|
|
recipeCode: '',
|
|
|
|
|
recipeName: '',
|
|
|
|
|
recipeType: '',
|
|
|
|
|
recipeType: undefined as number | undefined,
|
|
|
|
|
productId: undefined as number | undefined,
|
|
|
|
|
deviceId: undefined as number | undefined,
|
|
|
|
|
remark: ''
|
|
|
|
|
@ -358,7 +333,7 @@ const openDialog = async (mode: DialogMode, row?: RecipeConfigVO) => {
|
|
|
|
|
dialogForm.id = undefined
|
|
|
|
|
dialogForm.recipeCode = ''
|
|
|
|
|
dialogForm.recipeName = ''
|
|
|
|
|
dialogForm.recipeType = ''
|
|
|
|
|
dialogForm.recipeType = undefined
|
|
|
|
|
dialogForm.productId = undefined
|
|
|
|
|
dialogForm.deviceId = undefined
|
|
|
|
|
dialogForm.remark = ''
|
|
|
|
|
@ -368,7 +343,7 @@ const openDialog = async (mode: DialogMode, row?: RecipeConfigVO) => {
|
|
|
|
|
dialogForm.id = row?.id
|
|
|
|
|
dialogForm.recipeCode = row?.recipeCode ?? ''
|
|
|
|
|
dialogForm.recipeName = row?.recipeName ?? ''
|
|
|
|
|
dialogForm.recipeType = row?.recipeType ?? ''
|
|
|
|
|
dialogForm.recipeType = typeof row?.recipeType === 'number' ? row.recipeType : Number(row?.recipeType) || undefined
|
|
|
|
|
dialogForm.productId = row?.productId
|
|
|
|
|
dialogForm.deviceId = row?.deviceId
|
|
|
|
|
dialogForm.remark = row?.remark ?? ''
|
|
|
|
|
@ -405,6 +380,7 @@ const submitDialog = async () => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const detailVisible = ref(false)
|
|
|
|
|
const detailActiveTab = ref('detail')
|
|
|
|
|
const detailLoading = ref(false)
|
|
|
|
|
const detailList = ref<RecipePointDetailVO[]>([])
|
|
|
|
|
const detailTotal = ref(0)
|
|
|
|
|
@ -442,11 +418,19 @@ const openDetail = async (row: RecipeConfigVO) => {
|
|
|
|
|
detailQueryParams.recipeId = row.id
|
|
|
|
|
detailQueryParams.pageNo = 1
|
|
|
|
|
detailVisible.value = true
|
|
|
|
|
detailActiveTab.value = 'detail'
|
|
|
|
|
await getDetailList()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleRowClick = async (row: RecipeConfigVO, column: any) => {
|
|
|
|
|
if (column?.type === 'selection') return
|
|
|
|
|
if (column?.label === '操作') return
|
|
|
|
|
await openDetail(row)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const closeDetail = () => {
|
|
|
|
|
detailVisible.value = false
|
|
|
|
|
detailActiveTab.value = 'detail'
|
|
|
|
|
detailMeta.recipeId = undefined
|
|
|
|
|
detailMeta.recipeCode = ''
|
|
|
|
|
detailMeta.recipeName = ''
|
|
|
|
|
@ -518,4 +502,21 @@ onMounted(() => {
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped></style>
|
|
|
|
|
<style scoped>
|
|
|
|
|
:deep(.formula-config-transfer.el-transfer) {
|
|
|
|
|
--el-transfer-panel-body-height: 440px;
|
|
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.formula-config-transfer .el-transfer-panel) {
|
|
|
|
|
width: calc((100% - 96px) / 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-transfer__buttons) {
|
|
|
|
|
display: flex;
|
|
|
|
|
text-align: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|