This commit is contained in:
Mr.j 2025-08-08 10:24:59 +08:00
commit 478aaf4a0a
10 changed files with 786 additions and 233 deletions

View File

@ -58,7 +58,8 @@ export function getFilesApi(params?: FileListParams) {
params: { params: {
page: params?.page || 1, page: params?.page || 1,
pageSize: params?.pageSize || 10, pageSize: params?.pageSize || 10,
folderId: params?.folderId || '0' folderId: params?.folderId || '0',
fileName: params?.fileName
} }
}) })
} }
@ -167,8 +168,19 @@ export function previewFileApi(fileId: string) {
}) })
} }
// 重命名文件(后端没有提供重命名接口,需要先删除再上传) // 重命名文件
export function updateFileNameApi(fileId: string, data: RenameFileParams) { export function renameFileApi(fileId: string, newFileName: string) {
// 注意后端没有提供文件重命名接口这里返回一个Promise.reject return request({
return Promise.reject(new Error('后端暂不支持文件重命名功能')) url: '/businessData/file/rename',
method: 'put',
params: {
fileId: fileId,
newFileName: newFileName
}
})
}
// 重命名文件(兼容旧接口)
export function updateFileNameApi(fileId: string, data: RenameFileParams) {
return renameFileApi(fileId, data.newFileName)
} }

View File

