From 1b6cf4896705048864bf9dd6fc16363e1549135d Mon Sep 17 00:00:00 2001 From: caiyuchao Date: Tue, 27 May 2025 12:01:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-antd/src/api/license/project/index.ts | 61 +++ .../src/locales/langs/en-US/menu.json | 3 +- .../src/locales/langs/zh-CN/menu.json | 3 +- apps/web-antd/src/utils/dict.ts | 2 + .../src/views/license/project/data.ts | 451 ++++++++++++++++++ .../src/views/license/project/index.vue | 142 ++++++ .../views/license/project/modules/form.vue | 89 ++++ 7 files changed, 749 insertions(+), 2 deletions(-) create mode 100644 apps/web-antd/src/api/license/project/index.ts create mode 100644 apps/web-antd/src/views/license/project/data.ts create mode 100644 apps/web-antd/src/views/license/project/index.vue create mode 100644 apps/web-antd/src/views/license/project/modules/form.vue diff --git a/apps/web-antd/src/api/license/project/index.ts b/apps/web-antd/src/api/license/project/index.ts new file mode 100644 index 0000000..21855da --- /dev/null +++ b/apps/web-antd/src/api/license/project/index.ts @@ -0,0 +1,61 @@ +import type { Dayjs } from 'dayjs'; + +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace ProjectApi { + /** 项目信息 */ + export interface Project { + id: number; // 主键 + customerId?: number; // 客户ID + name?: string; // 项目名称 + code?: string; // 项目编号 + contractCode?: string; // 合同编号 + businessStatus: number; // 商务状态 + businessOwner?: number; // 业务负责人 + customerOwner?: number; // 客户对接人 + technicalOwnerA?: number; // 技术负责人1 + technicalOwnerB: number; // 技术负责人2 + technicalOwnerC: number; // 技术负责人3 + startTime: Dayjs | string; // 项目开始时间 + endTime: Dayjs | string; // 项目结束时间 + status?: number; // 项目状态 + envInfo: string; // 环境信息 + envFileId: number; // 环境信息附件id + remark: string; // 备注 + } +} + +/** 查询项目分页 */ +export function getProjectPage(params: PageParam) { + return requestClient.get>( + '/license/project/page', + { params }, + ); +} + +/** 查询项目详情 */ +export function getProject(id: number) { + return requestClient.get(`/license/project/get?id=${id}`); +} + +/** 新增项目 */ +export function createProject(data: ProjectApi.Project) { + return requestClient.post('/license/project/create', data); +} + +/** 修改项目 */ +export function updateProject(data: ProjectApi.Project) { + return requestClient.put('/license/project/update', data); +} + +/** 删除项目 */ +export function deleteProject(id: number) { + return requestClient.delete(`/license/project/delete?id=${id}`); +} + +/** 导出项目 */ +export function exportProject(params: any) { + return requestClient.download('/license/project/export-excel', params); +} diff --git a/apps/web-antd/src/locales/langs/en-US/menu.json b/apps/web-antd/src/locales/langs/en-US/menu.json index 8f4ee17..39c45aa 100644 --- a/apps/web-antd/src/locales/langs/en-US/menu.json +++ b/apps/web-antd/src/locales/langs/en-US/menu.json @@ -82,5 +82,6 @@ "track": "Link Tracking" } }, - "customer": "Customer Management" + "customer": "Customer Management", + "project": "Project Management" } diff --git a/apps/web-antd/src/locales/langs/zh-CN/menu.json b/apps/web-antd/src/locales/langs/zh-CN/menu.json index b869be7..fddacba 100644 --- a/apps/web-antd/src/locales/langs/zh-CN/menu.json +++ b/apps/web-antd/src/locales/langs/zh-CN/menu.json @@ -82,5 +82,6 @@ "track": "链路追踪" } }, - "customer": "客户管理" + "customer": "客户管理", + "project": "项目管理" } diff --git a/apps/web-antd/src/utils/dict.ts b/apps/web-antd/src/utils/dict.ts index 7480127..0cfa7e0 100644 --- a/apps/web-antd/src/utils/dict.ts +++ b/apps/web-antd/src/utils/dict.ts @@ -220,7 +220,9 @@ enum DICT_TYPE { IOT_UNIT_TYPE = 'iot_unit_type', // IOT 单位类型 IOT_VALIDATE_TYPE = 'iot_validate_type', // IOT 数据校验级别 // ========== LICENSE 模块 ========== + LIC_BUSINESS_STATUS = 'lic_business_status', // 商务状态 LIC_CUSTOMER_TYPE = 'lic_customer_type', // 客户类型 + LIC_PROJECT_STATUS = 'lic_project_status', // 项目状态 MEMBER_EXPERIENCE_BIZ_TYPE = 'member_experience_biz_type', // 会员经验业务类型 // ========== Member 会员模块 ========== MEMBER_POINT_BIZ_TYPE = 'member_point_biz_type', // 积分的业务类型 diff --git a/apps/web-antd/src/views/license/project/data.ts b/apps/web-antd/src/views/license/project/data.ts new file mode 100644 index 0000000..6b11cf2 --- /dev/null +++ b/apps/web-antd/src/views/license/project/data.ts @@ -0,0 +1,451 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { ProjectApi } from '#/api/license/project'; + +import { useAccess } from '@vben/access'; + +import { getSimpleUserList } from '#/api/system/user'; +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +const { hasAccessByCodes } = useAccess(); + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'customerId', + label: '客户ID', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入客户ID', + }, + }, + { + fieldName: 'name', + label: '项目名称', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入项目名称', + }, + }, + { + fieldName: 'code', + label: '项目编号', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入项目编号', + }, + }, + { + fieldName: 'contractCode', + label: '合同编号', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入合同编号', + }, + }, + { + fieldName: 'businessStatus', + label: '商务状态', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.LIC_BUSINESS_STATUS, 'number'), + placeholder: '请选择商务状态', + }, + }, + { + fieldName: 'businessOwner', + label: '业务负责人', + rules: 'required', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + showSearch: true, + filterOption: (input: string, option: any) => + option.label.toLowerCase().includes(input.toLowerCase()), + }, + }, + { + fieldName: 'customerOwner', + label: '客户对接人', + rules: 'required', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + showSearch: true, + filterOption: (input: string, option: any) => + option.label.toLowerCase().includes(input.toLowerCase()), + }, + }, + { + fieldName: 'technicalOwnerA', + label: '技术负责人1', + rules: 'required', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + showSearch: true, + filterOption: (input: string, option: any) => + option.label.toLowerCase().includes(input.toLowerCase()), + }, + }, + { + fieldName: 'technicalOwnerB', + label: '技术负责人2', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + showSearch: true, + filterOption: (input: string, option: any) => + option.label.toLowerCase().includes(input.toLowerCase()), + }, + }, + { + fieldName: 'technicalOwnerC', + label: '技术负责人3', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + showSearch: true, + filterOption: (input: string, option: any) => + option.label.toLowerCase().includes(input.toLowerCase()), + }, + }, + { + fieldName: 'startTime', + label: '项目开始时间', + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + { + fieldName: 'endTime', + label: '项目结束时间', + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + { + fieldName: 'status', + label: '项目状态', + rules: 'required', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.LIC_PROJECT_STATUS, 'number'), + placeholder: '请选择项目状态', + }, + }, + { + fieldName: 'envInfo', + label: '环境信息', + component: 'Input', + componentProps: { + placeholder: '请输入环境信息', + }, + }, + { + fieldName: 'envFileId', + label: '环境信息附件id', + component: 'Input', + componentProps: { + placeholder: '请输入环境信息附件id', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '项目名称', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入项目名称', + }, + }, + { + fieldName: 'code', + label: '项目编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入项目编号', + }, + }, + { + fieldName: 'contractCode', + label: '合同编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入合同编号', + }, + }, + { + fieldName: 'businessStatus', + label: '商务状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.LIC_BUSINESS_STATUS, 'number'), + placeholder: '请选择商务状态', + }, + }, + { + fieldName: 'businessOwner', + label: '业务负责人', + component: 'Select', + componentProps: { + allowClear: true, + options: [], + placeholder: '请选择业务负责人', + }, + }, + { + fieldName: 'customerOwner', + label: '客户对接人', + component: 'Select', + componentProps: { + allowClear: true, + options: [], + placeholder: '请选择客户对接人', + }, + }, + { + fieldName: 'technicalOwnerA', + label: '技术负责人1', + component: 'Select', + componentProps: { + allowClear: true, + options: [], + placeholder: '请选择技术负责人1', + }, + }, + { + fieldName: 'technicalOwnerB', + label: '技术负责人2', + component: 'Select', + componentProps: { + allowClear: true, + options: [], + placeholder: '请选择技术负责人2', + }, + }, + { + fieldName: 'technicalOwnerC', + label: '技术负责人3', + component: 'Select', + componentProps: { + allowClear: true, + options: [], + placeholder: '请选择技术负责人3', + }, + }, + { + fieldName: 'startTime', + label: '项目开始时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + { + fieldName: 'endTime', + label: '项目结束时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + { + fieldName: 'status', + label: '项目状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.LIC_PROJECT_STATUS, 'number'), + placeholder: '请选择项目状态', + }, + }, + { + fieldName: 'envInfo', + label: '环境信息', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入环境信息', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns( + onActionClick?: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '项目名称', + minWidth: 120, + }, + { + field: 'code', + title: '项目编号', + minWidth: 120, + }, + { + field: 'contractCode', + title: '合同编号', + minWidth: 120, + }, + { + field: 'businessStatus', + title: '商务状态', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.LIC_BUSINESS_STATUS }, + }, + }, + { + field: 'businessOwner', + title: '业务负责人', + minWidth: 120, + }, + { + field: 'customerOwner', + title: '客户对接人', + minWidth: 120, + }, + { + field: 'technicalOwnerA', + title: '技术负责人1', + minWidth: 120, + }, + { + field: 'technicalOwnerB', + title: '技术负责人2', + minWidth: 120, + }, + { + field: 'technicalOwnerC', + title: '技术负责人3', + minWidth: 120, + }, + { + field: 'startTime', + title: '项目开始时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'endTime', + title: '项目结束时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '项目状态', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.LIC_PROJECT_STATUS }, + }, + }, + { + field: 'envInfo', + title: '环境信息', + minWidth: 120, + }, + { + field: 'remark', + title: '备注', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'operation', + title: '操作', + minWidth: 200, + align: 'center', + fixed: 'right', + headerAlign: 'center', + showOverflow: false, + cellRender: { + attrs: { + nameField: 'id', + nameTitle: '项目', + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'edit', + show: hasAccessByCodes(['license:project:update']), + }, + { + code: 'delete', + show: hasAccessByCodes(['license:project:delete']), + }, + ], + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/license/project/index.vue b/apps/web-antd/src/views/license/project/index.vue new file mode 100644 index 0000000..c46ff9e --- /dev/null +++ b/apps/web-antd/src/views/license/project/index.vue @@ -0,0 +1,142 @@ + + + diff --git a/apps/web-antd/src/views/license/project/modules/form.vue b/apps/web-antd/src/views/license/project/modules/form.vue new file mode 100644 index 0000000..c05d83a --- /dev/null +++ b/apps/web-antd/src/views/license/project/modules/form.vue @@ -0,0 +1,89 @@ + + +