fix(mes): 工艺路线前端 TODO 修复:状态按钮化、MdItemSelect、字段优化

- index.vue 状态操作改为按钮,启用后禁用「禁用」和「删除」按钮
- RouteProcessList 前3列 fixed、label 改名、布尔字段用 dict-tag、颜色显示 hex 值
- RouteProductList/RouteProductBomList 物料选择改用 MdItemSelect 组件
- RouteProductList BOM 弹窗移入产品编辑表单,动态宽度
- RouteProductBomList label 改名、processId 类型修复
pull/871/MERGE
YunaiV 2026-02-19 18:45:50 +08:00
parent 1c0cbc0dc6
commit 112e24f97d
7 changed files with 148 additions and 118 deletions

View File

@ -1,8 +1,11 @@
<!-- MES 排班管理-班组成员 列表 -->
<template>
<div>
<!-- 操作栏 -->
<el-button type="primary" plain size="small" @click="openForm()" class="mb-10px">
<Icon icon="ep:plus" class="mr-5px" /> 添加成员
</el-button>
<!-- 列表 -->
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" border>
<el-table-column label="用户编号" align="center" prop="userId" width="100" />
<el-table-column label="用户昵称" align="center" prop="nickname" min-width="120" />
@ -15,7 +18,39 @@
</el-table-column>
</el-table>
<CalTeamMemberForm ref="formRef" @success="getList" />
<!-- 表单弹窗添加 -->
<Dialog title="添加成员" v-model="dialogVisible" width="500px">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="80px"
v-loading="formLoading"
>
<el-form-item label="用户" prop="userId">
<el-select
v-model="formData.userId"
placeholder="请选择用户"
filterable
class="!w-1/1"
>
<el-option
v-for="user in userList"
:key="user.id"
:label="user.nickname"
:value="user.id"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</div>
</template>
@ -24,17 +59,19 @@ import { CalTeamMemberApi, CalTeamMemberVO } from '@/api/mes/cal/team/member'
import { getSimpleUserList } from '@/api/system/user'
import type { UserVO } from '@/api/system/user'
defineOptions({ name: 'CalTeamMemberList' })
const props = defineProps<{
teamId: number //
}>()
const message = useMessage()
const { t } = useI18n() //
const message = useMessage() //
const loading = ref(false)
const list = ref<CalTeamMemberVO[]>([])
const formRef = ref<InstanceType<typeof CalTeamMemberForm>>()
const loading = ref(false) //
const list = ref<CalTeamMemberVO[]>([]) //
/** 加载列表 */
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
@ -44,9 +81,43 @@ const getList = async () => {
}
}
/** 打开添加弹窗 */
const openForm = () => {
formRef.value?.open(props.teamId)
// ==================== / ====================
const dialogVisible = ref(false) //
const formLoading = ref(false) //
const formRef = ref() // Ref
const userList = ref<UserVO[]>([]) //
const formData = ref({
teamId: undefined as number | undefined,
userId: undefined as number | undefined,
remark: undefined as string | undefined
})
const formRules = reactive({
userId: [{ required: true, message: '用户不能为空', trigger: 'change' }]
})
/** 打开表单弹窗 */
const openForm = async () => {
dialogVisible.value = true
formData.value = { teamId: props.teamId, userId: undefined, remark: undefined }
formRef.value?.resetFields()
userList.value = await getSimpleUserList()
}
/** 提交表单 */
const submitForm = async () => {
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
formLoading.value = true
try {
await CalTeamMemberApi.createTeamMember(formData.value as unknown as CalTeamMemberVO)
message.success(t('common.createSuccess'))
dialogVisible.value = false
//
await getList()
} finally {
formLoading.value = false
}
}
/** 删除 */
@ -59,6 +130,7 @@ const handleDelete = async (id: number) => {
} catch {}
}
/** 监听 teamId 变化,加载列表 */
watch(
() => props.teamId,
(val) => {

View File

@ -9,27 +9,23 @@
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="序号" align="center" prop="sort" width="70" />
<el-table-column label="工序编码" align="center" prop="processCode" width="120" />
<el-table-column label="工序名称" align="center" prop="processName" width="120" />
<el-table-column label="序号" align="center" prop="sort" width="70" fixed="left" />
<el-table-column label="工序编码" align="center" prop="processCode" width="120" fixed="left" />
<el-table-column label="工序名称" align="center" prop="processName" width="120" fixed="left" />
<el-table-column label="下一道工序" align="center" prop="nextProcessName" width="120" />
<el-table-column label="工序关系" align="center" prop="linkType" width="130">
<el-table-column label="与下一道工序关系" align="center" prop="linkType" width="150">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_PRO_LINK_TYPE" :value="scope.row.linkType" />
</template>
</el-table-column>
<el-table-column label="关键工序" align="center" prop="keyFlag" width="80">
<template #default="scope">
<el-tag :type="scope.row.keyFlag ? 'danger' : 'info'" size="small">
{{ scope.row.keyFlag ? '是' : '否' }}
</el-tag>
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.keyFlag" />
</template>
</el-table-column>
<el-table-column label="质检工序" align="center" prop="checkFlag" width="80">
<template #default="scope">
<el-tag :type="scope.row.checkFlag ? 'warning' : 'info'" size="small">
{{ scope.row.checkFlag ? '是' : '否' }}
</el-tag>
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.checkFlag" />
</template>
</el-table-column>
<el-table-column label="准备时间" align="center" prop="prepareTime" width="90">
@ -42,18 +38,19 @@
{{ scope.row.waitTime ? scope.row.waitTime + '分钟' : '' }}
</template>
</el-table-column>
<el-table-column label="颜色" align="center" prop="colorCode" width="70">
<el-table-column label="颜色" align="center" prop="colorCode" width="100">
<template #default="scope">
<div
v-if="scope.row.colorCode"
:style="{
backgroundColor: scope.row.colorCode,
width: '20px',
height: '20px',
borderRadius: '4px',
margin: '0 auto'
}"
></div>
<div v-if="scope.row.colorCode" style="display: flex; align-items: center; justify-content: center; gap: 4px">
<div
:style="{
backgroundColor: scope.row.colorCode,
width: '16px',
height: '16px',
borderRadius: '4px'
}"
></div>
<span>{{ scope.row.colorCode }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="130" fixed="right">
@ -65,7 +62,7 @@
</el-table>
<!-- 表单弹窗添加/修改 -->
<Dialog :title="formTitle" v-model="formVisible" width="600px">
<Dialog :title="formTitle" v-model="formVisible" width="960px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
@ -88,7 +85,7 @@
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="工序关系" prop="linkType">
<el-form-item label="与下道工序关系" prop="linkType">
<el-select v-model="formData.linkType" placeholder="请选择">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.MES_PRO_LINK_TYPE)"
@ -101,7 +98,10 @@
</el-col>
<el-col :span="12">
<el-form-item label="颜色" prop="colorCode">
<el-color-picker v-model="formData.colorCode" />
<div style="display: flex; align-items: center; gap: 8px">
<el-color-picker v-model="formData.colorCode" />
<span v-if="formData.colorCode">{{ formData.colorCode }}</span>
</div>
</el-form-item>
</el-col>
</el-row>