@ -30,6 +30,7 @@ export interface FileListParams {
page?: number page?: number
pageSize?: number pageSize?: number
folderId?: string folderId?: string
fileName?: string
} }
/** 文件夹列表响应 */ /** 文件夹列表响应 */
@ -91,5 +92,5 @@ export interface PreviewFileParams {
/** 重命名文件请求参数 */ /** 重命名文件请求参数 */
export interface RenameFileParams { export interface RenameFileParams {
fileId: string fileId: string
newName: string newFileName: string
} }

View File

@ -0,0 +1,64 @@
import request from '@/utils/http'
// 合同查询参数类型
export interface ContractQueryParams {
page?: number
pageSize?: number
code?: string
customer?: string
contractStatus?: string
type?: string
signDate?: string
paymentDate?: string
performanceDeadline?: string
salespersonId?: string
departmentId?: string
projectId?: string
}
// 合同响应数据类型
export interface ContractData {
accountNumber: string
amount: number
code: string
contractId: string
contractStatus: string
contractText: string
customer: string
departmentId: string
duration: string
notes: string
page: number
pageSize: number
paymentAddress: string
paymentDate: string
performanceDeadline: string
productService: string
projectId: string
projectName: string
receivedAmount: number
salespersonDeptName: string
salespersonId: string
salespersonName: string
settlementAmount: number
signDate: string
type: string
}
// 合同列表响应类型
export interface ContractListResponse {
code: number
msg: string
rows: ContractData[]
total: number
}
const BASE_URL = '/contract'
/**
*
* @param params
*/
export function getContractList(params: ContractQueryParams) {
return request.get<ContractListResponse>(`${BASE_URL}/list`, params)
}

View File

@ -26,53 +26,52 @@ export const systemRoutes: RouteRecordRaw[] = [
// } // }
// ], // ],
// }, // },
{ // {
path: '/regulation', // path: '/regulation',
name: 'Regulation', // name: 'Regulation',
component: Layout, // component: Layout,
redirect: '/regulation/system-regulation', // redirect: '/regulation/system-regulation',
meta: { title: '制度管理', icon: 'file-text', hidden: false, sort: 1.5 }, // meta: { title: '制度管理', icon: 'file-text', hidden: false, sort: 1.5 },
children: [ // children: [
{ // {
path: '/regulation/system-regulation', // path: '/regulation/system-regulation',
name: 'SystemRegulation', // name: 'SystemRegulation',
component: () => import('@/views/regulation/repository.vue'), // component: () => import('@/views/regulation/repository.vue'),
meta: { title: '制度公告', icon: 'file-text', hidden: false }, // meta: { title: '制度公告', icon: 'file-text', hidden: false },
}, // },
{ // {
path: '/regulation/process-management', // path: '/regulation/process-management',
name: 'ProcessManagement', // name: 'ProcessManagement',
component: () => import('@/views/regulation/confirm.vue'), // component: () => import('@/views/regulation/confirm.vue'),
meta: { title: '制度公示', icon: 'workflow', hidden: false }, // meta: { title: '制度公示', icon: 'workflow', hidden: false },
}, // },
{ // {
path: '/regulation/proposal', // path: '/regulation/proposal',
name: 'RegulationProposal', // name: 'RegulationProposal',
component: () => import('@/views/regulation/proposal/index.vue'), // component: () => import('@/views/regulation/proposal/index.vue'),
meta: { title: '制度提案', icon: 'edit', hidden: false }, // meta: { title: '制度提案', icon: 'edit', hidden: false },
}, // },
{ // {
path: '/regulation/type', // path: '/regulation/type',
name: 'RegulationType', // name: 'RegulationType',
component: () => import('@/views/regulation/type/index.vue'), // component: () => import('@/views/regulation/type/index.vue'),
meta: { title: '制度类型', icon: 'tag', hidden: false }, // meta: { title: '制度类型', icon: 'tag', hidden: false },
}, // },
// ],
], // },
},
{ {
path: '/organization', path: '/organization',
name: 'Organization', name: 'Organization',
component: Layout, component: Layout,
redirect: '/organization/dept', redirect: '/organization/dept',
meta: { title: '组织架构', icon: 'user-group', hidden: false, sort: 2 }, meta: { title: '企业管理', icon: 'user-group', hidden: false, sort: 2 },
children: [ children: [
{ // {
path: '/organization/user', // path: '/organization/user',
name: 'OrganizationUser', // name: 'OrganizationUser',
component: () => import('@/views/system/user/index.vue'), // component: () => import('@/views/system/user/index.vue'),
meta: { title: '用户管理', icon: 'user', hidden: false, sort: 2.25 }, // meta: { title: '用户管理', icon: 'user', hidden: false, sort: 2.25 },
}, // },
{ {
path: '/organization/dept', path: '/organization/dept',
name: 'OrganizationDept', name: 'OrganizationDept',
@ -85,6 +84,39 @@ export const systemRoutes: RouteRecordRaw[] = [
component: () => import('@/views/system/post/index.vue'), component: () => import('@/views/system/post/index.vue'),
meta: { title: '岗位管理', icon: 'nav', hidden: false, sort: 2.75 }, meta: { title: '岗位管理', icon: 'nav', hidden: false, sort: 2.75 },
}, },
{
path: '/regulation',
name: 'Regulation',
// component: Layout,
redirect: '/regulation/system-regulation',
meta: { title: '制度管理', icon: 'file-text', hidden: false, sort: 1.5 },
children: [
{
path: '/regulation/system-regulation',
name: 'SystemRegulation',
component: () => import('@/views/regulation/repository.vue'),
meta: { title: '制度公告', icon: 'file-text', hidden: false },
},
{
path: '/regulation/process-management',
name: 'ProcessManagement',
component: () => import('@/views/regulation/confirm.vue'),
meta: { title: '制度公示', icon: 'workflow', hidden: false },
},
{
path: '/regulation/proposal',
name: 'RegulationProposal',
component: () => import('@/views/regulation/proposal/index.vue'),
meta: { title: '制度提案', icon: 'edit', hidden: false },
},
{
path: '/regulation/type',
name: 'RegulationType',
component: () => import('@/views/regulation/type/index.vue'),
meta: { title: '制度类型', icon: 'tag', hidden: false },
},
],
},
// { // {
// path: '/organization/hr/workload', // path: '/organization/hr/workload',
// name: 'HRWorkload', // name: 'HRWorkload',
@ -435,99 +467,86 @@ export const systemRoutes: RouteRecordRaw[] = [
], ],
}, },
{ {
path: '/project-management', path: '/project-marketing',
name: 'ProjectManagement', name: 'Projectmarketing',
component: Layout, component: Layout,
redirect: '/project-management/project-template/project-management', redirect: '/project-marketing/project-marketing',
meta: { title: '项目管理', icon: 'apps', hidden: false, sort: 4 }, meta: { title: '营销管理', icon: 'file-text', hidden: false, sort: 3 },
children: [ children: [
{ {
path: '/project-management/contract/project-source', path: '/project-marketing/contract/revenue-contract2',
name: 'ProjectSource', name: 'RevenueContract2',
component: () => import('@/views/default/error/404.vue'),
meta: {
title: '市场营销(N)',
icon: 'dollar',
hidden: false,
},
},
{
path: '/project-marketing/contract/procurement-business',
name: 'ProcurementBusiness',
component: () => import('@/components/ParentView/index.vue'), component: () => import('@/components/ParentView/index.vue'),
meta: { meta: {
title: '项目来源', title: '招采业务',
icon: 'dollar', icon: 'dollar',
hidden: false, hidden: false,
}, },
children: [ children: [
{ {
path: '/project-management/contract/procurement-business', path: '/project-marketing/project-template/tender-documents',
name: 'ProcurementBusiness', name: 'TenderDocuments',
component: () => import('@/components/ParentView/index.vue'), component: () => import('@/views/project-management/bidding/tender-documents/index.vue'),
meta: { meta: {
title: '招采业务', title: '招标文件',
icon: 'dollar', icon: 'file-text',
hidden: false,
},
children: [
{
path: '/project-management/project-template/tender-documents',
name: 'TenderDocuments',
component: () => import('@/views/project-management/bidding/tender-documents/index.vue'),
meta: {
title: '招标文件',
icon: 'file-text',
hidden: false,
},
},
{
path: '/project-management/project-template/bid-documents',
name: 'BidDocuments',
component: () => import('@/views/project-management/bidding/bid-documents/index.vue'),
meta: {
title: '投标文件',
icon: 'file-text',
hidden: false,
},
},
{
path: '/project-management/project-template/award-notice',
name: 'AwardNotice',
component: () => import('@/views/project-management/bidding/award-notice/index.vue'),
meta: {
title: '中标通知书',
icon: 'trophy',
hidden: false,
},
},
{
path: '/project-management/project-template/information-retrieval',
name: 'InformationRetrieval',
component: () => import ('@/views/project-management/bidding/information-retrieval/index.vue'),
meta: {
title: '信息检索(N)',
icon: 'trophy',
hidden: false,
},
},
],
},
{
path: '/project-management/contract/revenue-contract2',
name: 'RevenueContract2',
component: () => import('@/views/default/error/404.vue'),
meta: {
title: '市场营销(N)',
icon: 'dollar',
hidden: false, hidden: false,
}, },
}, },
{ {
path: '/project-management/project-source/privateproject', path: '/project-marketing/project-template/bid-documents',
name: 'PrivateProject', name: 'BidDocuments',
component: () => import('@/views/default/error/404.vue'), component: () => import('@/views/project-management/bidding/bid-documents/index.vue'),
meta: { meta: {
title: '自建项目(N)', title: '投标文件',
icon: 'dollar', icon: 'file-text',
hidden: false,
},
},
{
path: '/project-marketing/project-template/award-notice',
name: 'AwardNotice',
component: () => import('@/views/project-management/bidding/award-notice/index.vue'),
meta: {
title: '中标通知书',
icon: 'trophy',
hidden: false,
},
},
{
path: '/project-marketing/project-template/information-retrieval',
name: 'InformationRetrieval',
component: () => import ('@/views/project-management/bidding/information-retrieval/index.vue'),
meta: {
title: '信息检索(N)',
icon: 'trophy',
hidden: false, hidden: false,
}, },
}, },
], ],
}, },
{
path: '/project-marketing/order-management/order-management',
name: 'OrderManagement',
component: () => import('@/views/project-management/order-management/index.vue'),
meta: {
title: '订单管理',
icon: 'file-text',
hidden: false,
},
},
{ path: '/project-management/contract', name: 'ProjectContract', component: () => import('@/components/ParentView/index.vue'), redirect: '/project-management/contract/revenue-contract', meta: { { path: '/project-management/contract', name: 'ProjectContract', component: () => import('@/components/ParentView/index.vue'), redirect: '/project-management/contract/revenue-contract', meta: {
title: '项目合同', title: '合同管理',
icon: 'file-text', icon: 'file-text',
hidden: false, hidden: false,
}, children: [ }, children: [
@ -562,6 +581,136 @@ export const systemRoutes: RouteRecordRaw[] = [
}, },
}, },
] }, ] },
],
},
{
path: '/project-management',
name: 'ProjectManagement',
component: Layout,
redirect: '/project-management/project-template/project-management',
meta: { title: '项目管理', icon: 'apps', hidden: false, sort: 4 },
children: [
{
path: '/project-management/contract/project-source',
name: 'ProjectSource',
component: () => import('@/components/ParentView/index.vue'),
meta: {
title: '项目来源',
icon: 'dollar',
hidden: false,
},
children: [
// {
// path: '/project-management/contract/procurement-business',
// name: 'ProcurementBusiness',
// component: () => import('@/components/ParentView/index.vue'),
// meta: {
// title: '招采业务',
// icon: 'dollar',
// hidden: false,
// },
// children: [
// {
// path: '/project-management/project-template/tender-documents',
// name: 'TenderDocuments',
// component: () => import('@/views/project-management/bidding/tender-documents/index.vue'),
// meta: {
// title: '招标文件',
// icon: 'file-text',
// hidden: false,
// },
// },
// {
// path: '/project-management/project-template/bid-documents',
// name: 'BidDocuments',
// component: () => import('@/views/project-management/bidding/bid-documents/index.vue'),
// meta: {
// title: '投标文件',
// icon: 'file-text',
// hidden: false,
// },
// },
// {
// path: '/project-management/project-template/award-notice',
// name: 'AwardNotice',
// component: () => import('@/views/project-management/bidding/award-notice/index.vue'),
// meta: {
// title: '中标通知书',
// icon: 'trophy',
// hidden: false,
// },
// },
// {
// path: '/project-management/project-template/information-retrieval',
// name: 'InformationRetrieval',
// component: () => import ('@/views/project-management/bidding/information-retrieval/index.vue'),
// meta: {
// title: '信息检索(N)',
// icon: 'trophy',
// hidden: false,
// },
// },
//
// ],
// },
// {
// path: '/project-management/contract/revenue-contract2',
// name: 'RevenueContract2',
// component: () => import('@/views/default/error/404.vue'),
// meta: {
// title: '市场营销(N)',
// icon: 'dollar',
// hidden: false,
// },
// },
{
path: '/project-management/project-source/privateproject',
name: 'PrivateProject',
component: () => import('@/views/default/error/404.vue'),
meta: {
title: '自建项目(N)',
icon: 'dollar',
hidden: false,
},
},
],
},
// { path: '/project-management/contract', name: 'ProjectContract', component: () => import('@/components/ParentView/index.vue'), redirect: '/project-management/contract/revenue-contract', meta: {
// title: '项目合同',
// icon: 'file-text',
// hidden: false,
// }, children: [
// {
// path: '/project-management/contract/revenue-contract',
// name: 'RevenueContract',
// component: () => import('@/views/project-management/contract/revenue-contract/index.vue'),
// meta: {
// title: '收入合同',
// icon: 'dollar',
// hidden: false,
// },
// },
// {
// path: '/project-management/contract/expense-contract',
// name: 'ExpenseContract',
// component: () => import('@/views/project-management/contract/expense-contract/index.vue'),
// meta: {
// title: '支出合同',
// icon: 'credit-card',
// hidden: false,
// },
// },
// {
// path: '/project-management/contract/cost-management',
// name: 'CostManagement',
// component: () => import('@/views/project-management/contract/cost-management/index.vue'),
// meta: {
// title: '成本费用',
// icon: 'bar-chart',
// hidden: false,
// },
// },
// ] },
{ {
path: '/project-management/project-template/project-aproval', path: '/project-management/project-template/project-aproval',
name: 'ProjectTemplate', name: 'ProjectTemplate',
@ -934,15 +1083,15 @@ export const systemRoutes: RouteRecordRaw[] = [
// }, // },
// 商务数据库信息模块 // 商务数据库信息模块
{ {
path: '/business-knowledge', path: '/bussiness-knowledge',
name: 'BusinessKnowledge', name: 'bussinesskonwledge',
component: Layout, component: Layout,
redirect: '/business-knowledge/data', redirect: '/bussiness-knowledge/data',
meta: { title: '商务数据库信息', icon: 'database', hidden: false, sort: 5.5 }, meta: { title: '商务资料知识库', icon: 'database', hidden: false, sort: 5.5 },
children: [ children: [
{ {
path: '/business-knowledge/data', path: '/bussiness-konwledge/data',
name: 'BusinessKnowledgeData', name: 'bussiness-knowledge',
component: () => import('@/views/bussiness-data/bussiness.vue'), component: () => import('@/views/bussiness-data/bussiness.vue'),
meta: { meta: {
title: '商务数据库信息', title: '商务数据库信息',
@ -971,30 +1120,30 @@ export const systemRoutes: RouteRecordRaw[] = [
// } // }
], ],
}, },
{ // {
path: '/user/profile', // path: '/user/profile',
name: 'UserProfile', // name: 'UserProfile',
component: Layout, // component: Layout,
redirect: '/user/profile', // redirect: '/user/profile',
meta: { // meta: {
title: '个人中心', // title: '个人中心',
icon: 'user', // icon: 'user',
hidden: false, // hidden: false,
sort: 100, // sort: 100,
}, // },
children: [ // children: [
{ // {
path: '/user/profile', // path: '/user/profile',
name: 'UsersProfile', // name: 'UsersProfile',
component: () => import('@/views/user/profile/index.vue'), // component: () => import('@/views/user/profile/index.vue'),
meta: { // meta: {
title: '个人中心', // title: '个人中心',
icon: 'user', // icon: 'user',
hidden: false, // hidden: false,
}, // },
}, // },
], // ],
}, // },
{ {
path: '/enterprise-settings', path: '/enterprise-settings',
name: 'EnterpriseSettings', name: 'EnterpriseSettings',
@ -1093,25 +1242,6 @@ export const systemRoutes: RouteRecordRaw[] = [
}, },
], ],
}, },
{
path: '/training',
name: 'Training',
component: Layout,
redirect: '/training/plan',
meta: { title: '培训管理', icon: 'book', hidden: false, sort: 9 },
children: [
{
path: '/training/plan',
name: 'TrainingPlan',
component: () => import('@/views/training/plan/index.vue'),
meta: {
title: '培训计划',
icon: 'calendar',
hidden: false,
},
},
],
},
{ {
path: '/system-resource', path: '/system-resource',
name: 'SystemResource', name: 'SystemResource',

View File

@ -149,6 +149,20 @@ const storeSetup = () => {
isHidden: false, isHidden: false,
sort: 3, sort: 3,
}, },
{
id: 1070,
parentId: 1000,
title: '个人中心',
type: 2,
path: '/user/profile',
name: 'UserProfile',
component: 'user/profile/index',
icon: 'user',
isExternal: false,
isCache: false,
isHidden: false,
sort: 4,
},
], ],
}, },
{ {

View File

@ -57,7 +57,6 @@ declare global {
const useCssVars: typeof import('vue')['useCssVars'] const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId'] const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink'] const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute'] const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter'] const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots'] const useSlots: typeof import('vue')['useSlots']

View File

@ -7,7 +7,66 @@ export {}
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
Avatar: typeof import('./../components/Avatar/index.vue')['default']
Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default']
CellCopy: typeof import('./../components/CellCopy/index.vue')['default']
Chart: typeof import('./../components/Chart/index.vue')['default']
ColumnSetting: typeof import('./../components/GiTable/src/components/ColumnSetting.vue')['default']
CronForm: typeof import('./../components/GenCron/CronForm/index.vue')['default']
CronModal: typeof import('./../components/GenCron/CronModal/index.vue')['default']
DateRangePicker: typeof import('./../components/DateRangePicker/index.vue')['default']
DayForm: typeof import('./../components/GenCron/CronForm/component/day-form.vue')['default']
FilePreview: typeof import('./../components/FilePreview/index.vue')['default']
GiCellAvatar: typeof import('./../components/GiCell/GiCellAvatar.vue')['default']
GiCellGender: typeof import('./../components/GiCell/GiCellGender.vue')['default']
GiCellStatus: typeof import('./../components/GiCell/GiCellStatus.vue')['default']
GiCellTag: typeof import('./../components/GiCell/GiCellTag.vue')['default']
GiCellTags: typeof import('./../components/GiCell/GiCellTags.vue')['default']
GiCodeView: typeof import('./../components/GiCodeView/index.vue')['default']
GiDot: typeof import('./../components/GiDot/index.tsx')['default']
GiEditTable: typeof import('./../components/GiEditTable/GiEditTable.vue')['default']
GiFooter: typeof import('./../components/GiFooter/index.vue')['default']
GiForm: typeof import('./../components/GiForm/src/GiForm.vue')['default']
GiIconBox: typeof import('./../components/GiIconBox/index.vue')['default']
GiIconSelector: typeof import('./../components/GiIconSelector/index.vue')['default']
GiIframe: typeof import('./../components/GiIframe/index.vue')['default']
GiOption: typeof import('./../components/GiOption/index.vue')['default']
GiOptionItem: typeof import('./../components/GiOptionItem/index.vue')['default']
GiPageLayout: typeof import('./../components/GiPageLayout/index.vue')['default']
GiSpace: typeof import('./../components/GiSpace/index.vue')['default']
GiSplitButton: typeof import('./../components/GiSplitButton/index.vue')['default']
GiSplitPane: typeof import('./../components/GiSplitPane/index.vue')['default']
GiSplitPaneFlexibleBox: typeof import('./../components/GiSplitPane/components/GiSplitPaneFlexibleBox.vue')['default']
GiSvgIcon: typeof import('./../components/GiSvgIcon/index.vue')['default']
GiTable: typeof import('./../components/GiTable/src/GiTable.vue')['default']
GiTag: typeof import('./../components/GiTag/index.tsx')['default']
GiThemeBtn: typeof import('./../components/GiThemeBtn/index.vue')['default']
HourForm: typeof import('./../components/GenCron/CronForm/component/hour-form.vue')['default']
Icon403: typeof import('./../components/icons/Icon403.vue')['default']
Icon404: typeof import('./../components/icons/Icon404.vue')['default']
Icon500: typeof import('./../components/icons/Icon500.vue')['default']
IconBorders: typeof import('./../components/icons/IconBorders.vue')['default']
IconTableSize: typeof import('./../components/icons/IconTableSize.vue')['default']
IconTreeAdd: typeof import('./../components/icons/IconTreeAdd.vue')['default']
IconTreeReduce: typeof import('./../components/icons/IconTreeReduce.vue')['default']
ImageImport: typeof import('./../components/ImageImport/index.vue')['default']
ImageImportWizard: typeof import('./../components/ImageImportWizard/index.vue')['default']
IndustrialImageList: typeof import('./../components/IndustrialImageList/index.vue')['default']
JsonPretty: typeof import('./../components/JsonPretty/index.vue')['default']
MinuteForm: typeof import('./../components/GenCron/CronForm/component/minute-form.vue')['default']
MonthForm: typeof import('./../components/GenCron/CronForm/component/month-form.vue')['default']
ParentView: typeof import('./../components/ParentView/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
SecondForm: typeof import('./../components/GenCron/CronForm/component/second-form.vue')['default']
SplitPanel: typeof import('./../components/SplitPanel/index.vue')['default']
TextCopy: typeof import('./../components/TextCopy/index.vue')['default']
TurbineGrid: typeof import('./../components/TurbineGrid/index.vue')['default']
UserSelect: typeof import('./../components/UserSelect/index.vue')['default']
Verify: typeof import('./../components/Verify/index.vue')['default']
VerifyPoints: typeof import('./../components/Verify/Verify/VerifyPoints.vue')['default']
VerifySlide: typeof import('./../components/Verify/Verify/VerifySlide.vue')['default']
WeekForm: typeof import('./../components/GenCron/CronForm/component/week-form.vue')['default']
YearForm: typeof import('./../components/GenCron/CronForm/component/year-form.vue')['default']
} }
} }

View File

@ -158,6 +158,20 @@
<a-layout-content class="file-content"> <a-layout-content class="file-content">
<a-card :bordered="false" class="file-card"> <a-card :bordered="false" class="file-card">
<a-descriptions :title="`文件列表 (${fileList.length})`" v-if="currentFolderId" /> <a-descriptions :title="`文件列表 (${fileList.length})`" v-if="currentFolderId" />
<!-- 文件搜索功能 -->
<div v-if="currentFolderId" class="file-search-container">
<a-input-search
v-model="fileSearchKeyword"
placeholder="搜索文件名..."
class="file-search-input"
@search="handleFileSearch"
@input="handleFileSearchInput"
@clear="handleFileSearchClear"
allow-clear
/>
</div>
<a-divider size="small" v-if="currentFolderId" /> <a-divider size="small" v-if="currentFolderId" />
<template v-if="!currentFolderId"> <template v-if="!currentFolderId">
@ -303,6 +317,21 @@
</a-row> </a-row>
</div> </div>
<!-- 文件分页 -->
<div v-if="currentFolderId && !loading && totalFiles > 0" class="file-pagination">
<a-pagination
:total="totalFiles"
:current="fileCurrentPage"
:page-size="filePageSize"
:show-total="true"
:show-page-size="true"
:page-size-options="[10, 20, 50, 100]"
:show-jumper="true"
@change="handleFilePageChange"
@page-size-change="handleFilePageSizeChange"
/>
</div>
<!-- 空状态 --> <!-- 空状态 -->
<a-empty <a-empty
v-if="!loading && currentFolderId && fileList.length === 0" v-if="!loading && currentFolderId && fileList.length === 0"
@ -384,7 +413,6 @@
:show-file-list="false" :show-file-list="false"
@change="handleFileChange" @change="handleFileChange"
:accept="allowedFileTypes" :accept="allowedFileTypes"
multiple
> >
<a-button type="primary" class="upload-btn"> <a-button type="primary" class="upload-btn">
<icon-upload /> <icon-upload />
@ -499,6 +527,26 @@
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>
<!-- 重命名文件对话框 -->
<a-modal
v-model:visible="renameFileModalVisible"
title="重命名文件"
width="520px"
@ok="confirmRenameFile"
@cancel="renameFileModalVisible = false"
>
<a-form layout="vertical">
<a-form-item label="新文件名">
<a-input
v-model="renameFileForm.newName"
placeholder="请输入新的文件名称(不含扩展名)"
max-length="100"
@keyup.enter="confirmRenameFile"
/>
</a-form-item>
</a-form>
</a-modal>
</a-layout> </a-layout>
</template> </template>
@ -534,6 +582,7 @@ import {
downloadFileApi, downloadFileApi,
uploadFileApi, uploadFileApi,
updateFileNameApi, updateFileNameApi,
renameFileApi,
previewFileApi previewFileApi
} from '@/apis/bussiness' } from '@/apis/bussiness'
@ -583,10 +632,10 @@ const folderColor = '#165DFF';
const refreshing = ref(false); const refreshing = ref(false);
const folderSubmitting = ref(false); const folderSubmitting = ref(false);
const uploading = ref(false); const uploading = ref(false);
const allowedFileTypes = '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.zip,.txt'; const allowedFileTypes = '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.zip,.txt,.jpg,.jpeg,.png,.gif,.bmp,.webp';
const allowedFileTypesText = 'PDF, Word, Excel, PPT, 压缩文件, 文本文件'; const allowedFileTypesText = 'PDF, Word, Excel, PPT, 压缩文件, 文本文件, 图片文件';
const maxFileSize = 100 * 1024 * 1024; // 100MB const maxFileSize = 1000 * 1024 * 1024; // 1000MB
const maxFileSizeText = '100MB'; const maxFileSizeText = '1000MB';
const cancelTokens = ref({}); const cancelTokens = ref({});
// //
@ -614,7 +663,8 @@ const canUpload = computed(() => {
}); });
// //
const searchKeyword = ref(''); const searchKeyword = ref(''); //
const fileSearchKeyword = ref(''); //
const searchTimeout = ref(null); const searchTimeout = ref(null);
// //
@ -735,13 +785,61 @@ const handleSearchClear = () => {
initData(); initData();
}; };
//
const handleFileSearch = () => {
console.log('=== 执行文件搜索 ===');
console.log('文件搜索关键词:', fileSearchKeyword.value);
//
fileCurrentPage.value = 1;
console.log('重置文件页码为:', fileCurrentPage.value);
if (currentFolderId.value) {
loadFiles(currentFolderId.value);
}
};
const handleFileSearchInput = (value) => {
console.log('=== 文件搜索输入 ===');
console.log('输入值:', value);
fileSearchKeyword.value = value;
console.log('设置文件搜索关键词为:', fileSearchKeyword.value);
// 300ms
if (searchTimeout.value) {
clearTimeout(searchTimeout.value);
console.log('清除之前的文件搜索定时器');
}
searchTimeout.value = setTimeout(() => {
console.log('=== 防抖文件搜索执行 ===');
fileCurrentPage.value = 1;
console.log('重置文件页码为:', fileCurrentPage.value);
if (currentFolderId.value) {
loadFiles(currentFolderId.value);
}
}, 300);
};
const handleFileSearchClear = () => {
console.log('=== 清除文件搜索 ===');
fileSearchKeyword.value = '';
console.log('清空文件搜索关键词');
if (searchTimeout.value) {
clearTimeout(searchTimeout.value);
console.log('清除文件搜索定时器');
}
fileCurrentPage.value = 1;
console.log('重置文件页码为:', fileCurrentPage.value);
if (currentFolderId.value) {
loadFiles(currentFolderId.value);
}
};
const loadFiles = async (folderId) => { const loadFiles = async (folderId) => {
try { try {
loading.value = true; loading.value = true;
const res = await getFilesApi({ const res = await getFilesApi({
folderId: folderId, folderId: folderId,
page: fileCurrentPage.value, page: fileCurrentPage.value,
pageSize: filePageSize.value pageSize: filePageSize.value,
fileName: fileSearchKeyword.value || undefined
}); });
// //
@ -777,6 +875,8 @@ const handleFolderClick = (folderId) => {
const id = String(folderId); const id = String(folderId);
if (currentFolderId.value !== id) { if (currentFolderId.value !== id) {
fileCurrentPage.value = 1; fileCurrentPage.value = 1;
//
fileSearchKeyword.value = '';
} }
currentFolderId.value = id; currentFolderId.value = id;
}; };
@ -790,6 +890,14 @@ const renameForm = reactive({
isRoot: false isRoot: false
}); });
//
const renameFileModalVisible = ref(false);
const renameFileForm = reactive({
fileId: '',
newName: '',
fileExtension: ''
});
// //
const handleRenameFolder = (folder, folderId, currentName) => { const handleRenameFolder = (folder, folderId, currentName) => {
console.log('handleRenameFolder 被调用:', { folder, folderId, currentName }); console.log('handleRenameFolder 被调用:', { folder, folderId, currentName });
@ -971,7 +1079,21 @@ const handleFileChange = (info) => {
console.log('文件列表:', fileList); console.log('文件列表:', fileList);
console.log('文件列表长度:', fileList.length); console.log('文件列表长度:', fileList.length);
// //
fileListTemp.value = [];
console.log('已清空之前的文件列表');
//
if (uploadRef.value) {
try {
uploadRef.value.reset();
console.log('已强制重置上传组件');
} catch (error) {
console.log('重置上传组件时出错:', error);
}
}
// -
fileList.forEach((file, index) => { fileList.forEach((file, index) => {
console.log(`处理第${index + 1}个文件:`, file); console.log(`处理第${index + 1}个文件:`, file);
console.log('文件名称:', file.name); console.log('文件名称:', file.name);
@ -990,35 +1112,22 @@ const handleFileChange = (info) => {
originFileObj: file.file || file // File originFileObj: file.file || file // File
}; };
// console.log('开始验证新文件...');
if (!fileListTemp.value.find(f => f.uid === fileObj.uid)) {
console.log('这是新文件,开始验证...');
// //
const isValid = validateFile(fileObj); const isValid = validateFile(fileObj);
console.log('文件验证结果:', isValid); console.log('文件验证结果:', isValid);
if (isValid) { if (isValid) {
fileListTemp.value.push(fileObj); //
console.log('✅ 成功添加文件到列表:', fileObj.name); fileListTemp.value = [fileObj]; //
} else { console.log('✅ 成功设置文件到列表:', fileObj.name);
console.log('❌ 文件验证失败:', fileObj.name, '错误:', fileObj.error);
}
} else { } else {
console.log('文件已存在,跳过:', fileObj.name); console.log('❌ 文件验证失败:', fileObj.name, '错误:', fileObj.error);
} }
}); });
// //
const beforeCleanCount = fileListTemp.value.length;
fileListTemp.value = fileListTemp.value.filter(file =>
fileList.some(f => f.uid === file.uid)
);
const afterCleanCount = fileListTemp.value.length;
if (beforeCleanCount !== afterCleanCount) {
console.log(`清理了 ${beforeCleanCount - afterCleanCount} 个已移除的文件`);
}
console.log('=== 当前文件列表状态 ==='); console.log('=== 当前文件列表状态 ===');
console.log('fileListTemp长度:', fileListTemp.value.length); console.log('fileListTemp长度:', fileListTemp.value.length);
@ -1081,7 +1190,14 @@ const fileColor = (extension) => {
ppt: '#faad14', ppt: '#faad14',
pptx: '#faad14', pptx: '#faad14',
zip: '#722ed1', zip: '#722ed1',
txt: '#8c8c8c' txt: '#8c8c8c',
//
jpg: '#52c41a',
jpeg: '#52c41a',
png: '#1890ff',
gif: '#faad14',
bmp: '#722ed1',
webp: '#13c2c2'
}; };
return colorMap[extension.toLowerCase()] || '#8c8c8c'; return colorMap[extension.toLowerCase()] || '#8c8c8c';
}; };
@ -1171,42 +1287,47 @@ const handleUploadSubmit = async () => {
fileItem.error = result.msg || '上传失败'; fileItem.error = result.msg || '上传失败';
hasError = true; hasError = true;
} }
}
//
if (hasFileExists && !hasError) {
Message.warning('文件已存在');
} else if (hasError) {
Message.error('上传失败');
} else {
Message.success('上传成功');
//
if (currentFolderId.value === uploadForm.folderId) {
loadFiles(currentFolderId.value);
} }
}
// resetUpload();
if (hasFileExists && !hasError) {
Message.warning('文件已存在');
} else if (hasError) {
Message.error('上传失败');
} else {
Message.success('上传成功');
//
if (currentFolderId.value === uploadForm.folderId) {
loadFiles(currentFolderId.value);
}
}
resetUpload();
uploading.value = false;
}; };
// //
const resetUpload = () => { const resetUpload = () => {
console.log('=== 重置上传表单 ===');
// //
Object.values(cancelTokens.value).forEach(source => { Object.values(cancelTokens.value).forEach(source => {
source.cancel('上传已取消'); source.cancel('上传已取消');
}); });
//
uploadDialogVisible.value = false; uploadDialogVisible.value = false;
uploadForm.folderId = currentFolderId.value || ''; uploadForm.folderId = currentFolderId.value || '';
fileListTemp.value = []; fileListTemp.value = [];
cancelTokens.value = {}; cancelTokens.value = {};
uploading.value = false;
// //
if (uploadRef.value) { if (uploadRef.value) {
uploadRef.value.reset(); uploadRef.value.reset();
console.log('已重置上传组件');
} }
console.log('上传表单重置完成');
}; };
// //
@ -1261,11 +1382,87 @@ const handleDownload = async (file) => {
// //
const handleEditFile = (file) => { const handleEditFile = (file) => {
Modal.warning({ console.log('=== 重命名文件函数被调用 ===');
title: '功能提示', console.log('重命名文件 - 文件对象:', file);
content: '后端暂不支持文件重命名功能,如需重命名请先删除文件再重新上传。', console.log('文件对象的所有属性:', Object.keys(file));
okText: '知道了' console.log('文件属性详情:', {
fileId: file.fileId,
fileName: file.fileName,
name: file.name,
originalName: file.originalName,
displayName: file.displayName,
title: file.title
}); });
//
let fileName = '';
if (file.fileName) {
fileName = file.fileName;
console.log('使用 fileName 字段:', fileName);
} else if (file.name) {
fileName = file.name;
console.log('使用 name 字段:', fileName);
} else if (file.originalName) {
fileName = file.originalName;
console.log('使用 originalName 字段:', fileName);
} else if (file.displayName) {
fileName = file.displayName;
console.log('使用 displayName 字段:', fileName);
} else if (file.title) {
fileName = file.title;
console.log('使用 title 字段:', fileName);
}
console.log('最终获取到的文件名:', fileName);
if (!fileName) {
console.error('无法获取文件名,文件对象:', file);
Message.error('无法获取文件名,请检查文件数据');
return;
}
const fileExtension = getFileExtension(fileName);
const fileNameWithoutExtension = fileExtension ? fileName.substring(0, fileName.lastIndexOf('.')) : fileName;
console.log('处理后的文件名信息:', {
originalName: fileName,
extension: fileExtension,
nameWithoutExtension: fileNameWithoutExtension
});
//
renameFileForm.fileId = file.fileId;
renameFileForm.newName = fileNameWithoutExtension;
renameFileForm.fileExtension = fileExtension;
console.log('设置的重命名表单数据:', renameFileForm);
//
renameFileModalVisible.value = true;
};
//
const confirmRenameFile = async () => {
if (!renameFileForm.newName.trim()) {
Message.warning('请输入文件名称');
return;
}
// 使
const newFileName = renameFileForm.newName.trim();
try {
await renameFileApi(renameFileForm.fileId, newFileName);
Message.success('文件重命名成功');
renameFileModalVisible.value = false;
//
if (currentFolderId.value) {
loadFiles(currentFolderId.value);
}
} catch (error) {
console.error('重命名文件失败:', error);
Message.error('重命名失败');
}
}; };
// //
@ -1344,6 +1541,13 @@ const fileTypeText = (type) => {
pptx: 'PPT演示', pptx: 'PPT演示',
zip: '压缩文件', zip: '压缩文件',
txt: '文本文件', txt: '文本文件',
//
jpg: 'JPG图片',
jpeg: 'JPEG图片',
png: 'PNG图片',
gif: 'GIF图片',
bmp: 'BMP图片',
webp: 'WebP图片',
unknown: '未知类型' unknown: '未知类型'
}; };
@ -2330,5 +2534,64 @@ onMounted(() => {
100% { transform: translateX(100%); } 100% { transform: translateX(100%); }
} }
/* 文件搜索样式 */
.file-search-container {
margin: 16px 0;
display: flex;
align-items: center;
gap: 12px;
}
.file-search-input {
max-width: 300px;
transition: all 0.3s ease;
&:focus-within {
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
}
}
/* 文件分页样式 */
.file-pagination {
margin-top: 24px;
padding: 16px 0;
display: flex;
justify-content: center;
border-top: 1px solid var(--color-border);
background: var(--color-bg-1);
.arco-pagination {
.arco-pagination-total {
color: var(--color-text-2);
font-size: 14px;
}
.arco-pagination-item {
border-radius: 6px;
transition: all 0.2s ease;
&:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
&.arco-pagination-item-active {
background: var(--color-primary);
border-color: var(--color-primary);
color: white;
}
}
.arco-pagination-prev,
.arco-pagination-next {
border-radius: 6px;
transition: all 0.2s ease;
&:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
}
}
}
</style> </style>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="scss">
</style>

