diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3d0a86b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib", + "i18n-ally.localesPaths": [ + "src/locales", + "src/locales/lang", + "src/components/basic/tinymce/langs" + ] +} \ No newline at end of file diff --git a/src/api/backend/api/index.ts b/src/api/backend/api/index.ts index df7de94..59951c8 100644 --- a/src/api/backend/api/index.ts +++ b/src/api/backend/api/index.ts @@ -27,6 +27,7 @@ import * as netDiskOverview from './netDiskOverview'; import * as businessTodo from './businessTodo'; import * as contract from './contract'; import * as materialsInventory from './materialsInventory'; +import * as project from './project'; import * as company from './company'; import * as product from './product'; import * as materialsInOut from './materialsInOut'; @@ -59,4 +60,5 @@ export default { company, product, materialsInOut, + project, }; diff --git a/src/api/backend/api/project.ts b/src/api/backend/api/project.ts new file mode 100644 index 0000000..9b41aab --- /dev/null +++ b/src/api/backend/api/project.ts @@ -0,0 +1,104 @@ +import { request, type RequestOptions } from '@/utils/request'; + +/** 获取项目列表 GET /api/project */ +export async function projectList(params: API.ProjectParams, options?: RequestOptions) { + return request<{ + items?: API.ProjectEntity[]; + meta?: { + itemCount?: number; + totalItems?: number; + itemsPerPage?: number; + totalPages?: number; + currentPage?: number; + }; + }>('/api/project', { + method: 'GET', + params: { + // page has a default value: 1 + page: '1', + // pageSize has a default value: 10 + pageSize: '10', + + ...params, + }, + ...(options || {}), + }); +} + +/** 新增项目 POST /api/project */ +export async function projectCreate(body: API.ProjectDto, options?: RequestOptions) { + return request('/api/project', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || { successMsg: '创建成功' }), + }); +} + +/** 获取项目信息 GET /api/project/${param0} */ +export async function projectInfo( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ProjectInfoParams, + options?: RequestOptions, +) { + const { id: param0, ...queryParams } = params; + return request(`/api/project/${param0}`, { + method: 'GET', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 解除项目和附件关联 PUT /api/project/unlink-attachments/${param0} */ +export async function unlinkAttachments( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ProjectUpdateParams, + body: API.ProjectUpdateDto, + options?: RequestOptions, +) { + const { id: param0, ...queryParams } = params; + return request(`/api/project/unlink-attachments/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...options, + }); +} + +/** 更新项目 PUT /api/project/${param0} */ +export async function projectUpdate( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ProjectUpdateParams, + body: API.ProjectUpdateDto, + options?: RequestOptions, +) { + const { id: param0, ...queryParams } = params; + return request(`/api/project/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || { successMsg: '更新成功' }), + }); +} + +/** 删除项目 DELETE /api/project/${param0} */ +export async function projectDelete( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ProjectDeleteParams, + options?: RequestOptions, +) { + const { id: param0, ...queryParams } = params; + return request(`/api/project/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || { successMsg: '删除成功' }), + }); +} diff --git a/src/api/backend/api/typings.d.ts b/src/api/backend/api/typings.d.ts index 2eb1013..ae253f2 100644 --- a/src/api/backend/api/typings.d.ts +++ b/src/api/backend/api/typings.d.ts @@ -1413,7 +1413,7 @@ declare namespace API { /** 领料单号 */ issuanceNumber?: number; /** 项目 */ - project: string; + project: ProjectEntity; /** 备注 */ remark: string; /** 附件 */ @@ -1513,6 +1513,49 @@ declare namespace API { type MaterialsInventoryDeleteParams = { id: number; }; + + // Project + type ProjectEntity = { + /** 项目名称 */ + name: string; + /** 是否删除 */ + isDelete: string; + /** 附件 */ + files?: StorageInfo[]; + id: number; + createdAt: string; + updatedAt: string; + }; + type ProjectDto = { + /** 项目名称 */ + name: string; + fileIds?: number[]; + }; + type ProjectUpdateParams = { + id: number; + }; + type ProjectParams = { + page?: number; + pageSize?: number; + name?: string; + productId?: number; + field?: string; + order?: 'ASC' | 'DESC'; + _t?: number; + }; + type ProjectInfoParams = { + id: number; + }; + type ProjectUpdateDto = { + /** 项目名称 */ + name?: string; + /** 附件 */ + fileIds?: number[]; + }; + type ProjectDeleteParams = { + id: number; + }; + // Company type CompanyEntity = { /** 公司名称 */ @@ -1624,6 +1667,7 @@ declare namespace API { time?: string; inventoryNumber?: string; isCreateOut?: boolean; + project?:string; field?: string; order?: 'ASC' | 'DESC'; _t?: number; @@ -1655,7 +1699,9 @@ declare namespace API { /** 领料单号 */ issuanceNumber?: number; /** 项目 */ - project: string; + project: ProjectEntity; + /** 项目ID */ + projectId?:number; /** 备注 */ remark: string; /** 附件 */ @@ -1685,7 +1731,7 @@ declare namespace API { /** 领料单号 */ issuanceNumber?: number; /** 项目 */ - project?: string; + projectId?: number; /** 备注 */ remark?: string; /** 附件 */ @@ -1709,7 +1755,7 @@ declare namespace API { /** 领料单号 */ issuanceNumber?: number; /** 项目 */ - project?: string; + projectId?:number; /** 备注 */ remark?: string; /** 附件 */ diff --git a/src/components/core/schema-form/src/hooks/useFormEvents.ts b/src/components/core/schema-form/src/hooks/useFormEvents.ts index 6d73161..bd6b03c 100644 --- a/src/components/core/schema-form/src/hooks/useFormEvents.ts +++ b/src/components/core/schema-form/src/hooks/useFormEvents.ts @@ -6,7 +6,7 @@ import type { UnwrapFormSchema } from '../types/form'; import type { NamePath } from 'ant-design-vue/lib/form/interface'; import type { FormState, FormMethods } from './index'; import type { SchemaFormEmitFn } from '../schema-form'; -import { isArray, isFunction, isObject, isString } from '@/utils/is'; +import { isArray, isEmpty, isFunction, isObject, isString } from '@/utils/is'; import { deepMerge } from '@/utils'; type UseFormActionContext = FormState & { @@ -250,10 +250,12 @@ export function useFormEvents(formActionContext: UseFormActionContext) { } async function validateFields(nameList?: NamePath[] | undefined) { + if (isEmpty(nameList)) return {}; return schemaFormRef.value?.validateFields(nameList); } async function validate(nameList?: NamePath[] | undefined) { + if (isEmpty(nameList)) return {}; return await schemaFormRef.value?.validate(nameList)!; } diff --git a/src/components/core/schema-form/src/schema-form-item.vue b/src/components/core/schema-form/src/schema-form-item.vue index 0cf0212..11d0ecc 100644 --- a/src/components/core/schema-form/src/schema-form-item.vue +++ b/src/components/core/schema-form/src/schema-form-item.vue @@ -238,28 +238,34 @@ /** * @description 表单组件props */ - const getComponentProps = computed(() => { + const getComponentProps = computed(() => { const { schema } = props; let { componentProps = {}, component } = schema; - + let finalComponentProps: ComponentProps = {}; if (isFunction(componentProps)) { - componentProps = componentProps(unref(getValues)) ?? {}; + finalComponentProps = { ...(componentProps(unref(getValues)) ?? {}) }; + } else { + finalComponentProps = { ...componentProps }; } if (component !== 'RangePicker' && isString(component)) { - componentProps.placeholder ??= createPlaceholderMessage(component, getLabel.value); + finalComponentProps = { + ...finalComponentProps, + placeholder: + finalComponentProps.placeholder ?? createPlaceholderMessage(component, getLabel.value), + }; } if (schema.component === 'Divider') { - componentProps = Object.assign({ type: 'horizontal' }, componentProps, { + finalComponentProps = Object.assign({ type: 'horizontal' }, finalComponentProps, { orientation: 'left', plain: true, }); } if (isVNode(getComponent.value)) { - Object.assign(componentProps, getComponent.value.props); + finalComponentProps = Object.assign({}, finalComponentProps, getComponent.value.props); } - return componentProps; + return finalComponentProps; }); /** @@ -408,8 +414,8 @@ options: [], } as ComponentProps, }); - // const componentProps = newSchema.componentProps as ComponentProps; - updateSchema(newSchema); + updateSchema(newSchema); + //会报表单校验的错误; // @ts-ignore const result = await request({ ...unref(getValues), schema: newSchema }); if (['Select', 'RadioGroup', 'CheckBoxGroup'].some((n) => n === component)) { @@ -443,6 +449,7 @@ }, wait), { ...options, + // immediate: false, }, ); } diff --git a/src/permission/permCode.ts b/src/permission/permCode.ts index 7aa94cc..178aeb4 100644 --- a/src/permission/permCode.ts +++ b/src/permission/permCode.ts @@ -90,9 +90,16 @@ const permissions = [ 'app:product:create', 'app:product:update', 'app:product:delete', - 'materials_inventory:history_in_out:export' + 'materials_inventory:history_in_out:export', + 'app:materials_inventory:list', + 'app:project:list', + 'app:project:create', + 'app:project:update', + 'app:project:delete', + 'app:project:read', ] as const; export type PermissionType = string; +// export type PermissionType = (typeof permissions)[number]; 目前添加这个类型判断会影响vscode的性能,暂时注释掉 // console.log('permissions', permissions); diff --git a/src/views/materials-inventory/in-out/columns.tsx b/src/views/materials-inventory/in-out/columns.tsx index 8aa2c37..d8dbbc1 100644 --- a/src/views/materials-inventory/in-out/columns.tsx +++ b/src/views/materials-inventory/in-out/columns.tsx @@ -19,6 +19,14 @@ export const baseColumns: TableColumnItem[] = [ labelWidth: 120, }, }, + { + title: '项目', + width: 80, + dataIndex: 'project', + customRender: ({ record }) => { + return record?.project?.name || ''; + }, + }, { title: '所属公司', width: 100, @@ -113,11 +121,7 @@ export const baseColumns: TableColumnItem[] = [ width: 80, dataIndex: 'issuanceNumber', }, - { - title: '项目', - width: 80, - dataIndex: 'project', - }, + { title: '备注', width: 80, diff --git a/src/views/materials-inventory/in-out/formSchemas.ts b/src/views/materials-inventory/in-out/formSchemas.ts index a67b220..106220e 100644 --- a/src/views/materials-inventory/in-out/formSchemas.ts +++ b/src/views/materials-inventory/in-out/formSchemas.ts @@ -15,7 +15,7 @@ export const formSchemas = (isEdit?: boolean): FormSchema ({ + showSearch: true, + filterOption: false, + fieldNames: { + label: 'label', + value: 'value', + }, + getPopupContainer: () => document.body, + defaultActiveFirstOption: true, + onClear: async () => { + const newSchema = { + field: schema.field, + componentProps: { + options: [] as LabelValueOptions, + }, + }; + const options = await getProjectOptions().finally(() => (schema.loading = false)); + newSchema.componentProps.options = options; + formInstance?.updateSchema([newSchema]); + }, + request: () => { + return getProjectOptions(); + }, + onSearch: debounce(async (keyword) => { + schema.loading = true; + const newSchema = { + field: schema.field, + componentProps: { + options: [] as LabelValueOptions, + }, + }; + formInstance?.updateSchema([newSchema]); + const options = await getProjectOptions(keyword).finally(() => (schema.loading = false)); + newSchema.componentProps.options = options; + formInstance?.updateSchema([newSchema]); + }, 500), + }), + }, { label: '时间', field: 'time', @@ -183,14 +229,7 @@ export const formSchemas = (isEdit?: boolean): FormSchema => { + const { items: result } = await Api.project.projectList({ pageSize: 100, name: keyword }); + return ( + result?.map((item) => ({ + label: `${item.name}`, + value: item.id, + })) || [] + ); +}; + const getProductOptions = async (keyword?: string): Promise => { const { items: result } = await Api.product.productList({ pageSize: 100, name: keyword }); return ( diff --git a/src/views/materials-inventory/in-out/index.vue b/src/views/materials-inventory/in-out/index.vue index 93d3172..e7fa2f8 100644 --- a/src/views/materials-inventory/in-out/index.vue +++ b/src/views/materials-inventory/in-out/index.vue @@ -153,7 +153,6 @@ const openEditModal = async (record: Partial) => { const [formRef] = await showModal({ modalProps: { - title: `${record.id ? '编辑' : '新增'}出入库记录`, width: '50%', onFinish: async (values) => { diff --git a/src/views/materials-inventory/product/formSchemas.ts b/src/views/materials-inventory/product/formSchemas.ts index e45115d..8696874 100644 --- a/src/views/materials-inventory/product/formSchemas.ts +++ b/src/views/materials-inventory/product/formSchemas.ts @@ -18,6 +18,9 @@ export const formSchemas: FormSchema[] = [ label: '单位', component: 'Select', field: 'unitId', + colProps: { + span: 12, + }, componentProps: ({ formInstance, schema, formModel }) => ({ showSearch: true, filterOption: (input: string, option: any) => { diff --git a/src/views/materials-inventory/project/columns.tsx b/src/views/materials-inventory/project/columns.tsx new file mode 100644 index 0000000..016aee5 --- /dev/null +++ b/src/views/materials-inventory/project/columns.tsx @@ -0,0 +1,10 @@ +import type { TableColumn } from '@/components/core/dynamic-table'; + +export type TableListItem = API.ProjectEntity; +export type TableColumnItem = TableColumn; +export const baseColumns: TableColumnItem[] = [ + { + title: '项目名称', + dataIndex: 'name', + }, +]; diff --git a/src/views/materials-inventory/project/formSchemas.ts b/src/views/materials-inventory/project/formSchemas.ts new file mode 100644 index 0000000..03f4b58 --- /dev/null +++ b/src/views/materials-inventory/project/formSchemas.ts @@ -0,0 +1,12 @@ +import type { FormSchema } from '@/components/core/schema-form/'; +export const formSchemas: FormSchema[] = [ + { + field: 'name', + component: 'Input', + label: '项目名称', + rules: [{ required: true, type: 'string' }], + colProps: { + span: 12, + }, + }, +]; diff --git a/src/views/materials-inventory/project/index.vue b/src/views/materials-inventory/project/index.vue new file mode 100644 index 0000000..219c50e --- /dev/null +++ b/src/views/materials-inventory/project/index.vue @@ -0,0 +1,201 @@ + + + + +