27 changed files with 1002 additions and 80 deletions
@ -1,3 +1,3 @@ |
|||||
NODE_ENV=development |
NODE_ENV=development |
||||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
VITE_APP_TITLE='律师公益法律服务活动申报子系统' |
||||
VITE_APP_API_URL='/api' |
VITE_APP_API_URL='/api' |
||||
@ -1,3 +1,3 @@ |
|||||
NODE_ENV=development |
NODE_ENV=development |
||||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
VITE_APP_TITLE='律师公益法律服务活动申报子系统' |
||||
VITE_APP_API_URL='/api' |
VITE_APP_API_URL='/api' |
||||
|
|||||
@ -1,3 +1,3 @@ |
|||||
NODE_ENV=production |
NODE_ENV=production |
||||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
VITE_APP_TITLE='律师公益法律服务活动申报子系统' |
||||
VITE_APP_API_URL='https://preview.smartadmin.vip/smart-admin-api' |
VITE_APP_API_URL='/api' |
||||
@ -1,3 +1,3 @@ |
|||||
NODE_ENV=production |
NODE_ENV=production |
||||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
VITE_APP_TITLE='律师公益法律服务活动申报子系统' |
||||
VITE_APP_API_URL='/api' |
VITE_APP_API_URL='/api' |
||||
@ -1,3 +1,3 @@ |
|||||
NODE_ENV=production |
NODE_ENV=production |
||||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
VITE_APP_TITLE='律师公益法律服务活动申报子系统' |
||||
VITE_APP_API_URL='/api' |
VITE_APP_API_URL='/api' |
||||
|
|||||
@ -0,0 +1,48 @@ |
|||||
|
/** |
||||
|
* 律师事务所年度经营报表 api 封装 |
||||
|
* |
||||
|
* @Author: wzh |
||||
|
* @Date: 2026-01-07 15:57:43 |
||||
|
* @Copyright 1.0 |
||||
|
*/ |
||||
|
import { postRequest, getRequest } from '/@/lib/axios'; |
||||
|
|
||||
|
export const firmReportsApi = { |
||||
|
|
||||
|
/** |
||||
|
* 分页查询 @author wzh |
||||
|
*/ |
||||
|
queryPage : (param) => { |
||||
|
return postRequest('/firmReports/queryPage', param); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 增加 @author wzh |
||||
|
*/ |
||||
|
add: (param) => { |
||||
|
return postRequest('/firmReports/add', param); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 修改 @author wzh |
||||
|
*/ |
||||
|
update: (param) => { |
||||
|
return postRequest('/firmReports/update', param); |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 删除 @author wzh |
||||
|
*/ |
||||
|
delete: (id) => { |
||||
|
return getRequest(`/firmReports/delete/${id}`); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 批量删除 @author wzh |
||||
|
*/ |
||||
|
batchDelete: (idList) => { |
||||
|
return postRequest('/firmReports/batchDelete', idList); |
||||
|
}, |
||||
|
|
||||
|
}; |
||||
@ -0,0 +1,59 @@ |
|||||
|
/* |
||||
|
* 成本管理常量 |
||||
|
*/ |
||||
|
|
||||
|
// 季度枚举
|
||||
|
export const QUARTER_ENUM = { |
||||
|
Q1: { |
||||
|
value: 'Q1', |
||||
|
desc: '第一季度', |
||||
|
}, |
||||
|
Q2: { |
||||
|
value: 'Q2', |
||||
|
desc: '第二季度', |
||||
|
}, |
||||
|
Q3: { |
||||
|
value: 'Q3', |
||||
|
desc: '第三季度', |
||||
|
}, |
||||
|
Q4: { |
||||
|
value: 'Q4', |
||||
|
desc: '第四季度', |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
// 审核状态枚举
|
||||
|
export const REVIEW_STATUS_ENUM = { |
||||
|
DRAFT: { |
||||
|
value: 0, |
||||
|
desc: '待提交', |
||||
|
}, |
||||
|
SUBMITTED: { |
||||
|
value: 1, |
||||
|
desc: '待审批', |
||||
|
}, |
||||
|
APPROVED: { |
||||
|
value: 2, |
||||
|
desc: '审批中', |
||||
|
}, |
||||
|
REJECTED: { |
||||
|
value: 3, |
||||
|
desc: '已通过', |
||||
|
}, |
||||
|
REFUSE: { |
||||
|
value: 4, |
||||
|
desc: '拒绝', |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
// 成本类型枚举
|
||||
|
export const COST_TYPE_ENUM = { |
||||
|
PUBLIC_WELFARE: { |
||||
|
value: 1, |
||||
|
desc: '公益活动成本', |
||||
|
}, |
||||
|
OTHER: { |
||||
|
value: 2, |
||||
|
desc: '其他成本', |
||||
|
}, |
||||
|
}; |
||||
@ -0,0 +1,255 @@ |
|||||
|
<!-- |
||||
|
* 律师事务所年度经营报表 |
||||
|
* |
||||
|
* @Author: wzh |
||||
|
* @Date: 2026-01-07 15:57:43 |
||||
|
* @Copyright 1.0 |
||||
|
--> |
||||
|
<template> |
||||
|
<a-modal |
||||
|
:title="form.id ? '编辑成本填报' : '新建成本填报'" |
||||
|
:width="600" |
||||
|
:open="visibleFlag" |
||||
|
@cancel="onClose" |
||||
|
:maskClosable="false" |
||||
|
:destroyOnClose="true" |
||||
|
> |
||||
|
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 6 }" > |
||||
|
<a-form-item label="律师事务所"> |
||||
|
<a-input v-model:value="departmentName" placeholder="律师事务所" disabled /> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item label="季度" name="declareQuarter"> |
||||
|
<DictSelect |
||||
|
dict-code="QUARTER" |
||||
|
v-model:value="form.declareQuarter" |
||||
|
placeholder="请选择季度" |
||||
|
@change="calculateCosts" |
||||
|
style="width: 100%" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item label="律所收入(万元)" name="revenue"> |
||||
|
<a-input-number |
||||
|
style="width: 100%" |
||||
|
v-model:value="form.revenue" |
||||
|
placeholder="请输入律所总收入" |
||||
|
:min="0" |
||||
|
:precision="2" |
||||
|
@change="calculateCosts" |
||||
|
addon-after="万元" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item label="公益活动成本(万元)" name="publicWelfareCost"> |
||||
|
<a-input-number |
||||
|
style="width: 100%" |
||||
|
v-model:value="form.publicWelfareCost" |
||||
|
placeholder="请输入公益活动成本" |
||||
|
:min="0" |
||||
|
:precision="2" |
||||
|
@change="calculateCosts" |
||||
|
addon-after="万元" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item label="其他成本(万元)" name="otherCost"> |
||||
|
<a-input-number |
||||
|
style="width: 100%" |
||||
|
v-model:value="form.otherCost" |
||||
|
placeholder="请输入其他成本" |
||||
|
:min="0" |
||||
|
:precision="2" |
||||
|
@change="calculateCosts" |
||||
|
addon-after="万元" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-row> |
||||
|
<a-col :span="12"> |
||||
|
<a-form-item label="总成本(万元)" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }"> |
||||
|
<a-input-number |
||||
|
style="width: 100%" |
||||
|
v-model:value="form.totalCost" |
||||
|
:precision="2" |
||||
|
disabled |
||||
|
addon-after="万元" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
</a-col> |
||||
|
<a-col :span="12"> |
||||
|
<a-form-item label="成本/收入比例" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }"> |
||||
|
<a-input |
||||
|
style="width: 100%" |
||||
|
v-model:value="form.costIncomeRatio" |
||||
|
disabled |
||||
|
addon-after="%" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
|
||||
|
<a-form-item label="报表年份" name="declareYear"> |
||||
|
<a-input-number |
||||
|
style="width: 100%" |
||||
|
v-model:value="form.declareYear" |
||||
|
placeholder="请输入报表年份" |
||||
|
disabled |
||||
|
:min="2000" |
||||
|
:max="2100" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
</a-form> |
||||
|
|
||||
|
<template #footer> |
||||
|
<a-space> |
||||
|
<a-button @click="onClose">取消</a-button> |
||||
|
<a-button @click="saveAsDraft" type="default" v-if="!form.id">保存草稿</a-button> |
||||
|
<a-button type="primary" @click="submitForReview">提交审核</a-button> |
||||
|
</a-space> |
||||
|
</template> |
||||
|
</a-modal> |
||||
|
</template> |
||||
|
<script setup> |
||||
|
import { reactive, ref, nextTick, computed } from 'vue'; |
||||
|
import _ from 'lodash'; |
||||
|
import { message } from 'ant-design-vue'; |
||||
|
import { SmartLoading } from '/@/components/framework/smart-loading'; |
||||
|
import { firmReportsApi } from '/@/api/business/cost/firm-reports-api'; |
||||
|
import { smartSentry } from '/@/lib/smart-sentry'; |
||||
|
import { useUserStore } from '/@/store/modules/system/user'; |
||||
|
import DictSelect from '/@/components/support/dict-select/index.vue'; |
||||
|
|
||||
|
// ------------------------ 事件 ------------------------ |
||||
|
|
||||
|
const emits = defineEmits(['reloadList']); |
||||
|
|
||||
|
// ------------------------ 用户信息 ------------------------ |
||||
|
const userStore = useUserStore(); |
||||
|
|
||||
|
// 律师事务所名称(部门名称) |
||||
|
const departmentName = computed(() => userStore.departmentName); |
||||
|
|
||||
|
// 部门ID |
||||
|
const departmentId = computed(() => userStore.departmentId); |
||||
|
|
||||
|
// ------------------------ 显示与隐藏 ------------------------ |
||||
|
// 是否显示 |
||||
|
const visibleFlag = ref(false); |
||||
|
|
||||
|
function show(rowData) { |
||||
|
Object.assign(form, formDefault); |
||||
|
|
||||
|
// 设置律师事务所ID(部门ID) |
||||
|
form.firmId = departmentId.value; |
||||
|
|
||||
|
if (rowData && !_.isEmpty(rowData)) { |
||||
|
Object.assign(form, rowData); |
||||
|
} |
||||
|
|
||||
|
visibleFlag.value = true; |
||||
|
nextTick(() => { |
||||
|
formRef.value.clearValidate(); |
||||
|
// 初始化计算 |
||||
|
calculateCosts(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function onClose() { |
||||
|
Object.assign(form, formDefault); |
||||
|
visibleFlag.value = false; |
||||
|
} |
||||
|
|
||||
|
// ------------------------ 表单 ------------------------ |
||||
|
|
||||
|
// 组件ref |
||||
|
const formRef = ref(); |
||||
|
|
||||
|
const formDefault = { |
||||
|
id: undefined, |
||||
|
firmId: undefined, // 律师事务所ID(部门ID) |
||||
|
declareYear: new Date().getFullYear(), // 报表年份 |
||||
|
declareQuarter: undefined, // 季度ID (1,2,3,4) |
||||
|
revenue: undefined, // 营业收入(万元) |
||||
|
totalCost: 0, // 总成本支出(万元) |
||||
|
publicWelfareCost: undefined, // 公益成本支出(万元) |
||||
|
costIncomeRatio: '0.00', // 成本收入比(%) |
||||
|
}; |
||||
|
|
||||
|
let form = reactive({ ...formDefault }); |
||||
|
|
||||
|
const rules = { |
||||
|
declareQuarter: [{ required: true, message: '请选择季度' }], |
||||
|
declareYear: [{ required: true, message: '请输入报表年份' }], |
||||
|
revenue: [{ required: true, message: '请输入律所收入' }], |
||||
|
publicWelfareCost: [{ required: true, message: '请输入公益活动成本' }], |
||||
|
}; |
||||
|
|
||||
|
// 自动计算总成本和成本/收入比例 |
||||
|
function calculateCosts() { |
||||
|
const revenue = parseFloat(form.revenue) || 0; |
||||
|
const publicWelfareCost = parseFloat(form.publicWelfareCost) || 0; |
||||
|
const otherCost = parseFloat(form.otherCost) || 0; |
||||
|
|
||||
|
// 计算总成本 |
||||
|
const totalCost = publicWelfareCost + otherCost; |
||||
|
form.totalCost = totalCost; |
||||
|
|
||||
|
// 计算成本/收入比例 |
||||
|
if (revenue > 0) { |
||||
|
const ratio = (totalCost / revenue) * 100; |
||||
|
form.costIncomeRatio = ratio.toFixed(2); |
||||
|
} else { |
||||
|
form.costIncomeRatio = '0.00'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 保存草稿 |
||||
|
async function saveAsDraft() { |
||||
|
try { |
||||
|
await formRef.value.validateFields(['declareQuarter', 'declareYear', 'revenue', 'publicWelfareCost']); |
||||
|
form.approvalStatus = '0'; // 草稿状态 |
||||
|
await save(); |
||||
|
message.success('保存草稿成功'); |
||||
|
} catch (err) { |
||||
|
message.error('请填写必填字段后再保存草稿!'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 提交审核 |
||||
|
async function submitForReview() { |
||||
|
try { |
||||
|
await formRef.value.validateFields(); |
||||
|
form.approvalStatus = '1'; // 待审核状态 |
||||
|
await save(); |
||||
|
message.success('提交审核成功'); |
||||
|
} catch (err) { |
||||
|
message.error('参数验证错误,请仔细填写表单数据!'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 新建、编辑API |
||||
|
async function save() { |
||||
|
SmartLoading.show(); |
||||
|
try { |
||||
|
// 确保计算最新的数据 |
||||
|
calculateCosts(); |
||||
|
|
||||
|
if (form.id) { |
||||
|
await firmReportsApi.update(form); |
||||
|
} else { |
||||
|
await firmReportsApi.add(form); |
||||
|
} |
||||
|
emits('reloadList'); |
||||
|
onClose(); |
||||
|
} catch (err) { |
||||
|
smartSentry.captureError(err); |
||||
|
} finally { |
||||
|
SmartLoading.hide(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
defineExpose({ |
||||
|
show, |
||||
|
}); |
||||
|
</script> |
||||
@ -0,0 +1,403 @@ |
|||||
|
<!-- |
||||
|
* 律师事务所年度经营报表 |
||||
|
* |
||||
|
* @Author: wzh |
||||
|
* @Date: 2026-01-07 15:57:43 |
||||
|
* @Copyright 1.0 |
||||
|
--> |
||||
|
<template> |
||||
|
<!---------- 查询表单form begin -----------> |
||||
|
<a-form class="smart-query-form"> |
||||
|
<a-row class="smart-query-form-row"> |
||||
|
<a-form-item label="律师事务所" class="smart-query-form-item"> |
||||
|
<DepartmentTreeSelect style="width: 150px" v-model:value="queryForm.firmId" placeholder="请选择律师事务所" /> |
||||
|
</a-form-item> |
||||
|
<a-form-item label="报表年份" class="smart-query-form-item"> |
||||
|
<a-input style="width: 150px" v-model:value="queryForm.declareYear" placeholder="请输入报表年份" /> |
||||
|
</a-form-item> |
||||
|
<a-form-item label="报表季度" class="smart-query-form-item"> |
||||
|
<DictSelect |
||||
|
dict-code="QUARTER" |
||||
|
v-model:value="queryForm.declareQuarter" |
||||
|
placeholder="请选择季度" |
||||
|
style="width: 100px" |
||||
|
/> |
||||
|
</a-form-item> |
||||
|
<a-form-item class="smart-query-form-item" style="margin-left: 120px;"> |
||||
|
<a-button type="primary" @click="onSearch"> |
||||
|
<template #icon> |
||||
|
<SearchOutlined /> |
||||
|
</template> |
||||
|
查询 |
||||
|
</a-button> |
||||
|
<a-button @click="resetQuery" class="smart-margin-left10"> |
||||
|
<template #icon> |
||||
|
<ReloadOutlined /> |
||||
|
</template> |
||||
|
重置 |
||||
|
</a-button> |
||||
|
</a-form-item> |
||||
|
</a-row> |
||||
|
</a-form> |
||||
|
<!---------- 查询表单form end -----------> |
||||
|
|
||||
|
<a-card size="small" :bordered="false" :hoverable="true"> |
||||
|
<!---------- 表格操作行 begin -----------> |
||||
|
<a-row class="smart-table-btn-block"> |
||||
|
<div class="smart-table-operate-block"> |
||||
|
<a-button @click="showForm" type="primary" > |
||||
|
<template #icon> |
||||
|
<PlusOutlined /> |
||||
|
</template> |
||||
|
新建 |
||||
|
</a-button> |
||||
|
<a-button @click="confirmBatchDelete" type="primary" danger :disabled="selectedRowKeyList.length == 0"> |
||||
|
<template #icon> |
||||
|
<DeleteOutlined /> |
||||
|
</template> |
||||
|
批量删除 |
||||
|
</a-button> |
||||
|
</div> |
||||
|
<div class="smart-table-setting-block"> |
||||
|
<TableOperator v-model="columns" :tableId="null" :refresh="queryData" /> |
||||
|
</div> |
||||
|
</a-row> |
||||
|
<!---------- 表格操作行 end -----------> |
||||
|
|
||||
|
<!---------- 表格 begin -----------> |
||||
|
<a-table |
||||
|
size="small" |
||||
|
:scroll="{ y: 800 }" |
||||
|
:dataSource="tableData" |
||||
|
:columns="columns" |
||||
|
rowKey="id" |
||||
|
bordered |
||||
|
:loading="tableLoading" |
||||
|
:pagination="false" |
||||
|
:row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }" |
||||
|
> |
||||
|
<template #bodyCell="{ text, record, column }"> |
||||
|
<template v-if="column.dataIndex === 'action'"> |
||||
|
<div class="smart-table-operate"> |
||||
|
<!--<a-button v-if="record.approvalStatus === 0 || record.approvalStatus === 4" @click="showForm(record)" type="link">编辑</a-button>--> |
||||
|
<a-button v-if="record.approvalStatus === 0" @click="onSubmit(record)" type="link">提交</a-button> |
||||
|
<a-button v-if="record.approvalStatus === 1 || record.approvalStatus === 2" @click="showAuditModal(record)" type="link">审核</a-button> |
||||
|
<a-button @click="onDelete(record)" danger type="link">删除</a-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</template> |
||||
|
</a-table> |
||||
|
<!---------- 表格 end -----------> |
||||
|
|
||||
|
<div class="smart-query-table-page"> |
||||
|
<a-pagination |
||||
|
showSizeChanger |
||||
|
showQuickJumper |
||||
|
show-less-items |
||||
|
:pageSizeOptions="PAGE_SIZE_OPTIONS" |
||||
|
:defaultPageSize="queryForm.pageSize" |
||||
|
v-model:current="queryForm.pageNum" |
||||
|
v-model:pageSize="queryForm.pageSize" |
||||
|
:total="total" |
||||
|
@change="queryData" |
||||
|
@showSizeChange="queryData" |
||||
|
:show-total="(total) => `共${total}条`" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<FirmReportsForm ref="formRef" @reloadList="queryData"/> |
||||
|
|
||||
|
</a-card> |
||||
|
</template> |
||||
|
<script setup> |
||||
|
import { reactive, ref, onMounted } from 'vue'; |
||||
|
import { message, Modal } from 'ant-design-vue'; |
||||
|
import { SmartLoading } from '/@/components/framework/smart-loading'; |
||||
|
import { firmReportsApi } from '/@/api/business/cost/firm-reports-api'; |
||||
|
import { PAGE_SIZE_OPTIONS } from '/@/constants/common-const'; |
||||
|
import { smartSentry } from '/@/lib/smart-sentry'; |
||||
|
import TableOperator from '/@/components/support/table-operator/index.vue'; |
||||
|
import FirmReportsForm from './firm-reports-form.vue'; |
||||
|
import { REVIEW_STATUS_ENUM } from '/@/constants/business/erp/cost-const'; |
||||
|
import DepartmentTreeSelect from '/@/components/system/department-tree-select/index.vue'; |
||||
|
import DictSelect from '/@/components/support/dict-select/index.vue'; |
||||
|
|
||||
|
// ---------------------------- 表格列 ---------------------------- |
||||
|
|
||||
|
const columns = ref([ |
||||
|
{ |
||||
|
title: '律师事务所', |
||||
|
dataIndex: 'firmName', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '报表年份', |
||||
|
dataIndex: 'declareYear', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '报表季度', |
||||
|
dataIndex: 'declareQuarter', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '营业收入(单位:万元)', |
||||
|
dataIndex: 'revenue', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '总成本支出(单位:万元)', |
||||
|
dataIndex: 'totalCost', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '公益成本支出(单位:万元)', |
||||
|
dataIndex: 'publicWelfareCost', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '成本收入比', |
||||
|
dataIndex: 'costIncomeRatio', |
||||
|
ellipsis: true, |
||||
|
customRender: ({ text }) => { |
||||
|
return text ? `${text}%` : ''; |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '审批状态', |
||||
|
dataIndex: 'approvalStatus', |
||||
|
ellipsis: true, |
||||
|
customRender: ({ text }) => { |
||||
|
const status = Object.values(REVIEW_STATUS_ENUM).find(item => item.value === text); |
||||
|
return status ? status.desc : text; |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '提交时间', |
||||
|
dataIndex: 'submissionTime', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '审批人', |
||||
|
dataIndex: 'approverId', |
||||
|
ellipsis: true, |
||||
|
}, |
||||
|
{ |
||||
|
title: '操作', |
||||
|
dataIndex: 'action', |
||||
|
fixed: 'right', |
||||
|
width: 150, |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
// ---------------------------- 查询数据表单和方法 ---------------------------- |
||||
|
|
||||
|
const queryFormState = { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
firmId: undefined, // 律师事务所ID |
||||
|
declareYear: undefined, // 报表年份 |
||||
|
declareQuarter: undefined, // 报表季度 |
||||
|
}; |
||||
|
// 查询表单form |
||||
|
const queryForm = reactive({ ...queryFormState }); |
||||
|
// 表格加载loading |
||||
|
const tableLoading = ref(false); |
||||
|
// 表格数据 |
||||
|
const tableData = ref([]); |
||||
|
// 总数 |
||||
|
const total = ref(0); |
||||
|
|
||||
|
// 重置查询条件 |
||||
|
function resetQuery() { |
||||
|
let pageSize = queryForm.pageSize; |
||||
|
Object.assign(queryForm, queryFormState); |
||||
|
queryForm.pageSize = pageSize; |
||||
|
queryData(); |
||||
|
} |
||||
|
|
||||
|
// 搜索 |
||||
|
function onSearch(){ |
||||
|
queryForm.pageNum = 1; |
||||
|
queryData(); |
||||
|
} |
||||
|
|
||||
|
// 查询数据 |
||||
|
async function queryData() { |
||||
|
tableLoading.value = true; |
||||
|
try { |
||||
|
let queryResult = await firmReportsApi.queryPage(queryForm); |
||||
|
tableData.value = queryResult.data.list; |
||||
|
total.value = queryResult.data.total; |
||||
|
} catch (e) { |
||||
|
smartSentry.captureError(e); |
||||
|
} finally { |
||||
|
tableLoading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ---------------------------- 单个提交 ---------------------------- |
||||
|
//确认提交 |
||||
|
function onSubmit(data){ |
||||
|
Modal.confirm({ |
||||
|
title: '提示', |
||||
|
content: '确定要提交该成本报表吗?', |
||||
|
okText: '提交', |
||||
|
okType: 'primary', |
||||
|
onOk() { |
||||
|
requestSubmit(data); |
||||
|
}, |
||||
|
cancelText: '取消', |
||||
|
onCancel() {}, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//请求提交 |
||||
|
async function requestSubmit(data){ |
||||
|
try { |
||||
|
SmartLoading.show(); |
||||
|
await firmReportsApi.submit(data.reportId); |
||||
|
message.success('提交成功'); |
||||
|
queryData(); |
||||
|
} catch (e) { |
||||
|
smartSentry.captureError(e); |
||||
|
} finally { |
||||
|
SmartLoading.hide(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ---------------------------- 审核相关 ---------------------------- |
||||
|
// 审核相关状态 |
||||
|
const auditModalVisible = ref(false); |
||||
|
const auditLoading = ref(false); |
||||
|
const currentAuditRecord = ref(null); |
||||
|
const auditForm = reactive({ |
||||
|
auditResult: 3, // 默认同意 |
||||
|
auditRemark: '' |
||||
|
}); |
||||
|
|
||||
|
// 显示审核弹框 |
||||
|
function showAuditModal(record) { |
||||
|
currentAuditRecord.value = record; |
||||
|
auditForm.auditResult = 3; |
||||
|
auditForm.auditRemark = ''; |
||||
|
auditModalVisible.value = true; |
||||
|
} |
||||
|
|
||||
|
// 处理审核 |
||||
|
async function handleAudit() { |
||||
|
if (!currentAuditRecord.value) { |
||||
|
message.error('未选择审核记录'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
auditLoading.value = true; |
||||
|
|
||||
|
const auditData = { |
||||
|
reportId: currentAuditRecord.value.reportId, |
||||
|
approvalStatus: auditForm.auditResult |
||||
|
}; |
||||
|
|
||||
|
try { |
||||
|
await firmReportsApi.review(auditData); |
||||
|
message.success('审核成功'); |
||||
|
auditModalVisible.value = false; |
||||
|
queryData(); |
||||
|
} catch (error) { |
||||
|
message.error('审核失败'); |
||||
|
console.error('审核失败:', error); |
||||
|
} finally { |
||||
|
auditLoading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 取消审核 |
||||
|
function handleAuditCancel() { |
||||
|
auditModalVisible.value = false; |
||||
|
currentAuditRecord.value = null; |
||||
|
auditForm.auditResult = 3; |
||||
|
auditForm.auditRemark = ''; |
||||
|
} |
||||
|
|
||||
|
onMounted(queryData); |
||||
|
|
||||
|
// ---------------------------- 添加/修改 ---------------------------- |
||||
|
const formRef = ref(); |
||||
|
|
||||
|
function showForm(data) { |
||||
|
formRef.value.show(data); |
||||
|
} |
||||
|
|
||||
|
// ---------------------------- 单个删除 ---------------------------- |
||||
|
//确认删除 |
||||
|
function onDelete(data){ |
||||
|
Modal.confirm({ |
||||
|
title: '提示', |
||||
|
content: '确定要删除选吗?', |
||||
|
okText: '删除', |
||||
|
okType: 'danger', |
||||
|
onOk() { |
||||
|
requestDelete(data); |
||||
|
}, |
||||
|
cancelText: '取消', |
||||
|
onCancel() {}, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//请求删除 |
||||
|
async function requestDelete(data){ |
||||
|
SmartLoading.show(); |
||||
|
try { |
||||
|
await firmReportsApi.delete(data.id); |
||||
|
message.success('删除成功'); |
||||
|
queryData(); |
||||
|
} catch (e) { |
||||
|
smartSentry.captureError(e); |
||||
|
} finally { |
||||
|
SmartLoading.hide(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ---------------------------- 批量删除 ---------------------------- |
||||
|
|
||||
|
// 选择表格行 |
||||
|
const selectedRowKeyList = ref([]); |
||||
|
|
||||
|
function onSelectChange(selectedRowKeys) { |
||||
|
// 限制只能选择一行,如果选择了多行,只保留最后选择的一行 |
||||
|
if (selectedRowKeys.length > 1) { |
||||
|
selectedRowKeyList.value = [selectedRowKeys[selectedRowKeys.length - 1]]; |
||||
|
} else { |
||||
|
selectedRowKeyList.value = selectedRowKeys; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 批量删除 |
||||
|
function confirmBatchDelete() { |
||||
|
Modal.confirm({ |
||||
|
title: '提示', |
||||
|
content: '确定要批量删除这些数据吗?', |
||||
|
okText: '删除', |
||||
|
okType: 'danger', |
||||
|
onOk() { |
||||
|
requestBatchDelete(); |
||||
|
}, |
||||
|
cancelText: '取消', |
||||
|
onCancel() {}, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//请求批量删除 |
||||
|
async function requestBatchDelete() { |
||||
|
try { |
||||
|
SmartLoading.show(); |
||||
|
await firmReportsApi.batchDelete(selectedRowKeyList.value); |
||||
|
message.success('删除成功'); |
||||
|
queryData(); |
||||
|
} catch (e) { |
||||
|
smartSentry.captureError(e); |
||||
|
} finally { |
||||
|
SmartLoading.hide(); |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
@ -0,0 +1,198 @@ |
|||||
|
<template> |
||||
|
<a-modal |
||||
|
v-model:visible="visible" |
||||
|
:title="noticeDetail.title || '平台协议'" |
||||
|
width="800px" |
||||
|
:maskClosable="false" |
||||
|
:keyboard="false" |
||||
|
:closable="false" |
||||
|
> |
||||
|
<a-spin :spinning="loading"> |
||||
|
<div class="agreement-content"> |
||||
|
<div v-if="noticeDetail.title" class="agreement-text"> |
||||
|
<div class="content-header"> |
||||
|
<h3>{{ noticeDetail.title }}</h3> |
||||
|
<div class="content-header-info"> |
||||
|
<span v-if="noticeDetail.author">作者:{{ noticeDetail.author }}</span> |
||||
|
<span v-if="noticeDetail.source">来源:{{ noticeDetail.source }}</span> |
||||
|
<span v-if="noticeDetail.publishTime">发布时间:{{ noticeDetail.publishTime }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="content-html" v-html="noticeDetail.contentHtml"></div> |
||||
|
<div v-if="!noticeDetail.contentHtml" class="default-content"> |
||||
|
<p>欢迎使用本系统!在开始使用前,请仔细阅读以下协议内容:</p> |
||||
|
|
||||
|
<h4>一、服务条款</h4> |
||||
|
<p>1. 您在使用本系统时,必须遵守相关法律法规和平台规定。</p> |
||||
|
<p>2. 不得利用本系统从事任何违法或不当行为。</p> |
||||
|
|
||||
|
<h4>二、隐私政策</h4> |
||||
|
<p>1. 我们将保护您的个人信息安全,仅用于系统功能使用。</p> |
||||
|
<p>2. 未经您同意,我们不会向第三方泄露您的个人信息。</p> |
||||
|
|
||||
|
<h4>三、使用规范</h4> |
||||
|
<p>1. 请妥善保管您的账号密码,避免泄露。</p> |
||||
|
<p>2. 如发现异常情况,请及时联系系统管理员。</p> |
||||
|
</div> |
||||
|
<p class="important">请仔细阅读以上协议内容,点击"同意并继续"表示您已阅读并同意本协议。</p> |
||||
|
</div> |
||||
|
<div v-else class="agreement-text"> |
||||
|
<h3>用户协议与隐私政策</h3> |
||||
|
<div class="default-content"> |
||||
|
<p>欢迎使用本系统!在开始使用前,请仔细阅读以下协议内容:</p> |
||||
|
|
||||
|
<h4>一、服务条款</h4> |
||||
|
<p>1. 您在使用本系统时,必须遵守相关法律法规和平台规定。</p> |
||||
|
<p>2. 不得利用本系统从事任何违法或不当行为。</p> |
||||
|
|
||||
|
<h4>二、隐私政策</h4> |
||||
|
<p>1. 我们将保护您的个人信息安全,仅用于系统功能使用。</p> |
||||
|
<p>2. 未经您同意,我们不会向第三方泄露您的个人信息。</p> |
||||
|
|
||||
|
<h4>三、使用规范</h4> |
||||
|
<p>1. 请妥善保管您的账号密码,避免泄露。</p> |
||||
|
<p>2. 如发现异常情况,请及时联系系统管理员。</p> |
||||
|
</div> |
||||
|
<p class="important">请仔细阅读以上协议内容,点击"同意并继续"表示您已阅读并同意本协议。</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</a-spin> |
||||
|
|
||||
|
<template #footer> |
||||
|
<a-button @click="handleCancel" size="large">不同意</a-button> |
||||
|
<a-button type="primary" @click="handleConfirm" size="large">同意并继续</a-button> |
||||
|
</template> |
||||
|
</a-modal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, onMounted, reactive } from 'vue'; |
||||
|
import { noticeApi } from '/@/api/business/oa/notice-api'; |
||||
|
import { smartSentry } from '/@/lib/smart-sentry'; |
||||
|
|
||||
|
const emit = defineEmits(['confirm', 'cancel']); |
||||
|
const visible = ref(false); |
||||
|
const loading = ref(false); |
||||
|
|
||||
|
// 公告详情数据 |
||||
|
const noticeDetail = reactive({ |
||||
|
title: '', |
||||
|
contentHtml: '', |
||||
|
author: '', |
||||
|
source: '', |
||||
|
publishTime: '' |
||||
|
}); |
||||
|
|
||||
|
onMounted(() => { |
||||
|
visible.value = true; |
||||
|
// 获取首页第一条公告的详情 |
||||
|
getFirstNoticeDetail(); |
||||
|
}); |
||||
|
|
||||
|
// 获取首页第一条公告的详情 |
||||
|
async function getFirstNoticeDetail() { |
||||
|
try { |
||||
|
loading.value = true; |
||||
|
// 查询首页公告列表(公告类型ID为1) |
||||
|
const queryForm = { |
||||
|
noticeTypeId: 1, |
||||
|
pageNum: 1, |
||||
|
pageSize: 1, |
||||
|
searchCount: false, |
||||
|
}; |
||||
|
|
||||
|
const result = await noticeApi.queryEmployeeNotice(queryForm); |
||||
|
|
||||
|
if (result.data && result.data.list && result.data.list.length > 0) { |
||||
|
const firstNotice = result.data.list[0]; |
||||
|
|
||||
|
// 获取公告详情 |
||||
|
const detailResult = await noticeApi.view(firstNotice.noticeId); |
||||
|
if (detailResult.data) { |
||||
|
Object.assign(noticeDetail, detailResult.data); |
||||
|
} |
||||
|
} |
||||
|
} catch (err) { |
||||
|
smartSentry.captureError(err); |
||||
|
console.error('获取公告详情失败:', err); |
||||
|
} finally { |
||||
|
loading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const handleConfirm = () => { |
||||
|
emit('confirm'); |
||||
|
visible.value = false; |
||||
|
}; |
||||
|
|
||||
|
const handleCancel = () => { |
||||
|
emit('cancel'); |
||||
|
visible.value = false; |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.agreement-content { |
||||
|
max-height: 400px; |
||||
|
overflow-y: auto; |
||||
|
padding: 0 10px; |
||||
|
} |
||||
|
|
||||
|
.agreement-text { |
||||
|
line-height: 1.6; |
||||
|
} |
||||
|
|
||||
|
.content-header { |
||||
|
border-bottom: 1px solid #e8e8e8; |
||||
|
padding-bottom: 15px; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.content-header h3 { |
||||
|
text-align: center; |
||||
|
color: #1890ff; |
||||
|
margin-bottom: 10px; |
||||
|
font-size: 18px; |
||||
|
} |
||||
|
|
||||
|
.content-header-info { |
||||
|
text-align: center; |
||||
|
color: #666; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.content-header-info span { |
||||
|
margin: 0 10px; |
||||
|
} |
||||
|
|
||||
|
.content-html { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.content-html >>> p { |
||||
|
margin-bottom: 10px; |
||||
|
line-height: 1.6; |
||||
|
} |
||||
|
|
||||
|
.content-html >>> h4 { |
||||
|
color: #333; |
||||
|
margin: 15px 0 10px 0; |
||||
|
} |
||||
|
|
||||
|
.default-content h4 { |
||||
|
color: #333; |
||||
|
margin: 15px 0 10px 0; |
||||
|
} |
||||
|
|
||||
|
.default-content p { |
||||
|
margin-bottom: 8px; |
||||
|
color: #666; |
||||
|
} |
||||
|
|
||||
|
.important { |
||||
|
color: #ff4d4f !important; |
||||
|
font-weight: bold; |
||||
|
margin-top: 20px !important; |
||||
|
text-align: center; |
||||
|
} |
||||
|
</style> |
||||
Loading…
Reference in new issue