fix: 修复附件上传字段名不匹配及下载接口问题
- 修复前端附件字段名 filePath -> fileUrl(管理后台expense/requirement) - 修复移动端附件上传字段名及预览逻辑(base64->URL) - 修复后端FileController下载接口支持COS文件重定向 - 修复其他前端API路径问题
This commit is contained in:
parent
cc6577b3df
commit
d613eae423
@ -19,6 +19,7 @@ CREATE TABLE IF NOT EXISTS project (
|
|||||||
project_code VARCHAR(64) NOT NULL COMMENT '项目编码',
|
project_code VARCHAR(64) NOT NULL COMMENT '项目编码',
|
||||||
project_name VARCHAR(128) NOT NULL COMMENT '项目名称',
|
project_name VARCHAR(128) NOT NULL COMMENT '项目名称',
|
||||||
customer_id VARCHAR(32) NOT NULL COMMENT '客户ID',
|
customer_id VARCHAR(32) NOT NULL COMMENT '客户ID',
|
||||||
|
customer_name VARCHAR(128) COMMENT '客户名称',
|
||||||
project_type VARCHAR(32) NOT NULL COMMENT '项目类型',
|
project_type VARCHAR(32) NOT NULL COMMENT '项目类型',
|
||||||
budget_amount DECIMAL(18,2) COMMENT '预算金额',
|
budget_amount DECIMAL(18,2) COMMENT '预算金额',
|
||||||
start_date DATE COMMENT '开始日期',
|
start_date DATE COMMENT '开始日期',
|
||||||
|
|||||||
@ -13,20 +13,20 @@ export function createExpenseType(data: any) {
|
|||||||
return request.post('/exp/expense-type', data)
|
return request.post('/exp/expense-type', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateExpenseType(id: number, data: any) {
|
export function updateExpenseType(id: string, data: any) {
|
||||||
return request.put(`/exp/expense-type/${id}`, data)
|
return request.put(`/exp/expense-type/${id}`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteExpenseType(id: number) {
|
export function deleteExpenseType(id: string) {
|
||||||
return request.delete(`/exp/expense-type/${id}`)
|
return request.delete(`/exp/expense-type/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 支出管理
|
// 支出管理
|
||||||
export function getExpenseList(params: { pageNum: number; pageSize: number; title?: string; expenseType?: number; approvalStatus?: number; payStatus?: number }) {
|
export function getExpenseList(params: { pageNum: number; pageSize: number; title?: string; expenseType?: string; approvalStatus?: number; payStatus?: number }) {
|
||||||
return request.get('/exp/expense/page', { params })
|
return request.get('/exp/expense/page', { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getExpenseById(id: number) {
|
export function getExpenseById(id: string) {
|
||||||
return request.get(`/exp/expense/${id}`)
|
return request.get(`/exp/expense/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,49 +34,49 @@ export function createExpense(data: any) {
|
|||||||
return request.post('/exp/expense', data)
|
return request.post('/exp/expense', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateExpense(id: number, data: any) {
|
export function updateExpense(id: string, data: any) {
|
||||||
return request.put(`/exp/expense/${id}`, data)
|
return request.put(`/exp/expense/${id}`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteExpense(id: number) {
|
export function deleteExpense(id: string) {
|
||||||
return request.delete(`/exp/expense/${id}`)
|
return request.delete(`/exp/expense/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审批流程
|
// 审批流程
|
||||||
export function submitExpense(id: number) {
|
export function submitExpense(id: string) {
|
||||||
return request.post(`/exp/expense/${id}/submit`)
|
return request.post(`/exp/expense/${id}/submit`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function withdrawExpense(id: number) {
|
export function withdrawExpense(id: string) {
|
||||||
return request.post(`/exp/expense/${id}/withdraw`)
|
return request.post(`/exp/expense/${id}/withdraw`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function approveExpense(id: number, comment: string) {
|
export function approveExpense(id: string, comment: string) {
|
||||||
return request.put(`/exp/expense/${id}/approve?comment=${encodeURIComponent(comment)}`)
|
return request.put(`/exp/expense/${id}/approve?comment=${encodeURIComponent(comment)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rejectExpense(id: number, comment: string) {
|
export function rejectExpense(id: string, comment: string) {
|
||||||
return request.put(`/exp/expense/${id}/reject?comment=${encodeURIComponent(comment)}`)
|
return request.put(`/exp/expense/${id}/reject?comment=${encodeURIComponent(comment)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function confirmPayExpense(id: number, payChannel: string, payVoucher?: string) {
|
export function confirmPayExpense(id: string, payChannel: string, payVoucher?: string) {
|
||||||
return request.put(`/exp/expense/${id}/confirm-pay?payChannel=${payChannel}&payVoucher=${payVoucher || ''}`)
|
return request.put(`/exp/expense/${id}/confirm-pay?payChannel=${payChannel}&payVoucher=${payVoucher || ''}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出支出明细
|
// 导出支出明细
|
||||||
export function exportExpense(params?: { title?: string; expenseType?: number; approvalStatus?: number; payStatus?: number }) {
|
export function exportExpense(params?: { title?: string; expenseType?: string; approvalStatus?: number; payStatus?: number }) {
|
||||||
const baseUrl = import.meta.env.VITE_API_URL || ''
|
const baseUrl = import.meta.env.VITE_API_URL || ''
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
const tenantId = localStorage.getItem('tenantId') || '1'
|
const tenantId = localStorage.getItem('tenantId') || '1'
|
||||||
|
|
||||||
const queryParams = new URLSearchParams()
|
const queryParams = new URLSearchParams()
|
||||||
if (params?.title) queryParams.append('title', params.title)
|
if (params?.title) queryParams.append('title', params.title)
|
||||||
if (params?.expenseType) queryParams.append('expenseType', String(params.expenseType))
|
if (params?.expenseType) queryParams.append('expenseType', params.expenseType)
|
||||||
if (params?.approvalStatus !== undefined) queryParams.append('approvalStatus', String(params.approvalStatus))
|
if (params?.approvalStatus !== undefined) queryParams.append('approvalStatus', String(params.approvalStatus))
|
||||||
if (params?.payStatus !== undefined) queryParams.append('payStatus', String(params.payStatus))
|
if (params?.payStatus !== undefined) queryParams.append('payStatus', String(params.payStatus))
|
||||||
|
|
||||||
const queryString = queryParams.toString()
|
const queryString = queryParams.toString()
|
||||||
const url = `${baseUrl}/exp/expense/export${queryString ? '?' + queryString : ''}`
|
const url = `${baseUrl}/fund/exp/expense/export${queryString ? '?' + queryString : ''}`
|
||||||
|
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { request } from './request'
|
import { request } from './request'
|
||||||
|
|
||||||
// 文件上传
|
// 文件上传
|
||||||
export function uploadFile(file: File, businessType?: string, businessId?: number, description?: string) {
|
export function uploadFile(file: File, businessType?: string, businessId?: string, description?: string) {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', file)
|
formData.append('file', file)
|
||||||
if (businessType) formData.append('businessType', businessType)
|
if (businessType) formData.append('businessType', businessType)
|
||||||
if (businessId) formData.append('businessId', String(businessId))
|
if (businessId) formData.append('businessId', businessId)
|
||||||
if (description) formData.append('description', description)
|
if (description) formData.append('description', description)
|
||||||
|
|
||||||
return request.post('/file/upload', formData, {
|
return request.post('/file/upload', formData, {
|
||||||
@ -16,26 +16,26 @@ export function uploadFile(file: File, businessType?: string, businessId?: numbe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件列表
|
// 获取文件列表
|
||||||
export function getFileList(params: { pageNum: number; pageSize: number; businessType?: string; businessId?: number; fileType?: string }) {
|
export function getFileList(params: { pageNum: number; pageSize: number; businessType?: string; businessId?: string; fileType?: string }) {
|
||||||
return request.get('/file/page', { params })
|
return request.get('/file/page', { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据业务查询文件
|
// 根据业务查询文件
|
||||||
export function getFilesByBusiness(businessType: string, businessId: number) {
|
export function getFilesByBusiness(businessType: string, businessId: string) {
|
||||||
return request.get('/file/list', { params: { businessType, businessId } })
|
return request.get('/file/list', { params: { businessType, businessId } })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件详情
|
// 获取文件详情
|
||||||
export function getFileById(id: number) {
|
export function getFileById(id: string) {
|
||||||
return request.get(`/file/${id}`)
|
return request.get(`/file/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除文件
|
// 删除文件
|
||||||
export function deleteFile(id: number) {
|
export function deleteFile(id: string) {
|
||||||
return request.delete(`/file/${id}`)
|
return request.delete(`/file/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件下载URL
|
// 获取文件下载URL
|
||||||
export function getFileDownloadUrl(filePath: string) {
|
export function getFileDownloadUrl(filePath: string) {
|
||||||
return `/file/download/${filePath}`
|
return `/fund/file/download/${filePath}`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export function getProjectList(params: { pageNum: number; pageSize: number; proj
|
|||||||
return request.get('/project/page', { params })
|
return request.get('/project/page', { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProjectById(id: number) {
|
export function getProjectById(id: string) {
|
||||||
return request.get(`/project/${id}`)
|
return request.get(`/project/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,11 +12,11 @@ export function createProject(data: any) {
|
|||||||
return request.post('/project', data)
|
return request.post('/project', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateProject(id: number, data: any) {
|
export function updateProject(id: string, data: any) {
|
||||||
return request.put(`/project/${id}`, data)
|
return request.put(`/project/${id}`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteProject(id: number) {
|
export function deleteProject(id: string) {
|
||||||
return request.delete(`/project/${id}`)
|
return request.delete(`/project/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ export function getRequirementList(params: { pageNum: number; pageSize: number;
|
|||||||
return request.get('/requirement/page', { params })
|
return request.get('/requirement/page', { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRequirementById(id: number) {
|
export function getRequirementById(id: string) {
|
||||||
return request.get(`/requirement/${id}`)
|
return request.get(`/requirement/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ export function createRequirement(data: any) {
|
|||||||
return request.post('/requirement', data)
|
return request.post('/requirement', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateRequirement(id: number, data: any) {
|
export function updateRequirement(id: string, data: any) {
|
||||||
return request.put(`/requirement/${id}`, data)
|
return request.put(`/requirement/${id}`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteRequirement(id: number) {
|
export function deleteRequirement(id: string) {
|
||||||
return request.delete(`/requirement/${id}`)
|
return request.delete(`/requirement/${id}`)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,22 +70,18 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="微信" prop="wechat">
|
<el-form-item label="邮箱" prop="email">
|
||||||
<el-input v-model="form.wechat" placeholder="请输入微信号" />
|
<el-input v-model="form.email" placeholder="请输入邮箱" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-form-item label="邮箱" prop="email">
|
|
||||||
<el-input v-model="form.email" placeholder="请输入邮箱" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="主联系人" prop="isPrimary">
|
<el-form-item label="主联系人" prop="isPrimary">
|
||||||
<el-switch v-model="form.isPrimary" />
|
<el-switch v-model="form.isPrimary" :active-value="1" :inactive-value="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="备注" prop="remarks">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.remarks" type="textarea" :rows="3" placeholder="请输入备注" />
|
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
@ -126,15 +122,15 @@ const dialogTitle = ref('新增联系人')
|
|||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
contactId: null as number | null,
|
id: null as string | null,
|
||||||
customerId: customerId.value,
|
customerId: customerId.value,
|
||||||
contactName: '',
|
contactName: '',
|
||||||
position: '',
|
position: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
email: '',
|
email: '',
|
||||||
wechat: '',
|
isPrimary: 0,
|
||||||
isPrimary: false,
|
status: 1,
|
||||||
remarks: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = reactive<FormRules>({
|
const rules = reactive<FormRules>({
|
||||||
@ -210,8 +206,8 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
submitLoading.value = true
|
submitLoading.value = true
|
||||||
try {
|
try {
|
||||||
if (form.contactId) {
|
if (form.id) {
|
||||||
await updateContact(form.contactId, form)
|
await updateContact(form.id, form)
|
||||||
ElMessage.success('更新成功')
|
ElMessage.success('更新成功')
|
||||||
} else {
|
} else {
|
||||||
await createContact(form)
|
await createContact(form)
|
||||||
@ -228,15 +224,15 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
form.contactId = null
|
form.id = null
|
||||||
form.customerId = customerId.value
|
form.customerId = customerId.value
|
||||||
form.contactName = ''
|
form.contactName = ''
|
||||||
form.position = ''
|
form.position = ''
|
||||||
form.phone = ''
|
form.phone = ''
|
||||||
form.email = ''
|
form.email = ''
|
||||||
form.wechat = ''
|
form.isPrimary = 0
|
||||||
form.isPrimary = false
|
form.status = 1
|
||||||
form.remarks = ''
|
form.remark = ''
|
||||||
formRef.value?.clearValidate()
|
formRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,12 +6,12 @@
|
|||||||
<el-input v-model="queryParams.title" placeholder="请输入支出标题" clearable style="width: 200px" />
|
<el-input v-model="queryParams.title" placeholder="请输入支出标题" clearable style="width: 200px" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="支出类型">
|
<el-form-item label="支出类型">
|
||||||
<el-select v-model="queryParams.expenseTypeId" placeholder="请选择" clearable filterable style="width: 150px">
|
<el-select v-model="queryParams.expenseType" placeholder="请选择" clearable filterable style="width: 150px">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in expenseTypeList"
|
v-for="item in expenseTypeList"
|
||||||
:key="item.typeId"
|
:key="item.id"
|
||||||
:label="item.typeName"
|
:label="item.typeName"
|
||||||
:value="item.typeId"
|
:value="item.id"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="tableData" v-loading="loading" border stripe>
|
<el-table :data="tableData" v-loading="loading" border stripe>
|
||||||
<el-table-column prop="expenseId" label="支出ID" width="80" />
|
<el-table-column prop="id" label="ID" width="80" />
|
||||||
<el-table-column prop="title" label="支出标题" min-width="180" show-overflow-tooltip />
|
<el-table-column prop="title" label="支出标题" min-width="180" show-overflow-tooltip />
|
||||||
<el-table-column prop="expenseTypeName" label="支出类型" width="120" />
|
<el-table-column prop="expenseTypeName" label="支出类型" width="120" />
|
||||||
<el-table-column prop="projectName" label="关联项目" width="140" show-overflow-tooltip />
|
<el-table-column prop="projectName" label="关联项目" width="140" show-overflow-tooltip />
|
||||||
@ -57,20 +57,20 @@
|
|||||||
<el-table-column prop="expenseDate" label="支出日期" width="120" />
|
<el-table-column prop="expenseDate" label="支出日期" width="120" />
|
||||||
<el-table-column prop="approvalStatus" label="审批状态" width="100">
|
<el-table-column prop="approvalStatus" label="审批状态" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag v-if="row.approvalStatus === 'DRAFT'" type="info">草稿</el-tag>
|
<el-tag v-if="row.approvalStatus === 0" type="info">待审批</el-tag>
|
||||||
<el-tag v-else-if="row.approvalStatus === 'PENDING'" type="warning">待审批</el-tag>
|
<el-tag v-else-if="row.approvalStatus === 1" type="warning">审批中</el-tag>
|
||||||
<el-tag v-else-if="row.approvalStatus === 'APPROVED'" type="success">已通过</el-tag>
|
<el-tag v-else-if="row.approvalStatus === 2" type="success">已通过</el-tag>
|
||||||
<el-tag v-else-if="row.approvalStatus === 'REJECTED'" type="danger">已拒绝</el-tag>
|
<el-tag v-else-if="row.approvalStatus === 3" type="danger">已拒绝</el-tag>
|
||||||
<el-tag v-else type="info">已撤回</el-tag>
|
<el-tag v-else type="info">已撤回</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="payStatus" label="支付状态" width="100">
|
<el-table-column prop="payStatus" label="支付状态" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag v-if="row.payStatus === 'UNPAID'" type="warning">未支付</el-tag>
|
<el-tag v-if="row.payStatus === 0" type="warning">未支付</el-tag>
|
||||||
<el-tag v-else type="success">已支付</el-tag>
|
<el-tag v-else type="success">已支付</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="applicant" label="申请人" width="100" />
|
<el-table-column prop="createdBy" label="申请人" width="100" />
|
||||||
<el-table-column label="附件" width="80">
|
<el-table-column label="附件" width="80">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-icon v-if="row.attachments" style="color: #409EFF;"><Document /></el-icon>
|
<el-icon v-if="row.attachments" style="color: #409EFF;"><Document /></el-icon>
|
||||||
@ -80,10 +80,10 @@
|
|||||||
<el-table-column label="操作" width="320" fixed="right">
|
<el-table-column label="操作" width="320" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button link type="primary" :icon="View" @click="handleView(row)">详情</el-button>
|
<el-button link type="primary" :icon="View" @click="handleView(row)">详情</el-button>
|
||||||
<el-button link type="primary" :icon="Edit" v-if="row.approvalStatus === 'DRAFT'" @click="handleEdit(row)">编辑</el-button>
|
<el-button link type="primary" :icon="Edit" v-if="row.approvalStatus === 0" @click="handleEdit(row)">编辑</el-button>
|
||||||
<el-button link type="success" :icon="Check" v-if="row.approvalStatus === 'DRAFT'" @click="handleSubmit(row)">提交</el-button>
|
<el-button link type="success" :icon="Check" v-if="row.approvalStatus === 0" @click="handleSubmit(row)">提交</el-button>
|
||||||
<el-button link type="warning" v-if="row.approvalStatus === 'PENDING'" @click="handleApprove(row)">审批</el-button>
|
<el-button link type="warning" v-if="row.approvalStatus === 1" @click="handleApprove(row)">审批</el-button>
|
||||||
<el-button link type="danger" :icon="Delete" v-if="row.approvalStatus === 'DRAFT'" @click="handleDelete(row)">删除</el-button>
|
<el-button link type="danger" :icon="Delete" v-if="row.approvalStatus === 0" @click="handleDelete(row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -115,13 +115,13 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="支出类型" prop="expenseTypeId">
|
<el-form-item label="支出类型" prop="expenseType">
|
||||||
<el-select v-model="form.expenseTypeId" placeholder="请选择" filterable style="width: 100%">
|
<el-select v-model="form.expenseType" placeholder="请选择" filterable style="width: 100%">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in expenseTypeList"
|
v-for="item in expenseTypeList"
|
||||||
:key="item.typeId"
|
:key="item.id"
|
||||||
:label="item.typeName"
|
:label="item.typeName"
|
||||||
:value="item.typeId"
|
:value="item.id"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -134,9 +134,9 @@
|
|||||||
<el-select v-model="form.projectId" placeholder="请选择项目" filterable clearable style="width: 100%">
|
<el-select v-model="form.projectId" placeholder="请选择项目" filterable clearable style="width: 100%">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in projectList"
|
v-for="item in projectList"
|
||||||
:key="item.projectId"
|
:key="item.id"
|
||||||
:label="item.projectName"
|
:label="item.projectName"
|
||||||
:value="item.projectId"
|
:value="item.id"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -156,22 +156,29 @@
|
|||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="支出日期" prop="expenseDate">
|
<el-form-item label="支出日期" prop="expenseDate">
|
||||||
<el-date-picker v-model="form.expenseDate" type="date" placeholder="请选择支出日期" style="width: 100%" />
|
<el-date-picker v-model="form.expenseDate" type="date" placeholder="请选择支出日期" value-format="YYYY-MM-DD" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="申请人" prop="applicant">
|
<el-form-item label="关联项目">
|
||||||
<el-input v-model="form.applicant" placeholder="请输入申请人" />
|
<el-select v-model="form.projectId" placeholder="请选择项目" filterable clearable style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in projectList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.projectName"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-form-item label="支出描述" prop="description">
|
<el-form-item label="支出描述" prop="purpose">
|
||||||
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入支出描述" />
|
<el-input v-model="form.purpose" type="textarea" :rows="3" placeholder="请输入支出描述" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="备注" prop="remarks">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.remarks" type="textarea" :rows="2" placeholder="请输入备注" />
|
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="附件">
|
<el-form-item label="附件">
|
||||||
@ -286,7 +293,7 @@ import { getExpenseTypeTree } from '@/api/expense'
|
|||||||
import { getProjectList } from '@/api/project'
|
import { getProjectList } from '@/api/project'
|
||||||
|
|
||||||
// 文件上传相关
|
// 文件上传相关
|
||||||
const uploadUrl = '/file/api/v1/file/upload'
|
const uploadUrl = '/fund/file/upload'
|
||||||
const uploadHeaders = {
|
const uploadHeaders = {
|
||||||
Authorization: `Bearer ${localStorage.getItem('token') || ''}`,
|
Authorization: `Bearer ${localStorage.getItem('token') || ''}`,
|
||||||
'X-Tenant-Id': localStorage.getItem('tenantId') || '1'
|
'X-Tenant-Id': localStorage.getItem('tenantId') || '1'
|
||||||
@ -305,7 +312,7 @@ const queryParams = reactive({
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
title: '',
|
title: '',
|
||||||
expenseTypeId: null as number | null,
|
expenseType: null as string | null,
|
||||||
approvalStatus: '',
|
approvalStatus: '',
|
||||||
payStatus: ''
|
payStatus: ''
|
||||||
})
|
})
|
||||||
@ -315,32 +322,30 @@ const dialogTitle = ref('新增支出')
|
|||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
expenseId: null as number | null,
|
id: null as string | null,
|
||||||
title: '',
|
title: '',
|
||||||
expenseTypeId: null as number | null,
|
expenseType: null as string | null,
|
||||||
projectId: null as number | null,
|
projectId: null as string | null,
|
||||||
amount: 0,
|
amount: 0,
|
||||||
payeeName: '',
|
payeeName: '',
|
||||||
expenseDate: '',
|
expenseDate: '',
|
||||||
applicant: '',
|
purpose: '',
|
||||||
description: '',
|
remark: '',
|
||||||
remarks: '',
|
|
||||||
attachments: ''
|
attachments: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = reactive<FormRules>({
|
const rules = reactive<FormRules>({
|
||||||
title: [{ required: true, message: '请输入支出标题', trigger: 'blur' }],
|
title: [{ required: true, message: '请输入支出标题', trigger: 'blur' }],
|
||||||
expenseTypeId: [{ required: true, message: '请选择支出类型', trigger: 'change' }],
|
expenseType: [{ required: true, message: '请选择支出类型', trigger: 'change' }],
|
||||||
amount: [{ required: true, message: '请输入支出金额', trigger: 'blur' }],
|
amount: [{ required: true, message: '请输入支出金额', trigger: 'blur' }],
|
||||||
payeeName: [{ required: true, message: '请输入收款单位', trigger: 'blur' }],
|
payeeName: [{ required: true, message: '请输入收款单位', trigger: 'blur' }],
|
||||||
expenseDate: [{ required: true, message: '请选择支出日期', trigger: 'change' }],
|
expenseDate: [{ required: true, message: '请选择支出日期', trigger: 'change' }]
|
||||||
applicant: [{ required: true, message: '请输入申请人', trigger: 'blur' }]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const approvalVisible = ref(false)
|
const approvalVisible = ref(false)
|
||||||
const approvalData = ref<any>({})
|
const approvalData = ref<any>({})
|
||||||
const approvalForm = reactive({
|
const approvalForm = reactive({
|
||||||
expenseId: null as number | null,
|
expenseId: null as string | null,
|
||||||
comment: ''
|
comment: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -351,8 +356,8 @@ const detailData = ref<any>({})
|
|||||||
const handleUploadSuccess = (response: any, _file: any, fileListVal: any[]) => {
|
const handleUploadSuccess = (response: any, _file: any, fileListVal: any[]) => {
|
||||||
if (response.code === 200 || response.code === 0) {
|
if (response.code === 200 || response.code === 0) {
|
||||||
const urls = fileListVal
|
const urls = fileListVal
|
||||||
.filter(f => f.response?.data?.filePath || f.url)
|
.filter(f => f.response?.data?.fileUrl || f.url)
|
||||||
.map(f => f.response?.data?.filePath || f.url)
|
.map(f => f.response?.data?.fileUrl || f.url)
|
||||||
form.attachments = urls.join(',')
|
form.attachments = urls.join(',')
|
||||||
ElMessage.success('上传成功')
|
ElMessage.success('上传成功')
|
||||||
} else {
|
} else {
|
||||||
@ -368,8 +373,8 @@ const handleUploadError = () => {
|
|||||||
// 移除文件
|
// 移除文件
|
||||||
const handleUploadRemove = (_file: any, fileListVal: any[]) => {
|
const handleUploadRemove = (_file: any, fileListVal: any[]) => {
|
||||||
const urls = fileListVal
|
const urls = fileListVal
|
||||||
.filter(f => f.response?.data?.filePath || f.url)
|
.filter(f => f.response?.data?.fileUrl || f.url)
|
||||||
.map(f => f.response?.data?.filePath || f.url)
|
.map(f => f.response?.data?.fileUrl || f.url)
|
||||||
form.attachments = urls.join(',')
|
form.attachments = urls.join(',')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +382,7 @@ const handleUploadRemove = (_file: any, fileListVal: any[]) => {
|
|||||||
const getFileUrl = (path: string) => {
|
const getFileUrl = (path: string) => {
|
||||||
if (!path) return '#'
|
if (!path) return '#'
|
||||||
if (path.startsWith('http')) return path
|
if (path.startsWith('http')) return path
|
||||||
return `/file/api/v1/file/download/${path}`
|
return `/fund/file/download/${path}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归展平树形数据
|
// 递归展平树形数据
|
||||||
@ -434,7 +439,7 @@ const handleSearch = () => {
|
|||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
queryParams.title = ''
|
queryParams.title = ''
|
||||||
queryParams.expenseTypeId = null
|
queryParams.expenseType = null
|
||||||
queryParams.approvalStatus = ''
|
queryParams.approvalStatus = ''
|
||||||
queryParams.payStatus = ''
|
queryParams.payStatus = ''
|
||||||
queryParams.pageNum = 1
|
queryParams.pageNum = 1
|
||||||
@ -474,7 +479,7 @@ const handleSubmit = (row: any) => {
|
|||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
try {
|
try {
|
||||||
await submitExpense(row.expenseId)
|
await submitExpense(row.id)
|
||||||
ElMessage.success('提交成功')
|
ElMessage.success('提交成功')
|
||||||
fetchData()
|
fetchData()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -485,7 +490,7 @@ const handleSubmit = (row: any) => {
|
|||||||
|
|
||||||
const handleApprove = (row: any) => {
|
const handleApprove = (row: any) => {
|
||||||
approvalData.value = row
|
approvalData.value = row
|
||||||
approvalForm.expenseId = row.expenseId
|
approvalForm.expenseId = row.id
|
||||||
approvalForm.comment = ''
|
approvalForm.comment = ''
|
||||||
approvalVisible.value = true
|
approvalVisible.value = true
|
||||||
}
|
}
|
||||||
@ -523,7 +528,7 @@ const handleDelete = (row: any) => {
|
|||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
try {
|
try {
|
||||||
await deleteExpense(row.expenseId)
|
await deleteExpense(row.id)
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
fetchData()
|
fetchData()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -539,8 +544,8 @@ const handleSaveExpense = async () => {
|
|||||||
|
|
||||||
submitLoading.value = true
|
submitLoading.value = true
|
||||||
try {
|
try {
|
||||||
if (form.expenseId) {
|
if (form.id) {
|
||||||
await updateExpense(form.expenseId, form)
|
await updateExpense(form.id, form)
|
||||||
ElMessage.success('更新成功')
|
ElMessage.success('更新成功')
|
||||||
} else {
|
} else {
|
||||||
await createExpense(form)
|
await createExpense(form)
|
||||||
@ -557,16 +562,15 @@ const handleSaveExpense = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
form.expenseId = null
|
form.id = null
|
||||||
form.title = ''
|
form.title = ''
|
||||||
form.expenseTypeId = null
|
form.expenseType = null
|
||||||
form.projectId = null
|
form.projectId = null
|
||||||
form.amount = 0
|
form.amount = 0
|
||||||
form.payeeName = ''
|
form.payeeName = ''
|
||||||
form.expenseDate = ''
|
form.expenseDate = ''
|
||||||
form.applicant = ''
|
form.purpose = ''
|
||||||
form.description = ''
|
form.remark = ''
|
||||||
form.remarks = ''
|
|
||||||
form.attachments = ''
|
form.attachments = ''
|
||||||
fileList.value = []
|
fileList.value = []
|
||||||
formRef.value?.clearValidate()
|
formRef.value?.clearValidate()
|
||||||
@ -578,7 +582,7 @@ const handleExport = async () => {
|
|||||||
try {
|
try {
|
||||||
const params: any = {}
|
const params: any = {}
|
||||||
if (queryParams.title) params.title = queryParams.title
|
if (queryParams.title) params.title = queryParams.title
|
||||||
if (queryParams.expenseTypeId) params.expenseType = queryParams.expenseTypeId
|
if (queryParams.expenseType) params.expenseType = queryParams.expenseType
|
||||||
if (queryParams.approvalStatus) params.approvalStatus = parseInt(queryParams.approvalStatus)
|
if (queryParams.approvalStatus) params.approvalStatus = parseInt(queryParams.approvalStatus)
|
||||||
if (queryParams.payStatus) params.payStatus = parseInt(queryParams.payStatus)
|
if (queryParams.payStatus) params.payStatus = parseInt(queryParams.payStatus)
|
||||||
|
|
||||||
|
|||||||
@ -105,8 +105,13 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="合同金额" prop="contractAmount">
|
<el-form-item label="项目类型" prop="projectType">
|
||||||
<el-input-number v-model="form.contractAmount" :precision="2" :min="0" style="width: 100%" />
|
<el-select v-model="form.projectType" placeholder="请选择" style="width: 100%">
|
||||||
|
<el-option label="开发项目" value="开发项目" />
|
||||||
|
<el-option label="运维项目" value="运维项目" />
|
||||||
|
<el-option label="咨询项目" value="咨询项目" />
|
||||||
|
<el-option label="集成项目" value="集成项目" />
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -131,23 +136,14 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="项目状态" prop="projectStatus">
|
<el-form-item label="预算金额" prop="budgetAmount">
|
||||||
<el-select v-model="form.projectStatus" placeholder="请选择" style="width: 100%">
|
<el-input-number v-model="form.budgetAmount" :precision="2" :min="0" style="width: 100%" />
|
||||||
<el-option label="待启动" value="PENDING" />
|
|
||||||
<el-option label="进行中" value="IN_PROGRESS" />
|
|
||||||
<el-option label="已完成" value="COMPLETED" />
|
|
||||||
<el-option label="已取消" value="CANCELLED" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-form-item label="项目描述" prop="description">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入项目描述" />
|
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="备注" prop="remarks">
|
|
||||||
<el-input v-model="form.remarks" type="textarea" :rows="2" placeholder="请输入备注" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
@ -210,26 +206,23 @@ const dialogTitle = ref('新增项目')
|
|||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
projectId: null as number | null,
|
id: null as string | null,
|
||||||
projectCode: '',
|
projectCode: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
customerId: null as number | null,
|
customerId: null as string | null,
|
||||||
contractAmount: 0,
|
projectType: '',
|
||||||
|
budgetAmount: 0,
|
||||||
startDate: '',
|
startDate: '',
|
||||||
endDate: '',
|
endDate: '',
|
||||||
projectManager: '',
|
projectManager: '',
|
||||||
projectStatus: 'PENDING',
|
remark: ''
|
||||||
description: '',
|
|
||||||
remarks: ''
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = reactive<FormRules>({
|
const rules = reactive<FormRules>({
|
||||||
projectCode: [{ required: true, message: '请输入项目编号', trigger: 'blur' }],
|
projectCode: [{ required: true, message: '请输入项目编号', trigger: 'blur' }],
|
||||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
||||||
customerId: [{ required: true, message: '请选择客户', trigger: 'change' }],
|
customerId: [{ required: true, message: '请选择客户', trigger: 'change' }],
|
||||||
contractAmount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
|
projectType: [{ required: true, message: '请选择项目类型', trigger: 'change' }]
|
||||||
startDate: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
|
|
||||||
projectStatus: [{ required: true, message: '请选择项目状态', trigger: 'change' }]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const detailVisible = ref(false)
|
const detailVisible = ref(false)
|
||||||
@ -310,8 +303,8 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
submitLoading.value = true
|
submitLoading.value = true
|
||||||
try {
|
try {
|
||||||
if (form.projectId) {
|
if (form.id) {
|
||||||
await updateProject(form.projectId, form)
|
await updateProject(form.id, form)
|
||||||
ElMessage.success('更新成功')
|
ElMessage.success('更新成功')
|
||||||
} else {
|
} else {
|
||||||
await createProject(form)
|
await createProject(form)
|
||||||
@ -328,17 +321,16 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
form.projectId = null
|
form.id = null
|
||||||
form.projectCode = ''
|
form.projectCode = ''
|
||||||
form.projectName = ''
|
form.projectName = ''
|
||||||
form.customerId = null
|
form.customerId = null
|
||||||
form.contractAmount = 0
|
form.projectType = ''
|
||||||
|
form.budgetAmount = 0
|
||||||
form.startDate = ''
|
form.startDate = ''
|
||||||
form.endDate = ''
|
form.endDate = ''
|
||||||
form.projectManager = ''
|
form.projectManager = ''
|
||||||
form.projectStatus = 'PENDING'
|
form.remark = ''
|
||||||
form.description = ''
|
|
||||||
form.remarks = ''
|
|
||||||
formRef.value?.clearValidate()
|
formRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -312,7 +312,7 @@ import { getProjectList } from '@/api/project'
|
|||||||
import { getCustomerList } from '@/api/customer'
|
import { getCustomerList } from '@/api/customer'
|
||||||
|
|
||||||
// 文件上传相关
|
// 文件上传相关
|
||||||
const uploadUrl = '/file/api/v1/file/upload'
|
const uploadUrl = '/fund/file/upload'
|
||||||
const uploadHeaders = {
|
const uploadHeaders = {
|
||||||
Authorization: `Bearer ${localStorage.getItem('token') || ''}`,
|
Authorization: `Bearer ${localStorage.getItem('token') || ''}`,
|
||||||
'X-Tenant-Id': localStorage.getItem('tenantId') || '1'
|
'X-Tenant-Id': localStorage.getItem('tenantId') || '1'
|
||||||
@ -380,8 +380,8 @@ const handleUploadSuccess = (response: any, _file: any, fileListVal: any[]) => {
|
|||||||
if (response.code === 200 || response.code === 0) {
|
if (response.code === 200 || response.code === 0) {
|
||||||
// 保存附件URL(多文件用逗号分隔)
|
// 保存附件URL(多文件用逗号分隔)
|
||||||
const urls = fileListVal
|
const urls = fileListVal
|
||||||
.filter(f => f.response?.data?.filePath || f.url)
|
.filter(f => f.response?.data?.fileUrl || f.url)
|
||||||
.map(f => f.response?.data?.filePath || f.url)
|
.map(f => f.response?.data?.fileUrl || f.url)
|
||||||
form.attachmentUrl = urls.join(',')
|
form.attachmentUrl = urls.join(',')
|
||||||
ElMessage.success('上传成功')
|
ElMessage.success('上传成功')
|
||||||
} else {
|
} else {
|
||||||
@ -397,8 +397,8 @@ const handleUploadError = () => {
|
|||||||
// 移除文件
|
// 移除文件
|
||||||
const handleUploadRemove = (_file: any, fileListVal: any[]) => {
|
const handleUploadRemove = (_file: any, fileListVal: any[]) => {
|
||||||
const urls = fileListVal
|
const urls = fileListVal
|
||||||
.filter(f => f.response?.data?.filePath || f.url)
|
.filter(f => f.response?.data?.fileUrl || f.url)
|
||||||
.map(f => f.response?.data?.filePath || f.url)
|
.map(f => f.response?.data?.fileUrl || f.url)
|
||||||
form.attachmentUrl = urls.join(',')
|
form.attachmentUrl = urls.join(',')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +406,7 @@ const handleUploadRemove = (_file: any, fileListVal: any[]) => {
|
|||||||
const getFileUrl = (path: string) => {
|
const getFileUrl = (path: string) => {
|
||||||
if (!path) return '#'
|
if (!path) return '#'
|
||||||
if (path.startsWith('http')) return path
|
if (path.startsWith('http')) return path
|
||||||
return `/file/api/v1/file/download/${path}`
|
return `/fund/file/download/${path}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchCustomers = async () => {
|
const fetchCustomers = async () => {
|
||||||
|
|||||||
@ -92,8 +92,8 @@
|
|||||||
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="应收款编号" prop="receivableCode">
|
<el-form-item label="应收金额" prop="receivableAmount">
|
||||||
<el-input v-model="form.receivableCode" placeholder="请输入应收款编号" />
|
<el-input-number v-model="form.receivableAmount" :precision="2" :min="0" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -124,35 +124,19 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="应收金额" prop="totalAmount">
|
<el-form-item label="应收日期" prop="receivableDate">
|
||||||
<el-input-number v-model="form.totalAmount" :precision="2" :min="0" style="width: 100%" />
|
<el-date-picker v-model="form.receivableDate" type="date" placeholder="请选择应收日期" value-format="YYYY-MM-DD" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="到期日期" prop="paymentDueDate">
|
||||||
|
<el-date-picker v-model="form.paymentDueDate" type="date" placeholder="请选择到期日期" value-format="YYYY-MM-DD" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row :gutter="20">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-col :span="12">
|
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||||
<el-form-item label="应收日期" prop="dueDate">
|
|
||||||
<el-date-picker v-model="form.dueDate" type="date" placeholder="请选择应收日期" style="width: 100%" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="收款状态" prop="receiptStatus">
|
|
||||||
<el-select v-model="form.receiptStatus" placeholder="请选择" style="width: 100%">
|
|
||||||
<el-option label="未收款" value="UNPAID" />
|
|
||||||
<el-option label="部分收款" value="PARTIAL" />
|
|
||||||
<el-option label="已收款" value="PAID" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-form-item label="账单描述" prop="description">
|
|
||||||
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入账单描述" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="备注" prop="remarks">
|
|
||||||
<el-input v-model="form.remarks" type="textarea" :rows="2" placeholder="请输入备注" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
@ -298,23 +282,22 @@ const dialogTitle = ref('新增应收款')
|
|||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
receivableId: null as number | null,
|
id: null as string | null,
|
||||||
receivableCode: '',
|
projectId: null as string | null,
|
||||||
projectId: null as number | null,
|
customerId: null as string | null,
|
||||||
customerId: null as number | null,
|
receivableAmount: 0,
|
||||||
totalAmount: 0,
|
receivableDate: '',
|
||||||
dueDate: '',
|
paymentDueDate: '',
|
||||||
receiptStatus: 'UNPAID',
|
paymentMethod: '',
|
||||||
description: '',
|
bankAccount: '',
|
||||||
remarks: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = reactive<FormRules>({
|
const rules = reactive<FormRules>({
|
||||||
receivableCode: [{ required: true, message: '请输入应收款编号', trigger: 'blur' }],
|
|
||||||
projectId: [{ required: true, message: '请选择关联项目', trigger: 'change' }],
|
projectId: [{ required: true, message: '请选择关联项目', trigger: 'change' }],
|
||||||
customerId: [{ required: true, message: '请选择客户', trigger: 'change' }],
|
customerId: [{ required: true, message: '请选择客户', trigger: 'change' }],
|
||||||
totalAmount: [{ required: true, message: '请输入应收金额', trigger: 'blur' }],
|
receivableAmount: [{ required: true, message: '请输入应收金额', trigger: 'blur' }],
|
||||||
dueDate: [{ required: true, message: '请选择应收日期', trigger: 'change' }]
|
receivableDate: [{ required: true, message: '请选择应收日期', trigger: 'change' }]
|
||||||
})
|
})
|
||||||
|
|
||||||
const receiptVisible = ref(false)
|
const receiptVisible = ref(false)
|
||||||
@ -473,8 +456,8 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
submitLoading.value = true
|
submitLoading.value = true
|
||||||
try {
|
try {
|
||||||
if (form.receivableId) {
|
if (form.id) {
|
||||||
await updateReceivable(form.receivableId, form)
|
await updateReceivable(form.id, form)
|
||||||
ElMessage.success('更新成功')
|
ElMessage.success('更新成功')
|
||||||
} else {
|
} else {
|
||||||
await createReceivable(form)
|
await createReceivable(form)
|
||||||
@ -491,15 +474,15 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
form.receivableId = null
|
form.id = null
|
||||||
form.receivableCode = ''
|
|
||||||
form.projectId = null
|
form.projectId = null
|
||||||
form.customerId = null
|
form.customerId = null
|
||||||
form.totalAmount = 0
|
form.receivableAmount = 0
|
||||||
form.dueDate = ''
|
form.receivableDate = ''
|
||||||
form.receiptStatus = 'UNPAID'
|
form.paymentDueDate = ''
|
||||||
form.description = ''
|
form.paymentMethod = ''
|
||||||
form.remarks = ''
|
form.bankAccount = ''
|
||||||
|
form.remark = ''
|
||||||
formRef.value?.clearValidate()
|
formRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,41 +20,11 @@ export default defineConfig(({ mode }) => {
|
|||||||
server: {
|
server: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/auth/': {
|
// 所有 /fund/ 请求代理到网关,去掉 /fund 前缀
|
||||||
target: 'http://localhost:8100',
|
'/fund/': {
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
'/sys/': {
|
|
||||||
target: 'http://localhost:8000',
|
target: 'http://localhost:8000',
|
||||||
changeOrigin: true
|
changeOrigin: true,
|
||||||
},
|
rewrite: (path) => path.replace(/^\/fund/, '')
|
||||||
'/cust/': {
|
|
||||||
target: 'http://localhost:8000',
|
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
'/proj/': {
|
|
||||||
target: 'http://localhost:8000',
|
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
'/req/': {
|
|
||||||
target: 'http://localhost:8000',
|
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
'/exp/': {
|
|
||||||
target: 'http://localhost:8000',
|
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
'/receipt/': {
|
|
||||||
target: 'http://localhost:8000',
|
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
'/file/': {
|
|
||||||
target: 'http://localhost:8000',
|
|
||||||
changeOrigin: true
|
|
||||||
},
|
|
||||||
'/report/': {
|
|
||||||
target: 'http://localhost:8000',
|
|
||||||
changeOrigin: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import com.fundplatform.file.data.entity.FileRecord;
|
|||||||
import com.fundplatform.file.data.service.FileRecordService;
|
import com.fundplatform.file.data.service.FileRecordService;
|
||||||
import com.fundplatform.file.service.CosStorageService;
|
import com.fundplatform.file.service.CosStorageService;
|
||||||
import com.fundplatform.file.vo.FileRecordVO;
|
import com.fundplatform.file.vo.FileRecordVO;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -151,25 +152,43 @@ public class FileController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载文件
|
* 下载文件
|
||||||
|
* 支持本地文件和COS文件下载
|
||||||
*/
|
*/
|
||||||
@GetMapping("/download/**")
|
@GetMapping("/download/**")
|
||||||
public void download(HttpServletResponse response,
|
public void download(HttpServletResponse response,
|
||||||
|
HttpServletRequest httpRequest,
|
||||||
@RequestHeader(value = "X-Tenant-Id", required = false) String tenantId) throws IOException {
|
@RequestHeader(value = "X-Tenant-Id", required = false) String tenantId) throws IOException {
|
||||||
String requestUri = request.getRequestURI();
|
String requestUri = httpRequest.getRequestURI();
|
||||||
String filePath = requestUri.substring(requestUri.indexOf("/download/") + 10);
|
String filePath = requestUri.substring(requestUri.indexOf("/download/") + 10);
|
||||||
String fullPath = uploadPath + "/" + filePath;
|
|
||||||
|
|
||||||
File file = new File(fullPath);
|
log.info("文件下载请求: filePath={}", filePath);
|
||||||
if (!file.exists()) {
|
|
||||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
// 检查是否是COS路径
|
||||||
|
if (filePath.startsWith("cos:")) {
|
||||||
|
// COS文件,重定向到COS URL
|
||||||
|
String cosUrl = filePath.substring(4);
|
||||||
|
response.sendRedirect(cosUrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找文件记录
|
// 检查是否已经是完整URL
|
||||||
// 简化处理,直接下载
|
if (filePath.startsWith("http://") || filePath.startsWith("https://")) {
|
||||||
|
response.sendRedirect(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地文件
|
||||||
|
String fullPath = uploadPath + "/" + filePath;
|
||||||
|
File file = new File(fullPath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
log.warn("文件不存在: {}", fullPath);
|
||||||
|
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.getWriter().write("{\"code\":404,\"message\":\"文件不存在\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String fileName = file.getName();
|
String fileName = file.getName();
|
||||||
// 尝试还原原始文件名(如果有扩展名的话)
|
|
||||||
response.setContentType("application/octet-stream");
|
response.setContentType("application/octet-stream");
|
||||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
|
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
"attachment; filename=\"" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + "\"");
|
"attachment; filename=\"" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + "\"");
|
||||||
@ -186,10 +205,6 @@ public class FileController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注入HttpServletRequest
|
|
||||||
@jakarta.annotation.Resource
|
|
||||||
private jakarta.servlet.http.HttpServletRequest request;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ID获取文件信息
|
* 根据ID获取文件信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -132,7 +132,7 @@ const onAfterRead = async (file: any) => {
|
|||||||
const res: any = await uploadFile(file.file, 'expense', undefined, '支出附件')
|
const res: any = await uploadFile(file.file, 'expense', undefined, '支出附件')
|
||||||
|
|
||||||
// 从响应中获取文件路径
|
// 从响应中获取文件路径
|
||||||
const filePath = res.data?.filePath || res.data?.url
|
const filePath = res.data?.fileUrl || res.data?.url
|
||||||
if (filePath) {
|
if (filePath) {
|
||||||
uploadedAttachments.value.push(filePath)
|
uploadedAttachments.value.push(filePath)
|
||||||
console.log('文件上传成功:', filePath)
|
console.log('文件上传成功:', filePath)
|
||||||
|
|||||||
@ -104,9 +104,18 @@ const getAttachmentCount = (attachments: string) => {
|
|||||||
const previewAttachments = (item: any) => {
|
const previewAttachments = (item: any) => {
|
||||||
if (!item.attachments) return
|
if (!item.attachments) return
|
||||||
|
|
||||||
// 将 base64 字符串转为图片 URL
|
// 将逗号分隔的URL字符串转为数组
|
||||||
const attachmentList = item.attachments.split(',')
|
const attachmentList = item.attachments.split(',').filter((s: string) => s.trim())
|
||||||
const imageUrls = attachmentList.map((b64: string) => `data:image/jpeg;base64,${b64}`)
|
|
||||||
|
// 构建图片URL列表
|
||||||
|
const imageUrls = attachmentList.map((url: string) => {
|
||||||
|
// 如果已经是完整URL,直接使用
|
||||||
|
if (url.startsWith('http')) return url
|
||||||
|
// 如果是COS路径
|
||||||
|
if (url.startsWith('cos:')) return url.substring(4)
|
||||||
|
// 否则使用文件下载接口
|
||||||
|
return `/fund/file/download/${url}`
|
||||||
|
})
|
||||||
|
|
||||||
ImagePreview.show({
|
ImagePreview.show({
|
||||||
images: imageUrls,
|
images: imageUrls,
|
||||||
|
|||||||
@ -189,7 +189,7 @@ const onSubmit = async () => {
|
|||||||
projectId: form.value.projectId,
|
projectId: form.value.projectId,
|
||||||
receivableAmount: parseFloat(form.value.receivableAmount),
|
receivableAmount: parseFloat(form.value.receivableAmount),
|
||||||
receivableDate: form.value.receivableDate,
|
receivableDate: form.value.receivableDate,
|
||||||
description: form.value.description
|
remark: form.value.description
|
||||||
})
|
})
|
||||||
showSuccessToast('提交成功')
|
showSuccessToast('提交成功')
|
||||||
router.back()
|
router.back()
|
||||||
|
|||||||
@ -19,7 +19,7 @@ public class FundReceiptController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public Result<Long> create(@Valid @RequestBody FundReceiptDTO dto) {
|
public Result<String> create(@Valid @RequestBody FundReceiptDTO dto) {
|
||||||
return Result.success(receiptService.createReceipt(dto));
|
return Result.success(receiptService.createReceipt(dto));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ public class FundReceiptController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public Result<FundReceiptVO> getById(@PathVariable Long id) {
|
public Result<FundReceiptVO> getById(@PathVariable String id) {
|
||||||
return Result.success(receiptService.getReceiptById(id));
|
return Result.success(receiptService.getReceiptById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,17 +44,17 @@ public class FundReceiptController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public Result<Boolean> delete(@PathVariable Long id) {
|
public Result<Boolean> delete(@PathVariable String id) {
|
||||||
return Result.success(receiptService.deleteReceipt(id));
|
return Result.success(receiptService.deleteReceipt(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}/confirm")
|
@PutMapping("/{id}/confirm")
|
||||||
public Result<Boolean> confirm(@PathVariable Long id) {
|
public Result<Boolean> confirm(@PathVariable String id) {
|
||||||
return Result.success(receiptService.confirm(id));
|
return Result.success(receiptService.confirm(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}/write-off")
|
@PutMapping("/{id}/write-off")
|
||||||
public Result<Boolean> writeOff(@PathVariable Long id) {
|
public Result<Boolean> writeOff(@PathVariable String id) {
|
||||||
return Result.success(receiptService.writeOff(id));
|
return Result.success(receiptService.writeOff(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ public class ReceivableController {
|
|||||||
* 创建应收款
|
* 创建应收款
|
||||||
*/
|
*/
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public Result<Long> create(@Valid @RequestBody ReceivableDTO dto) {
|
public Result<String> create(@Valid @RequestBody ReceivableDTO dto) {
|
||||||
return Result.success(receivableService.createReceivable(dto));
|
return Result.success(receivableService.createReceivable(dto));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ public class ReceivableController {
|
|||||||
* 更新应收款(仅待确认状态可修改)
|
* 更新应收款(仅待确认状态可修改)
|
||||||
*/
|
*/
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
public Result<Boolean> update(@PathVariable Long id, @Valid @RequestBody ReceivableDTO dto) {
|
public Result<Boolean> update(@PathVariable String id, @Valid @RequestBody ReceivableDTO dto) {
|
||||||
dto.setId(id);
|
dto.setId(id);
|
||||||
return Result.success(receivableService.updateReceivable(dto));
|
return Result.success(receivableService.updateReceivable(dto));
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ public class ReceivableController {
|
|||||||
* 根据ID查询应收款
|
* 根据ID查询应收款
|
||||||
*/
|
*/
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public Result<ReceivableVO> getById(@PathVariable Long id) {
|
public Result<ReceivableVO> getById(@PathVariable String id) {
|
||||||
return Result.success(receivableService.getReceivableById(id));
|
return Result.success(receivableService.getReceivableById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +67,8 @@ public class ReceivableController {
|
|||||||
public Result<Page<ReceivableVO>> page(
|
public Result<Page<ReceivableVO>> page(
|
||||||
@RequestParam(defaultValue = "1") int pageNum,
|
@RequestParam(defaultValue = "1") int pageNum,
|
||||||
@RequestParam(defaultValue = "10") int pageSize,
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
@RequestParam(required = false) Long projectId,
|
@RequestParam(required = false) String projectId,
|
||||||
@RequestParam(required = false) Long customerId,
|
@RequestParam(required = false) String customerId,
|
||||||
@RequestParam(required = false) String status,
|
@RequestParam(required = false) String status,
|
||||||
@RequestParam(required = false) Integer confirmStatus) {
|
@RequestParam(required = false) Integer confirmStatus) {
|
||||||
return Result.success(receivableService.pageReceivables(pageNum, pageSize, projectId, customerId, status, confirmStatus));
|
return Result.success(receivableService.pageReceivables(pageNum, pageSize, projectId, customerId, status, confirmStatus));
|
||||||
@ -79,8 +79,8 @@ public class ReceivableController {
|
|||||||
*/
|
*/
|
||||||
@PutMapping("/{id}/confirm")
|
@PutMapping("/{id}/confirm")
|
||||||
public Result<Boolean> confirm(
|
public Result<Boolean> confirm(
|
||||||
@PathVariable Long id,
|
@PathVariable String id,
|
||||||
@RequestHeader(value = "X-User-Id", required = false) Long confirmBy) {
|
@RequestHeader(value = "X-User-Id", required = false) String confirmBy) {
|
||||||
return Result.success(receivableService.confirmReceivable(id, confirmBy));
|
return Result.success(receivableService.confirmReceivable(id, confirmBy));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ public class ReceivableController {
|
|||||||
* 取消确认
|
* 取消确认
|
||||||
*/
|
*/
|
||||||
@PutMapping("/{id}/cancel-confirm")
|
@PutMapping("/{id}/cancel-confirm")
|
||||||
public Result<Boolean> cancelConfirm(@PathVariable Long id) {
|
public Result<Boolean> cancelConfirm(@PathVariable String id) {
|
||||||
return Result.success(receivableService.cancelConfirm(id));
|
return Result.success(receivableService.cancelConfirm(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ public class ReceivableController {
|
|||||||
* 记录收款
|
* 记录收款
|
||||||
*/
|
*/
|
||||||
@PostMapping("/{id}/receipt")
|
@PostMapping("/{id}/receipt")
|
||||||
public Result<Boolean> recordReceipt(@PathVariable Long id, @RequestParam BigDecimal amount) {
|
public Result<Boolean> recordReceipt(@PathVariable String id, @RequestParam BigDecimal amount) {
|
||||||
return Result.success(receivableService.recordReceipt(id, amount));
|
return Result.success(receivableService.recordReceipt(id, amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ public class ReceivableController {
|
|||||||
* 获取应收款的收款记录列表
|
* 获取应收款的收款记录列表
|
||||||
*/
|
*/
|
||||||
@GetMapping("/{id}/receipts")
|
@GetMapping("/{id}/receipts")
|
||||||
public Result<List<FundReceiptVO>> getReceipts(@PathVariable Long id) {
|
public Result<List<FundReceiptVO>> getReceipts(@PathVariable String id) {
|
||||||
return Result.success(receivableService.getReceiptsByReceivableId(id));
|
return Result.success(receivableService.getReceiptsByReceivableId(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ public class ReceivableController {
|
|||||||
* 删除应收款(仅待确认状态可删除)
|
* 删除应收款(仅待确认状态可删除)
|
||||||
*/
|
*/
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public Result<Boolean> delete(@PathVariable Long id) {
|
public Result<Boolean> delete(@PathVariable String id) {
|
||||||
return Result.success(receivableService.deleteReceivable(id));
|
return Result.success(receivableService.deleteReceivable(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,8 +166,8 @@ public class ReceivableController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/export")
|
@GetMapping("/export")
|
||||||
public void exportExcel(
|
public void exportExcel(
|
||||||
@RequestParam(required = false) Long projectId,
|
@RequestParam(required = false) String projectId,
|
||||||
@RequestParam(required = false) Long customerId,
|
@RequestParam(required = false) String customerId,
|
||||||
@RequestParam(required = false) String status,
|
@RequestParam(required = false) String status,
|
||||||
@RequestParam(required = false) Integer confirmStatus,
|
@RequestParam(required = false) Integer confirmStatus,
|
||||||
HttpServletResponse response) {
|
HttpServletResponse response) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user