diff --git a/src/api/project.ts b/src/api/project.ts index a7636ee..0dc06cf 100644 --- a/src/api/project.ts +++ b/src/api/project.ts @@ -605,3 +605,148 @@ export const getTaskStatusStats = (projectId: string) => { { params: { projectId } } ); }; + +// ==================== 资源管理 API ==================== + +/** 资源实体 - 根据 OpenAPI 定义 */ +export type Resource = { + id?: string; + resourceCode?: string; + projectId?: string; + resourceType?: string; // human-人力, material-物料, equipment-设备, software-软件, finance-资金, other-其他 + resourceName?: string; + description?: string; + specification?: string; + unit?: string; + planQuantity?: number; + actualQuantity?: number; + unitPrice?: number; + currency?: string; + supplier?: string; + status?: string; // planned-计划中, requested-已申请, approved-已批准, procuring-采购中, arrived-已到货, in_use-使用中, completed-已完成 + planArriveDate?: string; + actualArriveDate?: string; + responsibleId?: string; + responsibleName?: string; + location?: string; + tags?: string[]; + extraData?: Record; + createBy?: string; + createTime?: string; + updateBy?: string; + updateTime?: string; +}; + +/** 资源更新请求 - 根据 OpenAPI 定义 */ +export type ResourceUpdateRequest = { + id: string; + resourceType?: string; + resourceName?: string; + description?: string; + specification?: string; + unit?: string; + planQuantity?: number; + actualQuantity?: number; + unitPrice?: number; + currency?: string; + supplier?: string; + status?: string; + planArriveDate?: string; + actualArriveDate?: string; + responsibleId?: string; + responsibleName?: string; + location?: string; + tags?: string[]; + extraData?: Record; +}; + +/** 资源查询参数 */ +export type ResourceQueryParams = { + pageNum?: number; + pageSize?: number; + projectId?: string; + resourceType?: string; + status?: string; + keyword?: string; +}; + +/** 分页数据结构(资源列表用) */ +export type PageResult = { + records: T[]; + total: number; + size: number; + current: number; +}; + +/** 分页查询资源列表 */ +export const getResourceList = (params?: ResourceQueryParams) => { + return http.request>>( + "get", + "/api/v1/resource/list", + { params } + ); +}; + +/** 根据ID查询资源详情 */ +export const getResourceById = (id: string) => { + return http.request>("get", `/api/v1/resource/${id}`); +}; + +/** 新增资源 */ +export const createResource = (data: Resource) => { + return http.request>("post", "/api/v1/resource", { data }); +}; + +/** 修改资源 */ +export const updateResource = (data: ResourceUpdateRequest) => { + return http.request>("put", "/api/v1/resource", { data }); +}; + +/** 删除资源 */ +export const deleteResource = (id: string) => { + return http.request>("delete", `/api/v1/resource/${id}`); +}; + +/** 更新资源状态 */ +export const updateResourceStatus = (id: string, status: string) => { + return http.request>("put", `/api/v1/resource/${id}/status`, { + params: { status } + }); +}; + +/** 更新资源数量 */ +export const updateResourceQuantity = (id: string, actualQuantity: string) => { + return http.request>("put", `/api/v1/resource/${id}/quantity`, { + params: { actualQuantity } + }); +}; + +/** 查询资源预算汇总 */ +export const getResourceBudgetStats = (projectId: string) => { + return http.request[]>>( + "get", + "/api/v1/resource/stats/budget", + { params: { projectId } } + ); +}; + +/** 查询即将到位的资源 */ +export const getPendingArrivalResources = ( + projectId: string, + days: number = 7 +) => { + return http.request>( + "get", + "/api/v1/resource/pending-arrival", + { params: { projectId, days } } + ); +}; + +/** 查询待审批的资源申请 */ +export const getPendingApprovalResources = (projectId?: string) => { + return http.request[]>>( + "get", + "/api/v1/resource/pending-approval", + { params: { projectId } } + ); +}; diff --git a/src/api/资源模块.openapi.json b/src/api/资源模块.openapi.json new file mode 100644 index 0000000..a6a2ce4 --- /dev/null +++ b/src/api/资源模块.openapi.json @@ -0,0 +1,917 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "默认模块", + "description": "", + "version": "1.0.0" + }, + "tags": [], + "paths": { + "/api/v1/resource/list": { + "get": { + "summary": "分页查询资源列表", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "pageNum", + "in": "query", + "description": "", + "required": true, + "example": 1, + "schema": { + "type": "integer" + } + }, + { + "name": "pageSize", + "in": "query", + "description": "", + "required": true, + "example": 10, + "schema": { + "type": "integer" + } + }, + { + "name": "projectId", + "in": "query", + "description": "", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "resourceType", + "in": "query", + "description": "", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "keyword", + "in": "query", + "description": "", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageMapObject" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/resource/{id}": { + "get": { + "summary": "根据ID查询资源详情", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseResource" + } + } + } + } + }, + "security": [] + }, + "delete": { + "summary": "删除资源", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/resource": { + "post": { + "summary": "新增资源", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Resource", + "description": "" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLong" + } + } + } + } + }, + "security": [] + }, + "put": { + "summary": "修改资源", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceUpdateRequest", + "description": "" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/resource/{id}/status": { + "put": { + "summary": "更新资源状态", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/resource/{id}/quantity": { + "put": { + "summary": "更新资源数量", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "actualQuantity", + "in": "query", + "description": "", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/resource/stats/budget": { + "get": { + "summary": "查询资源预算汇总", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "projectId", + "in": "query", + "description": "", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListMapObject" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/resource/pending-arrival": { + "get": { + "summary": "查询即将到位的资源", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "projectId", + "in": "query", + "description": "", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "days", + "in": "query", + "description": "", + "required": true, + "example": 7, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListResource" + } + } + } + } + }, + "security": [] + } + }, + "/api/v1/resource/pending-approval": { + "get": { + "summary": "查询待审批的资源申请", + "deprecated": false, + "description": "", + "tags": [], + "parameters": [ + { + "name": "projectId", + "in": "query", + "description": "", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "Authorization", + "in": "header", + "description": "", + "example": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95", + "schema": { + "type": "string", + "default": "Bearer b35c6f5b-bc0b-4652-bef2-eca04a5cdd95" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListMapObject" + } + } + } + } + }, + "security": [] + } + } + }, + "components": { + "schemas": { + "OrderItem": { + "type": "object", + "properties": { + "column": { + "type": "string", + "description": "需要进行排序的字段" + }, + "asc": { + "type": "boolean", + "description": "是否正序排列,默认 true", + "default": true + } + } + }, + "MapObject": { + "type": "object", + "properties": { + "key": { + "$ref": "#/components/schemas/key" + } + } + }, + "PageMapObject": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MapObject" + }, + "description": "查询数据列表", + "default": "Collections.emptyList()" + }, + "total": { + "type": "integer", + "description": "总数", + "format": "int64", + "default": 0 + }, + "size": { + "type": "integer", + "description": "每页显示条数,默认 10", + "format": "int64", + "default": 10 + }, + "current": { + "type": "integer", + "description": "当前页", + "format": "int64", + "default": 1 + }, + "orders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderItem", + "description": "com.baomidou.mybatisplus.core.metadata.OrderItem" + }, + "description": "排序字段信息", + "default": "new ArrayList<>()" + }, + "optimizeCountSql": { + "type": "boolean", + "description": "自动优化 COUNT SQL", + "default": true + }, + "searchCount": { + "type": "boolean", + "description": "是否进行 count 查询", + "default": true + }, + "optimizeJoinOfCountSql": { + "type": "boolean", + "description": "{@link #optimizeJoinOfCountSql()}", + "default": true + }, + "maxLimit": { + "type": "integer", + "description": "单页分页条数限制", + "format": "int64" + }, + "countId": { + "type": "string", + "description": "countId" + }, + "pages": { + "type": "integer", + "format": "int64" + } + } + }, + "BaseResponsePageMapObject": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/PageMapObject", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "Resource": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "", + "format": "int64" + }, + "resourceCode": { + "type": "string", + "description": "资源编号" + }, + "projectId": { + "type": "integer", + "description": "项目ID", + "format": "int64" + }, + "resourceType": { + "type": "string", + "description": "资源类型: human-人力, material-物料, equipment-设备, software-软件, finance-资金, other-其他" + }, + "resourceName": { + "type": "string", + "description": "资源名称" + }, + "description": { + "type": "string", + "description": "资源描述" + }, + "specification": { + "type": "string", + "description": "规格型号" + }, + "unit": { + "type": "string", + "description": "单位" + }, + "planQuantity": { + "type": "number", + "description": "计划数量" + }, + "actualQuantity": { + "type": "number", + "description": "实际数量" + }, + "unitPrice": { + "type": "number", + "description": "单价" + }, + "currency": { + "type": "string", + "description": "币种" + }, + "supplier": { + "type": "string", + "description": "供应商/来源" + }, + "status": { + "type": "string", + "description": "状态: planned-计划中, requested-已申请, approved-已批准, procuring-采购中, arrived-已到货, in_use-使用中, completed-已完成" + }, + "planArriveDate": { + "type": "string", + "description": "计划到位日期" + }, + "actualArriveDate": { + "type": "string", + "description": "实际到位日期" + }, + "responsibleId": { + "type": "integer", + "description": "负责人ID", + "format": "int64" + }, + "location": { + "type": "string", + "description": "存放位置" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "标签" + }, + "extraData": { + "type": "object", + "properties": {}, + "description": "扩展数据" + }, + "createBy": { + "type": "integer", + "description": "创建人", + "format": "int64" + }, + "createTime": { + "type": "string", + "description": "创建时间" + }, + "updateBy": { + "type": "integer", + "description": "更新人", + "format": "int64" + }, + "updateTime": { + "type": "string", + "description": "更新时间" + }, + "deleted": { + "type": "integer", + "description": "删除标记" + } + } + }, + "key": { + "type": "object", + "properties": {} + }, + "BaseResponseLong": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "type": "integer", + "description": "", + "format": "int64" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "BaseResponseResource": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "$ref": "#/components/schemas/Resource", + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "BaseResponseVoid": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "description": "", + "type": "null" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "ResourceUpdateRequest": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "资源ID(必填)", + "format": "int64" + }, + "resourceType": { + "type": "string", + "description": "资源类型: human-人力, material-物料, equipment-设备, software-软件, finance-资金, other-其他" + }, + "resourceName": { + "type": "string", + "description": "资源名称" + }, + "description": { + "type": "string", + "description": "资源描述" + }, + "specification": { + "type": "string", + "description": "规格型号" + }, + "unit": { + "type": "string", + "description": "单位" + }, + "planQuantity": { + "type": "number", + "description": "计划数量" + }, + "actualQuantity": { + "type": "number", + "description": "实际数量" + }, + "unitPrice": { + "type": "number", + "description": "单价" + }, + "currency": { + "type": "string", + "description": "币种" + }, + "supplier": { + "type": "string", + "description": "供应商/来源" + }, + "status": { + "type": "string", + "description": "状态: planned-计划中, requested-已申请, approved-已批准, procuring-采购中, arrived-已到货, in_use-使用中, completed-已完成" + }, + "planArriveDate": { + "type": "string", + "description": "计划到位日期" + }, + "actualArriveDate": { + "type": "string", + "description": "实际到位日期" + }, + "responsibleId": { + "type": "integer", + "description": "负责人ID(直接传递ID时使用)", + "format": "int64" + }, + "responsibleName": { + "type": "string", + "description": "负责人姓名(根据姓名自动匹配用户ID)" + }, + "location": { + "type": "string", + "description": "存放位置" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "标签" + }, + "extraData": { + "type": "object", + "properties": {}, + "description": "扩展数据" + } + } + }, + "BaseResponseListMapObject": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MapObject" + }, + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + }, + "BaseResponseListResource": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Resource", + "description": "资源实体类\n对应数据库表: resource" + }, + "description": "" + }, + "message": { + "type": "string", + "description": "" + } + } + } + }, + "responses": {}, + "securitySchemes": {} + }, + "servers": [], + "security": [] +} diff --git a/src/views/project/detail.vue b/src/views/project/detail.vue index 9721c8f..898634d 100644 --- a/src/views/project/detail.vue +++ b/src/views/project/detail.vue @@ -10,12 +10,17 @@ import { createMilestone, updateMilestone, deleteMilestone, + createResource, + updateResource, + deleteResource, type ProjectDetail, type ProjectMember, type ProjectMilestone, type ProjectTask, type ProjectResource, - type ProjectRisk + type ProjectRisk, + type Resource, + type ResourceUpdateRequest } from "@/api/project"; import { hasPerms } from "@/utils/auth"; import { GGanttChart, GGanttRow } from "@infectoone/vue-ganttastic"; @@ -56,6 +61,13 @@ const canCreateMilestone = computed(() => hasPerms("project:milestone:create")); const canUpdateMilestone = computed(() => hasPerms("project:milestone:update")); const canDeleteMilestone = computed(() => hasPerms("project:milestone:delete")); +// 权限控制 - 资源(基础权限) +const canCreateResource = computed(() => hasPerms("project:resource:create")); +const canUpdateResource = computed(() => hasPerms("project:resource:update")); +const canDeleteResource = computed(() => hasPerms("project:resource:delete")); +const canViewResource = computed(() => hasPerms("project:resource:view")); +const canStatsResource = computed(() => hasPerms("project:resource:stats")); + // 加载状态 const loading = ref(false); const ganttLoading = ref(false); @@ -121,6 +133,32 @@ const milestoneEditForm = ref({ const milestoneEditLoading = ref(false); const isMilestoneEdit = ref(false); // true=编辑, false=新增 +// 资源编辑模态框 +const resourceEditModal = ref(false); +const resourceEditForm = ref({ + id: "", + resourceCode: "", + resourceType: "material", + resourceName: "", + description: "", + specification: "", + unit: "", + planQuantity: 0, + actualQuantity: 0, + unitPrice: 0, + currency: "CNY", + supplier: "", + status: "planned", + planArriveDate: "", + actualArriveDate: "", + responsibleId: "", + responsibleName: "", + location: "", + tags: [] +}); +const resourceEditLoading = ref(false); +const isResourceEdit = ref(false); // true=编辑, false=新增 + // 权限控制 - 派生权限(需要放在 isTaskEdit/isMilestoneEdit 定义之后) // 任务编辑权限:新增或编辑任一即可显示按钮 const canEditTask = computed(() => canCreateTask.value || canUpdateTask.value); @@ -138,6 +176,16 @@ const canSaveMilestone = computed(() => { ? canUpdateMilestone.value : canCreateMilestone.value; }); +// 资源编辑权限:新增或编辑任一即可显示按钮 +const canEditResource = computed( + () => canCreateResource.value || canUpdateResource.value +); +// 资源保存权限:新增时需要create权限,编辑时需要update权限 +const canSaveResource = computed(() => { + return isResourceEdit.value + ? canUpdateResource.value + : canCreateResource.value; +}); // 项目基本信息(计算属性) const projectInfo = computed(() => { @@ -736,6 +784,103 @@ async function handleDeleteMilestone(milestoneId: string) { } } +// ==================== 资源编辑功能 ==================== + +/** 打开新增资源对话框 */ +function openAddResourceModal() { + isResourceEdit.value = false; + resourceEditForm.value = { + id: "", + resourceCode: "", + resourceType: "material", + resourceName: "", + description: "", + specification: "", + unit: "", + planQuantity: 0, + actualQuantity: 0, + unitPrice: 0, + currency: "CNY", + supplier: "", + status: "planned", + planArriveDate: "", + actualArriveDate: "", + responsibleId: "", + responsibleName: "", + location: "", + tags: [] + }; + resourceEditModal.value = true; +} + +/** 打开编辑资源对话框 */ +function openEditResourceModal(resource: Resource) { + isResourceEdit.value = true; + resourceEditForm.value = { ...resource }; + resourceEditModal.value = true; +} + +/** 保存资源 */ +async function saveResource() { + if (!resourceEditForm.value.resourceName) { + message("请输入资源名称", { type: "warning" }); + return; + } + resourceEditLoading.value = true; + try { + if (isResourceEdit.value) { + const updateData: ResourceUpdateRequest = { + id: resourceEditForm.value.id!, + resourceType: resourceEditForm.value.resourceType, + resourceName: resourceEditForm.value.resourceName, + description: resourceEditForm.value.description, + specification: resourceEditForm.value.specification, + unit: resourceEditForm.value.unit, + planQuantity: resourceEditForm.value.planQuantity, + actualQuantity: resourceEditForm.value.actualQuantity, + unitPrice: resourceEditForm.value.unitPrice, + currency: resourceEditForm.value.currency, + supplier: resourceEditForm.value.supplier, + status: resourceEditForm.value.status, + planArriveDate: resourceEditForm.value.planArriveDate, + actualArriveDate: resourceEditForm.value.actualArriveDate, + responsibleId: resourceEditForm.value.responsibleId, + responsibleName: resourceEditForm.value.responsibleName, + location: resourceEditForm.value.location, + tags: resourceEditForm.value.tags + }; + await updateResource(updateData); + message("资源更新成功", { type: "success" }); + } else { + const createData = { + ...resourceEditForm.value, + projectId: projectId.value + }; + await createResource(createData); + message("资源创建成功", { type: "success" }); + } + resourceEditModal.value = false; + await fetchProjectDetail(); + } catch (error) { + console.error("保存资源失败:", error); + message("保存资源失败", { type: "error" }); + } finally { + resourceEditLoading.value = false; + } +} + +/** 删除资源 */ +async function handleDeleteResource(resourceId: string) { + try { + await deleteResource(resourceId); + message("资源删除成功", { type: "success" }); + await fetchProjectDetail(); + } catch (error) { + console.error("删除资源失败:", error); + message("删除资源失败", { type: "error" }); + } +} + onMounted(() => { fetchProjectDetail(); fetchGanttData(); @@ -1210,11 +1355,27 @@ onMounted(() => {
项目物料清单 + {{ resourceList.length }} 个 +
+
+ + + 新增资源 + + + 查看全部 + +
- - 查看全部 - - @@ -1263,9 +1424,28 @@ onMounted(() => { - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +