新增质效评价页面
This commit is contained in:
parent
9ecfbd3b19
commit
017818ee07
@ -0,0 +1,36 @@
|
||||
import { request } from '@/service/request';
|
||||
|
||||
/** 获取质效评价数据列表 */
|
||||
export function fetchGetPerformanceEvaluationList (params?: Api.Evaluation.PerformanceEvaluationSearchParams) {
|
||||
return request<Api.Evaluation.PerformanceEvaluationList>({
|
||||
url: '/evaluation/performanceEvaluation/list',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 新增质效评价数据 */
|
||||
export function fetchCreatePerformanceEvaluation (data: Api.Evaluation.PerformanceEvaluationOperateParams) {
|
||||
return request<boolean>({
|
||||
url: '/evaluation/performanceEvaluation',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改质效评价数据 */
|
||||
export function fetchUpdatePerformanceEvaluation (data: Api.Evaluation.PerformanceEvaluationOperateParams) {
|
||||
return request<boolean>({
|
||||
url: '/evaluation/performanceEvaluation',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除质效评价数据 */
|
||||
export function fetchBatchDeletePerformanceEvaluation (ids: CommonType.IdType[]) {
|
||||
return request<boolean>({
|
||||
url: `/evaluation/performanceEvaluation/${ids.join(',')}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
110
cds-fontend-2025.V1/src/typings/api/evaluation.performance-evaluation.api.d.ts
vendored
Normal file
110
cds-fontend-2025.V1/src/typings/api/evaluation.performance-evaluation.api.d.ts
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
|
||||
/**
|
||||
* Namespace Api
|
||||
*
|
||||
* All backend api type
|
||||
*/
|
||||
declare namespace Api {
|
||||
|
||||
/**
|
||||
* namespace Evaluation
|
||||
*
|
||||
* backend api module: "Evaluation"
|
||||
*/
|
||||
namespace Evaluation {
|
||||
/** performance evaluation */
|
||||
type PerformanceEvaluation = Common.CommonRecord<{
|
||||
/** 主键 */
|
||||
id: CommonType.IdType;
|
||||
/** 存款金额日均 */
|
||||
depositDailyAvg: number;
|
||||
/** 较上月 */
|
||||
depositMonthlyChange: string;
|
||||
/** 较期初 */
|
||||
depositInitialChange: string;
|
||||
/** 考核结果 */
|
||||
depositAssessmentResult: string;
|
||||
/** 人均持有产品 */
|
||||
productPerCapita: string;
|
||||
/** 较上月 */
|
||||
productMonthlyChange: string;
|
||||
/** 较年初 */
|
||||
productYearlyChange: string;
|
||||
/** 考核结果 */
|
||||
productAssessmentResult: string;
|
||||
/** 智e通月活跃客户数 */
|
||||
mobileActiveCustomers: string;
|
||||
/** 较上月 */
|
||||
mobileMonthlyChange: string;
|
||||
/** 考核结果 */
|
||||
mobileAssessmentResult: string;
|
||||
/** 银行卡月活跃客户数 */
|
||||
cardActiveCustomers: string;
|
||||
/** 较上月 */
|
||||
cardMonthlyChange: string;
|
||||
/** 考核结果 */
|
||||
cardAssessmentResult: string;
|
||||
/** 季度对接率 */
|
||||
quarterlyContactRate: number;
|
||||
/** 考核结果 */
|
||||
contactAssessmentResult: string;
|
||||
/** 计价月份 */
|
||||
importTime: string;
|
||||
/** 租户编号 */
|
||||
tenantId: CommonType.IdType;
|
||||
}>;
|
||||
|
||||
/** performance evaluation search params */
|
||||
type PerformanceEvaluationSearchParams = CommonType.RecordNullable<
|
||||
Pick<
|
||||
Api.Evaluation.PerformanceEvaluation,
|
||||
| 'depositDailyAvg'
|
||||
| 'depositMonthlyChange'
|
||||
| 'depositInitialChange'
|
||||
| 'depositAssessmentResult'
|
||||
| 'productPerCapita'
|
||||
| 'productMonthlyChange'
|
||||
| 'productYearlyChange'
|
||||
| 'productAssessmentResult'
|
||||
| 'mobileActiveCustomers'
|
||||
| 'mobileMonthlyChange'
|
||||
| 'mobileAssessmentResult'
|
||||
| 'cardActiveCustomers'
|
||||
| 'cardMonthlyChange'
|
||||
| 'cardAssessmentResult'
|
||||
| 'quarterlyContactRate'
|
||||
| 'contactAssessmentResult'
|
||||
| 'importTime'
|
||||
> &
|
||||
Api.Common.CommonSearchParams
|
||||
>;
|
||||
|
||||
/** performance evaluation operate params */
|
||||
type PerformanceEvaluationOperateParams = CommonType.RecordNullable<
|
||||
Pick<
|
||||
Api.Evaluation.PerformanceEvaluation,
|
||||
| 'id'
|
||||
| 'depositDailyAvg'
|
||||
| 'depositMonthlyChange'
|
||||
| 'depositInitialChange'
|
||||
| 'depositAssessmentResult'
|
||||
| 'productPerCapita'
|
||||
| 'productMonthlyChange'
|
||||
| 'productYearlyChange'
|
||||
| 'productAssessmentResult'
|
||||
| 'mobileActiveCustomers'
|
||||
| 'mobileMonthlyChange'
|
||||
| 'mobileAssessmentResult'
|
||||
| 'cardActiveCustomers'
|
||||
| 'cardMonthlyChange'
|
||||
| 'cardAssessmentResult'
|
||||
| 'quarterlyContactRate'
|
||||
| 'contactAssessmentResult'
|
||||
| 'importTime'
|
||||
>
|
||||
>;
|
||||
|
||||
/** performance evaluation list */
|
||||
type PerformanceEvaluationList = Api.Common.PaginatingQueryRecord<PerformanceEvaluation>;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,548 @@
|
||||
<script setup lang="tsx">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { NDivider } from 'naive-ui';
|
||||
import {
|
||||
fetchBatchDeletePerformanceEvaluation,
|
||||
fetchGetPerformanceEvaluationList
|
||||
} from '@/service/api/evaluation/performance-evaluation';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useAuth } from '@/hooks/business/auth';
|
||||
import { useDownload } from '@/hooks/business/download';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import ButtonIcon from '@/components/custom/button-icon.vue';
|
||||
import PerformanceEvaluationOperateDrawer from './modules/performance-evaluation-operate-drawer.vue';
|
||||
import PerformanceEvaluationSearch from './modules/performance-evaluation-search.vue';
|
||||
import PerformanceEvaluationImportModal from './modules/performance-evaluation-import-modal.vue';
|
||||
import { useBoolean } from '~/packages/hooks';
|
||||
defineOptions({
|
||||
name: 'PerformanceEvaluationList'
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
const { download } = useDownload();
|
||||
const { hasAuth } = useAuth();
|
||||
const { bool: importVisible, setTrue: openImportModal } = useBoolean();
|
||||
|
||||
const {
|
||||
columns,
|
||||
columnChecks,
|
||||
data,
|
||||
getData,
|
||||
getDataByPage,
|
||||
loading,
|
||||
mobilePagination,
|
||||
searchParams,
|
||||
resetSearchParams
|
||||
} = useTable({
|
||||
apiFn: fetchGetPerformanceEvaluationList,
|
||||
apiParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
||||
depositDailyAvg: null,
|
||||
depositMonthlyChange: null,
|
||||
depositInitialChange: null,
|
||||
depositAssessmentResult: null,
|
||||
productPerCapita: null,
|
||||
productMonthlyChange: null,
|
||||
productYearlyChange: null,
|
||||
productAssessmentResult: null,
|
||||
mobileActiveCustomers: null,
|
||||
mobileMonthlyChange: null,
|
||||
mobileAssessmentResult: null,
|
||||
cardActiveCustomers: null,
|
||||
cardMonthlyChange: null,
|
||||
cardAssessmentResult: null,
|
||||
quarterlyContactRate: null,
|
||||
contactAssessmentResult: null,
|
||||
importTime: null,
|
||||
params: {}
|
||||
},
|
||||
columns: () => [
|
||||
{
|
||||
type: 'selection',
|
||||
align: 'center',
|
||||
width: 48
|
||||
},
|
||||
{
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64,
|
||||
resizable: true
|
||||
},
|
||||
// {
|
||||
// key: 'id',
|
||||
// title: '主键',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
{
|
||||
key: 'depositDailyAvg',
|
||||
title: '管户存款余额日均',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true,
|
||||
children: [
|
||||
{
|
||||
key: 'depositDailyAvg',
|
||||
title: '存款金额日均',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'depositMonthlyChange',
|
||||
title: '较上月',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'depositInitialChange',
|
||||
title: '较期初',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'depositAssessmentResult',
|
||||
title: '考核结果',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
]
|
||||
},
|
||||
// {
|
||||
// key: 'depositMonthlyChange',
|
||||
// title: '较上月',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
// {
|
||||
// key: 'depositInitialChange',
|
||||
// title: '较期初',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
// {
|
||||
// key: 'depositAssessmentResult',
|
||||
// title: '考核结果',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
{
|
||||
key: 'productPerCapita',
|
||||
title: '管户人均持有产品',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true,
|
||||
children: [
|
||||
{
|
||||
key: 'productPerCapita',
|
||||
title: '人均持有产品',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'productMonthlyChange',
|
||||
title: '较上月',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'productYearlyChange',
|
||||
title: '较年初',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'productAssessmentResult',
|
||||
title: '考核结果',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
]
|
||||
},
|
||||
// {
|
||||
// key: 'productMonthlyChange',
|
||||
// title: '较上月',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
// {
|
||||
// key: 'productYearlyChange',
|
||||
// title: '较年初',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
// {
|
||||
// key: 'productAssessmentResult',
|
||||
// title: '考核结果',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
{
|
||||
key: 'mobileActiveCustomers',
|
||||
title: '智e通活跃情况',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true,
|
||||
children: [
|
||||
{
|
||||
key: 'mobileActiveCustomers',
|
||||
title: '智e通月活跃客户数',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'mobileMonthlyChange',
|
||||
title: '较上月',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'mobileAssessmentResult',
|
||||
title: '考核结果',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// key: 'mobileMonthlyChange',
|
||||
// title: '较上月',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
// {
|
||||
// key: 'mobileAssessmentResult',
|
||||
// title: '考核结果',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
{
|
||||
key: 'cardActiveCustomers',
|
||||
title: '银行卡活跃情况',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true,
|
||||
children: [
|
||||
{
|
||||
key: 'cardActiveCustomers',
|
||||
title: '银行卡月活跃客户数',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'cardMonthlyChange',
|
||||
title: '较上月',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'cardAssessmentResult',
|
||||
title: '考核结果',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// key: 'cardMonthlyChange',
|
||||
// title: '较上月',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
// {
|
||||
// key: 'cardAssessmentResult',
|
||||
// title: '考核结果',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
{
|
||||
key: 'quarterlyContactRate',
|
||||
title: '对接率',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true,
|
||||
children: [
|
||||
{
|
||||
key: 'quarterlyContactRate',
|
||||
title: '季度对接率',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'contactAssessmentResult',
|
||||
title: '考核结果',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
key: 'importTime',
|
||||
title: '计价月份',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
ellipsis: true,
|
||||
resizable: true
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// key: 'contactAssessmentResult',
|
||||
// title: '考核结果',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
// {
|
||||
// key: 'importTime',
|
||||
// title: '计价月份',
|
||||
// align: 'center',
|
||||
// minWidth: 120,
|
||||
// ellipsis: true,
|
||||
// resizable: true
|
||||
// },
|
||||
{
|
||||
key: 'operate',
|
||||
title: $t('common.operate'),
|
||||
fixed: 'right',
|
||||
width: 130,
|
||||
render: row => {
|
||||
const divider = () => {
|
||||
if (
|
||||
!hasAuth('evaluation:performanceEvaluation:edit') ||
|
||||
!hasAuth('evaluation:performanceEvaluation:remove')
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return <NDivider vertical />;
|
||||
};
|
||||
|
||||
const editBtn = () => {
|
||||
if (!hasAuth('evaluation:performanceEvaluation:edit')) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<ButtonIcon
|
||||
text
|
||||
type="primary"
|
||||
local-icon="drive-file-rename-outline-outline"
|
||||
tooltipContent={$t('common.edit')}
|
||||
onClick={() => edit(row.id!)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const deleteBtn = () => {
|
||||
if (!hasAuth('evaluation:performanceEvaluation:remove')) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<ButtonIcon
|
||||
text
|
||||
type="error"
|
||||
local-icon="delete-outline"
|
||||
tooltipContent={$t('common.delete')}
|
||||
popconfirmContent={$t('common.confirmDelete')}
|
||||
onPositiveClick={() => handleDelete(row.id!)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="flex-center gap-8px">
|
||||
{editBtn()}
|
||||
{divider()}
|
||||
{deleteBtn()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const scrollX = ref(0);
|
||||
// 计算总宽度函数
|
||||
const calculateTotalWidth = () => {
|
||||
let totalWidth = 0;
|
||||
const visibleColumns = columns.value;
|
||||
for (let i = 0; i < visibleColumns.length; i++) {
|
||||
const column = visibleColumns[i];
|
||||
// 获取列的实际渲染宽度
|
||||
// 注意:调整大小时会更新 column.width
|
||||
let width = column.width;
|
||||
// 如果没有显式宽度,则使用minWidth或默认值
|
||||
if (!width) {
|
||||
width = column.minWidth || 120;
|
||||
}
|
||||
// 转换为数字类型
|
||||
width = typeof width === 'string' ? Number.parseInt(width) : width;
|
||||
totalWidth += width;
|
||||
}
|
||||
|
||||
// 添加额外的50px余量防止边缘裁剪
|
||||
return totalWidth + 50;
|
||||
};
|
||||
|
||||
// 监听列变化并计算宽度
|
||||
watch(
|
||||
columns,
|
||||
newColumns => {
|
||||
scrollX.value = calculateTotalWidth();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
|
||||
useTableOperate(data, getData);
|
||||
|
||||
async function handleBatchDelete() {
|
||||
// request
|
||||
const { error } = await fetchBatchDeletePerformanceEvaluation(checkedRowKeys.value);
|
||||
if (error) return;
|
||||
onBatchDeleted();
|
||||
}
|
||||
|
||||
async function handleDelete(id: CommonType.IdType) {
|
||||
// request
|
||||
const { error } = await fetchBatchDeletePerformanceEvaluation([id]);
|
||||
if (error) return;
|
||||
onDeleted();
|
||||
}
|
||||
|
||||
function edit(id: CommonType.IdType) {
|
||||
handleEdit('id', id);
|
||||
}
|
||||
|
||||
function handleImport() {
|
||||
openImportModal();
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
download('/evaluation/performanceEvaluation/export', searchParams, `质效评价数据_${new Date().getTime()}.xlsx`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<PerformanceEvaluationSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
|
||||
<NCard title="质效评价数据列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation
|
||||
v-model:columns="columnChecks"
|
||||
:disabled-delete="checkedRowKeys.length === 0"
|
||||
:loading="loading"
|
||||
:show-add="hasAuth('evaluation:performanceEvaluation:add')"
|
||||
:show-delete="hasAuth('evaluation:performanceEvaluation:remove')"
|
||||
:show-export="hasAuth('evaluation:performanceEvaluation:export')"
|
||||
@add="handleAdd"
|
||||
@delete="handleBatchDelete"
|
||||
@export="handleExport"
|
||||
@refresh="getData"
|
||||
>
|
||||
<template #after>
|
||||
<NButton
|
||||
v-if="hasAuth('evaluation:performanceEvaluation::import')"
|
||||
size="small"
|
||||
ghost
|
||||
@click="handleImport"
|
||||
>
|
||||
<template #icon>
|
||||
<SvgIcon local-icon="upload-rounded" />
|
||||
</template>
|
||||
{{ $t('common.import') }}
|
||||
</NButton>
|
||||
</template>
|
||||
</TableHeaderOperation>
|
||||
</template>
|
||||
|
||||
<!--scroll-x : 所有表格列宽度之和(包含操作列)+操作列宽度-->
|
||||
<NDataTable
|
||||
v-model:checked-row-keys="checkedRowKeys"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
size="small"
|
||||
:flex-height="!appStore.isMobile"
|
||||
:scroll-x="scrollX"
|
||||
:loading="loading"
|
||||
remote
|
||||
:row-key="row => row.id"
|
||||
:pagination="mobilePagination"
|
||||
class="sm:h-full"
|
||||
@update-resize-widths="scrollX = calculateTotalWidth()"
|
||||
/>
|
||||
|
||||
<PerformanceEvaluationImportModal v-model:visible="importVisible" @submitted="getDataByPage" />
|
||||
|
||||
<PerformanceEvaluationOperateDrawer
|
||||
v-model:visible="drawerVisible"
|
||||
:operate-type="operateType"
|
||||
:row-data="editingData"
|
||||
@submitted="getDataByPage"
|
||||
/>
|
||||
</NCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,162 @@
|
||||
[[[
|
||||
<script setup lang="ts">
|
||||
import { h, ref, watch } from 'vue';
|
||||
import type { UploadFileInfo } from 'naive-ui';
|
||||
import { getToken } from '@/store/modules/auth/shared';
|
||||
import { useDownload } from '@/hooks/business/download';
|
||||
import { getServiceBaseURL } from '@/utils/service';
|
||||
import type FileUpload from '@/components/custom/file-upload.vue';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'PerformanceEvaluationImportModal'
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'submitted'): void;
|
||||
}
|
||||
|
||||
const { download } = useDownload();
|
||||
|
||||
const { baseURL } = getServiceBaseURL(import.meta.env);
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: `Bearer ${ getToken() }`,
|
||||
clientid: import.meta.env.VITE_APP_CLIENT_ID!
|
||||
};
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const uploadRef = ref<typeof FileUpload>();
|
||||
const message = ref<string>('');
|
||||
const success = ref<boolean>(false);
|
||||
|
||||
const visible = defineModel<boolean>('visible', {
|
||||
default: false
|
||||
});
|
||||
|
||||
const data = ref<Record<string, any>>({
|
||||
updateSupport: false
|
||||
});
|
||||
|
||||
const fileList = ref<UploadFileInfo[]>([]);
|
||||
|
||||
function closeDrawer() {
|
||||
visible.value = false;
|
||||
if (success.value) {
|
||||
emit('submitted');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
fileList.value.forEach(item => {
|
||||
item.status = 'pending';
|
||||
});
|
||||
uploadRef.value?.submit();
|
||||
}
|
||||
|
||||
function isErrorState(xhr: XMLHttpRequest) {
|
||||
const responseText = xhr?.responseText;
|
||||
const response = JSON.parse(responseText);
|
||||
return response.code !== 200;
|
||||
}
|
||||
|
||||
function handleFinish(options: { file: UploadFileInfo; event?: ProgressEvent }) {
|
||||
const { file, event } = options;
|
||||
// @ts-expect-error Ignore type errors
|
||||
const responseText = event?.target?.responseText;
|
||||
const response = JSON.parse(responseText);
|
||||
message.value = response.msg;
|
||||
window.$message?.success($t('common.importSuccess'));
|
||||
success.value = true;
|
||||
return file;
|
||||
}
|
||||
|
||||
function handleError(options: { file: UploadFileInfo; event?: ProgressEvent }) {
|
||||
const { event } = options;
|
||||
// @ts-expect-error Ignore type errors
|
||||
const responseText = event?.target?.responseText;
|
||||
const msg = JSON.parse(responseText).msg;
|
||||
message.value = msg;
|
||||
window.$message?.error(() => h('div', { innerHTML: msg || $t('common.importFail') }));
|
||||
success.value = false;
|
||||
}
|
||||
|
||||
function handleDownloadTemplate() {
|
||||
download(
|
||||
'/evaluation/performanceEvaluation/importTemplate',
|
||||
{},
|
||||
`${ $t('mps.common') }_${ $t('common.importTemplate') }_${ new Date().getTime() }.xlsx`
|
||||
);
|
||||
closeDrawer();
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
if (visible.value) {
|
||||
fileList.value = [];
|
||||
success.value = false;
|
||||
message.value = '';
|
||||
}
|
||||
} );
|
||||
</script>
|
||||
]]]
|
||||
|
||||
<template>
|
||||
<NModal
|
||||
v-model:show="visible"
|
||||
:title="$t('common.import')"
|
||||
preset="card"
|
||||
:bordered="false"
|
||||
display-directive="show"
|
||||
class="max-w-90% w-600px"
|
||||
@close="closeDrawer"
|
||||
>
|
||||
<NUpload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="fileList"
|
||||
:action="`${baseURL}/evaluation/performanceEvaluation/importData`"
|
||||
:headers="headers"
|
||||
:data="data"
|
||||
:max="1"
|
||||
:file-size="50"
|
||||
accept=".xls,.xlsx"
|
||||
:multiple="false"
|
||||
directory-dnd
|
||||
:default-upload="false"
|
||||
list-type="text"
|
||||
:is-error-state="isErrorState"
|
||||
@finish="handleFinish"
|
||||
@error="handleError"
|
||||
>
|
||||
<NUploadDragger>
|
||||
<div class="mb-12px flex-center">
|
||||
<SvgIcon local-icon="unarchive-outline" class="text-58px color-#d8d8db dark:color-#a1a1a2" />
|
||||
</div>
|
||||
<NText class="text-16px">{{ $t('common.importTip') }}</NText>
|
||||
<NP depth="3" class="mt-8px text-center">
|
||||
{{ $t('common.importSize') }}
|
||||
<b class="text-red-500">50MB</b>
|
||||
{{ $t('common.importFormat') }}
|
||||
<b class="text-red-500">xls/xlsx</b>
|
||||
{{ $t('common.importEnd') }}
|
||||
</NP>
|
||||
</NUploadDragger>
|
||||
</NUpload>
|
||||
<div class="flex-center">
|
||||
<NCheckbox v-model="data.updateSupport">{{ $t('common.updateExisting') }}</NCheckbox>
|
||||
</div>
|
||||
<NAlert v-if="message" :title="$t('common.importResult')" :type="success ? 'success' : 'error'" :bordered="false">
|
||||
<template #default>
|
||||
<div v-html="message"></div>
|
||||
</template>
|
||||
</NAlert>
|
||||
<template #footer>
|
||||
<NSpace justify="end" :size="16">
|
||||
<NButton @click="handleDownloadTemplate">{{ $t('common.downloadTemplate') }}</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">{{ $t('common.import') }}</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NModal>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,197 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import { fetchCreatePerformanceEvaluation, fetchUpdatePerformanceEvaluation } from '@/service/api/evaluation/performance-evaluation';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'PerformanceEvaluationOperateDrawer'
|
||||
});
|
||||
|
||||
interface Props {
|
||||
/** the type of operation */
|
||||
operateType: NaiveUI.TableOperateType;
|
||||
/** the edit row data */
|
||||
rowData?: Api.Evaluation.PerformanceEvaluation | null;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
interface Emits {
|
||||
(e: 'submitted'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const visible = defineModel<boolean>('visible', {
|
||||
default: false
|
||||
});
|
||||
|
||||
|
||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
const { createRequiredRule } = useFormRules();
|
||||
|
||||
const title = computed(() => {
|
||||
const titles: Record<NaiveUI.TableOperateType, string> = {
|
||||
add: '新增质效评价数据',
|
||||
edit: '编辑质效评价数据'
|
||||
};
|
||||
return titles[props.operateType];
|
||||
});
|
||||
|
||||
type Model = Api.Evaluation.PerformanceEvaluationOperateParams;
|
||||
|
||||
const model: Model = reactive(createDefaultModel());
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
depositDailyAvg: undefined,
|
||||
depositMonthlyChange: '',
|
||||
depositInitialChange: '',
|
||||
depositAssessmentResult: '',
|
||||
productPerCapita: '',
|
||||
productMonthlyChange: '',
|
||||
productYearlyChange: '',
|
||||
productAssessmentResult: '',
|
||||
mobileActiveCustomers: '',
|
||||
mobileMonthlyChange: '',
|
||||
mobileAssessmentResult: '',
|
||||
cardActiveCustomers: '',
|
||||
cardMonthlyChange: '',
|
||||
cardAssessmentResult: '',
|
||||
quarterlyContactRate: undefined,
|
||||
contactAssessmentResult: '',
|
||||
importTime: '',
|
||||
};
|
||||
}
|
||||
|
||||
type RuleKey = Extract<
|
||||
keyof Model,
|
||||
| 'tenantId'
|
||||
| 'createDept'
|
||||
| 'createBy'
|
||||
| 'createTime'
|
||||
| 'updateBy'
|
||||
| 'updateTime'
|
||||
>;
|
||||
|
||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
tenantId: createRequiredRule('租户编号不能为空'),
|
||||
createDept: createRequiredRule('创建部门不能为空'),
|
||||
createBy: createRequiredRule('创建者不能为空'),
|
||||
createTime: createRequiredRule('创建时间不能为空'),
|
||||
updateBy: createRequiredRule('更新者不能为空'),
|
||||
updateTime: createRequiredRule('更新时间不能为空')
|
||||
};
|
||||
|
||||
function handleUpdateModelWhenEdit() {
|
||||
if (props.operateType === 'add') {
|
||||
Object.assign(model, createDefaultModel());
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.operateType === 'edit' && props.rowData) {
|
||||
Object.assign(model, props.rowData);
|
||||
}
|
||||
}
|
||||
|
||||
function closeDrawer() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
|
||||
const { id, depositDailyAvg, depositMonthlyChange, depositInitialChange, depositAssessmentResult, productPerCapita, productMonthlyChange, productYearlyChange, productAssessmentResult, mobileActiveCustomers, mobileMonthlyChange, mobileAssessmentResult, cardActiveCustomers, cardMonthlyChange, cardAssessmentResult, quarterlyContactRate, contactAssessmentResult, importTime } = model;
|
||||
|
||||
// request
|
||||
if (props.operateType === 'add') {
|
||||
const { error } = await fetchCreatePerformanceEvaluation({ depositDailyAvg, depositMonthlyChange, depositInitialChange, depositAssessmentResult, productPerCapita, productMonthlyChange, productYearlyChange, productAssessmentResult, mobileActiveCustomers, mobileMonthlyChange, mobileAssessmentResult, cardActiveCustomers, cardMonthlyChange, cardAssessmentResult, quarterlyContactRate, contactAssessmentResult, importTime });
|
||||
if (error) return;
|
||||
}
|
||||
|
||||
if (props.operateType === 'edit') {
|
||||
const { error } = await fetchUpdatePerformanceEvaluation({ id, depositDailyAvg, depositMonthlyChange, depositInitialChange, depositAssessmentResult, productPerCapita, productMonthlyChange, productYearlyChange, productAssessmentResult, mobileActiveCustomers, mobileMonthlyChange, mobileAssessmentResult, cardActiveCustomers, cardMonthlyChange, cardAssessmentResult, quarterlyContactRate, contactAssessmentResult, importTime });
|
||||
if (error) return;
|
||||
}
|
||||
|
||||
window.$message?.success($t('common.updateSuccess'));
|
||||
closeDrawer();
|
||||
emit('submitted');
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
if (visible.value) {
|
||||
handleUpdateModelWhenEdit();
|
||||
restoreValidation();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
|
||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
||||
<NForm ref="formRef" :model="model" :rules="rules">
|
||||
<NFormItem label="存款金额日均" path="depositDailyAvg">
|
||||
<NInput v-model:value="model.depositDailyAvg" placeholder="请输入存款金额日均" />
|
||||
</NFormItem>
|
||||
<NFormItem label="较上月" path="depositMonthlyChange">
|
||||
<NInput v-model:value="model.depositMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItem>
|
||||
<NFormItem label="较期初" path="depositInitialChange">
|
||||
<NInput v-model:value="model.depositInitialChange" placeholder="请输入较期初" />
|
||||
</NFormItem>
|
||||
<NFormItem label="考核结果" path="depositAssessmentResult">
|
||||
<NInput v-model:value="model.depositAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItem>
|
||||
<NFormItem label="人均持有产品" path="productPerCapita">
|
||||
<NInput v-model:value="model.productPerCapita" placeholder="请输入人均持有产品" />
|
||||
</NFormItem>
|
||||
<NFormItem label="较上月" path="productMonthlyChange">
|
||||
<NInput v-model:value="model.productMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItem>
|
||||
<NFormItem label="较年初" path="productYearlyChange">
|
||||
<NInput v-model:value="model.productYearlyChange" placeholder="请输入较年初" />
|
||||
</NFormItem>
|
||||
<NFormItem label="考核结果" path="productAssessmentResult">
|
||||
<NInput v-model:value="model.productAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItem>
|
||||
<NFormItem label="智e通月活跃客户数" path="mobileActiveCustomers">
|
||||
<NInput v-model:value="model.mobileActiveCustomers" placeholder="请输入智e通月活跃客户数" />
|
||||
</NFormItem>
|
||||
<NFormItem label="较上月" path="mobileMonthlyChange">
|
||||
<NInput v-model:value="model.mobileMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItem>
|
||||
<NFormItem label="考核结果" path="mobileAssessmentResult">
|
||||
<NInput v-model:value="model.mobileAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItem>
|
||||
<NFormItem label="银行卡月活跃客户数" path="cardActiveCustomers">
|
||||
<NInput v-model:value="model.cardActiveCustomers" placeholder="请输入银行卡月活跃客户数" />
|
||||
</NFormItem>
|
||||
<NFormItem label="较上月" path="cardMonthlyChange">
|
||||
<NInput v-model:value="model.cardMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItem>
|
||||
<NFormItem label="考核结果" path="cardAssessmentResult">
|
||||
<NInput v-model:value="model.cardAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItem>
|
||||
<NFormItem label="季度对接率" path="quarterlyContactRate">
|
||||
<NInput v-model:value="model.quarterlyContactRate" placeholder="请输入季度对接率" />
|
||||
</NFormItem>
|
||||
<NFormItem label="考核结果" path="contactAssessmentResult">
|
||||
<NInput v-model:value="model.contactAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItem>
|
||||
<NFormItem label="计价月份" path="importTime">
|
||||
<NInput v-model:value="model.importTime" placeholder="请输入计价月份" />
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
<template #footer>
|
||||
<NSpace :size="16">
|
||||
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,115 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'PerformanceEvaluationSearch'
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'reset'): void;
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
|
||||
|
||||
const model = defineModel<Api.Evaluation.PerformanceEvaluationSearchParams>('model', { required: true });
|
||||
|
||||
|
||||
async function reset() {
|
||||
Object.assign(model.value.params!, {});
|
||||
await restoreValidation();
|
||||
emit('reset');
|
||||
}
|
||||
|
||||
async function search() {
|
||||
await validate();
|
||||
emit('search');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NCard :bordered="false" size="small" class="card-wrapper">
|
||||
<NCollapse>
|
||||
<NCollapseItem :title="$t('common.search')" name="user-search">
|
||||
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
|
||||
<NGrid responsive="screen" item-responsive>
|
||||
<NFormItemGi span="24 s:12 m:6" label="存款金额日均" path="depositDailyAvg" class="pr-24px">
|
||||
<NInput v-model:value="model.depositDailyAvg" placeholder="请输入存款金额日均" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="较上月" path="depositMonthlyChange" class="pr-24px">
|
||||
<NInput v-model:value="model.depositMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="较期初" path="depositInitialChange" class="pr-24px">
|
||||
<NInput v-model:value="model.depositInitialChange" placeholder="请输入较期初" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="考核结果" path="depositAssessmentResult" class="pr-24px">
|
||||
<NInput v-model:value="model.depositAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="人均持有产品" path="productPerCapita" class="pr-24px">
|
||||
<NInput v-model:value="model.productPerCapita" placeholder="请输入人均持有产品" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="较上月" path="productMonthlyChange" class="pr-24px">
|
||||
<NInput v-model:value="model.productMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="较年初" path="productYearlyChange" class="pr-24px">
|
||||
<NInput v-model:value="model.productYearlyChange" placeholder="请输入较年初" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="考核结果" path="productAssessmentResult" class="pr-24px">
|
||||
<NInput v-model:value="model.productAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="智e通月活跃客户数" path="mobileActiveCustomers" class="pr-24px">
|
||||
<NInput v-model:value="model.mobileActiveCustomers" placeholder="请输入智e通月活跃客户数" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="较上月" path="mobileMonthlyChange" class="pr-24px">
|
||||
<NInput v-model:value="model.mobileMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="考核结果" path="mobileAssessmentResult" class="pr-24px">
|
||||
<NInput v-model:value="model.mobileAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="银行卡月活跃客户数" path="cardActiveCustomers" class="pr-24px">
|
||||
<NInput v-model:value="model.cardActiveCustomers" placeholder="请输入银行卡月活跃客户数" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="较上月" path="cardMonthlyChange" class="pr-24px">
|
||||
<NInput v-model:value="model.cardMonthlyChange" placeholder="请输入较上月" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="考核结果" path="cardAssessmentResult" class="pr-24px">
|
||||
<NInput v-model:value="model.cardAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="季度对接率" path="quarterlyContactRate" class="pr-24px">
|
||||
<NInput v-model:value="model.quarterlyContactRate" placeholder="请输入季度对接率" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="考核结果" path="contactAssessmentResult" class="pr-24px">
|
||||
<NInput v-model:value="model.contactAssessmentResult" placeholder="请输入考核结果" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="计价月份" path="importTime" class="pr-24px">
|
||||
<NInput v-model:value="model.importTime" placeholder="请输入计价月份" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24" class="pr-24px">
|
||||
<NSpace class="w-full" justify="end">
|
||||
<NButton @click="reset">
|
||||
<template #icon>
|
||||
<SvgIcon local-icon="round-refresh"/>
|
||||
</template>
|
||||
{{ $t('common.reset') }}
|
||||
</NButton>
|
||||
<NButton type="primary" ghost @click="search">
|
||||
<template #icon>
|
||||
<SvgIcon local-icon="round-search"/>
|
||||
</template>
|
||||
{{ $t('common.search') }}
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
</NForm>
|
||||
</NCollapseItem>
|
||||
</NCollapse>
|
||||
</NCard>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Loading…
Reference in New Issue
Block a user