View File

@ -29,7 +29,7 @@
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">所属部门</div> <div class="info-label">所属部门</div>
<div class="info-value">{{ primaryInfo?.department || '技术部' }}</div> <div class="info-value">{{ primaryInfo?.deptName || '技术部' }}</div>
</div> </div>
<div class="info-item"> <div class="info-item">
<div class="info-label">直接上级岗位</div> <div class="info-label">直接上级岗位</div>
@ -68,7 +68,7 @@
<div class="section-title">主要职责与工作任务</div> <div class="section-title">主要职责与工作任务</div>
<div class="content-container"> <div class="content-container">
<ul> <ul>
<li v-for="(task, idx) in (primaryInfo?.tasks || ['负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。','制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。'])" :key="idx">{{ task }}</li> <li v-for="(task, idx) in (primaryInfo?.tasks || ['负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。', '制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。'])" :key="idx">{{ task }}</li>
</ul> </ul>
</div> </div>
@ -76,7 +76,7 @@
<div class="section-title">工作权限</div> <div class="section-title">工作权限</div>
<div class="content-container"> <div class="content-container">
<ul> <ul>
<li v-for="(perm, idx) in (primaryInfo?.permissions || ['有权审批部门内5000元以下的采购申请。','有权对项目团队成员的工作任务进行分配和调整。'])" :key="idx">{{ perm }}</li> <li v-for="(perm, idx) in (primaryInfo?.permissions || ['有权审批部门内5000元以下的采购申请。', '有权对项目团队成员的工作任务进行分配和调整。'])" :key="idx">{{ perm }}</li>
</ul> </ul>
</div> </div>
@ -244,7 +244,7 @@ const getDetail = async (id: string) => {
id: data.postId ?? data.id ?? '10001', id: data.postId ?? data.id ?? '10001',
name: data.postName ?? data.name ?? '-', name: data.postName ?? data.name ?? '-',
status: data.status, status: data.status,
department: data.department ?? '技术部', department: data.department ?? data.deptName ?? '技术部',
superior: data.superior ?? '技术总监', superior: data.superior ?? '技术总监',
level: data.level ?? 'P5', level: data.level ?? 'P5',
version: data.version ?? '2024-06-01 / V1.0', version: data.version ?? '2024-06-01 / V1.0',
@ -252,11 +252,11 @@ const getDetail = async (id: string) => {
summary: data.summary ?? '负责公司核心产品开发,支撑业务增长。', summary: data.summary ?? '负责公司核心产品开发,支撑业务增长。',
tasks: data.tasks ?? [ tasks: data.tasks ?? [
'负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。', '负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。',
'制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。' '制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。',
], ],
permissions: data.permissions ?? [ permissions: data.permissions ?? [
'有权审批部门内5000元以下的采购申请。', '有权审批部门内5000元以下的采购申请。',
'有权对项目团队成员的工作任务进行分配和调整。' '有权对项目团队成员的工作任务进行分配和调整。',
], ],
subordinates: data.subordinates ?? '无', subordinates: data.subordinates ?? '无',
collaboration: data.collaboration ?? '与产品部、销售部、客服部紧密合作', collaboration: data.collaboration ?? '与产品部、销售部、客服部紧密合作',