365 lines
11 KiB
TypeScript
365 lines
11 KiB
TypeScript
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,
|
||
};
|
||
}
|