Browse Source

批量申报修改

master
wang 2 months ago
parent
commit
4b17b548d7
  1. BIN
      dist.zip
  2. 14
      src/api/business/cost/firm-reports-api.js
  3. 52
      src/constants/business/erp/cost-const.js
  4. 212
      src/views/business/erp/cost/firm-reports-form.vue
  5. 59
      src/views/business/erp/cost/firm-reports-list.vue
  6. 89
      src/views/business/erp/service/service-applications-list.vue
  7. 8
      src/views/business/erp/service/service-applications-report-list.vue

BIN
dist.zip

Binary file not shown.

14
src/api/business/cost/firm-reports-api.js

@ -52,6 +52,20 @@ export const firmReportsApi = {
return postRequest('/firmReports/commit', idList);
},
/**
* 查询有无填报 @author wzh
*/
query: () => {
return getRequest('/firmReports/query');
},
/**
* 查询本年度已经提交的收入 @author wzh
*/
income: () => {
return postRequest('/firmReports/income');
},
/**
* 审核 @author wzh
*/

52
src/constants/business/erp/cost-const.js

@ -1,7 +1,6 @@
/*
* 成本管理常量
*/
// 季度枚举
export const QUARTER_ENUM = {
Q1: {
@ -20,6 +19,57 @@ export const QUARTER_ENUM = {
value: 'Q4',
desc: '第四季度',
},
}
// 月份枚举
export const MONTH_ENUM = {
M1: {
value: '1月',
desc: '1月',
},
M2: {
value: '2月',
desc: '2月',
},
M3: {
value: '3月',
desc: '3月',
},
M4: {
value: '4月',
desc: '4月',
},
M5: {
value: '5月',
desc: '5月',
},
M6: {
value: '6月',
desc: '6月',
},
M7: {
value: '7月',
desc: '7月',
},
M8: {
value: '8月',
desc: '8月',
},
M9: {
value: '9月',
desc: '9月',
},
M10: {
value: '10月',
desc: '10月',
},
M11: {
value: '11月',
desc: '11月',
},
M12: {
value: '12月',
desc: '12月',
},
};
// 审核状态枚举

212
src/views/business/erp/cost/firm-reports-form.vue

@ -28,16 +28,28 @@
:max="2100"
/>
</a-form-item>
<a-form-item label="季度" name="declareQuarter">
<DictSelect
dict-code="QUARTER"
v-model:value="form.declareQuarter"
placeholder="请选择季度"
@change="onQuarterChange"
<a-form-item label="月份" name="declareMonth">
<a-select
v-model:value="form.declareMonth"
placeholder="请选择月份"
@change="onMonthChange"
style="width: 100%"
/>
>
<a-select-option v-for="month in monthOptions" :key="month.value" :value="month.value">
{{ month.label }}
</a-select-option>
</a-select>
</a-form-item>
<!-- 本年度已填报收入信息
<a-form-item v-if="!form.id" :wrapper-col="{ offset: 8 }">
<div style="background: #f5f5f5; padding: 8px 12px; border-radius: 4px; font-size: 12px;">
<div style="color: #666;">本年度已填报收入</div>
<div style="font-weight: bold; color: #1890ff; font-size: 14px;">{{ annualIncomeInfo.revenue || 0 }} 万元</div>
<div style="color: #666; margin-top: 4px;">本年度已填报总成本{{ annualIncomeInfo.totalCost || 0 }} 万元</div>
</div>
</a-form-item>-->
<a-form-item label="律所收入(万元)" name="revenue">
<a-input-number
style="width: 100%"
@ -48,6 +60,10 @@
@change="calculateCosts"
addon-after="万元"
/>
<div style="font-size: 12px; color: #666; margin-top: 4px;">
本年度已填报收入{{ annualIncomeInfo.revenue || 0 }} 万元
<span v-if="annualIncomeInfo.revenue > 0 && form.revenue">合计{{ formatNumber((annualIncomeInfo.revenue || 0) + (form.revenue || 0)) }} 万元</span>
</div>
</a-form-item>
<a-form-item label="公益活动成本(万元)" name="publicWelfareCost">
@ -116,7 +132,6 @@
import { serviceApplicationsApi } from '/@/api/business/service-applications/service-applications-api';
import { smartSentry } from '/@/lib/smart-sentry';
import { useUserStore } from '/@/store/modules/system/user';
import DictSelect from '/@/components/support/dict-select/index.vue';
// ------------------------ ------------------------
@ -135,9 +150,71 @@
//
const visibleFlag = ref(false);
//
const annualIncomeInfo = ref({
revenue: 0, //
totalCost: 0 //
});
//
const monthOptions = ref([]);
//
async function initMonthOptions() {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth() + 1; // 1-12
//
let lastMonth = currentMonth - 1;
let lastMonthYear = currentYear;
if (lastMonth === 0) {
lastMonth = 12;
lastMonthYear = currentYear - 1;
}
//
form.declareYear = lastMonthYear;
//
monthOptions.value = [
{ label: `${lastMonth}`, value: `${lastMonth}` }
];
//
form.declareMonth = `${lastMonth}`;
//
await getPublicWelfareCost();
}
//
function formatNumber(value) {
if (value === null || value === undefined) return '-';
const num = Number(value);
return isNaN(num) ? '-' : num.toFixed(2);
}
//
async function fetchAnnualIncome() {
try {
const result = await firmReportsApi.income();
if (result.data) {
annualIncomeInfo.value = {
revenue: result.data.revenue || 0,
totalCost: result.data.totalCost || 0
};
}
} catch (error) {
console.error('获取本年度已填报收入失败:', error);
annualIncomeInfo.value = { revenue: 0, totalCost: 0 };
}
}
//
async function getPublicWelfareCost() {
console.log('开始获取公益成本,部门ID:', departmentId.value, '年份:', form.declareYear, '季度:', form.declareQuarter);
console.log('开始获取公益成本,部门ID:', departmentId.value, '年份:', form.declareYear, '月份:', form.declareMonth);
if (!departmentId.value) {
message.warning('无法获取机构信息,请重新登录');
@ -150,20 +227,28 @@
return;
}
if (!form.declareQuarter) {
console.log('季度未选择,跳过API调用');
if (!form.declareMonth) {
console.log('月份未选择,跳过API调用');
return;
}
try {
// Q1 -> 1, Q2 -> 2, Q3 -> 3, Q4 -> 4
const quarterNumber = form.declareQuarter.replace('Q', '');
// "1" -> 1, "2" -> 2, ..., "12" -> 12
let monthNumber;
if (typeof form.declareMonth === 'string') {
const monthMatch = form.declareMonth.match(/^(\d+)/);
if (monthMatch && monthMatch[1]) {
monthNumber = parseInt(monthMatch[1]);
}
} else if (typeof form.declareMonth === 'number') {
monthNumber = form.declareMonth;
}
// ID
// ID
const queryForm = {
firmId: departmentId.value,
year: form.declareYear, // year
quarter: parseInt(quarterNumber) //
month: monthNumber //
};
console.log('调用接口: /serviceApplications/statistics/cost, 参数:', queryForm);
@ -198,20 +283,23 @@
console.log('编辑模式,使用现有数据');
Object.assign(form, rowData);
// declareQuarter
if (form.declareQuarter && typeof form.declareQuarter === 'number') {
// declareMonth
if (form.declareMonth && typeof form.declareMonth === 'number') {
//
form.declareQuarter = 'Q' + form.declareQuarter;
} else if (form.declareQuarter && form.declareQuarter.includes('(')) {
// " (Q1)"
const match = form.declareQuarter.match(/\(([^)]+)\)/);
form.declareMonth = form.declareMonth + '月';
} else if (form.declareMonth && form.declareMonth.includes('(')) {
// "1 (1)"
const match = form.declareMonth.match(/\(([^)]+)\)/);
if (match && match[1]) {
form.declareQuarter = match[1]; // Q1
form.declareMonth = match[1] + '月'; // ""
}
}
} else {
console.log('新建模式,等待用户选择季度后获取公益成本');
//
console.log('新建模式,等待用户选择月份后获取公益成本');
//
initMonthOptions();
//
fetchAnnualIncome();
}
visibleFlag.value = true;
@ -236,7 +324,7 @@
id: undefined,
firmId: undefined, // IDID
declareYear: new Date().getFullYear(), //
declareQuarter: undefined, // ID (1,2,3,4)
declareMonth: undefined, // ID (1,2,3,4,5,6,7,8,9,10,11,12)
revenue: undefined, //
//totalCost: 0, //
publicWelfareCost: undefined, //
@ -246,7 +334,7 @@
let form = reactive({ ...formDefault });
const rules = {
declareQuarter: [{ required: true, message: '请选择季度' }],
declareMonth: [{ required: true, message: '请选择月份' }],
declareYear: [{ required: true, message: '请输入报表年份' }],
revenue: [{ required: true, message: '请输入律所收入' }],
publicWelfareCost: [{ required: true, message: '系统正在计算公益成本,请稍后' }],
@ -257,12 +345,12 @@
const showCostWarning = ref(false);
const costRatio = ref(0); //
//
function onQuarterChange() {
console.log('季度选择变化:', form.declareQuarter);
//
function onMonthChange() {
console.log('月份选择变化:', form.declareMonth);
//
if (form.declareQuarter) {
//
if (form.declareMonth) {
getPublicWelfareCost();
}
@ -272,12 +360,21 @@
// /
function calculateCosts() {
const revenue = parseFloat(form.revenue) || 0;
const publicWelfareCost = parseFloat(form.publicWelfareCost) || 0;
// NaN
const currentRevenue = safeParseFloat(form.revenue);
const publicWelfareCost = safeParseFloat(form.publicWelfareCost);
const annualRevenue = safeParseFloat(annualIncomeInfo.value.revenue);
const annualTotalCost = safeParseFloat(annualIncomeInfo.value.totalCost);
//
if (revenue > 0) {
costRatio.value = (publicWelfareCost / revenue) * 100;
// +
const totalRevenue = currentRevenue + annualRevenue;
// +
const totalCost = publicWelfareCost + annualTotalCost;
//
if (totalRevenue > 0) {
costRatio.value = (totalCost / totalRevenue) * 100;
// 20%
if (costRatio.value >= 20) {
@ -285,21 +382,25 @@
// 25%25%
if (costRatio.value > 25) {
const maxAllowedCost = revenue * 0.25; // 25%
calculatedPublicWelfareCost.value = maxAllowedCost.toFixed(2);
const maxAllowedAnnualCost = totalRevenue * 0.25; //
const remainingAllowedCost = Math.max(0, maxAllowedAnnualCost - annualTotalCost);
//
calculatedPublicWelfareCost.value = Math.min(publicWelfareCost, remainingAllowedCost).toFixed(2);
// /使
const ratio = (maxAllowedCost / revenue) * 100;
const actualAnnualCost = annualTotalCost + parseFloat(calculatedPublicWelfareCost.value);
const ratio = (actualAnnualCost / totalRevenue) * 100;
form.costIncomeRatio = ratio.toFixed(2);
} else {
// 20%25%使
calculatedPublicWelfareCost.value = publicWelfareCost;
calculatedPublicWelfareCost.value = publicWelfareCost.toFixed(2);
form.costIncomeRatio = costRatio.value.toFixed(2);
}
} else {
// 20%
showCostWarning.value = false;
calculatedPublicWelfareCost.value = publicWelfareCost;
calculatedPublicWelfareCost.value = publicWelfareCost.toFixed(2);
form.costIncomeRatio = costRatio.value.toFixed(2);
}
} else {
@ -307,18 +408,24 @@
showCostWarning.value = false;
costRatio.value = 0;
form.costIncomeRatio = '0.00';
calculatedPublicWelfareCost.value = publicWelfareCost;
calculatedPublicWelfareCost.value = publicWelfareCost.toFixed(2);
}
//
form.totalCost = showCostWarning.value ? parseFloat(calculatedPublicWelfareCost.value) : publicWelfareCost;
}
//
const totalCost = showCostWarning.value ? parseFloat(calculatedPublicWelfareCost.value) : publicWelfareCost;
form.totalCost = totalCost;
//
function safeParseFloat(value) {
if (value === null || value === undefined || value === '') return 0;
const num = parseFloat(value);
return isNaN(num) ? 0 : num;
}
// 稿
async function saveAsDraft() {
try {
await formRef.value.validateFields(['declareQuarter', 'declareYear', 'revenue', 'publicWelfareCost']);
await formRef.value.validateFields(['declareMonth', 'declareYear', 'revenue', 'publicWelfareCost']);
form.approvalStatus = '0'; // 稿
await save();
} catch (err) {
@ -348,6 +455,19 @@
// 使
const saveData = { ...form };
// "1" -> 1, "2" -> 2
if (saveData.declareMonth && typeof saveData.declareMonth === 'string') {
const monthMatch = saveData.declareMonth.match(/^(\d+)/);
if (monthMatch && monthMatch[1]) {
saveData.declareMonth = parseInt(monthMatch[1]);
}
}
//
if (saveData.declareYear) {
saveData.declareYear = parseInt(saveData.declareYear);
}
if (showCostWarning.value) {
// 使
saveData.publicWelfareCost = parseFloat(calculatedPublicWelfareCost.value);

59
src/views/business/erp/cost/firm-reports-list.vue

@ -13,16 +13,19 @@
<a-form-item label="律师事务所" class="smart-query-form-item" v-if="isCeo">
<DepartmentTreeSelect style="width: 250px" v-model:value="queryForm.firmId" placeholder="请选择律师事务所" />
</a-form-item>
<a-form-item label="报表年份" class="smart-query-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="请选择季度"
<a-form-item label="月份" class="smart-query-form-item">
<a-select
v-model:value="queryForm.declareMonth"
placeholder="请选择月份"
style="width: 100px"
/>
>
<a-select-option v-for="month in monthOptions" :key="month.value" :value="month.value">
{{ month.label }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="smart-query-form-item" :style="{ marginLeft: '120px' }">
<a-button type="primary" @click="onSearch">
@ -46,12 +49,12 @@
<!---------- 表格操作行 begin ----------->
<a-row class="smart-table-btn-block">
<div class="smart-table-operate-block">
<a-button v-if="isCto" @click="showForm" type="primary" >
<!--<a-button v-if="isCeo" @click="showForm" type="primary" >
<template #icon>
<PlusOutlined />
</template>
新建
</a-button>
</a-button>-->
<a-button v-if="isCto" @click="confirmBatchDelete" type="primary" danger :disabled="selectedRowKeyList.length == 0">
<template #icon>
<DeleteOutlined />
@ -121,7 +124,6 @@
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';
import { loginApi } from '/@/api/system/login-api';
// ---------------------------- ----------------------------
@ -157,13 +159,13 @@
ellipsis: true,
},
{
title: '报表年份',
title: '年份',
dataIndex: 'declareYear',
ellipsis: true,
},
{
title: '报表季度',
dataIndex: 'declareQuarter',
title: '月份',
dataIndex: 'declareMonth',
ellipsis: true,
},
{
@ -223,8 +225,24 @@
pageSize: 10,
firmId: undefined, // ID
declareYear: undefined, //
declareQuarter: undefined, //
declareMonth: undefined, //
};
//
const monthOptions = ref([
{ label: '1月', value: '1月' },
{ label: '2月', value: '2月' },
{ label: '3月', value: '3月' },
{ label: '4月', value: '4月' },
{ label: '5月', value: '5月' },
{ label: '6月', value: '6月' },
{ label: '7月', value: '7月' },
{ label: '8月', value: '8月' },
{ label: '9月', value: '9月' },
{ label: '10月', value: '10月' },
{ label: '11月', value: '11月' },
{ label: '12月', value: '12月' }
]);
// form
const queryForm = reactive({ ...queryFormState });
// loading
@ -252,7 +270,18 @@
async function queryData() {
tableLoading.value = true;
try {
let queryResult = await firmReportsApi.queryPage(queryForm);
//
const queryParams = { ...queryForm };
// "2" -> 2
if (queryParams.declareMonth && typeof queryParams.declareMonth === 'string') {
const monthMatch = queryParams.declareMonth.match(/^(\d+)/);
if (monthMatch && monthMatch[1]) {
queryParams.declareMonth = parseInt(monthMatch[1]);
}
}
let queryResult = await firmReportsApi.queryPage(queryParams);
tableData.value = queryResult.data.list;
total.value = queryResult.data.total;
} catch (e) {

89
src/views/business/erp/service/service-applications-list.vue

@ -57,7 +57,7 @@
</a-select>
</a-form-item>
<a-form-item label="执业机构审核时间" v-if="isCtoRole || isFirmRole" class="smart-query-form-item">
<a-range-picker style="width: 240px" v-model:value="queryForm.firmAuditTimeRange" placeholder="" />
<a-range-picker style="width: 240px" v-model:value="queryForm.firmAuditTimeRange" :placeholder="['开始时间', '结束时间']" />
</a-form-item>
<a-form-item class="smart-query-form-item smart-margin-left10">
<a-button v-privilege="'serviceApplications:query'" type="primary" @click="onSearch">
@ -90,13 +90,13 @@
新建申报
</a-button>-->
<!-- 批量提交按钮非CEO角色显示 -->
<!-- 批量提交按钮非CEO角色显示
<a-button v-if="!isCeo" @click="batchSubmit" type="primary" :disabled="selectedRowKeyList.length == 0">
<template #icon>
<SendOutlined />
</template>
批量提交
</a-button>
</a-button>-->
<!-- 批量审核按钮不是user角色显示 -->
<a-button
@ -259,7 +259,8 @@
/>
</div>
<ServiceApplicationsForm ref="formRef" @reloadList="queryData"/>
<ServiceApplicationsForm ref="formRef" @reloadList="queryData" />
<FirmReportsForm ref="costReportFormRef" @reloadList="queryData" />
<AgreementModal ref="agreementModalRef" @confirm="handleAgreementConfirm" />
<!-- 导入弹窗 -->
@ -309,10 +310,12 @@ import TableOperator from '/@/components/support/table-operator/index.vue';
import ServiceApplicationsForm from './service-applications-form.vue';
import DepartmentTreeSelect from '/@/components/system/department-tree-select/index.vue';
import PositionSelect from '/@/components/system/position-select/index.vue';
import FirmReportsForm from '/@/views/business/erp/cost/firm-reports-form.vue';
import { employeeApi } from '/@/api/system/employee-api';
import { REVIEW_ENUM, SERVICEC_REVIEW_ENUM} from '/@/constants/system/review-const';
import { PlusOutlined, DeleteOutlined, SendOutlined, ImportOutlined, ExportOutlined, DownloadOutlined, UploadOutlined, CheckCircleOutlined } from '@ant-design/icons-vue';
import { loginApi } from '/@/api/system/login-api';
import { firmReportsApi } from '/@/api/business/cost/firm-reports-api';
import AgreementModal from '/@/views/system/home/components/agreement-modal.vue';
// ---------------------------- ----------------------------
@ -357,6 +360,7 @@ import AgreementModal from '/@/views/system/home/components/agreement-modal.vue'
dataIndex: 'beneficiaryCount',
ellipsis: true,
},
{
title: '组织单位名称',
dataIndex: 'organizerName',
@ -372,6 +376,12 @@ import AgreementModal from '/@/views/system/home/components/agreement-modal.vue'
dataIndex: 'organizerPhone',
ellipsis: true,
},
{
title: '提交时间',
dataIndex: 'reportTime',
ellipsis: true,
width: 150,
},
{
title: '执业机构审核状态',
dataIndex: 'firmAuditStatus',
@ -638,7 +648,7 @@ import AgreementModal from '/@/views/system/home/components/agreement-modal.vue'
}
//
function batchReport() {
async function batchReport() {
if (selectedRowKeyList.value.length === 0) {
message.warning('请选择要上报的记录');
return;
@ -650,13 +660,33 @@ import AgreementModal from '/@/views/system/home/components/agreement-modal.vue'
return;
}
//
if (loginInfo.value && loginInfo.value.lawFirmAgreementSignFlag === true) {
//
if (loginInfo.value.costVisibleFlag === true) {
try {
const costPermissionResult = await firmReportsApi.query();
if (costPermissionResult.data === false) {
// false
message.warning('您需要先填报和提交律所收入,才能进行服务上报。');
//
showCostReportForm();
return;
}
} catch (error) {
console.error('检查成本权限失败:', error);
}
}
//
}
//
const canReportRecords = tableData.value.filter(record =>
selectedRowKeyList.value.includes(record.applicationId) && canReportRecord(record)
);
if (canReportRecords.length === 0) {
message.warning('选中的记录不符合上报条件');
message.warning('选中的记录不符合上报条件,请勿提交其它月份数据');
return;
}
@ -674,8 +704,46 @@ import AgreementModal from '/@/views/system/home/components/agreement-modal.vue'
function canReportRecord(record) {
// 3
// 0
return record.firmAuditStatus === 3 &&
const isAuditPassed = record.firmAuditStatus === 3 &&
record.associationAuditStatus === 0;
//
const hasCostPermission = loginInfo.value && loginInfo.value.costVisibleFlag === true;
if (hasCostPermission) {
//
const isLastMonthData = isLastMonthRecord(record);
return isAuditPassed && isLastMonthData;
} else {
//
return isAuditPassed;
}
}
//
function isLastMonthRecord(record) {
if (!record.reportTime) return false;
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth() + 1;
//
let lastMonth = currentMonth - 1;
let lastMonthYear = currentYear;
if (lastMonth === 0) {
lastMonth = 12;
lastMonthYear = currentYear - 1;
}
//
const reportDate = new Date(record.reportTime);
const reportYear = reportDate.getFullYear();
const reportMonth = reportDate.getMonth() + 1;
//
return reportYear === lastMonthYear && reportMonth === lastMonth;
}
//
@ -839,6 +907,7 @@ onMounted(async () => {
// ---------------------------- / ----------------------------
const formRef = ref();
const costReportFormRef = ref();
function showForm(data) {
//
@ -851,6 +920,12 @@ onMounted(async () => {
}
}
// ---------------------------- ----------------------------
function showCostReportForm() {
//
costReportFormRef.value.show();
}
// ---------------------------- ----------------------------
async function showDetail(record) {
try {

8
src/views/business/erp/service/service-applications-report-list.vue

@ -33,7 +33,7 @@
</a-form-item>
<a-form-item label="执业机构审核时间" v-if="isCtoRole || isFirmRole" class="smart-query-form-item">
<a-range-picker style="width: 240px" v-model:value="queryForm.firmAuditTimeRange" placeholder="" />
<a-range-picker style="width: 240px" v-model:value="queryForm.firmAuditTimeRange" :placeholder="['开始时间', '结束时间']" />
</a-form-item>
<a-form-item class="smart-query-form-item smart-margin-left10">
<a-button type="primary" @click="onSearch">
@ -313,6 +313,12 @@ import AgreementModal from '/@/views/system/home/components/agreement-modal.vue'
dataIndex: 'organizerPhone',
ellipsis: true,
},
{
title: '提交时间',
dataIndex: 'reportTime',
ellipsis: true,
width: 150,
},
{
title: '执业机构审核状态',
dataIndex: 'firmAuditStatus',

Loading…
Cancel
Save