From 7d5f9791941d0ef9cd6d2daae80b5ae391e18b43 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 01 七月 2026 16:10:10 +0800
Subject: [PATCH] 银川 1.联调产品维护页面 2.添加采购申请页面、联调
---
src/preferences.ts | 4
src/packages/icons/src/offline-icons.ts | 15
src/views/erp/purchase/request/modules/process-select-modal.vue | 78 ++++
src/views/erp/purchase/request/modules/item-form.vue | 62 ++-
src/views/system/menu/data.ts | 2
pnpm-lock.yaml | 3
src/packages/icons/package.json | 1
/dev/null | 523 -----------------------------
src/views/erp/purchase/request/index.vue | 100 ++---
src/views/erp/purchase/request/data.ts | 102 ++++-
src/views/erp/purchase/request/modules/form.vue | 13
src/views/erp/purchase/supplier/modules/form.vue | 2
src/views/basicData/mdm/index.vue | 24
src/views/erp/purchase/supplier/data.ts | 11
src/api/erp/purchase/request/index.ts | 51 +-
src/views/erp/purchase/request/modules/order-form.vue | 71 +++
16 files changed, 400 insertions(+), 662 deletions(-)
diff --git a/mdm_frontend_change.md b/mdm_frontend_change.md
deleted file mode 100644
index 3e9c175..0000000
--- a/mdm_frontend_change.md
+++ /dev/null
@@ -1,523 +0,0 @@
-# 鐗╂枡涓绘暟鎹ā鍧� (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
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 54fadff..97d3ddd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1620,6 +1620,9 @@
src/packages/icons:
dependencies:
+ '@iconify/json':
+ specifier: ^2.2.483
+ version: 2.2.489
'@vben-core/icons':
specifier: workspace:*
version: link:../@core/base/icons
diff --git a/src/api/erp/purchase/request/index.ts b/src/api/erp/purchase/request/index.ts
index c35f89c..a7702d1 100644
--- a/src/api/erp/purchase/request/index.ts
+++ b/src/api/erp/purchase/request/index.ts
@@ -7,15 +7,23 @@
export interface PurchaseRequest {
id?: number; // 缂栧彿
no?: string; // 鐢宠缂栧彿
+ status?: number; // 鐘舵�侊細0鏈彁浜� 10瀹℃壒涓� 20瀹℃牳閫氳繃 30瀹℃牳涓嶉�氳繃 40宸插彇娑�
+ requestUserId?: number; // 鐢宠浜虹紪鍙�
+ requestUserName?: string; // 鐢宠浜哄悕绉�
+ requestDeptId?: number; // 鐢宠閮ㄩ棬缂栧彿
+ requestDeptName?: string; // 鐢宠閮ㄩ棬鍚嶇О
+ requestTime: string; // 鐢宠鏃堕棿
+ requestReason?: string; // 鐢宠鐞嗙敱
supplierId?: number; // 渚涘簲鍟嗙紪鍙�
supplierName?: string; // 渚涘簲鍟嗗悕绉�
- requestTime: string; // 鐢宠鏃堕棿
- requesterId?: number; // 鐢宠浜虹紪鍙�
- requesterName?: string; // 鐢宠浜哄悕绉�
- reason?: string; // 鐢宠鐞嗙敱
- estimatedAmount?: number; // 棰勪及閲戦
- status?: number; // 鐘舵��
+ discountPercent?: number; // 浼樻儬鐜�
+ fileUrl?: string; // 闄勪欢鍦板潃
remark?: string; // 澶囨敞
+ totalCount?: number; // 鎬绘暟閲�
+ totalPrice?: number; // 鎬婚噾棰�
+ productNames?: string; // 浜у搧鍚嶇О鍒楄〃
+ orderId?: number; // 鐢熸垚鐨勯噰璐鍗曠紪鍙�
+ orderNo?: string; // 鐢熸垚鐨勯噰璐鍗曞彿
items?: PurchaseRequestItem[]; // 鐢宠鏄庣粏
createTime?: string; // 鍒涘缓鏃堕棿
}
@@ -25,11 +33,13 @@
id?: number; // 缂栧彿
productId: number; // 浜у搧缂栧彿
productName?: string; // 浜у搧鍚嶇О
- productUnitName?: string; // 浜у搧鍗曚綅
+ productUnitId?: number; // 浜у搧鍗曚綅缂栧彿
+ productUnitName?: string; // 浜у搧鍗曚綅鍚嶇О
productBarCode?: string; // 浜у搧鏉$爜
- requestCount: number; // 鐢宠鏁伴噺
- estimatedPrice?: number; // 棰勪及鍗曚环
- requiredDate?: string; // 闇�姹傛棩鏈�
+ productPrice?: number; // 浜у搧鍗曚环锛堝弬鑰冧环锛�
+ count: number; // 鏁伴噺
+ taxPercent?: number; // 绋庣巼
+ demandTime?: string; // 闇�姹傛棩鏈�
remark?: string; // 澶囨敞
}
}
@@ -44,18 +54,14 @@
return requestClient.put('/erp/purchase-request/update', data);
}
-/** 瀹℃壒閲囪喘鐢宠 */
-export function approvePurchaseRequest(params: {
- id: number;
- status: number;
- remark?: string;
-}) {
- return requestClient.put('/erp/purchase-request/approve', null, { params });
+/** 鎻愪氦閲囪喘鐢宠瀹℃壒 */
+export function submitPurchaseRequest(id: number, processDefinitionKey: string) {
+ return requestClient.put('/erp/purchase-request/submit', null, { params: { id, processDefinitionKey } });
}
-/** 杞负閲囪喘璁㈠崟 */
-export function convertToPurchaseOrder(id: number) {
- return requestClient.put('/erp/purchase-request/convert', null, { params: { id } });
+/** 鐢熸垚閲囪喘璁㈠崟 */
+export function generatePurchaseOrder(id: number, supplierId: number) {
+ return requestClient.post<number>('/erp/purchase-request/generate-order', null, { params: { id, supplierId } });
}
/** 鍒犻櫎閲囪喘鐢宠 */
@@ -82,3 +88,8 @@
export function exportPurchaseRequest(params: any) {
return requestClient.download('/erp/purchase-request/export-excel', { params });
}
+
+/** 鑾峰彇瀹℃壒娴佺▼鍒楄〃 */
+export function getApproveProcessList(id: number) {
+ return requestClient.get(`/erp/purchase-request/approve-process-list`, { params: { id } });
+}
diff --git a/src/packages/icons/package.json b/src/packages/icons/package.json
index 1a5fc72..0f8273c 100644
--- a/src/packages/icons/package.json
+++ b/src/packages/icons/package.json
@@ -17,6 +17,7 @@
}
},
"dependencies": {
+ "@iconify/json": "^2.2.483",
"@vben-core/icons": "workspace:*"
}
}
diff --git a/src/packages/icons/src/offline-icons.ts b/src/packages/icons/src/offline-icons.ts
new file mode 100644
index 0000000..d873267
--- /dev/null
+++ b/src/packages/icons/src/offline-icons.ts
@@ -0,0 +1,15 @@
+/**
+ * 绂荤嚎鍥炬爣棰勫姞杞介厤缃�
+ * 鏆傛椂绂佺敤锛屼娇鐢ㄥ湪绾垮姞杞芥柟寮�
+ */
+
+import { addCollection } from '@iconify/vue';
+
+/**
+ * 鍒濆鍖栫绾垮浘鏍�
+ * 鐩墠浣跨敤鍦ㄧ嚎鍔犺浇锛屾鍑芥暟涓虹┖
+ */
+export function initOfflineIcons() {
+ // 鏆傛椂涓嶉鍔犺浇锛屼娇鐢� Iconify 鍦ㄧ嚎 API
+ // 濡傛灉闇�瑕佺绾垮姞杞斤紝闇�瑕佸皢 JSON 鏂囦欢澶嶅埗鍒伴」鐩腑
+}
diff --git a/src/preferences.ts b/src/preferences.ts
index 131be05..626b2ff 100644
--- a/src/preferences.ts
+++ b/src/preferences.ts
@@ -32,6 +32,10 @@
companyName: import.meta.env.VITE_APP_TITLE,
companySiteLink: 'https://gitee.com/yudaocode/yudao-ui-admin-vben',
},
+ tabbar: {
+ /** 鍒锋柊娴忚鍣ㄥ悗鍙繚鐣欏綋鍓嶉〉闈紝涓嶆寔涔呭寲鎵�鏈夋爣绛鹃〉 */
+ persist: false,
+ },
});
export const preferencesExtension =
diff --git a/src/views/basicData/mdm/index.vue b/src/views/basicData/mdm/index.vue
index c10a75f..16b34d4 100644
--- a/src/views/basicData/mdm/index.vue
+++ b/src/views/basicData/mdm/index.vue
@@ -13,7 +13,7 @@
import {
deleteItem,
deleteItemList,
- exportItem,
+ // exportItem,
getItemPage,
updateItemStatus,
} from '#/api/mdm/item';
@@ -35,10 +35,10 @@
}
/** 瀵煎嚭琛ㄦ牸 */
-async function handleExport() {
- const data = await exportItem(await gridApi.formApi.getValues());
- downloadFileFromBlobPart({ fileName: '鐗╂枡.xls', source: data });
-}
+// async function handleExport() {
+// const data = await exportItem(await gridApi.formApi.getValues());
+// downloadFileFromBlobPart({ fileName: '鐗╂枡.xls', source: data });
+// }
/** 鍒涘缓鐗╂枡 */
function handleCreate() {
@@ -156,13 +156,13 @@
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.export'),
+ // type: 'primary',
+ // icon: ACTION_ICON.DOWNLOAD,
+ // auth: ['mdm:item:export'],
+ // onClick: handleExport,
+ // },
{
label: $t('ui.actionTitle.deleteBatch'),
type: 'primary',
diff --git a/src/views/erp/purchase/request/data.ts b/src/views/erp/purchase/request/data.ts
index 34682d6..fb3c4ae 100644
--- a/src/views/erp/purchase/request/data.ts
+++ b/src/views/erp/purchase/request/data.ts
@@ -14,10 +14,11 @@
/** 鐘舵�佸父閲� */
export const PURCHASE_REQUEST_STATUS = {
- PENDING: 0, // 寰呭鎵�
- APPROVED: 1, // 宸插鎵�
- REJECTED: 2, // 宸叉嫆缁�
- CONVERTED: 3, // 宸茶浆璁㈠崟
+ DRAFT: 0, // 鏈彁浜わ紙鑽夌锛�
+ PROCESSING: 10, // 瀹℃壒涓�
+ APPROVED: 20, // 瀹℃牳閫氳繃
+ REJECTED: 30, // 瀹℃牳涓嶉�氳繃
+ CANCELLED: 40, // 宸插彇娑�
};
/** 琛ㄥ崟鐨勯厤缃」 */
@@ -54,7 +55,7 @@
rules: 'required',
},
{
- label: '渚涘簲鍟�',
+ label: '渚涘簲鍟嗭紙鍙�夛級',
fieldName: 'supplierId',
component: 'ApiSelect',
componentProps: {
@@ -68,12 +69,37 @@
},
},
{
- fieldName: 'reason',
+ fieldName: 'discountPercent',
+ label: '浼樻儬鐜�(%)',
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '璇疯緭鍏ヤ紭鎯犵巼',
+ min: 0,
+ max: 100,
+ precision: 2,
+ disabled: formType === 'detail',
+ },
+ },
+ {
+ fieldName: 'requestReason',
label: '鐢宠鐞嗙敱',
component: 'Textarea',
componentProps: {
placeholder: '璇疯緭鍏ョ敵璇风悊鐢�',
autoSize: { minRows: 1, maxRows: 1 },
+ disabled: formType === 'detail',
+ },
+ formItemClass: 'col-span-2',
+ },
+ {
+ fieldName: 'fileUrl',
+ label: '闄勪欢',
+ component: 'FileUpload',
+ componentProps: {
+ placeholder: '璇蜂笂浼犻檮浠�',
+ maxNumber: 5,
+ maxSize: 20,
+ accept: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'jpg', 'png'],
disabled: formType === 'detail',
},
formItemClass: 'col-span-2',
@@ -121,18 +147,18 @@
minWidth: 80,
},
{
- field: 'requestCount',
- title: '鐢宠鏁伴噺',
+ field: 'count',
+ title: '鏁伴噺',
minWidth: 120,
fixed: 'right',
- slots: { default: 'requestCount' },
+ slots: { default: 'count' },
},
{
- field: 'estimatedPrice',
- title: '棰勪及鍗曚环',
+ field: 'productPrice',
+ title: '鍗曚环锛堝弬鑰冧环锛�',
minWidth: 120,
fixed: 'right',
- slots: { default: 'estimatedPrice' },
+ slots: { default: 'productPrice' },
},
{
field: 'totalPrice',
@@ -142,11 +168,18 @@
formatter: 'formatAmount2',
},
{
- field: 'requiredDate',
+ field: 'taxPercent',
+ title: '绋庣巼(%)',
+ minWidth: 100,
+ fixed: 'right',
+ slots: { default: 'taxPercent' },
+ },
+ {
+ field: 'demandTime',
title: '闇�姹傛棩鏈�',
minWidth: 140,
fixed: 'right',
- slots: { default: 'requiredDate' },
+ slots: { default: 'demandTime' },
},
{
field: 'remark',
@@ -199,7 +232,7 @@
},
},
{
- fieldName: 'requesterId',
+ fieldName: 'requestUserId',
label: '鐢宠浜�',
component: 'ApiSelect',
componentProps: {
@@ -217,10 +250,11 @@
component: 'Select',
componentProps: {
options: [
- { label: '寰呭鎵�', value: 0 },
- { label: '宸插鎵�', value: 1 },
- { label: '宸叉嫆缁�', value: 2 },
- { label: '宸茶浆璁㈠崟', value: 3 },
+ { label: '鏈彁浜�', value: 0 },
+ { label: '瀹℃壒涓�', value: 10 },
+ { label: '瀹℃牳閫氳繃', value: 20 },
+ { label: '瀹℃牳涓嶉�氳繃', value: 30 },
+ { label: '宸插彇娑�', value: 40 },
],
placeholder: '璇烽�夋嫨鐘舵��',
allowClear: true,
@@ -255,15 +289,37 @@
formatter: 'formatDate',
},
{
- field: 'requesterName',
+ field: 'requestUserName',
title: '鐢宠浜�',
minWidth: 120,
},
{
- field: 'estimatedAmount',
+ field: 'requestDeptName',
+ title: '鐢宠閮ㄩ棬',
+ minWidth: 120,
+ },
+ {
+ field: 'totalCount',
+ title: '鐢宠鏁伴噺',
+ minWidth: 120,
+ formatter: 'formatAmount3',
+ },
+ {
+ field: 'totalPrice',
title: '棰勪及閲戦',
formatter: 'formatAmount2',
minWidth: 120,
+ },
+ {
+ field: 'productNames',
+ title: '鐢宠浜у搧',
+ minWidth: 150,
+ showOverflow: 'tooltip',
+ },
+ {
+ field: 'orderNo',
+ title: '閲囪喘璁㈠崟',
+ minWidth: 180,
},
{
field: 'status',
@@ -272,7 +328,7 @@
slots: { default: 'status' },
},
{
- field: 'reason',
+ field: 'requestReason',
title: '鐢宠鐞嗙敱',
minWidth: 150,
showOverflow: 'tooltip',
@@ -285,7 +341,7 @@
},
{
title: '鎿嶄綔',
- width: 200,
+ width: 240,
fixed: 'right',
slots: { default: 'actions' },
},
diff --git a/src/views/erp/purchase/request/index.vue b/src/views/erp/purchase/request/index.vue
index a3cd39c..1eebbc5 100644
--- a/src/views/erp/purchase/request/index.vue
+++ b/src/views/erp/purchase/request/index.vue
@@ -4,29 +4,41 @@
import { ref } from 'vue';
-import { Page, useVbenModal } from '../../../../packages/effects/common-ui/src';
+import { confirm, Page, useVbenModal } from '../../../../packages/effects/common-ui/src';
import { downloadFileFromBlobPart, isEmpty } from '../../../../packages/utils/src';
import { message, Tag } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
- approvePurchaseRequest,
- convertToPurchaseOrder,
deletePurchaseRequest,
exportPurchaseRequest,
+ getApproveProcessList,
getPurchaseRequestPage,
+ submitPurchaseRequest,
} from '#/api/erp/purchase/request';
import { $t } from '#/locales';
-import { useGridColumns, useGridFormSchema, PURCHASE_REQUEST_STATUS } from './data';
+import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
+import OrderForm from './modules/order-form.vue';
+import ProcessSelectModal from './modules/process-select-modal.vue';
/** ERP 閲囪喘鐢宠鍒楄〃 */
defineOptions({ name: 'ErpPurchaseRequest' });
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
+ destroyOnClose: true,
+});
+
+const [OrderFormModal, orderFormModalApi] = useVbenModal({
+ connectedComponent: OrderForm,
+ destroyOnClose: true,
+});
+
+const [ProcessModal, processModalApi] = useVbenModal({
+ connectedComponent: ProcessSelectModal,
destroyOnClose: true,
});
@@ -66,34 +78,29 @@
}
}
-/** 瀹℃壒閲囪喘鐢宠 */
-async function handleApprove(row: ErpPurchaseRequestApi.PurchaseRequest, status: number) {
+/** 鎻愪氦瀹℃壒 - 鍏堣幏鍙栨祦绋嬪垪琛� */
+async function handleSubmit(row: ErpPurchaseRequestApi.PurchaseRequest) {
const hideLoading = message.loading({
- content: `纭畾${status === 1 ? '瀹℃壒閫氳繃' : '瀹℃壒鎷掔粷'}璇ョ敵璇峰悧锛焋,
+ content: '鑾峰彇瀹℃壒娴佺▼...',
duration: 0,
});
try {
- await approvePurchaseRequest({ id: row.id!, status, remark: '' });
- message.success(`${status === 1 ? '瀹℃壒閫氳繃' : '瀹℃壒鎷掔粷'}鎴愬姛`);
- handleRefresh();
- } finally {
+ const processList = await getApproveProcessList(row.id!);
+ hideLoading();
+ if (!processList || processList.length === 0) {
+ message.warning('鏆傛棤鍙敤瀹℃壒娴佺▼锛岃鍏堥厤缃� BPM 娴佺▼');
+ return;
+ }
+ // 鎵撳紑娴佺▼閫夋嫨寮圭獥
+ processModalApi.setData({ id: row.id, processList }).open();
+ } catch {
hideLoading();
}
}
-/** 杞负閲囪喘璁㈠崟 */
-async function handleConvert(row: ErpPurchaseRequestApi.PurchaseRequest) {
- const hideLoading = message.loading({
- content: '姝e湪杞负閲囪喘璁㈠崟...',
- duration: 0,
- });
- try {
- await convertToPurchaseOrder(row.id!);
- message.success('宸叉垚鍔熻浆涓洪噰璐鍗�');
- handleRefresh();
- } finally {
- hideLoading();
- }
+/** 鐢熸垚閲囪喘璁㈠崟 */
+function handleGenerateOrder(row: ErpPurchaseRequestApi.PurchaseRequest) {
+ orderFormModalApi.setData({ id: row.id, supplierId: row.supplierId }).open();
}
const checkedIds = ref<number[]>([]);
@@ -148,6 +155,8 @@
<template>
<Page auto-content-height>
<FormModal @success="handleRefresh" />
+ <OrderFormModal @success="handleRefresh" />
+ <ProcessModal @success="handleRefresh" />
<Grid table-title="閲囪喘鐢宠鍒楄〃">
<template #toolbar-tools>
<TableAction
@@ -182,10 +191,11 @@
/>
</template>
<template #status="{ row }">
- <Tag v-if="row.status === 0" color="warning">寰呭鎵�</Tag>
- <Tag v-else-if="row.status === 1" color="success">宸插鎵�</Tag>
- <Tag v-else-if="row.status === 2" color="error">宸叉嫆缁�</Tag>
- <Tag v-else-if="row.status === 3" color="default">宸茶浆璁㈠崟</Tag>
+ <Tag v-if="row.status === 0" color="default">鏈彁浜�</Tag>
+ <Tag v-else-if="row.status === 10" color="processing">瀹℃壒涓�</Tag>
+ <Tag v-else-if="row.status === 20" color="success">瀹℃牳閫氳繃</Tag>
+ <Tag v-else-if="row.status === 30" color="error">瀹℃牳涓嶉�氳繃</Tag>
+ <Tag v-else-if="row.status === 40" color="warning">宸插彇娑�</Tag>
</template>
<template #actions="{ row }">
<TableAction
@@ -206,35 +216,17 @@
onClick: handleEdit.bind(null, row),
},
{
- label: '瀹℃壒閫氳繃',
+ label: '鎻愪氦',
type: 'link',
- auth: ['erp:purchase-request:approve'],
- ifShow: () => row.status === 0,
- popConfirm: {
- title: '纭瀹℃壒閫氳繃璇ョ敵璇峰悧锛�',
- confirm: handleApprove.bind(null, row, 1),
- },
+ ifShow: () => row.status === 0 || row.status === 30,
+ onClick: handleSubmit.bind(null, row),
},
{
- label: '瀹℃壒鎷掔粷',
+ label: '鐢熸垚璁㈠崟',
type: 'link',
- danger: true,
- auth: ['erp:purchase-request:approve'],
- ifShow: () => row.status === 0,
- popConfirm: {
- title: '纭瀹℃壒鎷掔粷璇ョ敵璇峰悧锛�',
- confirm: handleApprove.bind(null, row, 2),
- },
- },
- {
- label: '杞鍗�',
- type: 'link',
- auth: ['erp:purchase-request:convert'],
- ifShow: () => row.status === 1,
- popConfirm: {
- title: '纭杞负閲囪喘璁㈠崟鍚楋紵',
- confirm: handleConvert.bind(null, row),
- },
+ auth: ['erp:purchase-request:generate-order'],
+ ifShow: () => row.status === 20 && !row.orderId,
+ onClick: handleGenerateOrder.bind(null, row),
},
{
label: $t('common.delete'),
@@ -253,4 +245,4 @@
</template>
</Grid>
</Page>
-</template>
\ No newline at end of file
+</template>
diff --git a/src/views/erp/purchase/request/modules/form.vue b/src/views/erp/purchase/request/modules/form.vue
index 4bf6954..ab656c1 100644
--- a/src/views/erp/purchase/request/modules/form.vue
+++ b/src/views/erp/purchase/request/modules/form.vue
@@ -7,7 +7,7 @@
import { useVbenModal } from '../../../../../packages/effects/common-ui/src';
-import { message, Tag } from 'ant-design-vue';
+import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
@@ -17,7 +17,7 @@
} from '#/api/erp/purchase/request';
import { $t } from '#/locales';
-import { useFormSchema, PURCHASE_REQUEST_STATUS } from '../data';
+import { useFormSchema } from '../data';
import PurchaseRequestItemForm from './item-form.vue';
const emit = defineEmits(['success']);
@@ -78,8 +78,13 @@
const data =
(await formApi.getValues()) as ErpPurchaseRequestApi.PurchaseRequest;
data.items = formData.value?.items?.map((item) => ({
- ...item,
- id: undefined,
+ productId: item.productId,
+ productUnitId: item.productUnitId,
+ productPrice: item.productPrice,
+ count: item.count,
+ taxPercent: item.taxPercent,
+ demandTime: item.demandTime,
+ remark: item.remark,
}));
try {
await (formType.value === 'create'
diff --git a/src/views/erp/purchase/request/modules/item-form.vue b/src/views/erp/purchase/request/modules/item-form.vue
index 14b2713..8cd2a2f 100644
--- a/src/views/erp/purchase/request/modules/item-form.vue
+++ b/src/views/erp/purchase/request/modules/item-form.vue
@@ -35,10 +35,10 @@
/** 鑾峰彇琛ㄦ牸鍚堣鏁版嵁 */
const summaries = computed(() => {
return {
- count: tableData.value.reduce((sum, item) => sum + (item.requestCount || 0), 0),
+ count: tableData.value.reduce((sum, item) => sum + (item.count || 0), 0),
totalPrice: tableData.value.reduce(
(sum, item) => {
- const price = erpPriceMultiply(item.estimatedPrice || 0, item.requestCount || 0) ?? 0;
+ const price = erpPriceMultiply(item.productPrice || 0, item.count || 0) ?? 0;
return sum + price;
},
0,
@@ -89,11 +89,13 @@
const newRow = {
id: undefined,
productId: undefined,
+ productUnitId: undefined,
productUnitName: undefined,
productBarCode: undefined,
- requestCount: 1,
- estimatedPrice: undefined,
- requiredDate: undefined,
+ count: 1,
+ productPrice: undefined,
+ taxPercent: undefined,
+ demandTime: undefined,
remark: undefined,
totalPrice: 0,
};
@@ -118,10 +120,11 @@
}
row.productId = productId;
row.productBarCode = product.barCode;
+ row.productUnitId = product.unitMeasureId;
row.productUnitName = product.unitMeasureName;
row.productName = product.name;
- row.estimatedPrice = product.purchasePrice || 0;
- row.requestCount = row.requestCount || 1;
+ row.productPrice = product.purchasePrice || 0;
+ row.count = row.count || 1;
handleRowChange(row);
}
@@ -134,16 +137,16 @@
tableData.value[index] = row;
}
// 璁$畻棰勪及閲戦
- if (row.estimatedPrice && row.requestCount) {
- row.totalPrice = erpPriceMultiply(row.estimatedPrice, row.requestCount) ?? 0;
+ if (row.productPrice && row.count) {
+ row.totalPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
}
emit('update:items', [...tableData.value]);
}
/** 鍒濆鍖栬鏁版嵁 */
function initRow(row: ErpPurchaseRequestApi.PurchaseRequestItem) {
- if (row.estimatedPrice && row.requestCount) {
- row.totalPrice = erpPriceMultiply(row.estimatedPrice, row.requestCount) ?? 0;
+ if (row.productPrice && row.count) {
+ row.totalPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
}
}
@@ -155,8 +158,8 @@
if (!item.productId) {
throw new Error(`绗� ${i + 1} 琛岋細浜у搧涓嶈兘涓虹┖`);
}
- if (!item.requestCount || item.requestCount <= 0) {
- throw new Error(`绗� ${i + 1} 琛岋細鐢宠鏁伴噺涓嶈兘涓虹┖`);
+ if (!item.count || item.count <= 0) {
+ throw new Error(`绗� ${i + 1} 琛岋細鏁伴噺涓嶈兘涓虹┖`);
}
}
}
@@ -191,35 +194,46 @@
/>
<span v-else>{{ row.productName || '-' }}</span>
</template>
- <template #requestCount="{ row }">
+ <template #count="{ row }">
<InputNumber
v-if="!disabled"
- v-model:value="row.requestCount"
+ v-model:value="row.count"
:min="0"
:precision="3"
@change="handleRowChange(row)"
/>
- <span v-else>{{ erpCountInputFormatter(row.requestCount) || '-' }}</span>
+ <span v-else>{{ erpCountInputFormatter(row.count) || '-' }}</span>
</template>
- <template #estimatedPrice="{ row }">
+ <template #productPrice="{ row }">
<InputNumber
v-if="!disabled"
- v-model:value="row.estimatedPrice"
+ v-model:value="row.productPrice"
:min="0"
:precision="2"
@change="handleRowChange(row)"
/>
- <span v-else>{{ erpPriceInputFormatter(row.estimatedPrice) || '-' }}</span>
+ <span v-else>{{ erpPriceInputFormatter(row.productPrice) || '-' }}</span>
</template>
- <template #requiredDate="{ row }">
+ <template #taxPercent="{ row }">
+ <InputNumber
+ v-if="!disabled"
+ v-model:value="row.taxPercent"
+ :min="0"
+ :max="100"
+ :precision="2"
+ @change="handleRowChange(row)"
+ />
+ <span v-else>{{ row.taxPercent ? `${row.taxPercent}%` : '-' }}</span>
+ </template>
+ <template #demandTime="{ row }">
<DatePicker
v-if="!disabled"
- v-model:value="row.requiredDate"
+ v-model:value="row.demandTime"
valueFormat="YYYY-MM-DD"
class="w-full"
@change="handleRowChange(row)"
/>
- <span v-else>{{ row.requiredDate || '-' }}</span>
+ <span v-else>{{ row.demandTime || '-' }}</span>
</template>
<template #remark="{ row }">
<Input v-if="!disabled" v-model:value="row.remark" class="w-full" @change="handleRowChange(row)" />
@@ -246,7 +260,7 @@
<div class="flex justify-between text-sm text-muted-foreground">
<span class="font-medium text-foreground">鍚堣锛�</span>
<div class="flex space-x-4">
- <span>鐢宠鏁伴噺锛歿{ erpCountInputFormatter(summaries.count) }}</span>
+ <span>鏁伴噺锛歿{ erpCountInputFormatter(summaries.count) }}</span>
<span>棰勪及閲戦锛歿{ erpPriceInputFormatter(summaries.totalPrice) }}</span>
</div>
</div>
@@ -264,4 +278,4 @@
/>
</template>
</Grid>
-</template>
\ No newline at end of file
+</template>
diff --git a/src/views/erp/purchase/request/modules/order-form.vue b/src/views/erp/purchase/request/modules/order-form.vue
new file mode 100644
index 0000000..8ea784d
--- /dev/null
+++ b/src/views/erp/purchase/request/modules/order-form.vue
@@ -0,0 +1,71 @@
+<script lang="ts" setup>
+import type { ErpPurchaseRequestApi } from '#/api/erp/purchase/request';
+
+import { ref, computed } from 'vue';
+
+import { useVbenModal } from '../../../../../packages/effects/common-ui/src';
+
+import { message, Select } from 'ant-design-vue';
+
+import { generatePurchaseOrder } from '#/api/erp/purchase/request';
+import { getSupplierSimpleList } from '#/api/erp/purchase/supplier';
+
+const emit = defineEmits(['success']);
+
+const requestId = ref<number>();
+const supplierId = ref<number>();
+const supplierOptions = ref<{ id: number; name: string }[]>([]);
+
+const supplierSelectOptions = computed(() => {
+ return supplierOptions.value.map((s) => ({
+ label: s.name,
+ value: s.id,
+ }));
+});
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ if (!supplierId.value) {
+ message.warning('璇烽�夋嫨渚涘簲鍟�');
+ return;
+ }
+ modalApi.lock();
+ try {
+ const orderId = await generatePurchaseOrder(requestId.value!, supplierId.value!);
+ await modalApi.close();
+ emit('success');
+ message.success(`鐢熸垚閲囪喘璁㈠崟鎴愬姛锛岃鍗曠紪鍙凤細${orderId}`);
+ } finally {
+ modalApi.unlock();
+ }
+ },
+ async onOpenChange(isOpen: boolean) {
+ if (!isOpen) {
+ requestId.value = undefined;
+ supplierId.value = undefined;
+ return;
+ }
+ const data = modalApi.getData<{ id: number; supplierId?: number }>();
+ requestId.value = data.id;
+ supplierId.value = data.supplierId;
+ // 鑾峰彇渚涘簲鍟嗗垪琛�
+ supplierOptions.value = await getSupplierSimpleList();
+ },
+});
+</script>
+
+<template>
+ <Modal title="鐢熸垚閲囪喘璁㈠崟" class="w-1/3">
+ <div class="mb-4">
+ <span class="mr-2">閫夋嫨渚涘簲鍟嗭細</span>
+ <Select
+ v-model:value="supplierId"
+ :options="supplierSelectOptions"
+ style="width: 200px"
+ placeholder="璇烽�夋嫨渚涘簲鍟�"
+ show-search
+ :filter-option="(input: string, option: any) => option.label.toLowerCase().includes(input.toLowerCase())"
+ />
+ </div>
+ </Modal>
+</template>
\ No newline at end of file
diff --git a/src/views/erp/purchase/request/modules/process-select-modal.vue b/src/views/erp/purchase/request/modules/process-select-modal.vue
new file mode 100644
index 0000000..f4b3d83
--- /dev/null
+++ b/src/views/erp/purchase/request/modules/process-select-modal.vue
@@ -0,0 +1,78 @@
+<script lang="ts" setup>
+import type { ErpPurchaseRequestApi } from '#/api/erp/purchase/request';
+
+import { ref, computed } from 'vue';
+
+import { useVbenModal } from '../../../../../packages/effects/common-ui/src';
+
+import { message, Select } from 'ant-design-vue';
+
+import { submitPurchaseRequest } from '#/api/erp/purchase/request';
+
+interface ProcessDefinition {
+ id: string;
+ name: string;
+ version: number;
+ key: string;
+}
+
+const emit = defineEmits(['success']);
+
+const requestId = ref<number>();
+const processList = ref<ProcessDefinition[]>([]);
+const selectedProcessKey = ref<string>('');
+
+const processOptions = computed(() => {
+ return processList.value.map((p) => ({
+ label: `${p.name} (V${p.version})`,
+ value: p.key,
+ }));
+});
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ if (!selectedProcessKey.value) {
+ message.warning('璇烽�夋嫨瀹℃壒娴佺▼');
+ return;
+ }
+ modalApi.lock();
+ try {
+ await submitPurchaseRequest(requestId.value!, selectedProcessKey.value);
+ await modalApi.close();
+ emit('success');
+ message.success('鎻愪氦鎴愬姛');
+ } finally {
+ modalApi.unlock();
+ }
+ },
+ async onOpenChange(isOpen: boolean) {
+ if (!isOpen) {
+ requestId.value = undefined;
+ selectedProcessKey.value = '';
+ processList.value = [];
+ return;
+ }
+ const data = modalApi.getData<{ id: number; processList: ProcessDefinition[] }>();
+ requestId.value = data.id;
+ processList.value = data.processList || [];
+ // 榛樿閫夋嫨绗竴涓祦绋�
+ if (processList.value.length > 0) {
+ selectedProcessKey.value = processList.value[0].key;
+ }
+ },
+});
+</script>
+
+<template>
+ <Modal title="閫夋嫨瀹℃壒娴佺▼" class="w-1/3">
+ <div class="mb-4">
+ <span class="mr-2">瀹℃壒娴佺▼锛�</span>
+ <Select
+ v-model:value="selectedProcessKey"
+ :options="processOptions"
+ style="width: 200px"
+ placeholder="璇烽�夋嫨瀹℃壒娴佺▼"
+ />
+ </div>
+ </Modal>
+</template>
\ No newline at end of file
diff --git a/src/views/erp/purchase/supplier/data.ts b/src/views/erp/purchase/supplier/data.ts
index 2dc2f3f..1277a48 100644
--- a/src/views/erp/purchase/supplier/data.ts
+++ b/src/views/erp/purchase/supplier/data.ts
@@ -116,6 +116,17 @@
rules: z.number().default(0),
},
{
+ fieldName: 'sort',
+ label: '鎺掑簭',
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '璇疯緭鍏ユ帓搴�',
+ min: 0,
+ class: '!w-full',
+ },
+ rules: z.number().default(0),
+ },
+ {
fieldName: 'qualification',
label: '璧勮川淇℃伅',
component: 'Textarea',
diff --git a/src/views/erp/purchase/supplier/modules/form.vue b/src/views/erp/purchase/supplier/modules/form.vue
index 423b63f..4b0b761 100644
--- a/src/views/erp/purchase/supplier/modules/form.vue
+++ b/src/views/erp/purchase/supplier/modules/form.vue
@@ -30,7 +30,7 @@
componentProps: {
class: 'w-full',
},
- labelWidth: 100,
+ labelWidth: 120,
},
wrapperClass: 'grid-cols-2',
layout: 'horizontal',
diff --git a/src/views/system/menu/data.ts b/src/views/system/menu/data.ts
index f20984c..9490a83 100644
--- a/src/views/system/menu/data.ts
+++ b/src/views/system/menu/data.ts
@@ -101,7 +101,7 @@
component: 'IconPicker',
componentProps: {
placeholder: '璇烽�夋嫨鑿滃崟鍥炬爣',
- prefix: 'carbon',
+ prefix: 'ep',
},
rules: 'required',
dependencies: {
--
Gitblit v1.9.3