sparkles: 物料类型
All checks were successful
Release / lint (push) Successful in 58s
Release / Release (push) Successful in 2m9s

This commit is contained in:
my_ong 2025-03-02 14:38:52 +08:00
parent 0b6c1e9000
commit 8953941362
15 changed files with 864 additions and 9 deletions

View File

@ -4162,6 +4162,169 @@
]
}
]
},
{
"description": "物料类型管理",
"name": "type",
"interfaces": [
{
"description": "增加/更新地区",
"name": "addAndModify",
"method": "post",
"path": "/area",
"response": {
"typeArgs": [],
"typeName": "Type",
"isDefsType": true,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"parameters": [
{
"required": true,
"in": "body",
"name": "requestBody",
"dataType": {
"typeArgs": [],
"typeName": "Type",
"isDefsType": true,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
}
]
},
{
"description": "级别",
"name": "levels",
"method": "get",
"path": "/area/levels",
"response": {
"typeArgs": [
{
"typeArgs": [],
"typeName": "Codebook",
"isDefsType": true,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
],
"typeName": "Array",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"parameters": []
},
{
"description": "类型树",
"name": "trees",
"method": "get",
"path": "/area/trees",
"response": {
"typeArgs": [
{
"typeArgs": [],
"typeName": "TypeTree",
"isDefsType": true,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
],
"typeName": "Array",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"parameters": []
},
{
"description": "删除类型",
"name": "deleteArea",
"method": "delete",
"path": "/area/{id}",
"response": {
"typeArgs": [],
"typeName": "",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"parameters": [
{
"description": "id",
"required": true,
"in": "path",
"name": "id",
"dataType": {
"typeArgs": [],
"typeName": "number",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
}
]
},
{
"description": "查询类型",
"name": "areas",
"method": "get",
"path": "/areas",
"response": {
"typeArgs": [
{
"typeArgs": [],
"typeName": "Type",
"isDefsType": true,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
],
"typeName": "Array",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"parameters": [
{
"description": "搜索关键词",
"required": false,
"in": "query",
"name": "key",
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
}
]
}
]
}
],
"name": "material",
@ -4877,6 +5040,55 @@
}
]
},
{
"description": "枚举码本",
"name": "Codebook",
"templateArgs": [],
"properties": [
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "code",
"description": "码本编码",
"required": true
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "description",
"description": "码本名称",
"required": true
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "name",
"description": "码本值",
"required": true
}
]
},
{
"name": "ComparisonResDTO",
"templateArgs": [],
@ -5826,6 +6038,191 @@
}
]
},
{
"description": "类型",
"name": "Type",
"templateArgs": [],
"properties": [
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "createdTime",
"required": false
},
{
"dataType": {
"typeArgs": [],
"typeName": "number",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "id",
"required": false
},
{
"dataType": {
"typeArgs": [],
"typeName": "",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": ["'ONE'", "'TWO'"],
"typeProperties": []
},
"name": "level",
"description": "类型级别",
"required": true
},
{
"dataType": {
"typeArgs": [],
"typeName": "Codebook",
"isDefsType": true,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "levelInfo",
"required": false
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "name",
"description": "类型名称",
"required": true
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "no",
"description": "类型编码",
"required": true
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "parentNo",
"description": "上级类型编码",
"required": false
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "updatedTime",
"required": false
}
]
},
{
"name": "TypeTree",
"templateArgs": [],
"properties": [
{
"dataType": {
"typeArgs": [
{
"typeArgs": [],
"typeName": "TypeTree",
"isDefsType": true,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
],
"typeName": "Array",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "children",
"required": false
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "label",
"description": "类型名称",
"required": true
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "parentNo",
"required": false
},
{
"dataType": {
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"name": "value",
"description": "类型编码",
"required": true
}
]
},
{
"name": "WaitScanInfo",
"templateArgs": [],

View File

@ -332,6 +332,52 @@ declare namespace material {
updatedTime?: string
}
/**
*
*/
export interface Type {
/** createdTime */
createdTime?: string
/** id */
id?: number
/** 类型级别 */
level: 'ONE' | 'TWO'
/** levelInfo */
levelInfo?: material.Codebook
/** 类型名称 */
name: string
/** 类型编码 */
no: string
/** 上级类型编码 */
parentNo?: string
/** updatedTime */
updatedTime?: string
}
/**
* TypeTree
*/
export interface TypeTree {
/** children */
children?: Array<material.TypeTree>
/** 类型名称 */
label: string
/** parentNo */
parentNo?: string
/** 类型编码 */
value: string
}
/**
* WaitScanInfo
*/

View File

@ -1,8 +1,11 @@
import apply from './apply';
import apply from './apply'
import material from './material';
import material from './material'
import type from './type'
export default {
apply,
material,
};
apply,
material,
type,
}

View File

@ -0,0 +1,22 @@
/**
* @desc /
*/
import { defaultSuccess, defaultError, http } from '@/plugins/axios'
import type { AxiosResponse } from 'axios'
export default async function (
/** 请求体 */
requestBody: material.Type,
success: (data: material.Type) => void = defaultSuccess,
fail: (error: { code: string; error?: string }) => void = defaultError,
): Promise<void> {
return http({
method: 'post',
url: `/area`,
data: requestBody,
})
.then((data: AxiosResponse<material.Type, unknown>) => {
success(data.data)
})
.catch((error: { code: string; error?: string }) => fail(error))
}

View File

@ -0,0 +1,26 @@
/**
* @desc
*/
import { defaultSuccess, defaultError, http } from '@/plugins/axios'
import type { AxiosResponse } from 'axios'
export interface Params {
/** 搜索关键词 */
key?: string
}
export default async function (
params: Params,
success: (data: Array<material.Type>) => void = defaultSuccess,
fail: (error: { code: string; error?: string }) => void = defaultError,
): Promise<void> {
return http({
method: 'get',
url: `/areas`,
params,
})
.then((data: AxiosResponse<Array<material.Type>, unknown>) => {
success(data.data)
})
.catch((error: { code: string; error?: string }) => fail(error))
}

View File

@ -0,0 +1,21 @@
/**
* @desc
*/
import { defaultSuccess, defaultError, http } from '@/plugins/axios'
import type { AxiosResponse } from 'axios'
export default async function (
/** id */
id: number,
success: (data: void) => void = defaultSuccess,
fail: (error: { code: string; error?: string }) => void = defaultError,
): Promise<void> {
return http({
method: 'delete',
url: `/area/${id}`,
})
.then((data: AxiosResponse<void, unknown>) => {
success(data.data)
})
.catch((error: { code: string; error?: string }) => fail(error))
}

View File

@ -0,0 +1,17 @@
/**
* @description
*
*/
import addAndModify from './addAndModify'
import levels from './levels'
import trees from './trees'
import deleteArea from './deleteArea'
import areas from './areas'
export default {
addAndModify,
levels,
trees,
deleteArea,
areas,
}

View File

@ -0,0 +1,20 @@
/**
* @desc
*/
import { defaultSuccess, defaultError, http } from '@/plugins/axios'
import type { AxiosResponse } from 'axios'
import type { Codebook } from '@/api/api'
export default async function (
success: (data: Array<Codebook>) => void = defaultSuccess,
fail: (error: { code: string; error?: string }) => void = defaultError,
): Promise<void> {
return http({
method: 'get',
url: `/area/levels`,
})
.then((data: AxiosResponse<Array<Codebook>, unknown>) => {
success(data.data)
})
.catch((error: { code: string; error?: string }) => fail(error))
}

View File

@ -0,0 +1,18 @@
/**
* @desc
*/
import { defaultSuccess, defaultError, http } from '@/plugins/axios'
import type { AxiosResponse } from 'axios'
export default async function (
success: (data: Array<material.TypeTree>) => void = defaultSuccess,
fail: (error: { code: string; error?: string }) => void = defaultError,
): Promise<void> {
return http({
method: 'get',
url: `/area/trees`,
})
.then((data: AxiosResponse<Array<material.TypeTree>, unknown>) => {
success(data.data)
})
.catch((error: { code: string; error?: string }) => fail(error))
}

View File

@ -29,7 +29,7 @@ export function defaultError(error: { code: string; error?: string }): void {
message: '操作异常: ',
placement: 'top',
description: error.error + '(' + error.code + ')',
duration: null,
duration: 6,
})
}
const config = {

View File

@ -42,6 +42,12 @@ export const routes: Array<RouteRecordRaw> = [
meta: { title: 'menus.acl.material', icon: 'icon-permission' },
component: () => import('../views/stock/material/material-page.vue'),
},
{
path: '/admin/acl/type', //物料类型
name: 'Type',
meta: { title: '物料类型', icon: 'icon-permission' },
component: () => import('../views/stock/type/type-page.vue'),
},
],
},
{

View File

@ -3,7 +3,7 @@
<!-- 页面操作栏 -->
<template #ops>
<a-row>
<a-col :span="18">
<a-col :span="6">
<a-input-search
v-model:value="searchKey"
:placeholder="`名称/编码/类型`"

View File

@ -0,0 +1,100 @@
import { Codebook } from '@/api/api'
import { FormItem, FormConfig } from '@/components/form-render/form-render-types'
export const config: FormConfig = {
layout: 'horizontal',
colon: true,
hideRequiredMark: false,
labelAlign: 'right',
scrollToFirstError: false,
validateOnRuleChange: true,
labelCol: {
span: 4,
offset: 0,
},
}
export const formItems = (levels: Codebook[]): FormItem[] => [
{
group: 'form',
type: 'input',
config: {
autoLink: true,
hasFeedback: false,
label: '类型编码',
name: 'no',
required: true,
},
properties: {
size: 'default',
type: 'text',
allowClear: true,
bordered: true,
showCount: true,
},
rules: [],
},
{
group: 'form',
type: 'input',
config: {
autoLink: true,
hasFeedback: false,
label: '上级编码',
name: 'parentNo',
},
properties: {
size: 'default',
type: 'text',
allowClear: true,
bordered: true,
showCount: true,
},
rules: [],
},
{
type: 'select',
group: 'form',
config: {
autoLink: true,
hasFeedback: false,
label: '类型级别',
name: 'level',
required: true,
},
properties: {
size: 'default',
allowClear: false,
autoClearSearchValue: true,
autofocus: false,
bordered: true,
defaultActiveFirstOption: true,
dropdownMatchSelectWidth: true,
labelInValue: false,
showSearch: false,
options: levels.map((item) => {
return { value: item.name, label: item.description }
}),
},
rules: [],
},
{
group: 'form',
type: 'input',
config: {
autoLink: true,
hasFeedback: false,
label: '类型名称',
name: 'name',
required: true,
},
properties: {
size: 'default',
type: 'text',
allowClear: true,
bordered: true,
showCount: true,
},
rules: [],
},
]

View File

@ -0,0 +1,179 @@
<template>
<page-container sub-title="物料类型管理">
<template #ops>
<a-row>
<a-col :span="16">
<a-input-search
v-model:value="searchKey"
placeholder="搜索物料"
enter-button
@search="loadData()"
></a-input-search>
</a-col>
<a-col :span="8">
<a-button type="primary" @click="addOrEdit()">
<template #icon>
<icon-font type="icon-plus"></icon-font>
</template>
添加
</a-button>
</a-col>
</a-row>
</template>
<div style="min-height: calc(100vh - 218px)">
<vxe-table
ref="xTree"
border
show-overflow
size="medium"
:loading="loading"
height="600"
:column-config="{ resizable: true }"
:scroll-y="{ enabled: true, gt: 0 }"
:expand-config="{
expandAll: true,
}"
:tree-config="{
iconOpen: 'vxe-icon-square-minus',
iconClose: 'vxe-icon-square-plus',
transform: true,
rowField: 'no',
parentField: 'parentNo',
expandAll: true,
line: true,
}"
:data="areas"
>
<vxe-column field="name" title="类型" tree-node></vxe-column>
<vxe-column field="no" title="类型编码"></vxe-column>
<vxe-column field="levelInfo.description" title="类型级别"></vxe-column>
<vxe-column field="parentNo" title="上级类型编码"></vxe-column>
<vxe-column field="ops" title="操作" width="350">
<template #default="{ row }">
<a-button type="link" @click="addOrEdit({ parentNo: row.no })">
<template #icon>
<icon-font type="icon-children" />
</template>
添加子级
</a-button>
<a-button type="link" style="margin-left: 10px" @click="addOrEdit(row)">
<template #icon>
<icon-font type="icon-edit" />
</template>
编辑
</a-button>
<a-popconfirm :title="$t('确定要删除地区', { name: row.name })" @confirm="deleteArea(row.id)">
<a-button type="link" danger style="margin-left: 10px">
<template #icon>
<icon-font type="icon-delete" />
</template>
删除
</a-button>
</a-popconfirm>
</template>
</vxe-column>
</vxe-table>
</div>
</page-container>
<form-drawer
ref="formDrawer"
v-model="area"
:form-items="items"
:config="formConfig"
:title="modalTitle"
:disabled-fields="disabledFields"
:hidden-fields="hiddenFields"
@ok="doSave"
/>
</template>
<script lang="ts" setup>
import api from '@/api'
import { config, formItems } from './form'
import FormDrawer from '@/components/form-render/form-drawer.vue'
import { notification } from 'ant-design-vue'
import { Codebook } from '@/api/api'
import { FormDataType } from '@/components/form-render/form-render-types'
const areas = ref<Array<material.Type>>([])
const loading = ref(false)
const searchKey = ref('')
const area = ref<Partial<material.Type>>({})
const levels = ref<Codebook[]>([])
api.materialApi.type.levels((data) => {
levels.value = data
})
//
const formDrawer = ref<typeof FormDrawer>()
const formConfig = computed(() => {
return config
})
//
const items = computed(() => {
return formItems(levels.value)
})
//
const disabledFields = computed(() => {
const no = area.value && area.value.id ? 'no' : ''
const parentNo = area.value && area.value.parentNo ? 'parentNo' : ''
return [no, parentNo]
})
//
const hiddenFields = computed(() => {
return area.value && area.value.parentNo ? [] : ['parentNo']
})
//
const modalTitle = computed(() => {
return area.value.id ? '编辑物料类型' : '添加物料类型'
})
//
const loadData = () => {
loading.value = true
api.materialApi.type.areas(
{
key: searchKey.value,
},
(data) => {
areas.value = data
loading.value = false
},
)
}
loadData()
//
const addOrEdit = (u?: Record<string, unknown>) => {
area.value = { ...u }
formDrawer.value?.show()
}
//
const doSave = (_data: FormDataType) => {
api.materialApi.type.addAndModify(_data as unknown as material.Type, () => {
formDrawer.value?.close()
notification.success({
message: '操作成功',
description: '新增保存成功,页面将自动刷新!',
onClose: () => {
loadData()
},
})
})
}
//
const deleteArea = (id: number) => {
api.materialApi.type.deleteArea(id, () => {
notification.success({
message: '操作成功',
description: '删除成功,页面将自动刷新!',
onClose: () => {
loadData()
},
})
})
}
</script>

View File

@ -59,8 +59,8 @@ export default defineConfig(({ mode }) => {
open: true,
proxy: {
'/api': {
// target: 'https://ims.riemann.tech/api/',
target: 'http://127.0.0.1:8888',
target: 'https://ims.riemann.tech/api/',
// target: 'http://127.0.0.1:8888',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},