View File

@ -17,8 +17,8 @@
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="bomList" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="物料编码" align="center" prop="itemCode" width="150" />
<el-table-column label="物料名称" align="center" prop="itemName" width="150" />
<el-table-column label="BOM 物料编码" align="center" prop="itemCode" width="150" />
<el-table-column label="BOM 物料名称" align="center" prop="itemName" width="150" />
<el-table-column label="规格型号" align="center" prop="specification" width="150" />
<el-table-column label="单位" align="center" prop="unitName" width="80" />
<el-table-column label="用料比例" align="center" prop="quantity" width="100" />
@ -35,14 +35,7 @@
<Dialog :title="formTitle" v-model="formVisible" width="500px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-form-item label="BOM 物料" prop="itemId">
<el-select v-model="formData.itemId" placeholder="请选择 BOM 物料" filterable>
<el-option
v-for="item in itemList"
:key="item.id"
:label="item.name + (item.code ? ' (' + item.code + ')' : '')"
:value="item.id"
/>
</el-select>
<MdItemSelect v-model="formData.itemId" placeholder="请选择 BOM 物料" />
</el-form-item>
<el-form-item label="用料比例" prop="quantity">
<el-input-number
@ -67,7 +60,7 @@
<script setup lang="ts">
import { ProRouteProductBomApi, ProRouteProductBomVO } from '@/api/mes/pro/route/productbom'
import { ProRouteProcessApi } from '@/api/mes/pro/route/process'
import { MdItemApi } from '@/api/mes/md/item'
import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue'
defineOptions({ name: 'RouteProductBomList' })
@ -84,7 +77,6 @@ const loading = ref(false) // 列表的加载中
const bomList = ref<ProRouteProductBomVO[]>([]) // BOM
const processList = ref<any[]>([]) // Tab
const activeProcessId = ref('') // Tab
const itemList = ref<any[]>([]) //
//
const formVisible = ref(false) //
@ -113,10 +105,9 @@ const getBomList = async () => {
if (!activeProcessId.value) return
loading.value = true
try {
// TODO @AIlinter
bomList.value = await ProRouteProductBomApi.getRouteProductBomList({
routeId: props.routeId,
processId: activeProcessId.value,
processId: Number(activeProcessId.value),
productId: props.productId
})
} finally {
@ -129,11 +120,6 @@ const handleTabChange = () => {
getBomList()
}
/** 加载物料列表 */
const loadItemList = async () => {
itemList.value = await MdItemApi.getItemSimpleList()
}
/** 添加/修改操作 */
const openForm = (type: string, row?: ProRouteProductBomVO) => {
formVisible.value = true
@ -185,6 +171,5 @@ const handleDelete = async (id: number) => {
/** 初始化 */
onMounted(() => {
loadProcessList()
loadItemList()
})
</script>

View File

@ -9,8 +9,8 @@
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="产品编码" align="center" prop="itemCode" width="150" />
<el-table-column label="产品名称" align="center" prop="itemName" width="150" />
<el-table-column label="产品物料编码" align="center" prop="itemCode" width="150" />
<el-table-column label="产品物料名称" align="center" prop="itemName" width="150" />
<el-table-column label="规格型号" align="center" prop="specification" width="150" />
<el-table-column label="单位" align="center" prop="unitName" width="80" />
<el-table-column label="生产数量" align="center" prop="quantity" width="100" />
@ -23,9 +23,8 @@
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="120" />
<el-table-column label="操作" align="center" width="180" fixed="right">
<el-table-column label="操作" align="center" width="130" fixed="right">
<template #default="scope">
<el-button link type="primary" @click="openBomDialog(scope.row)">BOM</el-button>
<el-button link type="primary" @click="openForm('update', scope.row)">编辑</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)"></el-button>
</template>
@ -33,17 +32,10 @@
</el-table>
<!-- 表单弹窗添加/修改 -->
<Dialog :title="formTitle" v-model="formVisible" width="500px">
<Dialog :title="formTitle" v-model="formVisible" width="960px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-form-item label="产品" prop="itemId">
<el-select v-model="formData.itemId" placeholder="请选择产品" filterable>
<el-option
v-for="item in itemList"
:key="item.id"
:label="item.name + (item.code ? ' (' + item.code + ')' : '')"
:value="item.id"
/>
</el-select>
<MdItemSelect v-model="formData.itemId" />
</el-form-item>
<el-form-item label="生产数量" prop="quantity">
<el-input-number v-model="formData.quantity" :min="1" controls-position="right" />
@ -76,28 +68,27 @@
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<!-- 编辑时展示产品 BOM 配置 -->
<template v-if="formType === 'update' && formData.id">
<el-divider content-position="left">产品 BOM 配置</el-divider>
<RouteProductBomList
:routeId="routeId"
:productId="formData.itemId"
:productName="formData.itemName"
/>
</template>
<template #footer>
<el-button @click="formVisible = false"> </el-button>
<el-button type="primary" @click="submitForm" :loading="formLoading"> </el-button>
</template>
</Dialog>
<!-- 产品 BOM 弹窗 -->
<Dialog title="产品 BOM 配置" v-model="bomDialogVisible" width="800px">
<RouteProductBomList
v-if="bomDialogVisible"
:routeId="routeId"
:productId="currentProduct.itemId"
:productName="currentProduct.itemName"
/>
</Dialog>
</div>
</template>
<script setup lang="ts">
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { ProRouteProductApi, ProRouteProductVO } from '@/api/mes/pro/route/product'
import { MdItemApi } from '@/api/mes/md/item'
import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue'
import RouteProductBomList from './RouteProductBomList.vue'
defineOptions({ name: 'RouteProductList' })
@ -111,7 +102,6 @@ const { t } = useI18n() // 国际化
const loading = ref(false) //
const list = ref<ProRouteProductVO[]>([]) //
const itemList = ref<any[]>([]) //
//
const formVisible = ref(false) //
@ -124,10 +114,6 @@ const formRules = reactive({
itemId: [{ required: true, message: '产品不能为空', trigger: 'change' }]
})
// BOM
const bomDialogVisible = ref(false) // BOM
const currentProduct = ref<any>({}) //
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -138,11 +124,6 @@ const getList = async () => {
}
}
/** 加载物料列表 */
const loadItemList = async () => {
itemList.value = await MdItemApi.getItemSimpleList()
}
/** 添加/修改操作 */
const openForm = (type: string, row?: ProRouteProductVO) => {
formVisible.value = true
@ -191,12 +172,6 @@ const handleDelete = async (id: number) => {
} catch {}
}
/** 打开 BOM 弹窗 */
const openBomDialog = (row: ProRouteProductVO) => {
currentProduct.value = row
bomDialogVisible.value = true
}
/** 监听路线编号变化 */
watch(
() => props.routeId,
@ -208,8 +183,4 @@ watch(
{ immediate: true }
)
/** 初始化 */
onMounted(() => {
loadItemList()
})
</script>

View File

@ -69,13 +69,7 @@
<el-table-column label="路线说明" align="center" prop="description" min-width="200" />
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="scope">
<el-switch
v-model="scope.row.status"
:active-value="0"
:inactive-value="1"
@change="handleStatusChange(scope.row)"
:disabled="!checkPermi(['mes:pro-route:update'])"
/>
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="120" />
@ -86,10 +80,8 @@
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" width="150">
<el-table-column label="操作" align="center" width="220">
<template #default="scope">
<!-- TODO @AI开启和关闭还是做成按钮好一点 -->
<!-- TODO @AI开启后不允许关闭删除前后端都要限制关联表都要限制 -->
<el-button
link
type="primary"
@ -98,11 +90,20 @@
>
编辑
</el-button>
<el-button
link
:type="scope.row.status === CommonStatusEnum.ENABLE ? 'warning' : 'success'"
@click="handleStatusChange(scope.row)"
v-hasPermi="['mes:pro-route:update']"
>
{{ scope.row.status === CommonStatusEnum.ENABLE ? '禁用' : '启用' }}
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['mes:pro-route:delete']"
:disabled="scope.row.status === CommonStatusEnum.ENABLE"
>
删除
</el-button>
@ -126,7 +127,6 @@
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import { CommonStatusEnum } from '@/utils/constants'
import { checkPermi } from '@/utils/permission'
import download from '@/utils/download'
import { ProRouteApi, ProRouteVO } from '@/api/mes/pro/route'
import RouteForm from './RouteForm.vue'
@ -182,25 +182,28 @@ const openForm = (type: string, id?: number) => {
/** 修改工艺路线状态 */
const handleStatusChange = async (row: ProRouteVO) => {
try {
//
const newStatus =
row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
const text = newStatus === CommonStatusEnum.ENABLE ? '启用' : '停用'
//
const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
await message.confirm('确认要"' + text + '""' + row.name + '"工艺路线吗?')
//
await ProRouteApi.updateRouteStatus(row.id!, row.status)
await ProRouteApi.updateRouteStatus(row.id!, newStatus)
message.success(text + '成功')
//
await getList()
} catch {
//
row.status =
row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
}
} catch {}
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await ProRouteApi.deleteRoute(id)
//
message.success(t('common.delSuccess'))
await getList()
} catch {}
@ -213,7 +216,6 @@ const handleExport = async () => {
exportLoading.value = true
const data = await ProRouteApi.exportRoute(queryParams)
download.excel(data, '工艺路线.xls')
} catch {
} finally {
exportLoading.value = false
}

View File

@ -1,7 +1,7 @@
<!-- MES 质检方案-检测指标项 子列表 -->
<template>
<div>
<!-- 操作按钮 -->
<!-- 操作 -->
<el-row class="mb-10px">
<el-button
type="primary"

View File

@ -1,7 +1,7 @@
<!-- MES 质检方案-产品关联 子列表 -->
<template>
<div>
<!-- 操作按钮 -->
<!-- 操作 -->
<el-row class="mb-10px">
<el-button
type="primary"