Compare commits
2 Commits
ff9fb9168b
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 50ab33f369 | |||
| bcbc45bb03 |
@@ -31,10 +31,16 @@ export const add = row => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const syncIamAccounts = () => {
|
export const syncIamAccounts = (current = 1, size = 50, signal) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-system/user/sync-iam-accounts',
|
url: '/blade-system/user/sync-iam-accounts',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
current,
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
timeout: 60000,
|
||||||
|
signal,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { getToken } from '@/utils/auth';
|
|||||||
import store from '@/store';
|
import store from '@/store';
|
||||||
import { generateIframePath, processUrlForQuery, isURL } from './router';
|
import { generateIframePath, processUrlForQuery, isURL } from './router';
|
||||||
import { wrapViewLoader } from '@/utils/chunk-reload';
|
import { wrapViewLoader } from '@/utils/chunk-reload';
|
||||||
|
|
||||||
|
// 保持懒加载,避免 eager 与 store 循环依赖(Cannot access 'store' before initialization)
|
||||||
const modules = import.meta.glob('../**/**/*.vue');
|
const modules = import.meta.glob('../**/**/*.vue');
|
||||||
|
|
||||||
// 将多级路由扁平化为二级路由,支持 keep-alive 跨层级缓存
|
// 将多级路由扁平化为二级路由,支持 keep-alive 跨层级缓存
|
||||||
|
|||||||
+47
-39
@@ -1,5 +1,8 @@
|
|||||||
import Layout from '@/page/index/index.vue';
|
import Layout from '@/page/index/index.vue';
|
||||||
import Store from '@/store/';
|
import Store from '@/store/';
|
||||||
|
import { wrapViewLoader } from '@/utils/chunk-reload';
|
||||||
|
|
||||||
|
const loadView = loader => wrapViewLoader(loader);
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
@@ -10,7 +13,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '汇票付款表单',
|
name: '汇票付款表单',
|
||||||
meta: { keepAlive: false, activeMenu: '/payment/bill-payment' },
|
meta: { keepAlive: false, activeMenu: '/payment/bill-payment' },
|
||||||
component: () => import('@/views/payment/bill-payment-form.vue'),
|
component: loadView(() => import('@/views/payment/bill-payment-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -22,7 +25,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '汇票台账表单',
|
name: '汇票台账表单',
|
||||||
meta: { keepAlive: false, activeMenu: '/payment/bill-ledger' },
|
meta: { keepAlive: false, activeMenu: '/payment/bill-ledger' },
|
||||||
component: () => import('@/views/payment/bill-ledger-form.vue'),
|
component: loadView(() => import('@/views/payment/bill-ledger-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -34,7 +37,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '认领记录详情',
|
name: '认领记录详情',
|
||||||
meta: { keepAlive: false, activeMenu: '/payment/receipt-claim-record' },
|
meta: { keepAlive: false, activeMenu: '/payment/receipt-claim-record' },
|
||||||
component: () => import('@/views/payment/receipt-claim-record-form.vue'),
|
component: loadView(() => import('@/views/payment/receipt-claim-record-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -46,7 +49,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '收款流水认领',
|
name: '收款流水认领',
|
||||||
meta: { keepAlive: false, activeMenu: '/payment/receipt-flow' },
|
meta: { keepAlive: false, activeMenu: '/payment/receipt-flow' },
|
||||||
component: () => import('@/views/payment/receipt-flow-form.vue'),
|
component: loadView(() => import('@/views/payment/receipt-flow-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -58,7 +61,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '收票登记',
|
name: '收票登记',
|
||||||
meta: { keepAlive: false, activeMenu: '/payment/invoice-receipt' },
|
meta: { keepAlive: false, activeMenu: '/payment/invoice-receipt' },
|
||||||
component: () => import('@/views/payment/invoice-receipt-form.vue'),
|
component: loadView(() => import('@/views/payment/invoice-receipt-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -70,7 +73,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '开票申请',
|
name: '开票申请',
|
||||||
meta: { keepAlive: false, activeMenu: '/payment/invoice-application' },
|
meta: { keepAlive: false, activeMenu: '/payment/invoice-application' },
|
||||||
component: () => import('@/views/payment/invoice-application-form.vue'),
|
component: loadView(() => import('@/views/payment/invoice-application-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -82,7 +85,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '付款申请',
|
name: '付款申请',
|
||||||
meta: { keepAlive: false, activeMenu: '/payment/payment-application' },
|
meta: { keepAlive: false, activeMenu: '/payment/payment-application' },
|
||||||
component: () => import('@/views/payment/payment-application-form.vue'),
|
component: loadView(() => import('@/views/payment/payment-application-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -97,7 +100,7 @@ export default [
|
|||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
activeMenu: '/settlement/pre-settlement',
|
activeMenu: '/settlement/pre-settlement',
|
||||||
},
|
},
|
||||||
component: () => import('@/views/settlement/pre-settlement-form.vue'),
|
component: loadView(() => import('@/views/settlement/pre-settlement-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -112,7 +115,7 @@ export default [
|
|||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
activeMenu: '/settlement/formal-settlement',
|
activeMenu: '/settlement/formal-settlement',
|
||||||
},
|
},
|
||||||
component: () => import('@/views/settlement/formal-settlement-form.vue'),
|
component: loadView(() => import('@/views/settlement/formal-settlement-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -127,7 +130,7 @@ export default [
|
|||||||
keepAlive: false,
|
keepAlive: false,
|
||||||
activeMenu: '/settlement/transport-reconciliation',
|
activeMenu: '/settlement/transport-reconciliation',
|
||||||
},
|
},
|
||||||
component: () => import('@/views/settlement/transport-reconciliation-form.vue'),
|
component: loadView(() => import('@/views/settlement/transport-reconciliation-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -139,7 +142,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '执行凭证批次详情',
|
name: '执行凭证批次详情',
|
||||||
meta: { keepAlive: false, activeMenu: '/business/voucher-manage' },
|
meta: { keepAlive: false, activeMenu: '/business/voucher-manage' },
|
||||||
component: () => import('@/views/business/voucher-manage-detail.vue'),
|
component: loadView(() => import('@/views/business/voucher-manage-detail.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -151,7 +154,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新增合同管理',
|
name: '新增合同管理',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/business/contract-manage.vue'),
|
component: loadView(() => import('@/views/business/contract-manage.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -163,7 +166,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '合同详情',
|
name: '合同详情',
|
||||||
meta: { keepAlive: false, activeMenu: '/business/contract-manage' },
|
meta: { keepAlive: false, activeMenu: '/business/contract-manage' },
|
||||||
component: () => import('@/views/business/contract-manage.vue'),
|
component: loadView(() => import('@/views/business/contract-manage.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -175,7 +178,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新增项目申请',
|
name: '新增项目申请',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/business/project-apply.vue'),
|
component: loadView(() => import('@/views/business/project-apply.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -187,7 +190,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新增编辑运单管理',
|
name: '新增编辑运单管理',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/business/waybill-manage.vue'),
|
component: loadView(() => import('@/views/business/waybill-manage.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -199,7 +202,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '运单管理详情',
|
name: '运单管理详情',
|
||||||
meta: { keepAlive: false, activeMenu: '/business/waybill-manage' },
|
meta: { keepAlive: false, activeMenu: '/business/waybill-manage' },
|
||||||
component: () => import('@/views/business/waybill-manage-detail.vue'),
|
component: loadView(() => import('@/views/business/waybill-manage-detail.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -211,7 +214,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '导入运单',
|
name: '导入运单',
|
||||||
meta: { keepAlive: false, activeMenu: '/business/waybill-import' },
|
meta: { keepAlive: false, activeMenu: '/business/waybill-import' },
|
||||||
component: () => import('@/views/business/waybill-import.vue'),
|
component: loadView(() => import('@/views/business/waybill-import.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -223,7 +226,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新建导入运单',
|
name: '新建导入运单',
|
||||||
meta: { keepAlive: false, activeMenu: '/business/waybill-import' },
|
meta: { keepAlive: false, activeMenu: '/business/waybill-import' },
|
||||||
component: () => import('@/views/business/waybill-import-form.vue'),
|
component: loadView(() => import('@/views/business/waybill-import-form.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -235,7 +238,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新增编辑配载管理',
|
name: '新增编辑配载管理',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/business/loading-manage.vue'),
|
component: loadView(() => import('@/views/business/loading-manage.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -259,7 +262,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新增编辑运输计划',
|
name: '新增编辑运输计划',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/business/transport-plan.vue'),
|
component: loadView(() => import('@/views/business/transport-plan.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -271,7 +274,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '导入运输计划',
|
name: '导入运输计划',
|
||||||
meta: { keepAlive: false, activeMenu: '/business/transport-plan' },
|
meta: { keepAlive: false, activeMenu: '/business/transport-plan' },
|
||||||
component: () => import('@/views/business/transport-plan-import.vue'),
|
component: loadView(() => import('@/views/business/transport-plan-import.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -283,7 +286,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '计划调度',
|
name: '计划调度',
|
||||||
meta: { keepAlive: false, activeMenu: '/business/transport-plan' },
|
meta: { keepAlive: false, activeMenu: '/business/transport-plan' },
|
||||||
component: () => import('@/views/business/transport-plan-dispatch.vue'),
|
component: loadView(() => import('@/views/business/transport-plan-dispatch.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -295,7 +298,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新增编辑运单模板',
|
name: '新增编辑运单模板',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/business/shipping-template.vue'),
|
component: loadView(() => import('@/views/business/shipping-template.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -307,7 +310,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '新增客商档案',
|
name: '新增客商档案',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/vehicle/customer-archive.vue'),
|
component: loadView(() => import('@/views/vehicle/customer-archive.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -319,7 +322,7 @@ export default [
|
|||||||
path: '',
|
path: '',
|
||||||
name: '合同变更',
|
name: '合同变更',
|
||||||
meta: { keepAlive: false },
|
meta: { keepAlive: false },
|
||||||
component: () => import('@/views/business/contract-manage-change.vue'),
|
component: loadView(() => import('@/views/business/contract-manage-change.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -335,7 +338,7 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'dashboard',
|
i18n: 'dashboard',
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "views" */ '@/views/wel/index.vue'),
|
component: loadView(() => import(/* webpackChunkName: "views" */ '@/views/wel/index.vue')),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'dashboard',
|
path: 'dashboard',
|
||||||
@@ -344,7 +347,7 @@ export default [
|
|||||||
i18n: 'dashboard',
|
i18n: 'dashboard',
|
||||||
menu: false,
|
menu: false,
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "views" */ '@/views/wel/dashboard.vue'),
|
component: loadView(() => import(/* webpackChunkName: "views" */ '@/views/wel/dashboard.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -359,7 +362,7 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'test',
|
i18n: 'test',
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "views" */ '@/views/util/test.vue'),
|
component: loadView(() => import(/* webpackChunkName: "views" */ '@/views/util/test.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -374,8 +377,9 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'dict',
|
i18n: 'dict',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: loadView(() =>
|
||||||
import(/* webpackChunkName: "views" */ '@/views/util/demo/dict-horizontal.vue'),
|
import(/* webpackChunkName: "views" */ '@/views/util/demo/dict-horizontal.vue')
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -390,8 +394,9 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'dict',
|
i18n: 'dict',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: loadView(() =>
|
||||||
import(/* webpackChunkName: "views" */ '@/views/util/demo/dict-vertical.vue'),
|
import(/* webpackChunkName: "views" */ '@/views/util/demo/dict-vertical.vue')
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -406,7 +411,7 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'info',
|
i18n: 'info',
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "views" */ '@/views/system/userinfo.vue'),
|
component: loadView(() => import(/* webpackChunkName: "views" */ '@/views/system/userinfo.vue')),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -421,8 +426,9 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'work',
|
i18n: 'work',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: loadView(() =>
|
||||||
import(/* webpackChunkName: "views" */ '@/views/work/process/leave/form.vue'),
|
import(/* webpackChunkName: "views" */ '@/views/work/process/leave/form.vue')
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'handle/:taskId/:processInstanceId/:businessId',
|
path: 'handle/:taskId/:processInstanceId/:businessId',
|
||||||
@@ -430,8 +436,9 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'work',
|
i18n: 'work',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: loadView(() =>
|
||||||
import(/* webpackChunkName: "views" */ '@/views/work/process/leave/handle.vue'),
|
import(/* webpackChunkName: "views" */ '@/views/work/process/leave/handle.vue')
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'detail/:processInstanceId/:businessId',
|
path: 'detail/:processInstanceId/:businessId',
|
||||||
@@ -439,8 +446,9 @@ export default [
|
|||||||
meta: {
|
meta: {
|
||||||
i18n: 'work',
|
i18n: 'work',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: loadView(() =>
|
||||||
import(/* webpackChunkName: "views" */ '@/views/work/process/leave/detail.vue'),
|
import(/* webpackChunkName: "views" */ '@/views/work/process/leave/detail.vue')
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -140,15 +140,14 @@
|
|||||||
@load="onLoad(page, query)"
|
@load="onLoad(page, query)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!--
|
<component
|
||||||
项目新增/编辑/查看/变更/补录全部是独立整页(openProjectDialog 一律 push /business/project-apply/form),
|
:is="projectFormContainer"
|
||||||
这里固定渲染普通容器,不再按 $route 在 div 与 el-dialog 之间切换。
|
v-if="projectBox"
|
||||||
原因:标签页 keep-alive 会缓存本页实例,若容器在离开本页后又变回 el-dialog,
|
v-bind="projectFormContainerProps"
|
||||||
缓存实例会把 append-to-body 的弹窗渲染进 body 并永久停留(Vue 的 KeepAlive.deactivate →
|
@update:model-value="projectBox = $event"
|
||||||
Teleport.move 不会搬走 append-to-body 的弹窗 DOM),表现为“点左侧菜单又弹出新增项目管理弹窗”。
|
@closed="resetProjectDialog"
|
||||||
-->
|
>
|
||||||
<div v-if="isProjectFormPage" class="project-apply-page-form">
|
<div v-if="isProjectFormPage" class="archive-page-form__title">
|
||||||
<div class="archive-page-form__title">
|
|
||||||
{{ projectDialogTitle }}
|
{{ projectDialogTitle }}
|
||||||
</div>
|
</div>
|
||||||
<el-form
|
<el-form
|
||||||
@@ -319,7 +318,7 @@
|
|||||||
<el-form-item prop="fundLimit" class="project-apply-form__tip-label">
|
<el-form-item prop="fundLimit" class="project-apply-form__tip-label">
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>项目资金使用额度</span>
|
<span>项目资金使用额度</span>
|
||||||
<el-tooltip content="实际业务回款周期内付款额度" placement="top">
|
<el-tooltip content="实际业务回款周期内付款" placement="top">
|
||||||
<el-icon class="project-apply-form__label-tip"><QuestionFilled /></el-icon>
|
<el-icon class="project-apply-form__label-tip"><QuestionFilled /></el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
@@ -789,7 +788,8 @@
|
|||||||
:class="{ 'project-apply-dialog__footer--change': isChangeDialog }"
|
:class="{ 'project-apply-dialog__footer--change': isChangeDialog }"
|
||||||
>
|
>
|
||||||
<template v-if="isChangeDialog">
|
<template v-if="isChangeDialog">
|
||||||
<el-button @click="closeProjectForm">取消</el-button>
|
<el-button v-if="!isProjectFormPage" @click="handleCancelProject">取消</el-button>
|
||||||
|
<el-button v-if="isProjectFormPage" @click="closeProjectForm">取消</el-button>
|
||||||
<el-button type="primary" plain :loading="submitLoading" @click="saveChangeProject">
|
<el-button type="primary" plain :loading="submitLoading" @click="saveChangeProject">
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -798,7 +798,8 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-button @click="closeProjectForm">取消</el-button>
|
<el-button v-if="!isProjectFormPage" @click="handleCancelProject">取消</el-button>
|
||||||
|
<el-button v-if="isProjectFormPage" @click="closeProjectForm">取消</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="!dialogReadonly"
|
v-if="!dialogReadonly"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -818,7 +819,7 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</component>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="attachmentDocumentPreviewVisible"
|
v-model="attachmentDocumentPreviewVisible"
|
||||||
@@ -1115,6 +1116,7 @@ export default {
|
|||||||
total: 0,
|
total: 0,
|
||||||
},
|
},
|
||||||
selectionList: [],
|
selectionList: [],
|
||||||
|
projectBox: false,
|
||||||
dialogType: 'add',
|
dialogType: 'add',
|
||||||
dialogReadonly: false,
|
dialogReadonly: false,
|
||||||
submitLoading: false,
|
submitLoading: false,
|
||||||
@@ -1308,6 +1310,21 @@ export default {
|
|||||||
isProjectFormPage() {
|
isProjectFormPage() {
|
||||||
return this.$route.path === '/business/project-apply/form';
|
return this.$route.path === '/business/project-apply/form';
|
||||||
},
|
},
|
||||||
|
projectFormContainer() {
|
||||||
|
return this.isProjectFormPage ? 'div' : 'el-dialog';
|
||||||
|
},
|
||||||
|
projectFormContainerProps() {
|
||||||
|
if (this.isProjectFormPage) return { class: 'project-apply-page-form' };
|
||||||
|
return {
|
||||||
|
modelValue: this.projectBox,
|
||||||
|
title: this.projectDialogTitle,
|
||||||
|
appendToBody: true,
|
||||||
|
destroyOnClose: true,
|
||||||
|
width: '1440px',
|
||||||
|
top: '4vh',
|
||||||
|
class: 'project-apply-dialog',
|
||||||
|
};
|
||||||
|
},
|
||||||
isBasicInfoReadonly() {
|
isBasicInfoReadonly() {
|
||||||
return this.dialogReadonly || this.isChangeDialog;
|
return this.dialogReadonly || this.isChangeDialog;
|
||||||
},
|
},
|
||||||
@@ -1346,12 +1363,6 @@ export default {
|
|||||||
this.openProjectFormPage();
|
this.openProjectFormPage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deactivated() {
|
|
||||||
this.closeInnerDialogs();
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
this.closeInnerDialogs();
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
buildTableOption() {
|
buildTableOption() {
|
||||||
return {
|
return {
|
||||||
@@ -1379,6 +1390,7 @@ export default {
|
|||||||
const id = this.$route.query.id;
|
const id = this.$route.query.id;
|
||||||
this.dialogType = type;
|
this.dialogType = type;
|
||||||
this.dialogReadonly = type === 'view';
|
this.dialogReadonly = type === 'view';
|
||||||
|
this.projectBox = true;
|
||||||
if (['add', 'majorSupplement'].includes(type)) {
|
if (['add', 'majorSupplement'].includes(type)) {
|
||||||
this.applyProjectDetail({
|
this.applyProjectDetail({
|
||||||
...emptyForm(),
|
...emptyForm(),
|
||||||
@@ -1399,15 +1411,11 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
closeProjectForm() {
|
closeProjectForm() {
|
||||||
this.$router.push('/business/project-apply');
|
if (this.isProjectFormPage) {
|
||||||
},
|
this.$router.push('/business/project-apply');
|
||||||
// 页面被 keep-alive 缓存/卸载时,关闭本页所有 append-to-body 的二级弹窗。
|
} else {
|
||||||
// 若不关闭,Teleport 出去的弹窗 DOM 在实例失活时不会被搬离 body,会残留盖在后续页面上。
|
this.projectBox = false;
|
||||||
closeInnerDialogs() {
|
}
|
||||||
this.changeRecordDetailVisible = false;
|
|
||||||
this.attachmentDocumentPreviewVisible = false;
|
|
||||||
this.attachmentImagePreviewVisible = false;
|
|
||||||
this.userBox = false;
|
|
||||||
},
|
},
|
||||||
statusValue(row) {
|
statusValue(row) {
|
||||||
return row[this.config.statusProp || 'status'];
|
return row[this.config.statusProp || 'status'];
|
||||||
@@ -1626,6 +1634,17 @@ export default {
|
|||||||
else if (type === 'change') query.name = '项目变更';
|
else if (type === 'change') query.name = '项目变更';
|
||||||
this.$router.push({ path: '/business/project-apply/form', query });
|
this.$router.push({ path: '/business/project-apply/form', query });
|
||||||
},
|
},
|
||||||
|
resetProjectDialog() {
|
||||||
|
this.$refs.projectForm?.clearValidate();
|
||||||
|
this.form = emptyForm();
|
||||||
|
this.customerRows = [];
|
||||||
|
this.carrierRows = [];
|
||||||
|
this.attachmentRows = [];
|
||||||
|
this.selectedAttachmentRows = [];
|
||||||
|
this.changeRows = [];
|
||||||
|
this.selectedCustomerId = [];
|
||||||
|
this.selectedCarrierIds = [];
|
||||||
|
},
|
||||||
applyProjectDetail(row) {
|
applyProjectDetail(row) {
|
||||||
const displayRow = {
|
const displayRow = {
|
||||||
...row,
|
...row,
|
||||||
@@ -1748,6 +1767,23 @@ export default {
|
|||||||
this.submitLoading = false;
|
this.submitLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleCancelProject() {
|
||||||
|
if (this.isProjectFormPage) {
|
||||||
|
this.closeProjectForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!['add', 'majorSupplement', 'change'].includes(this.dialogType)) {
|
||||||
|
this.closeProjectForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$confirm('确认后直接关闭弹窗,列表无数据变更,是否继续?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
this.closeProjectForm();
|
||||||
|
});
|
||||||
|
},
|
||||||
saveChangeProject() {
|
saveChangeProject() {
|
||||||
this.submitChangeForm(false);
|
this.submitChangeForm(false);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,14 +22,6 @@
|
|||||||
@tree-load="treeLoad"
|
@tree-load="treeLoad"
|
||||||
>
|
>
|
||||||
<template #menu-left>
|
<template #menu-left>
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
plain
|
|
||||||
:loading="iamSyncLoading"
|
|
||||||
v-if="userInfo.authority.includes('admin')"
|
|
||||||
@click="handleIamOrganizationSync"
|
|
||||||
>同步组织
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
icon="el-icon-delete"
|
icon="el-icon-delete"
|
||||||
@@ -135,7 +127,6 @@ import {
|
|||||||
add,
|
add,
|
||||||
getDept,
|
getDept,
|
||||||
getDeptTree,
|
getDeptTree,
|
||||||
syncIamOrganizations,
|
|
||||||
} from '@/api/system/dept';
|
} from '@/api/system/dept';
|
||||||
import { getLeaderList } from '@/api/system/user';
|
import { getLeaderList } from '@/api/system/user';
|
||||||
import { getList as getCustomerArchiveList } from '@/api/vehicle/customer-archive';
|
import { getList as getCustomerArchiveList } from '@/api/vehicle/customer-archive';
|
||||||
@@ -168,7 +159,6 @@ export default {
|
|||||||
selectionList: [],
|
selectionList: [],
|
||||||
query: {},
|
query: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
iamSyncLoading: false,
|
|
||||||
parentId: 0,
|
parentId: 0,
|
||||||
page: {
|
page: {
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -708,26 +698,6 @@ export default {
|
|||||||
done(row);
|
done(row);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleIamOrganizationSync() {
|
|
||||||
this.$confirm('确定从IAM同步组织信息?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning',
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.iamSyncLoading = true;
|
|
||||||
return syncIamOrganizations();
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
const count = res?.data?.data ?? 0;
|
|
||||||
this.$message.success(`IAM组织同步完成,共处理${count}条`);
|
|
||||||
this.parentId = 0;
|
|
||||||
this.onLoad(this.page, this.query);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.iamSyncLoading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleDelete() {
|
handleDelete() {
|
||||||
if (this.selectionList.length === 0) {
|
if (this.selectionList.length === 0) {
|
||||||
this.$message.warning('请选择至少一条数据');
|
this.$message.warning('请选择至少一条数据');
|
||||||
|
|||||||
+218
-15
@@ -340,6 +340,45 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="oaSyncVisible"
|
||||||
|
width="480px"
|
||||||
|
append-to-body
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="!oaSyncRunning"
|
||||||
|
:show-close="!oaSyncRunning"
|
||||||
|
class="oa-sync-dialog"
|
||||||
|
@close="closeOaSyncDialog"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span class="dialog-title">{{ oaSyncDialogTitle }}</span>
|
||||||
|
</template>
|
||||||
|
<div class="oa-sync-body">
|
||||||
|
<el-progress
|
||||||
|
:percentage="oaSyncPercent"
|
||||||
|
:status="oaSyncProgressStatus"
|
||||||
|
:stroke-width="12"
|
||||||
|
/>
|
||||||
|
<div class="oa-sync-meta">当前进度:第 {{ oaSyncProgress.current || 0 }} / {{ oaSyncTotalPage }} 页</div>
|
||||||
|
<div class="oa-sync-stats">
|
||||||
|
<div class="oa-sync-stat">
|
||||||
|
<span class="oa-sync-stat__label">同步成功</span>
|
||||||
|
<span class="oa-sync-stat__value oa-sync-stat__value--success">{{ oaSyncProgress.synced }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="oa-sync-stat">
|
||||||
|
<span class="oa-sync-stat__label">跳过</span>
|
||||||
|
<span class="oa-sync-stat__value oa-sync-stat__value--skip">{{ oaSyncProgress.skipped }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button v-if="oaSyncRunning" @click="cancelOaSync">取消</el-button>
|
||||||
|
<el-button v-else type="primary" @click="closeOaSyncDialog">关闭</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 认证日志组件 -->
|
<!-- 认证日志组件 -->
|
||||||
<auth-log ref="authLog" />
|
<auth-log ref="authLog" />
|
||||||
<!-- 认证锁定配置组件 -->
|
<!-- 认证锁定配置组件 -->
|
||||||
@@ -403,6 +442,18 @@ export default {
|
|||||||
query: {},
|
query: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
iamSyncLoading: false,
|
iamSyncLoading: false,
|
||||||
|
oaSyncVisible: false,
|
||||||
|
oaSyncRunning: false,
|
||||||
|
oaSyncCancelled: false,
|
||||||
|
oaSyncStatus: 'running',
|
||||||
|
oaSyncController: null,
|
||||||
|
oaSyncProgress: {
|
||||||
|
current: 0,
|
||||||
|
size: 50,
|
||||||
|
total: 0,
|
||||||
|
synced: 0,
|
||||||
|
skipped: 0,
|
||||||
|
},
|
||||||
page: {
|
page: {
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
@@ -453,6 +504,46 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['userInfo', 'permission']),
|
...mapGetters(['userInfo', 'permission']),
|
||||||
|
oaSyncDialogTitle() {
|
||||||
|
if (this.oaSyncStatus === 'done') {
|
||||||
|
return '同步完成';
|
||||||
|
}
|
||||||
|
if (this.oaSyncStatus === 'cancelled') {
|
||||||
|
return '已取消同步';
|
||||||
|
}
|
||||||
|
if (this.oaSyncStatus === 'error') {
|
||||||
|
return '同步失败';
|
||||||
|
}
|
||||||
|
return '同步人员';
|
||||||
|
},
|
||||||
|
oaSyncTotalPage() {
|
||||||
|
const total = Number(this.oaSyncProgress.total) || 0;
|
||||||
|
const size = Number(this.oaSyncProgress.size) || 50;
|
||||||
|
if (total <= 0) {
|
||||||
|
return this.oaSyncProgress.current || 0;
|
||||||
|
}
|
||||||
|
return Math.max(1, Math.ceil(total / size));
|
||||||
|
},
|
||||||
|
oaSyncPercent() {
|
||||||
|
if (this.oaSyncStatus === 'done') {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
const totalPage = this.oaSyncTotalPage;
|
||||||
|
const current = Number(this.oaSyncProgress.current) || 0;
|
||||||
|
if (totalPage <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Math.min(100, Math.round((current / totalPage) * 100));
|
||||||
|
},
|
||||||
|
oaSyncProgressStatus() {
|
||||||
|
if (this.oaSyncStatus === 'done') {
|
||||||
|
return 'success';
|
||||||
|
}
|
||||||
|
if (this.oaSyncStatus === 'error') {
|
||||||
|
return 'exception';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
// 所属组织级联配置:checkStrictly 为 false 时只能选择最后一级(叶子节点)
|
// 所属组织级联配置:checkStrictly 为 false 时只能选择最后一级(叶子节点)
|
||||||
deptCascaderProps() {
|
deptCascaderProps() {
|
||||||
return {
|
return {
|
||||||
@@ -564,23 +655,87 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleIamSync() {
|
handleIamSync() {
|
||||||
this.$confirm('确定从IAM同步人员信息?', '提示', {
|
this.$confirm('确定从OA同步人员及组织信息?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
}).then(() => {
|
||||||
.then(() => {
|
this.startOaSync();
|
||||||
this.iamSyncLoading = true;
|
});
|
||||||
return syncIamAccounts();
|
},
|
||||||
})
|
startOaSync() {
|
||||||
.then(res => {
|
this.iamSyncLoading = true;
|
||||||
const count = res?.data?.data ?? 0;
|
this.oaSyncVisible = true;
|
||||||
this.$message.success(`IAM人员同步完成,共处理${count}条`);
|
this.oaSyncRunning = true;
|
||||||
|
this.oaSyncCancelled = false;
|
||||||
|
this.oaSyncStatus = 'running';
|
||||||
|
this.oaSyncController = new AbortController();
|
||||||
|
this.oaSyncProgress = {
|
||||||
|
current: 0,
|
||||||
|
size: 50,
|
||||||
|
total: 0,
|
||||||
|
synced: 0,
|
||||||
|
skipped: 0,
|
||||||
|
};
|
||||||
|
this.runOaSyncPages();
|
||||||
|
},
|
||||||
|
isOaSyncCanceledError(error) {
|
||||||
|
return (
|
||||||
|
this.oaSyncCancelled ||
|
||||||
|
error?.code === 'ERR_CANCELED' ||
|
||||||
|
error?.name === 'CanceledError' ||
|
||||||
|
error?.name === 'AbortError'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
async runOaSyncPages() {
|
||||||
|
const size = 50;
|
||||||
|
let current = 1;
|
||||||
|
try {
|
||||||
|
while (!this.oaSyncCancelled) {
|
||||||
|
const res = await syncIamAccounts(current, size, this.oaSyncController?.signal);
|
||||||
|
const page = res?.data?.data || {};
|
||||||
|
this.oaSyncProgress.current = page.current || current;
|
||||||
|
this.oaSyncProgress.size = page.size || size;
|
||||||
|
this.oaSyncProgress.total = page.total || 0;
|
||||||
|
this.oaSyncProgress.synced += page.syncedCount || 0;
|
||||||
|
this.oaSyncProgress.skipped += page.skippedCount || 0;
|
||||||
|
if (page.finished) {
|
||||||
|
this.oaSyncStatus = 'done';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current += 1;
|
||||||
|
}
|
||||||
|
if (this.oaSyncCancelled && this.oaSyncStatus === 'running') {
|
||||||
|
this.oaSyncStatus = 'cancelled';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (this.isOaSyncCanceledError(error)) {
|
||||||
|
this.oaSyncStatus = 'cancelled';
|
||||||
|
} else {
|
||||||
|
this.oaSyncStatus = 'error';
|
||||||
|
this.$message.error(error?.message || 'OA人员同步失败');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.oaSyncRunning = false;
|
||||||
|
this.iamSyncLoading = false;
|
||||||
|
if (this.oaSyncStatus === 'done' || this.oaSyncStatus === 'cancelled') {
|
||||||
this.onLoad(this.page, this.query);
|
this.onLoad(this.page, this.query);
|
||||||
})
|
}
|
||||||
.finally(() => {
|
}
|
||||||
this.iamSyncLoading = false;
|
},
|
||||||
});
|
cancelOaSync() {
|
||||||
|
if (!this.oaSyncRunning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.oaSyncCancelled = true;
|
||||||
|
this.oaSyncController?.abort();
|
||||||
|
},
|
||||||
|
closeOaSyncDialog() {
|
||||||
|
if (this.oaSyncRunning) {
|
||||||
|
this.cancelOaSync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.oaSyncVisible = false;
|
||||||
},
|
},
|
||||||
handleSetLeader(row) {
|
handleSetLeader(row) {
|
||||||
const tip = row.isLeader === 1 ? '确定取消用户的主管职务?' : '确定设置用户为主管职务?';
|
const tip = row.isLeader === 1 ? '确定取消用户的主管职务?' : '确定设置用户为主管职务?';
|
||||||
@@ -1150,14 +1305,16 @@ export default {
|
|||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-edit-dialog .dialog-title {
|
.user-edit-dialog .dialog-title,
|
||||||
|
.oa-sync-dialog .dialog-title {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-edit-dialog .dialog-title::before {
|
.user-edit-dialog .dialog-title::before,
|
||||||
|
.oa-sync-dialog .dialog-title::before {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
@@ -1165,6 +1322,52 @@ export default {
|
|||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.oa-sync-body {
|
||||||
|
padding: 8px 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oa-sync-meta {
|
||||||
|
margin-top: 12px;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oa-sync-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oa-sync-stat {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #fafafa;
|
||||||
|
border: 1px solid #eff1f7;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oa-sync-stat__label {
|
||||||
|
display: block;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oa-sync-stat__value {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oa-sync-stat__value--success {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oa-sync-stat__value--skip {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
.user-edit-dialog .el-form-item {
|
.user-edit-dialog .el-form-item {
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user