律师系统前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

622 lines
20 KiB

4 months ago
<!--
* 服务申报表
*
* @Author: wzh
* @Date: 2025-12-20 14:44:06
* @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-select
v-model:value="queryForm.userId"
style="width: 150px"
placeholder="请选择律师"
:showSearch="true"
:allowClear="true"
@focus="loadAllEmployees"
>
<a-select-option v-for="item in employeeList" :key="item.employeeId" :value="item.employeeId">
{{ item.actualName }}
<template v-if="item.departmentName"> {{ item.departmentName }} </template>
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="服务开始时间" class="smart-query-form-item">
<a-date-picker style="width: 150px" v-model:value="queryForm.serviceStart" placeholder="开始时间" />
</a-form-item>
<a-form-item label="服务结束时间" class="smart-query-form-item">
<a-date-picker style="width: 150px" v-model:value="queryForm.serviceEnd" placeholder="结束时间" />
</a-form-item>
<a-form-item label="组织单位名称" class="smart-query-form-item">
<a-input style="width: 150px" v-model:value="queryForm.organizerName" placeholder="组织单位名称" />
</a-form-item>
<a-form-item label="负责人姓名" class="smart-query-form-item">
<a-input style="width: 150px" v-model:value="queryForm.managerName" placeholder="负责人姓名" />
</a-form-item>
<a-form-item class="smart-query-form-item smart-margin-left10">
<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="batchSubmit" type="primary" :disabled="selectedRowKeyList.length == 0">
<template #icon>
<SendOutlined />
</template>
批量提交
</a-button>
<a-button @click="confirmBatchDelete" type="primary" danger :disabled="selectedRowKeyList.length == 0">
<template #icon>
<DeleteOutlined />
</template>
批量删除
</a-button>
<a-button @click="showImportModal" type="primary">
<template #icon>
<ImportOutlined />
</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="applicationId"
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">
4 months ago
<a-button v-if="record.firmAuditStatus === 0 || record.firmAuditStatus === 4" @click="showForm(record)" type="link">编辑</a-button>
4 months ago
<a-button v-if="record.firmAuditStatus === 0" @click="onSubmit(record)" type="link">提交</a-button>
4 months ago
<a-button v-if="record.firmAuditStatus === 1 || record.firmAuditStatus === 2" @click="showAuditModal(record)" type="link">审核</a-button>
4 months ago
<a-button @click="onDelete(record)" danger type="link">删除</a-button>
</div>
</template>
</template>
</a-table>
<!---------- 表格 end ----------->
4 months ago
<!---------- 审核弹框 begin ----------->
<a-modal
v-model:visible="auditModalVisible"
title="服务申报审核"
:confirm-loading="auditLoading"
@ok="handleAudit"
@cancel="handleAuditCancel"
width="400px"
>
<div style="text-align: center; padding: 20px 0;">
<p style="margin-bottom: 20px; font-size: 16px;">请选择审核结果</p>
<a-radio-group v-model:value="auditForm.auditResult" size="large">
<a-radio :value="3" style="margin-right: 30px;">
<span style="font-size: 16px;">同意</span>
</a-radio>
<a-radio :value="4">
<span style="font-size: 16px;">拒绝</span>
</a-radio>
</a-radio-group>
</div>
</a-modal>
<!---------- 审核弹框 end ----------->
<div class="smart-query-table-page">
4 months ago
<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>
<ServiceApplicationsForm ref="formRef" @reloadList="queryData"/>
<!-- 导入弹窗 -->
<a-modal v-model:open="importModalShowFlag" title="导入" @onCancel="hideImportModal" @ok="hideImportModal">
<div style="text-align: center; width: 400px; margin: 0 auto">
<a-button @click="downloadExcel">
<DownloadOutlined />
第一步下载模板
</a-button>
<br />
<br />
<a-upload
v-model:fileList="fileList"
name="file"
:multiple="false"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
accept=".xls,.xlsx"
:before-upload="beforeUpload"
@remove="handleRemove"
>
<a-button>
<UploadOutlined />
第二步选择文件
</a-button>
</a-upload>
<br />
<a-button @click="onImport">
<ImportOutlined />
第三步开始导入
</a-button>
</div>
</a-modal>
</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 { serviceApplicationsApi } from '/@/api/business/service-applications/service-applications-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 ServiceApplicationsForm from './service-applications-form.vue';
import DepartmentTreeSelect from '/@/components/system/department-tree-select/index.vue';
import { employeeApi } from '/@/api/system/employee-api';
import { REVIEW_ENUM } from '/@/constants/system/review-const';
import { PlusOutlined, DeleteOutlined, SendOutlined, ImportOutlined, ExportOutlined, DownloadOutlined, UploadOutlined } from '@ant-design/icons-vue';
// ---------------------------- 表格列 ----------------------------
const columns = ref([
{
title: '执业机构',
dataIndex: 'departmentName',
ellipsis: true,
},
{
title: '律师名称',
dataIndex: 'userName',
ellipsis: true,
},
{
title: '服务开始时间',
dataIndex: 'serviceStart',
ellipsis: true,
},
{
title: '服务结束时间',
dataIndex: 'serviceEnd',
ellipsis: true,
},
{
title: '服务时长(小时)',
dataIndex: 'serviceDuration',
ellipsis: true,
},
{
title: '受益人数',
dataIndex: 'beneficiaryCount',
ellipsis: true,
},
{
title: '组织单位名称',
dataIndex: 'organizerName',
ellipsis: true,
},
{
title: '负责人姓名',
dataIndex: 'organizerContact',
ellipsis: true,
},
{
title: '联系方式',
dataIndex: 'organizerPhone',
ellipsis: true,
},
{
title: '工作量换算得分',
dataIndex: 'workloadScore',
ellipsis: true,
},
{
title: '执业机构审核状态',
dataIndex: 'firmAuditStatus',
ellipsis: true,
customRender: ({ text }) => {
const status = Object.values(REVIEW_ENUM).find(item => item.value === text);
return status ? status.desc : text;
},
},
{
title: '执业机构审核人',
dataIndex: 'firmAuditUser',
ellipsis: true,
},
{
title: '执业机构审核时间',
dataIndex: 'firmAuditTime',
ellipsis: true,
},
{
title: '操作',
dataIndex: 'action',
fixed: 'right',
width: 150,
},
]);
// ---------------------------- 查询数据表单和方法 ----------------------------
const queryFormState = {
pageNum: 1,
pageSize: 10,
firmId: undefined, // 执业机构ID
userId: undefined, // 律师ID
serviceStart: undefined, // 服务开始时间
serviceEnd: undefined, // 服务结束时间
organizerName: undefined, // 组织单位名称
managerName: undefined, // 负责人姓名
};
// 查询表单form
const queryForm = reactive({ ...queryFormState });
// 表格加载loading
const tableLoading = ref(false);
// 表格数据
const tableData = ref([]);
4 months ago
4 months ago
// 员工列表数据
const employeeList = ref([]);
4 months ago
// 审核相关状态
const auditModalVisible = ref(false);
const auditLoading = ref(false);
const currentAuditRecord = ref(null);
const auditForm = reactive({
auditResult: 3, // 默认同意
auditRemark: ''
});
4 months ago
// 加载所有员工数据
async function loadAllEmployees() {
try {
if (employeeList.value.length === 0) {
let resp = await employeeApi.queryAll();
employeeList.value = resp.data;
}
} catch (e) {
console.error('加载员工数据失败:', e);
}
}
// 总数
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 serviceApplicationsApi.queryPage(queryForm);
tableData.value = queryResult.data.list;
total.value = queryResult.data.total;
} catch (e) {
smartSentry.captureError(e);
} finally {
tableLoading.value = false;
}
}
onMounted(queryData);
// ---------------------------- 添加/修改 ----------------------------
const formRef = ref();
function showForm(data) {
formRef.value.show(data);
}
// ---------------------------- 单个提交 ----------------------------
//确认提交
function onSubmit(data){
Modal.confirm({
title: '提示',
content: '确定要提交该申报记录吗?',
okText: '提交',
okType: 'primary',
onOk() {
requestSubmit(data);
},
cancelText: '取消',
onCancel() {},
});
}
//请求提交
async function requestSubmit(data){
try {
SmartLoading.show();
await serviceApplicationsApi.submit(data.applicationId);
message.success('提交成功');
queryData();
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
// ---------------------------- 单个删除 ----------------------------
//确认删除
function onDelete(data){
Modal.confirm({
title: '提示',
content: '确定要删除选吗?',
okText: '删除',
okType: 'danger',
onOk() {
requestDelete(data);
},
cancelText: '取消',
onCancel() {},
});
}
//请求删除
4 months ago
async function requestDelete(data){
SmartLoading.show();
try {
let deleteForm = {
goodsIdList: selectedRowKeyList.value,
};
await serviceApplicationsApi.delete(data.applicationId);
message.success('删除成功');
queryData();
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
// 显示审核弹框
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 = {
applicationId: currentAuditRecord.value.applicationId,
firmAuditStatus: auditForm.auditResult
};
4 months ago
try {
4 months ago
await serviceApplicationsApi.review(auditData);
message.success('审核成功');
auditModalVisible.value = false;
4 months ago
queryData();
4 months ago
} catch (error) {
message.error('审核失败');
console.error('审核失败:', error);
4 months ago
} finally {
4 months ago
auditLoading.value = false;
4 months ago
}
}
4 months ago
// 取消审核
function handleAuditCancel() {
auditModalVisible.value = false;
currentAuditRecord.value = null;
auditForm.auditResult = 3;
auditForm.auditRemark = '';
}
4 months ago
// ---------------------------- 批量删除 ----------------------------
// 选择表格行
const selectedRowKeyList = ref([]);
function onSelectChange(selectedRowKeys) {
selectedRowKeyList.value = selectedRowKeys;
}
// 批量删除
function confirmBatchDelete() {
Modal.confirm({
title: '提示',
content: '确定要批量删除这些数据吗?',
okText: '删除',
okType: 'danger',
onOk() {
requestBatchDelete();
},
cancelText: '取消',
onCancel() {},
});
}
//请求批量删除
async function requestBatchDelete() {
try {
SmartLoading.show();
await serviceApplicationsApi.batchDelete(selectedRowKeyList.value);
message.success('删除成功');
queryData();
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
// ------------------------------- 导出和导入 ---------------------------------
// 导入弹窗
const importModalShowFlag = ref(false);
const fileList = ref([]);
// 显示导入
function showImportModal() {
fileList.value = [];
importModalShowFlag.value = true;
}
// 关闭 导入
function hideImportModal() {
importModalShowFlag.value = false;
}
function handleChange() {}
function handleDrop() {}
function handleRemove(file) {
const index = fileList.value.indexOf(file);
const newFileList = fileList.value.slice();
newFileList.splice(index, 1);
fileList.value = newFileList;
}
function beforeUpload(file) {
fileList.value = [...(fileList.value || []), file];
return false;
}
function downloadExcel() {
serviceApplicationsApi.downloadTemplate();
}
async function onImport() {
const formData = new FormData();
fileList.value.forEach((file) => {
formData.append('file', file.originFileObj);
});
SmartLoading.show();
try {
let res = await serviceApplicationsApi.importServiceApplications(formData);
message.success(res.msg);
hideImportModal();
queryData();
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
async function onExport() {
await serviceApplicationsApi.exportServiceApplications();
}
// ---------------------------- 批量提交 ----------------------------
// 批量提交
function batchSubmit() {
// 检查所有选中的记录是否都是未提交状态
const selectedRecords = tableData.value.filter(record =>
selectedRowKeyList.value.includes(record.applicationId)
);
const nonSubmitRecords = selectedRecords.filter(record => record.firmAuditStatus !== 0);
if (nonSubmitRecords.length > 0) {
message.warning(`选中的记录中有 ${nonSubmitRecords.length} 条不是未提交状态,无法批量提交`);
return;
}
Modal.confirm({
title: '提示',
content: `确定要批量提交选中的 ${selectedRowKeyList.value.length} 条申报记录吗?`,
okText: '提交',
okType: 'primary',
onOk() {
requestBatchSubmit();
},
cancelText: '取消',
onCancel() {},
});
}
// 请求批量提交
async function requestBatchSubmit() {
try {
SmartLoading.show();
await serviceApplicationsApi.batchSubmit(selectedRowKeyList.value);
message.success('批量提交成功');
queryData();
} catch (e) {
smartSentry.captureError(e);
} finally {
SmartLoading.hide();
}
}
//提交
</script>