| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # ç©æä¸»æ°æ®æ¨¡å (MDM) åç«¯åæ´ææ¡£ |
| | | |
| | | ## ä¸ãæ°å¢é¡µé¢ |
| | | |
| | | ### 1.1 ç©æä¸»æ°æ®ç®¡ç |
| | | |
| | | #### æ¶åé¡µé¢ |
| | | |
| | | - ç©æå表页 (`views/mdm/item/index.vue`) |
| | | - ç©ææ°å¢/ç¼è¾å¼¹çª (`views/mdm/item/ItemForm.vue`) |
| | | - ç©æè¯¦æ
页 (`views/mdm/item/detail.vue`) |
| | | |
| | | #### API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /mdm/item/page | ç©æå页æ¥è¯¢ | |
| | | | GET | /mdm/item/list | ç©æå表æ¥è¯¢ | |
| | | | GET | /mdm/item/get | è·åç©æè¯¦æ
| |
| | | | POST | /mdm/item/create | åå»ºç©æ | |
| | | | PUT | /mdm/item/update | æ´æ°ç©æ | |
| | | | DELETE | /mdm/item/delete | å é¤ç©æ | |
| | | | PUT | /mdm/item/update-status | æ´æ°ç©æç¶æ | |
| | | |
| | | **请æ±åæ°ï¼ç©ææ¥è¯¢ï¼ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | code | String | å¦ | ç©æç¼ç | |
| | | | name | String | å¦ | ç©æåç§° | |
| | | | categoryId | Long | å¦ | åç±»ID | |
| | | | itemType | Integer | å¦ | ç©æç±»å(1:åæ,2:åæå,3:æå,4:è¾
æ) | |
| | | | status | Integer | å¦ | ç¶æ | |
| | | |
| | | **ååºï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "data": { |
| | | "list": [ |
| | | { |
| | | "id": 1, |
| | | "code": "M001", |
| | | "name": "ç©æåç§°", |
| | | "barCode": "æ¡ç ", |
| | | "specification": "è§æ ¼åå·", |
| | | "categoryId": 10, |
| | | "categoryName": "åç±»åç§°", |
| | | "unitMeasureId": 1, |
| | | "unitMeasureName": "åä½åç§°", |
| | | "brandId": 1, |
| | | "brandName": "åçåç§°", |
| | | "itemType": 1, |
| | | "status": 0, |
| | | "purchasePrice": 100.00, |
| | | "salesPrice": 150.00, |
| | | "costPrice": 80.00, |
| | | "safetyStock": 50.00, |
| | | "minStock": 20.00, |
| | | "maxStock": 200.00, |
| | | "isBatchManaged": true, |
| | | "expiryDay": 365, |
| | | "remark": "夿³¨" |
| | | } |
| | | ], |
| | | "total": 100 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | #### å端修æ¹ç¹ |
| | | |
| | | **1. ç©æå表页é¢ç»æï¼** |
| | | |
| | | ```html |
| | | <template> |
| | | <ContentWrap> |
| | | <!-- æç´¢åºå --> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true"> |
| | | <el-form-item label="ç©æç¼ç " prop="code"> |
| | | <el-input v-model="queryParams.code" placeholder="请è¾å
¥ç©æç¼ç " /> |
| | | </el-form-item> |
| | | <el-form-item label="ç©æåç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥ç©æåç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç©æåç±»" prop="categoryId"> |
| | | <el-tree-select v-model="queryParams.categoryId" :data="categoryTree" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç©æç±»å" prop="itemType"> |
| | | <el-select v-model="queryParams.itemType" placeholder="è¯·éæ©ç©æç±»å"> |
| | | <el-option label="åæ" :value="1" /> |
| | | <el-option label="åæå" :value="2" /> |
| | | <el-option label="æå" :value="3" /> |
| | | <el-option label="è¾
æ" :value="4" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery">æç´¢</el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- æä½æé® --> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain @click="handleCreate">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- è¡¨æ ¼ --> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column label="ç©æç¼ç " prop="code" width="120" /> |
| | | <el-table-column label="ç©æåç§°" prop="name" width="180" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specification" width="150" /> |
| | | <el-table-column label="åç±»" prop="categoryName" width="100" /> |
| | | <el-table-column label="åä½" prop="unitMeasureName" width="80" /> |
| | | <el-table-column label="ç©æç±»å" prop="itemType" width="80"> |
| | | <template #default="{ row }"> |
| | | <dict-tag :type="DICT_TYPE.MDM_ITEM_TYPE" :value="row.itemType" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="éè´ä»·" prop="purchasePrice" width="100" /> |
| | | <el-table-column label="éå®ä»·" prop="salesPrice" width="100" /> |
| | | <el-table-column label="æ¹æ¬¡ç®¡ç" prop="isBatchManaged" width="80"> |
| | | <template #default="{ row }"> |
| | | <el-tag v-if="row.isBatchManaged" type="success">æ¯</el-tag> |
| | | <el-tag v-else type="info">å¦</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¶æ" prop="status" width="80"> |
| | | <template #default="{ row }"> |
| | | <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="180" fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button link type="primary" @click="handleUpdate(row)">ç¼è¾</el-button> |
| | | <el-button link type="danger" @click="handleDelete(row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页 --> |
| | | <Pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | </ContentWrap> |
| | | </template> |
| | | ``` |
| | | |
| | | **2. ç©æè¡¨åå¼¹çªï¼** |
| | | |
| | | ```html |
| | | <el-dialog v-model="dialogVisible" title="ç©æä¿¡æ¯" width="800px"> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç©æç¼ç " prop="code"> |
| | | <el-input v-model="formData.code" placeholder="请è¾å
¥ç©æç¼ç " /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç©æåç§°" prop="name"> |
| | | <el-input v-model="formData.name" placeholder="请è¾å
¥ç©æåç§°" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¡ç " prop="barCode"> |
| | | <el-input v-model="formData.barCode" placeholder="请è¾å
¥æ¡ç " /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è§æ ¼åå·" prop="specification"> |
| | | <el-input v-model="formData.specification" placeholder="请è¾å
¥è§æ ¼åå·" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç©æåç±»" prop="categoryId"> |
| | | <el-tree-select v-model="formData.categoryId" :data="categoryTree" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="计éåä½" prop="unitMeasureId"> |
| | | <el-select v-model="formData.unitMeasureId" placeholder="è¯·éæ©åä½"> |
| | | <el-option v-for="unit in unitList" :key="unit.id" :label="unit.name" :value="unit.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åç" prop="brandId"> |
| | | <el-select v-model="formData.brandId" placeholder="è¯·éæ©åç"> |
| | | <el-option v-for="brand in brandList" :key="brand.id" :label="brand.name" :value="brand.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç©æç±»å" prop="itemType"> |
| | | <el-select v-model="formData.itemType" placeholder="è¯·éæ©ç©æç±»å"> |
| | | <el-option label="åæ" :value="1" /> |
| | | <el-option label="åæå" :value="2" /> |
| | | <el-option label="æå" :value="3" /> |
| | | <el-option label="è¾
æ" :value="4" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- ä»·æ ¼ä¿¡æ¯ --> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="éè´ä»·" prop="purchasePrice"> |
| | | <el-input-number v-model="formData.purchasePrice" :precision="2" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="éå®ä»·" prop="salesPrice"> |
| | | <el-input-number v-model="formData.salesPrice" :precision="2" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="ææ¬ä»·" prop="costPrice"> |
| | | <el-input-number v-model="formData.costPrice" :precision="2" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- åºå管ç --> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å®å
¨åºå" prop="safetyStock"> |
| | | <el-input-number v-model="formData.safetyStock" :precision="2" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¹æ¬¡ç®¡ç" prop="isBatchManaged"> |
| | | <el-switch v-model="formData.isBatchManaged" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="formData.remark" type="textarea" :rows="3" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | ``` |
| | | |
| | | **3. æ°æ®å®ä¹ï¼** |
| | | |
| | | ```js |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import * as ItemApi from '@/api/mdm/item' |
| | | |
| | | const loading = ref(false) |
| | | const list = ref([]) |
| | | const total = ref(0) |
| | | const queryParams = reactive({ |
| | | pageNo: 1, |
| | | pageSize: 10, |
| | | code: '', |
| | | name: '', |
| | | categoryId: null, |
| | | itemType: null, |
| | | status: null |
| | | }) |
| | | |
| | | const dialogVisible = ref(false) |
| | | const formData = ref({ |
| | | id: undefined, |
| | | code: '', |
| | | name: '', |
| | | barCode: '', |
| | | specification: '', |
| | | categoryId: null, |
| | | unitMeasureId: null, |
| | | brandId: null, |
| | | itemType: 1, |
| | | purchasePrice: null, |
| | | salesPrice: null, |
| | | costPrice: null, |
| | | safetyStock: null, |
| | | isBatchManaged: false, |
| | | remark: '' |
| | | }) |
| | | |
| | | const getList = async () => { |
| | | loading.value = true |
| | | try { |
| | | const data = await ItemApi.getItemPage(queryParams) |
| | | list.value = data.list |
| | | total.value = data.total |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | const handleCreate = () => { |
| | | formData.value = { ...initialFormData } |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | const handleUpdate = (row) => { |
| | | formData.value = { ...row } |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | const submitForm = async () => { |
| | | await formRef.value.validate() |
| | | if (formData.value.id) { |
| | | await ItemApi.updateItem(formData.value) |
| | | } else { |
| | | await ItemApi.createItem(formData.value) |
| | | } |
| | | dialogVisible.value = false |
| | | getList() |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### 1.2 ç©æå类管ç |
| | | |
| | | #### æ¶åé¡µé¢ |
| | | |
| | | - ç©æå类管ç页 (`views/mdm/category/index.vue`) |
| | | |
| | | #### API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /mdm/category/list | åç±»å表æ¥è¯¢ | |
| | | | GET | /mdm/category/get | è·åå类详æ
| |
| | | | POST | /mdm/category/create | å建åç±» | |
| | | | PUT | /mdm/category/update | æ´æ°åç±» | |
| | | | DELETE | /mdm/category/delete | å é¤åç±» | |
| | | |
| | | --- |
| | | |
| | | ### 1.3 计éåä½ç®¡ç |
| | | |
| | | #### æ¶åé¡µé¢ |
| | | |
| | | - 计éåä½ç®¡ç页 (`views/mdm/unit/index.vue`) |
| | | |
| | | #### API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /mdm/unit/page | åä½å页æ¥è¯¢ | |
| | | | GET | /mdm/unit/list | åä½å表æ¥è¯¢ | |
| | | | POST | /mdm/unit/create | å建åä½ | |
| | | | PUT | /mdm/unit/update | æ´æ°åä½ | |
| | | | DELETE | /mdm/unit/delete | å é¤åä½ | |
| | | |
| | | --- |
| | | |
| | | ### 1.4 åç管ç |
| | | |
| | | #### æ¶åé¡µé¢ |
| | | |
| | | - åç管ç页 (`views/mdm/brand/index.vue`) |
| | | |
| | | #### API |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /mdm/brand/page | åçå页æ¥è¯¢ | |
| | | | GET | /mdm/brand/list | åçå表æ¥è¯¢ | |
| | | | POST | /mdm/brand/create | å建åç | |
| | | | PUT | /mdm/brand/update | æ´æ°åç | |
| | | | DELETE | /mdm/brand/delete | å é¤åç | |
| | | |
| | | --- |
| | | |
| | | ## äºãä¿®æ¹é¡µé¢ |
| | | |
| | | ### 2.1 ERP 产å管çé¡µé¢ |
| | | |
| | | #### ä¿®æ¹å
容 |
| | | |
| | | **å页é¢**ï¼`views/erp/product/index.vue` |
| | | |
| | | **ä¿®æ¹ç¹**ï¼ |
| | | 1. API æ¥å£ä» `/erp/product/*` æ¹ä¸ºè°ç¨ `/mdm/item/*` |
| | | 2. æ°æ®å段æ å°è°æ´ï¼`productId` â `itemId`ï¼ |
| | | 3. å¢å ç©æç±»åçéï¼åæ/åæå/æå/è¾
æï¼ |
| | | |
| | | **注æäºé¡¹**ï¼ |
| | | - ERP 产å页颿°æ®æ¥æºä» MDM ç©æè·å |
| | | - ä¿ç ERP ç¹æåæ®µï¼éè´ä»·ãéå®ä»·ãæä½ä»·ï¼çç¼è¾è½å |
| | | |
| | | --- |
| | | |
| | | ### 2.2 MES ç©æç®¡çé¡µé¢ |
| | | |
| | | #### ä¿®æ¹å
容 |
| | | |
| | | **å页é¢**ï¼`views/mes/md/item/index.vue` |
| | | |
| | | **ä¿®æ¹ç¹**ï¼ |
| | | 1. API æ¥å£ä» `/mes/md-item/*` æ¹ä¸ºè°ç¨ `/mdm/item/*` |
| | | 2. æ°æ®å段æ å°è°æ´ï¼`itemTypeId` â `categoryId`ï¼ |
| | | 3. æ¹æ¬¡é
ç½®ä»ç¬ç«é¡µé¢æ¹ä¸ºç©æè¯¦æ
页忍¡å |
| | | |
| | | **注æäºé¡¹**ï¼ |
| | | - MES ç©æé¡µé¢æ°æ®æ¥æºä» MDM ç©æè·å |
| | | - æ¹æ¬¡å±æ§é
ç½®ä¿çå¨ MDM 模å管ç |
| | | |
| | | --- |
| | | |
| | | ### 2.3 WMS åå管çé¡µé¢ |
| | | |
| | | #### ä¿®æ¹å
容 |
| | | |
| | | **å页é¢**ï¼`views/wms/item/index.vue` |
| | | |
| | | **ä¿®æ¹ç¹**ï¼ |
| | | 1. API æ¥å£ä» `/wms/item/*` æ¹ä¸ºè°ç¨ `/mdm/item/*` |
| | | 2. SKU ç®¡çæ¹ä¸ºç©æè¯¦æ
页忍¡å |
| | | 3. åºåæ¥è¯¢æ¹ç¨ç»ä¸æ¥å£ `/wms/stock/*` |
| | | |
| | | **注æäºé¡¹**ï¼ |
| | | - WMS åå页颿°æ®æ¥æºä» MDM ç©æè·å |
| | | - SKU ä½ä¸ºç©æçè§æ ¼å±æ§ç®¡ç |
| | | |
| | | --- |
| | | |
| | | ## ä¸ãæ°å¢åå
¸ç±»å |
| | | |
| | | | åå
¸ç±»å | åå
¸å¼ | 说æ | |
| | | |---------|-------|------| |
| | | | MDM_ITEM_TYPE | 1 | åæ | |
| | | | MDM_ITEM_TYPE | 2 | åæå | |
| | | | MDM_ITEM_TYPE | 3 | æå | |
| | | | MDM_ITEM_TYPE | 4 | è¾
æ | |
| | | | STOCK_BIZ_TYPE | 10 | éè´å
¥åº | |
| | | | STOCK_BIZ_TYPE | 20 | éå®åºåº | |
| | | | STOCK_BIZ_TYPE | 30 | ç产å
¥åº | |
| | | | STOCK_BIZ_TYPE | 40 | çäº§é¢æ | |
| | | | STOCK_BIZ_TYPE | 50 | çäº§éæ | |
| | | | STOCK_BIZ_TYPE | 60 | éè´éè´§åºåº | |
| | | | STOCK_BIZ_TYPE | 70 | éå®éè´§å
¥åº | |
| | | | STOCK_BIZ_TYPE | 80 | è°æ¨å
¥åº | |
| | | | STOCK_BIZ_TYPE | 90 | è°æ¨åºåº | |
| | | | STOCK_BIZ_TYPE | 100 | ççå
¥åº | |
| | | | STOCK_BIZ_TYPE | 110 | çäºåºåº | |
| | | |
| | | --- |
| | | |
| | | ## åãè·¯ç±é
ç½® |
| | | |
| | | ```js |
| | | // æ°å¢è·¯ç± |
| | | { |
| | | path: '/mdm', |
| | | component: Layout, |
| | | name: 'MDM', |
| | | meta: { title: 'ä¸»æ°æ®ç®¡ç', icon: 'ep:goods' }, |
| | | children: [ |
| | | { |
| | | path: 'item', |
| | | name: 'MdmItem', |
| | | component: () => import('@/views/mdm/item/index.vue'), |
| | | meta: { title: 'ç©æç®¡ç' } |
| | | }, |
| | | { |
| | | path: 'category', |
| | | name: 'MdmCategory', |
| | | component: () => import('@/views/mdm/category/index.vue'), |
| | | meta: { title: 'ç©æåç±»' } |
| | | }, |
| | | { |
| | | path: 'unit', |
| | | name: 'MdmUnit', |
| | | component: () => import('@/views/mdm/unit/index.vue'), |
| | | meta: { title: '计éåä½' } |
| | | }, |
| | | { |
| | | path: 'brand', |
| | | name: 'MdmBrand', |
| | | component: () => import('@/views/mdm/brand/index.vue'), |
| | | meta: { title: 'åç管ç' } |
| | | }, |
| | | { |
| | | path: 'warehouse', |
| | | name: 'MdmWarehouse', |
| | | component: () => import('@/views/mdm/warehouse/index.vue'), |
| | | meta: { title: 'ä»åºç®¡ç' } |
| | | } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## äºã注æäºé¡¹ |
| | | |
| | | 1. **æ°æ®è¿ç§»**ï¼æ§è¡æ°æ®è¿ç§» SQL åï¼åæ ERP/MES/WMS çç©æé¡µé¢å°å±ç¤ºè¿ç§»åç MDM æ°æ® |
| | | 2. **æéé
ç½®**ï¼æ°å¢ MDM 模åèååæéé
ç½® |
| | | 3. **API 对æ¥**ï¼å端éè¦æ°å¢ MDM ç¸å
³ API æä»¶ (`api/mdm/item.js`, `api/mdm/category.js` ç) |
| | | 4. **åæ®µå
¼å®¹**ï¼æ§é¡µé¢çåæ®µåç§°éè¦æ å°å°æ°å段ï¼å¦ `productId` â `itemId` |
| | | 5. **ç¶æåæ¥**ï¼ç©æç¶æåæ´åï¼éè¦åæ¥æ´æ°å模åå¼ç¨ç¶æ |
| | | |
| | | --- |
| | | |
| | | **ææ¡£çæ¬**: v1.0 |
| | | **åå»ºæ¥æ**: 2026-06-29 |
| | | **ä½è
**: Claude Code |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '#/packages/effects/request/src'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MdmItemApi { |
| | | /** ç©æä¿¡æ¯ */ |
| | | export interface Item { |
| | | id?: number; |
| | | code: string; |
| | | name: string; |
| | | barCode?: string; |
| | | specification?: string; |
| | | categoryId?: number; |
| | | categoryName?: string; |
| | | unitMeasureId?: number; |
| | | unitMeasureName?: string; |
| | | brandId?: number; |
| | | brandName?: string; |
| | | itemType: number; |
| | | status: number; |
| | | purchasePrice?: number; |
| | | salesPrice?: number; |
| | | costPrice?: number; |
| | | safetyStock?: number; |
| | | minStock?: number; |
| | | maxStock?: number; |
| | | isBatchManaged: boolean; |
| | | expiryDay?: number; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | |
| | | /** ç©æå页æ¥è¯¢åæ° */ |
| | | export interface PageParams extends PageParam { |
| | | code?: string; |
| | | name?: string; |
| | | categoryId?: number; |
| | | itemType?: number; |
| | | status?: number; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢ç©æå页å表 */ |
| | | export function getItemPage(params: MdmItemApi.PageParams) { |
| | | return requestClient.get<PageResult<MdmItemApi.Item>>('/mdm/item/page', { |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | /** æ¥è¯¢ç©æå表 */ |
| | | export function getItemList(params?: Partial<MdmItemApi.Item>) { |
| | | return requestClient.get<MdmItemApi.Item[]>('/mdm/item/list', { params }); |
| | | } |
| | | |
| | | /** æ¥è¯¢ç©æè¯¦æ
*/ |
| | | export function getItem(id: number) { |
| | | return requestClient.get<MdmItemApi.Item>(`/mdm/item/get?id=${id}`); |
| | | } |
| | | |
| | | /** æ°å¢ç©æ */ |
| | | export function createItem(data: MdmItemApi.Item) { |
| | | return requestClient.post('/mdm/item/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹ç©æ */ |
| | | export function updateItem(data: MdmItemApi.Item) { |
| | | return requestClient.put('/mdm/item/update', data); |
| | | } |
| | | |
| | | /** å é¤ç©æ */ |
| | | export function deleteItem(id: number) { |
| | | return requestClient.delete(`/mdm/item/delete?id=${id}`); |
| | | } |
| | | |
| | | /** æ¹éå é¤ç©æ */ |
| | | export function deleteItemList(ids: number[]) { |
| | | return requestClient.delete(`/mdm/item/delete-list?ids=${ids.join(',')}`); |
| | | } |
| | | |
| | | /** æ´æ°ç©æç¶æ */ |
| | | export function updateItemStatus(id: number, status: number) { |
| | | return requestClient.put('/mdm/item/update-status', { id, status }); |
| | | } |
| | | |
| | | /** 导åºç©æ */ |
| | | export function exportItem(params: Partial<MdmItemApi.Item>) { |
| | | return requestClient.download('/mdm/item/export-excel', { params }); |
| | | } |
| | |
| | | WMS_SHIPMENT_ORDER_TYPE: 'wms_shipment_order_type', // WMS åºåºåç±»å |
| | | } as const; |
| | | |
| | | /** ========== MDM - ä¸»æ°æ®ç®¡ç模å ========== */ |
| | | const MDM_DICT = { |
| | | MDM_ITEM_TYPE: 'mdm_item_type', // MDM ç©æç±»å |
| | | STOCK_BIZ_TYPE: 'stock_biz_type', // åºåä¸å¡ç±»å |
| | | } as const; |
| | | |
| | | /** åå
¸ç±»åæä¸¾ - ç»ä¸å¯¼åº */ |
| | | const DICT_TYPE = { |
| | | ...AI_DICT, |
| | |
| | | ...IM_DICT, |
| | | ...IOT_DICT, |
| | | ...MES_DICT, |
| | | ...MDM_DICT, |
| | | ...WMS_DICT, |
| | | ...MEMBER_DICT, |
| | | ...MP_DICT, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { CommonStatusEnum, DICT_TYPE } from '#/packages/constants/src'; |
| | | import { getDictOptions } from '#/packages/effects/hooks/src'; |
| | | |
| | | import { z } from '#/adapter/form'; |
| | | |
| | | /** ç©æç±»åé项 */ |
| | | export const ITEM_TYPE_OPTIONS = [ |
| | | { label: 'åæ', value: 1 }, |
| | | { label: 'åæå', value: 2 }, |
| | | { label: 'æå', value: 3 }, |
| | | { label: 'è¾
æ', value: 4 }, |
| | | ]; |
| | | |
| | | /** æ°å¢/ä¿®æ¹ç表å */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | component: 'Input', |
| | | fieldName: 'id', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Input', |
| | | fieldName: 'code', |
| | | label: 'ç©æç¼ç ', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç©æç¼ç ', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | component: 'Input', |
| | | fieldName: 'name', |
| | | label: 'ç©æåç§°', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç©æåç§°', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | component: 'Input', |
| | | fieldName: 'barCode', |
| | | label: 'æ¡ç ', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ¡ç ', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Input', |
| | | fieldName: 'specification', |
| | | label: 'è§æ ¼åå·', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è§æ ¼åå·', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'TreeSelect', |
| | | fieldName: 'categoryId', |
| | | label: 'ç©æåç±»', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ç©æåç±»', |
| | | allowClear: true, |
| | | treeData: [], |
| | | fieldNames: { label: 'name', value: 'id', children: 'children' }, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | fieldName: 'unitMeasureId', |
| | | label: '计éåä½', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©è®¡éåä½', |
| | | allowClear: true, |
| | | options: [], |
| | | fieldNames: { label: 'name', value: 'id' }, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | fieldName: 'brandId', |
| | | label: 'åç', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©åç', |
| | | allowClear: true, |
| | | options: [], |
| | | fieldNames: { label: 'name', value: 'id' }, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | fieldName: 'itemType', |
| | | label: 'ç©æç±»å', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ç©æç±»å', |
| | | options: ITEM_TYPE_OPTIONS, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | component: 'InputNumber', |
| | | fieldName: 'purchasePrice', |
| | | label: 'éè´ä»·', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥éè´ä»·', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'InputNumber', |
| | | fieldName: 'salesPrice', |
| | | label: 'éå®ä»·', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥éå®ä»·', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'InputNumber', |
| | | fieldName: 'costPrice', |
| | | label: 'ææ¬ä»·', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥ææ¬ä»·', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'InputNumber', |
| | | fieldName: 'safetyStock', |
| | | label: 'å®å
¨åºå', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥å®å
¨åºå', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'InputNumber', |
| | | fieldName: 'minStock', |
| | | label: 'æä½åºå', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æä½åºå', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'InputNumber', |
| | | fieldName: 'maxStock', |
| | | label: 'æé«åºå', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | precision: 2, |
| | | placeholder: '请è¾å
¥æé«åºå', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Switch', |
| | | fieldName: 'isBatchManaged', |
| | | label: 'æ¹æ¬¡ç®¡ç', |
| | | componentProps: { |
| | | checkedChildren: 'æ¯', |
| | | unCheckedChildren: 'å¦', |
| | | }, |
| | | rules: z.boolean().default(false), |
| | | }, |
| | | { |
| | | component: 'InputNumber', |
| | | fieldName: 'expiryDay', |
| | | label: 'æææ(天)', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0, |
| | | placeholder: '请è¾å
¥æææ', |
| | | }, |
| | | }, |
| | | { |
| | | component: 'RadioGroup', |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), |
| | | buttonStyle: 'solid', |
| | | optionType: 'button', |
| | | }, |
| | | rules: z.number().default(CommonStatusEnum.ENABLE), |
| | | }, |
| | | { |
| | | component: 'Textarea', |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 3, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'code', |
| | | label: 'ç©æç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç©æç¼ç ', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'ç©æåç§°', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç©æåç§°', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'categoryId', |
| | | label: 'ç©æåç±»', |
| | | component: 'TreeSelect', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ç©æåç±»', |
| | | allowClear: true, |
| | | treeData: [], |
| | | fieldNames: { label: 'name', value: 'id', children: 'children' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'itemType', |
| | | label: 'ç©æç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ç©æç±»å', |
| | | allowClear: true, |
| | | options: ITEM_TYPE_OPTIONS, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'checkbox', width: 40 }, |
| | | { |
| | | field: 'code', |
| | | title: 'ç©æç¼ç ', |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'name', |
| | | title: 'ç©æåç§°', |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'specification', |
| | | title: 'è§æ ¼åå·', |
| | | minWidth: 150, |
| | | }, |
| | | { |
| | | field: 'categoryName', |
| | | title: 'åç±»', |
| | | minWidth: 100, |
| | | }, |
| | | { |
| | | field: 'unitMeasureName', |
| | | title: 'åä½', |
| | | minWidth: 80, |
| | | }, |
| | | { |
| | | field: 'itemType', |
| | | title: 'ç©æç±»å', |
| | | minWidth: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MDM_ITEM_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'purchasePrice', |
| | | title: 'éè´ä»·', |
| | | minWidth: 100, |
| | | formatter: ({ cellValue }) => { |
| | | return cellValue != null ? `Â¥${Number(cellValue).toFixed(2)}` : ''; |
| | | }, |
| | | }, |
| | | { |
| | | field: 'salesPrice', |
| | | title: 'éå®ä»·', |
| | | minWidth: 100, |
| | | formatter: ({ cellValue }) => { |
| | | return cellValue != null ? `Â¥${Number(cellValue).toFixed(2)}` : ''; |
| | | }, |
| | | }, |
| | | { |
| | | field: 'isBatchManaged', |
| | | title: 'æ¹æ¬¡ç®¡ç', |
| | | minWidth: 80, |
| | | slots: { default: 'isBatchManaged' }, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | minWidth: 80, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.COMMON_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | minWidth: 180, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 180, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MdmItemApi } from '#/api/mdm/item'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { confirm, Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteItem, |
| | | deleteItemList, |
| | | exportItem, |
| | | getItemPage, |
| | | updateItemStatus, |
| | | } from '#/api/mdm/item'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | defineOptions({ name: 'MdmItem' }); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 导åºè¡¨æ ¼ */ |
| | | async function handleExport() { |
| | | const data = await exportItem(await gridApi.formApi.getValues()); |
| | | downloadFileFromBlobPart({ fileName: 'ç©æ.xls', source: data }); |
| | | } |
| | | |
| | | /** åå»ºç©æ */ |
| | | function handleCreate() { |
| | | formModalApi.setData(null).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ç©æ */ |
| | | function handleEdit(row: MdmItemApi.Item) { |
| | | formModalApi.setData(row).open(); |
| | | } |
| | | |
| | | /** å é¤ç©æ */ |
| | | async function handleDelete(row: MdmItemApi.Item) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.name]), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteItem(row.id!); |
| | | message.success($t('ui.actionMessage.deleteSuccess', [row.name])); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æ¹éå é¤ç©æ */ |
| | | async function handleDeleteBatch() { |
| | | await confirm($t('ui.actionMessage.deleteBatchConfirm')); |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deletingBatch'), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteItemList(checkedIds.value); |
| | | checkedIds.value = []; |
| | | message.success($t('ui.actionMessage.deleteSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æ´æ°ç¶æ */ |
| | | async function handleStatusChange(row: MdmItemApi.Item, status: boolean) { |
| | | const newStatus = status ? 0 : 1; |
| | | const hideLoading = message.loading({ |
| | | content: 'æ£å¨æ´æ°ç¶æ...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await updateItemStatus(row.id!, newStatus); |
| | | message.success('ç¶ææ´æ°æå'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const checkedIds = ref<number[]>([]); |
| | | function handleRowCheckboxChange({ |
| | | records, |
| | | }: { |
| | | records: MdmItemApi.Item[]; |
| | | }) { |
| | | checkedIds.value = records.map((item) => item.id!); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getItemPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MdmItemApi.Item>, |
| | | gridEvents: { |
| | | checkboxAll: handleRowCheckboxChange, |
| | | checkboxChange: handleRowCheckboxChange, |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="ç©æå表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['ç©æ']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mdm:item:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['mdm:item:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.deleteBatch'), |
| | | type: 'primary', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mdm:item:delete'], |
| | | disabled: isEmpty(checkedIds), |
| | | onClick: handleDeleteBatch, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #isBatchManaged="{ row }"> |
| | | <Tag v-if="row.isBatchManaged" color="success">æ¯</Tag> |
| | | <Tag v-else>å¦</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mdm:item:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: row.status === 0 ? 'åç¨' : 'å¯ç¨', |
| | | type: 'link', |
| | | auth: ['mdm:item:update'], |
| | | onClick: handleStatusChange.bind(null, row, row.status === 0), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mdm:item:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.name]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MdmItemApi } from '#/api/mdm/item'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createItem, getItem, updateItem } from '#/api/mdm/item'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | defineOptions({ name: 'ItemForm' }); |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<MdmItemApi.Item>(); |
| | | const getTitle = computed(() => { |
| | | return formData.value?.id |
| | | ? $t('ui.actionTitle.edit', ['ç©æ']) |
| | | : $t('ui.actionTitle.create', ['ç©æ']); |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 100, |
| | | }, |
| | | layout: 'horizontal', |
| | | schema: useFormSchema(), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as MdmItemApi.Item; |
| | | try { |
| | | await (formData.value?.id ? updateItem(data) : createItem(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<MdmItemApi.Item>(); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getItem(data.id); |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal class="w-[800px]" :title="getTitle"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |