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.
365 lines
11 KiB
365 lines
11 KiB
7 months ago
|
import { createVNode, inject } from 'vue';
|
||
|
import { NsMessage } from '../component/message';
|
||
|
import { NsModal } from '../component/modal';
|
||
|
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||
|
import { useRouter, useRoute } from 'vue-router';
|
||
|
import { cloneDeep, isBoolean, isEmpty, isFunction, isString, isUndefined } from 'lodash-es';
|
||
|
import { useParams } from '/nerv-lib/use/use-params';
|
||
|
import { usePath } from '/nerv-lib/use/use-path';
|
||
|
import { useApi } from '/nerv-lib/use/use-api';
|
||
|
import type { AxiosRequestConfig } from 'axios';
|
||
|
import { authorizationService } from '/nerv-base/store/modules/authorization-service';
|
||
|
import { stringUtil } from '/nerv-lib/util/string-util';
|
||
|
import { appConfigStore } from '/nerv-base/store/modules/app-config';
|
||
|
import { xlsxExport, xlsxImport } from '/nerv-lib/util/xlsx-util';
|
||
|
|
||
|
export interface Confirm {
|
||
|
title: string; // 弹窗标题
|
||
|
content: string; // 弹窗内容
|
||
|
icon: string; //弹窗图标
|
||
|
okButtonProps: object;
|
||
|
okText: string; //确定按钮文本
|
||
|
}
|
||
|
export interface Action {
|
||
|
label: string; //操作中文名
|
||
|
name: string; //操作英文名
|
||
|
openPermission?: boolean; // true则不鉴权
|
||
|
checkApi?: string | Function | AxiosRequestConfig; // 检查api
|
||
|
checkDynamicParams?: string | Array<string> | object; //check api传参 || url传参
|
||
|
checkDefaultParams?: object; //check默认参数 固定值
|
||
|
route?: string | Recordable; // 配置了路由则直接跳转
|
||
|
confirm?: boolean | Confirm; //先弹窗再操作, true则使用默认显示方案
|
||
|
showSuccess?: Boolean;
|
||
|
api?: string | Function | AxiosRequestConfig; // 自动请求api
|
||
|
dynamicParams?: string | Array<string> | object; //api传参 || url传参
|
||
|
defaultParams?: object; //默认参数 固定值
|
||
|
handle?: Function; //自定义回调,路由模式不触发
|
||
|
finalHandle?: Function; //最终执行的函数
|
||
|
ifShow?: boolean | Function; //显示依赖
|
||
|
type?: string; //按钮 primary | ghost | dashed | link | text | default
|
||
|
dynamicDisabled?: boolean | Function;
|
||
|
isReload?: boolean;
|
||
|
state?: String; // edit 为编辑态 其他为编辑中
|
||
|
extra?: Recordable;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* step1:检测route,有则直接跳转。
|
||
|
* step2:检测api,有则设置handle先行请求api,请求成功,有默认handle则执行。
|
||
|
* step3:检测confirm,有则先弹窗,再执行step2
|
||
|
*/
|
||
|
interface actionParams {
|
||
|
reload?: Function;
|
||
|
}
|
||
|
export function useAction(actionParams: actionParams = {}) {
|
||
|
const router = useRouter();
|
||
|
const route = useRoute();
|
||
|
const { reload } = actionParams;
|
||
|
const { getPath } = usePath();
|
||
|
const { httpRequest } = useApi();
|
||
|
const authService = authorizationService();
|
||
|
const appConfig = appConfigStore();
|
||
|
|
||
|
//todo 类型定义需简化
|
||
|
const { tableEdit, tableSave, tableCancel, addRow, validate, getValue, getKey, tableDelete } =
|
||
|
inject('tableEdit', {
|
||
|
tableEdit: () => {},
|
||
|
tableSave: () => {},
|
||
|
tableCancel: () => {},
|
||
|
addRow: () => {},
|
||
|
validate: () => {},
|
||
|
getValue: () => {},
|
||
|
getKey: () => {},
|
||
|
tableDelete: () => {},
|
||
|
}) as {
|
||
|
tableEdit: Function;
|
||
|
tableSave: Function;
|
||
|
tableCancel: Function;
|
||
|
addRow: Function;
|
||
|
validate: Function;
|
||
|
getValue: Function;
|
||
|
getKey: Function;
|
||
|
tableDelete: Function;
|
||
|
};
|
||
|
|
||
|
function isIfShow(action: Action, data: any): boolean {
|
||
|
const ifShow = action.ifShow;
|
||
|
if (isBoolean(ifShow)) return ifShow;
|
||
|
if (isFunction(ifShow)) return ifShow(data);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function hasPermission(action: Action, data: any) {
|
||
|
//todo 临时处理saas不鉴权
|
||
|
if (__APP_INFO__.serviceMode === 'saas') {
|
||
|
if (action.children) {
|
||
|
return true;
|
||
|
}
|
||
|
if (action.openPermission) return true;
|
||
|
|
||
|
return authService.checkAllPermission(action.name);
|
||
|
}
|
||
|
if (action.openPermission) return true;
|
||
|
if (!appConfig.actionPermission) {
|
||
|
return true;
|
||
|
}
|
||
|
if (isUndefined(route.name) || isUndefined(route.matched[0].name)) {
|
||
|
console.error('route name is required');
|
||
|
}
|
||
|
const { projectName } = route.params;
|
||
|
//处理IASSAction判断
|
||
|
if (data && data.viewInfo && Array.isArray(data.viewInfo.actions)) {
|
||
|
return data.viewInfo.actions.includes(action.name);
|
||
|
} else {
|
||
|
return authService.checkPermission(
|
||
|
route.meta?.app ? route.meta?.app : (route.matched[0].name as string),
|
||
|
route.meta?.bindView ? route.meta?.bindView : (route.name as string),
|
||
|
stringUtil.firstToLower(
|
||
|
action.name.replace(
|
||
|
route.meta?.bindView ? route.meta?.bindView : (route.name as string),
|
||
|
'',
|
||
|
),
|
||
|
),
|
||
|
data.projectName || projectName,
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function filterAction(action: Action, data: any) {
|
||
|
const { state } = action;
|
||
|
let stateShow = true;
|
||
|
if (state && state !== 'add') {
|
||
|
if (getValue(getKey(data))) {
|
||
|
stateShow = state === 'edit' || isUndefined(state) ? false : true;
|
||
|
} else {
|
||
|
stateShow = state === 'edit' || isUndefined(state) ? true : false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return stateShow && hasPermission(action, data) && isIfShow(action, data);
|
||
|
}
|
||
|
|
||
|
function filterActionNoAuth(action: Action, data: any) {
|
||
|
const { state } = action;
|
||
|
let stateShow = true;
|
||
|
if (state && state !== 'add') {
|
||
|
if (getValue(getKey(data))) {
|
||
|
stateShow = state === 'edit' || isUndefined(state) ? false : true;
|
||
|
} else {
|
||
|
stateShow = state === 'edit' || isUndefined(state) ? true : false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return stateShow && isIfShow(action, data);
|
||
|
}
|
||
|
|
||
|
function transformAction(action: Action, data: any) {
|
||
|
const {
|
||
|
label,
|
||
|
name,
|
||
|
state,
|
||
|
route: toRoute,
|
||
|
api,
|
||
|
dynamicParams,
|
||
|
defaultParams,
|
||
|
showSuccess,
|
||
|
confirm,
|
||
|
checkApi,
|
||
|
checkDynamicParams,
|
||
|
checkDefaultParams,
|
||
|
handle,
|
||
|
isReload = false,
|
||
|
extra,
|
||
|
} = action;
|
||
|
const { getParams } = useParams();
|
||
|
const tableDynamicDisabledAction = ['deletes', 'exports']; //表格默认动态禁用操作
|
||
|
let { dynamicDisabled } = action;
|
||
|
const extraData = { router, reload, action }; // handle传出数据
|
||
|
if (tableDynamicDisabledAction.includes(name)) {
|
||
|
dynamicDisabled = (data: any) => {
|
||
|
return data.list.length === 0;
|
||
|
};
|
||
|
}
|
||
|
if (dynamicDisabled) {
|
||
|
if (isFunction(dynamicDisabled)) {
|
||
|
action.dynamicDisabled = dynamicDisabled(data);
|
||
|
}
|
||
|
} else {
|
||
|
action.dynamicDisabled = false;
|
||
|
}
|
||
|
|
||
|
if (state === 'edit') {
|
||
|
action.finalHandle = () => {
|
||
|
tableEdit(getKey(data));
|
||
|
};
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
if (state === 'save') {
|
||
|
action.finalHandle = () => {
|
||
|
console.log('save', getKey(data));
|
||
|
|
||
|
validate(getKey(data))
|
||
|
.then(() => {
|
||
|
tableSave(getKey(data));
|
||
|
})
|
||
|
.catch((_: any) => {});
|
||
|
};
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
if (state === 'cancel') {
|
||
|
action.finalHandle = () => {
|
||
|
console.log('cancel', getKey(data));
|
||
|
tableCancel(getKey(data));
|
||
|
};
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
if (state === 'delete') {
|
||
|
action.finalHandle = () => {
|
||
|
console.log("state === 'delete'", getKey(data));
|
||
|
|
||
|
tableDelete(getKey(data));
|
||
|
};
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
if (state === 'add') {
|
||
|
action.finalHandle = () => {
|
||
|
addRow(data);
|
||
|
};
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
const handleList: Recordable = {
|
||
|
confirm: null,
|
||
|
checkApi: null,
|
||
|
route: null,
|
||
|
api: null,
|
||
|
handle,
|
||
|
isReload,
|
||
|
};
|
||
|
let modelInstance: Recordable = {};
|
||
|
if (name && name.toLowerCase().includes('exports')) {
|
||
|
action.finalHandle = () => {
|
||
|
xlsxExport({ data: data.list, ...extra } as any);
|
||
|
};
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
if (name && name.toLowerCase().includes('import')) {
|
||
|
if (!action.handle) {
|
||
|
action.finalHandle = () => {
|
||
|
xlsxImport({ ...extra, reload } as any);
|
||
|
};
|
||
|
return action;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function routeGo(toRoute: any) {
|
||
|
const query = getParams(data, dynamicParams, defaultParams);
|
||
|
|
||
|
if (isString(toRoute)) {
|
||
|
router.push({ path: getPath(toRoute, data), query });
|
||
|
} else {
|
||
|
if (toRoute.path) {
|
||
|
toRoute.path = getPath(toRoute.path, data);
|
||
|
toRoute.query = query;
|
||
|
}
|
||
|
if (toRoute.name) {
|
||
|
toRoute.query = query;
|
||
|
}
|
||
|
router.push(toRoute);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (checkApi) {
|
||
|
handleList.checkApi = () => {
|
||
|
const params = getParams(data, checkDynamicParams, checkDefaultParams);
|
||
|
const requestConfig: AxiosRequestConfig = { method: 'get' };
|
||
|
return httpRequest({ api: checkApi, params, pathParams: data, requestConfig });
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (api) {
|
||
|
handleList.api = () => {
|
||
|
const params = getParams(data, dynamicParams, defaultParams);
|
||
|
const requestConfig: AxiosRequestConfig = { method: 'post' };
|
||
|
if (__APP_INFO__.serviceMode === 'saas') {
|
||
|
if (requestConfig.headers) {
|
||
|
requestConfig.headers.resourceCode = action.name;
|
||
|
} else {
|
||
|
requestConfig.headers = {
|
||
|
resourceCode: action.name,
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
console.log('eeee', requestConfig);
|
||
|
return httpRequest({ api, params, pathParams: data, requestConfig }).then(() => {
|
||
|
showSuccess !== false && NsMessage.success(`${label}成功`);
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//todo router name支持
|
||
|
if (toRoute) {
|
||
|
handleList.route = () => {
|
||
|
return routeGo(toRoute);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
const modeUpdate = (prop: Recordable) => {
|
||
|
if (!isEmpty(modelInstance)) {
|
||
|
modelInstance.update(prop);
|
||
|
}
|
||
|
};
|
||
|
action.finalHandle = async () => {
|
||
|
modeUpdate({
|
||
|
okButtonProps: {
|
||
|
disabled: true,
|
||
|
},
|
||
|
});
|
||
|
if (handleList.checkApi) await handleList.checkApi();
|
||
|
if (handleList.route) return handleList.route();
|
||
|
if (handleList.api) await handleList.api();
|
||
|
// handleList.api && showSuccess !== false && NsMessage.success(`${label}成功`);
|
||
|
if (handleList.handle) await handleList.handle(data, name, { ...extraData });
|
||
|
if (isReload) {
|
||
|
isFunction(reload) && reload();
|
||
|
}
|
||
|
setTimeout(() => {
|
||
|
modeUpdate({
|
||
|
okButtonProps: {
|
||
|
disabled: false,
|
||
|
},
|
||
|
});
|
||
|
}, 100);
|
||
|
};
|
||
|
|
||
|
if (confirm) {
|
||
|
const _finalHandle: any = action.finalHandle;
|
||
|
const { title, content, icon, okText, okButtonProps } = confirm as Confirm;
|
||
|
action.finalHandle = () => {
|
||
|
modelInstance = NsModal.confirm({
|
||
|
title: title || '警告',
|
||
|
content: content || `确定要${label}吗?`,
|
||
|
icon: icon || createVNode(ExclamationCircleOutlined),
|
||
|
okText: okText || '确认',
|
||
|
cancelText: '取消',
|
||
|
okButtonProps,
|
||
|
onOk: _finalHandle,
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
filterAction,
|
||
|
filterActionNoAuth,
|
||
|
transformAction,
|
||
|
};
|
||
|
}
|