添加表单设计页面
parent
49a92b86bd
commit
e54b264bd4
|
|
@ -10,6 +10,9 @@
|
|||
/>
|
||||
<title><%= VITE_GLOB_APP_TITLE %></title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="learunui/learunui.css">
|
||||
<link rel="stylesheet" href="learunForm/lformdesign.css">
|
||||
<link rel="stylesheet" href="learunQuickBI/learun.bi.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
|
@ -154,5 +157,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
|
||||
|
||||
<script type="module" src="/public/learunui/learunui.umd.min.js" ></script>
|
||||
<script type="module" src="/public/learunForm/lformdesign.umd.min.js"></script>
|
||||
<script type="module" src="/public/learunQuickBI/learun.bi.umd.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<meta charset="utf-8">
|
||||
<title>lformdesign demo</title>
|
||||
<script src="./lformdesign.umd.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./lformdesign.css">
|
||||
|
||||
|
||||
<script>
|
||||
console.log(lformdesign)
|
||||
</script>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,10 @@
|
|||
<meta charset="utf-8">
|
||||
<title>learun.bi demo</title>
|
||||
<script src="./learun.bi.umd.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./learun.bi.css">
|
||||
|
||||
|
||||
<script>
|
||||
console.log(learun.bi)
|
||||
</script>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
|||
.l-quick-bi-design{background-color:#dcdfe6}.l-quick-bi-design__main .l-panel--title{border-bottom:0}.l-quick-bi-design__app-bar{box-sizing:border-box;background-color:#fff;position:absolute;top:8px;left:0;height:40px;width:100%;display:flex;align-items:center;padding-left:8px}.l-quick-bi-design__app-content{width:381px;height:100%;border:3px solid #000;margin:auto;background-size:contain!important;border-radius:10px;overflow:hidden auto;background-color:"#dcdfe6"}.l-quick-bi-design__main-content{background-color:#dcdfe6!important;overflow:hidden auto;background-size:480px 381px!important}.l-quick-bi-design .myComponent-title{padding:8px 2px;font-size:14px;color:#606266}.l-quick-bi-design .myComponent-item{display:inline-block;width:46%;margin:2%;transition:transform 0ms}.l-quick-bi-design .myComponent-item-body{padding:8px 10px;background:#f3f9ff;font-size:12px;cursor:move;border:1px dashed #f3f9ff;border-radius:3px;color:#043254;line-height:16px}.l-quick-bi-design .myComponent-item-icon{padding-left:8px;width:16px;color:#043254;display:inline-block}.l-quick-bi-design .myComponent-item-body:hover{border:1px dashed #409eff;color:#409eff}.l-quick-bi-design .myComponent-item-body:hover .myComponent-item-icon{color:#409eff}.l-quick-bi-design .mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.l-quick-bi-design .vue-grid-item{touch-action:none;box-sizing:border-box;border:1px solid #fff}.l-quick-bi-design .vue-grid-item.active-item{border:1px solid #409eff}.l-quick-bi-design__app-content .vue-grid-item{border-radius:8px}.l-quick-bi-design .vue-grid-item>.vue-resizable-handle{z-index:11}.l-quick-bi-design .action-clone,.l-quick-bi-design .action-delete{position:absolute;top:-10px;padding:4px;z-index:20}.l-quick-bi-design .action-clone{right:48px}.l-quick-bi-design .action-delete{right:16px}.l-quick-bi-design .component-config{box-sizing:border-box;position:relative;height:100%;width:100%;overflow:hidden auto;padding:16px;padding-bottom:8px}.l-quick-bi-viewer{background-color:#f0f2f5}.l-quick-bi-app-viewer-inner{overflow:hidden auto}.l-quick-bi-app-viewer{width:381px;padding:16px 0;margin:auto}.l-quick-bi-app-viewer .l-quick-bi-app-viewer-inner{border:3px solid #000;border-radius:8px;background-color:#dcdfe6}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,10 @@
|
|||
<meta charset="utf-8">
|
||||
<title>learunui demo</title>
|
||||
<script src="./learunui.umd.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./learunui.css">
|
||||
|
||||
|
||||
<script>
|
||||
console.log(learunui)
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,16 @@
|
|||
import { defHttp } from '@/utils/http/lraxios';
|
||||
import { DemoOptionsItem, selectParams, AccountListGetResultModel, AccountParams } from './model/index';
|
||||
|
||||
enum Api {
|
||||
OPTIONS_LIST = '/data/dataitem/details/FormSort',
|
||||
FORMS_LIST = '/custmerform/scheme/page',
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Get sample options value
|
||||
*/
|
||||
export const optionsListApi = (params?: selectParams) =>
|
||||
defHttp.get<DemoOptionsItem[]>({ url: Api.OPTIONS_LIST, params });
|
||||
|
||||
export const getFormGroupList = (params: AccountParams) =>
|
||||
defHttp.get<AccountListGetResultModel>({ url: Api.FORMS_LIST, params });
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { BasicPageParams, BasicFetchResult } from '@/api/model/baseModel';
|
||||
|
||||
export interface DemoOptionsItem {
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface selectParams {
|
||||
id: number | string;
|
||||
}
|
||||
|
||||
export type AccountParams = BasicPageParams & {
|
||||
account?: string;
|
||||
nickname?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export interface AccountListItem {
|
||||
id: string;
|
||||
account: string;
|
||||
email: string;
|
||||
nickname: string;
|
||||
role: number;
|
||||
createTime: string;
|
||||
remark: string;
|
||||
status: number;
|
||||
}
|
||||
/**
|
||||
* @description: Request list return value
|
||||
*/
|
||||
export type DemoOptionsGetResultModel = BasicFetchResult<DemoOptionsItem>;
|
||||
|
||||
export type AccountListGetResultModel = BasicFetchResult<AccountListItem>;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import lrLayout from './src/lrLayout.vue'
|
||||
|
||||
lrLayout.install = function(Vue) {
|
||||
Vue.component(lrLayout.name, lrLayout)
|
||||
}
|
||||
|
||||
export default lrLayout
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
<template>
|
||||
<div class="l-layout" :style="{'padding-left':leftWidth}">
|
||||
<div class="l-layout--left" :style="{'width':leftWidth}" >
|
||||
<div class="l-layout--wrapper" ><slot name="left"></slot></div>
|
||||
<div v-if="leftMove" class="l-layout--move" @mousedown="onMousedown('left',$event)" ></div>
|
||||
</div>
|
||||
<div class="l-layout--container" :style="{'padding-right':rightWidth}" >
|
||||
<div class="l-layout--right" :style="{ 'width':rightWidth}">
|
||||
<div class="l-layout--wrapper" ><slot name="right"></slot></div>
|
||||
<div v-if="rightMove" class="l-layout--move" @mousedown="onMousedown('right',$event)" ></div>
|
||||
</div>
|
||||
<div class="l-layout--container" :style="{'padding-bottom':bottomHight}" >
|
||||
<div class="l-layout--bottom" :style="{'height':bottomHight}" >
|
||||
<div class="l-layout--wrapper" > <slot name="bottom"></slot></div>
|
||||
<div v-if="bottomMove" class="l-layout--move" @mousedown="onMousedown('bottom',$event)" ></div>
|
||||
</div>
|
||||
<div class="l-layout--container" :style="{'padding-top':topHight}" >
|
||||
<div class="l-layout--top" :style="{'height':topHight}" >
|
||||
<div class="l-layout--wrapper" ><slot name="top"></slot></div>
|
||||
<div v-if="topMove" class="l-layout--move" @mousedown="onMousedown('top',$event)" ></div>
|
||||
</div>
|
||||
<div class="l-layout--wrapper" ref="mid">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name:'l-layout',
|
||||
props: {
|
||||
left: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
leftMove: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
right: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
rightMove:{
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
top: {
|
||||
type: Number,
|
||||
default: 60
|
||||
},
|
||||
topMove:{
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
bottom:{
|
||||
type: Number,
|
||||
default: 60
|
||||
},
|
||||
bottomMove:{
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
mleft:this.left,
|
||||
mright:this.right,
|
||||
mtop:this.top,
|
||||
mbottom:this.bottom,
|
||||
|
||||
move:{
|
||||
type:'',
|
||||
isMove:false,
|
||||
pageX:0,
|
||||
pageY:0,
|
||||
size:0,
|
||||
h:0,
|
||||
w:0,
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
watch:{
|
||||
left(val){
|
||||
this.mleft = val;
|
||||
},
|
||||
right(val){
|
||||
this.mright = val;
|
||||
},
|
||||
top(val){
|
||||
this.mtop = val;
|
||||
},
|
||||
bottom(val){
|
||||
this.mbottom = val;
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
leftWidth:function(){
|
||||
if(this.$slots.left){
|
||||
return this.mleft + 'px'
|
||||
}
|
||||
else{
|
||||
return '0'
|
||||
}
|
||||
},
|
||||
rightWidth:function(){
|
||||
if(this.$slots.right){
|
||||
return this.mright + 'px'
|
||||
}
|
||||
else{
|
||||
return '0'
|
||||
}
|
||||
},
|
||||
topHight:function(){
|
||||
if(this.$slots.top){
|
||||
return this.mtop + 'px'
|
||||
}
|
||||
else{
|
||||
return '0'
|
||||
}
|
||||
},
|
||||
bottomHight:function(){
|
||||
if(this.$slots.bottom){
|
||||
return this.mbottom + 'px'
|
||||
}
|
||||
else{
|
||||
return '0'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
onMousedown:function(type,e){
|
||||
this.move.type = type;
|
||||
this.move.isMove = true;
|
||||
this.move.pageX = e.pageX;
|
||||
this.move.pageY = e.pageY;
|
||||
this.move.size = this["m"+type];
|
||||
|
||||
this.move.h = this.$refs.mid.clientHeight;
|
||||
this.move.w = this.$refs.mid.clientWidth;
|
||||
|
||||
document.onmouseup = this.onMouseup;
|
||||
document.onmousemove = this.onMousemove;
|
||||
},
|
||||
onMousemove:function(e){
|
||||
if(this.move.isMove){
|
||||
switch(this.move.type){
|
||||
case 'left':
|
||||
var x1 = e.pageX - this.move.pageX;
|
||||
var left = this.move.size + x1;
|
||||
if(left < 0){
|
||||
left = 4;
|
||||
}
|
||||
else if(left > this.move.size + this.move.w){
|
||||
left = this.move.size + this.move.w
|
||||
}
|
||||
this.mleft = left;
|
||||
break;
|
||||
case 'right':
|
||||
var x2 = e.pageX - this.move.pageX;
|
||||
var right = this.move.size - x2;
|
||||
if(right < 0){
|
||||
right = 4;
|
||||
}
|
||||
else if(right > this.move.size + this.move.w){
|
||||
right = this.move.size + this.move.w
|
||||
}
|
||||
this.mright = right;
|
||||
break;
|
||||
case 'top':
|
||||
var y = e.pageY - this.move.pageY;
|
||||
var top = this.move.size + y;
|
||||
if(top < 0){
|
||||
top = 4;
|
||||
}
|
||||
else if(top > this.move.size + this.move.h){
|
||||
top = this.move.size + this.move.h
|
||||
}
|
||||
this.mtop = top;
|
||||
break;
|
||||
case 'bottom':
|
||||
var y2 = e.pageY - this.move.pageY;
|
||||
var bottom = this.move.size - y2;
|
||||
if(bottom < 0){
|
||||
bottom = 4;
|
||||
}
|
||||
else if(bottom > this.move.size + this.move.h){
|
||||
bottom = this.move.size + this.move.h
|
||||
}
|
||||
this.mbottom = bottom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
onMouseup:function(){
|
||||
this.move.isMove = false;
|
||||
document.onmousemove = document.onmouseup = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
// @import './index.less';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import lrPanel from './src/lrPanel.vue'
|
||||
|
||||
lrPanel.install = function(Vue) {
|
||||
Vue.component(lrPanel.name, lrPanel)
|
||||
}
|
||||
|
||||
export default lrPanel
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<div class="l-panel">
|
||||
<div class="l-panel--warpper" :style="{'padding-top':paddingTop}" >
|
||||
<div v-if="title || $slots.title" class="l-panel--title" >
|
||||
<slot name="title">{{ title }}</slot>
|
||||
</div>
|
||||
<div v-if="$slots.toolLeft || $slots.toolRight" class="l-panel--tool" :style="{'top':toolTop}" >
|
||||
<div class="l-panel--tool-left">
|
||||
<slot name="toolLeft" ></slot>
|
||||
</div>
|
||||
<div class="l-panel--tool-right">
|
||||
<slot name="toolRight" ></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-panel--body" >
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name:'l-panel',
|
||||
props: {
|
||||
title:String,
|
||||
loading:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
|
||||
},
|
||||
computed:{
|
||||
paddingTop:function(){
|
||||
var ptop = 0;
|
||||
if(this.title || this.$slots.title){
|
||||
ptop += 40;
|
||||
}
|
||||
if(this.$slots.toolLeft || this.$slots.toolRight){
|
||||
ptop += 40;
|
||||
}
|
||||
return ptop + 'px';
|
||||
},
|
||||
toolTop:function(){
|
||||
if(this.title || this.$slots.title){
|
||||
return '40px'
|
||||
}
|
||||
else{
|
||||
return '0'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
// @import './index.less';
|
||||
</style>
|
||||
|
|
@ -3,13 +3,14 @@ import type { GlobConfig } from '#/config';
|
|||
import { getAppEnvConfig } from '@/utils/env';
|
||||
|
||||
export const useGlobSetting = (): Readonly<GlobConfig> => {
|
||||
const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } =
|
||||
const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL,VITE_LR_API_URL } =
|
||||
getAppEnvConfig();
|
||||
|
||||
// Take global configuration
|
||||
const glob: Readonly<GlobConfig> = {
|
||||
title: VITE_GLOB_APP_TITLE,
|
||||
apiUrl: VITE_GLOB_API_URL,
|
||||
lrApi: VITE_LR_API_URL,
|
||||
shortName: VITE_GLOB_APP_TITLE.replace(/\s/g, '_').replace(/-/g, '_'),
|
||||
urlPrefix: VITE_GLOB_API_URL_PREFIX,
|
||||
uploadUrl: VITE_GLOB_UPLOAD_URL,
|
||||
|
|
|
|||
|
|
@ -32,12 +32,14 @@ export function getAppEnvConfig() {
|
|||
: (window[ENV_NAME] as unknown as GlobEnvConfig);
|
||||
const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } = ENV;
|
||||
let { VITE_GLOB_API_URL } = ENV;
|
||||
let { VITE_LR_API_URL } = ENV;
|
||||
if (localStorage.getItem(API_ADDRESS)) {
|
||||
const address = JSON.parse(localStorage.getItem(API_ADDRESS) || '{}');
|
||||
if (address?.key) VITE_GLOB_API_URL = address?.val;
|
||||
}
|
||||
return {
|
||||
VITE_GLOB_APP_TITLE,
|
||||
VITE_LR_API_URL,
|
||||
VITE_GLOB_API_URL,
|
||||
VITE_GLOB_API_URL_PREFIX,
|
||||
VITE_GLOB_UPLOAD_URL,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import axios from 'axios';
|
|||
const globSetting = useGlobSetting();
|
||||
const urlPrefix = globSetting.urlPrefix;
|
||||
const { createMessage, createErrorModal, createSuccessModal } = useMessage();
|
||||
|
||||
console.log('globSetting',globSetting)
|
||||
/**
|
||||
* @description: 数据处理,方便区分多种处理方式
|
||||
*/
|
||||
|
|
@ -52,7 +52,7 @@ const transform: AxiosTransform = {
|
|||
}
|
||||
// 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
|
||||
const { code, result, message } = data;
|
||||
|
||||
console.log('result',result)
|
||||
// 这里逻辑可以根据项目进行修改
|
||||
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
|
||||
if (hasSuccess) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
import type {
|
||||
AxiosRequestConfig,
|
||||
AxiosInstance,
|
||||
AxiosResponse,
|
||||
AxiosError,
|
||||
InternalAxiosRequestConfig,
|
||||
} from 'axios';
|
||||
import type { RequestOptions, Result, UploadFileParams } from '#/axios';
|
||||
import type { CreateAxiosOptions } from './axiosTransform';
|
||||
import axios from 'axios';
|
||||
import qs from 'qs';
|
||||
import { AxiosCanceler } from './axiosCancel';
|
||||
import { isFunction } from '@/utils/is';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { ContentTypeEnum, RequestEnum } from '@/enums/httpEnum';
|
||||
|
||||
export * from './axiosTransform';
|
||||
|
||||
/**
|
||||
* @description: axios module
|
||||
*/
|
||||
export class VAxios {
|
||||
private axiosInstance: AxiosInstance;
|
||||
private readonly options: CreateAxiosOptions;
|
||||
|
||||
constructor(options: CreateAxiosOptions) {
|
||||
this.options = options;
|
||||
this.axiosInstance = axios.create(options);
|
||||
this.setupInterceptors();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Create axios instance
|
||||
*/
|
||||
private createAxios(config: CreateAxiosOptions): void {
|
||||
this.axiosInstance = axios.create(config);
|
||||
}
|
||||
|
||||
private getTransform() {
|
||||
const { transform } = this.options;
|
||||
return transform;
|
||||
}
|
||||
|
||||
getAxios(): AxiosInstance {
|
||||
return this.axiosInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Reconfigure axios
|
||||
*/
|
||||
configAxios(config: CreateAxiosOptions) {
|
||||
if (!this.axiosInstance) {
|
||||
return;
|
||||
}
|
||||
this.createAxios(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Set general header
|
||||
*/
|
||||
setHeader(headers: any): void {
|
||||
if (!this.axiosInstance) {
|
||||
return;
|
||||
}
|
||||
Object.assign(this.axiosInstance.defaults.headers, headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Interceptor configuration 拦截器配置
|
||||
*/
|
||||
private setupInterceptors() {
|
||||
// const transform = this.getTransform();
|
||||
const {
|
||||
axiosInstance,
|
||||
options: { transform },
|
||||
} = this;
|
||||
if (!transform) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
requestInterceptors,
|
||||
requestInterceptorsCatch,
|
||||
responseInterceptors,
|
||||
responseInterceptorsCatch,
|
||||
} = transform;
|
||||
|
||||
const axiosCanceler = new AxiosCanceler();
|
||||
|
||||
// Request interceptor configuration processing
|
||||
this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
// If cancel repeat request is turned on, then cancel repeat request is prohibited
|
||||
const requestOptions =
|
||||
(config as unknown as any).requestOptions ?? this.options.requestOptions;
|
||||
const ignoreCancelToken = requestOptions?.ignoreCancelToken ?? true;
|
||||
|
||||
!ignoreCancelToken && axiosCanceler.addPending(config);
|
||||
|
||||
if (requestInterceptors && isFunction(requestInterceptors)) {
|
||||
config = requestInterceptors(config, this.options);
|
||||
}
|
||||
return config;
|
||||
}, undefined);
|
||||
|
||||
// Request interceptor error capture
|
||||
requestInterceptorsCatch &&
|
||||
isFunction(requestInterceptorsCatch) &&
|
||||
this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);
|
||||
|
||||
// Response result interceptor processing
|
||||
this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
|
||||
res && axiosCanceler.removePending(res.config);
|
||||
if (responseInterceptors && isFunction(responseInterceptors)) {
|
||||
res = responseInterceptors(res);
|
||||
}
|
||||
return res;
|
||||
}, undefined);
|
||||
|
||||
// Response result interceptor error capture
|
||||
responseInterceptorsCatch &&
|
||||
isFunction(responseInterceptorsCatch) &&
|
||||
this.axiosInstance.interceptors.response.use(undefined, (error) => {
|
||||
return responseInterceptorsCatch(axiosInstance, error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: File Upload
|
||||
*/
|
||||
uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) {
|
||||
const formData = new window.FormData();
|
||||
const customFilename = params.name || 'file';
|
||||
|
||||
if (params.filename) {
|
||||
formData.append(customFilename, params.file, params.filename);
|
||||
} else {
|
||||
formData.append(customFilename, params.file);
|
||||
}
|
||||
|
||||
if (params.data) {
|
||||
Object.keys(params.data).forEach((key) => {
|
||||
const value = params.data![key];
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((item) => {
|
||||
formData.append(`${key}[]`, item);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
formData.append(key, params.data![key]);
|
||||
});
|
||||
}
|
||||
return this.axiosInstance.request<T>({
|
||||
...config,
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-type': ContentTypeEnum.FORM_DATA,
|
||||
// @ts-ignore
|
||||
ignoreCancelToken: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// support form-data
|
||||
supportFormData(config: AxiosRequestConfig) {
|
||||
const headers = config.headers || this.options.headers;
|
||||
const contentType = headers?.['Content-Type'] || headers?.['content-type'];
|
||||
|
||||
if (
|
||||
contentType !== ContentTypeEnum.FORM_URLENCODED ||
|
||||
!Reflect.has(config, 'data') ||
|
||||
config.method?.toUpperCase() === RequestEnum.GET
|
||||
) {
|
||||
return config;
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
data: qs.stringify(config.data, { arrayFormat: 'brackets' }),
|
||||
};
|
||||
}
|
||||
|
||||
get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'GET' }, options);
|
||||
}
|
||||
|
||||
post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'POST' }, options);
|
||||
}
|
||||
|
||||
put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'PUT' }, options);
|
||||
}
|
||||
|
||||
delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
return this.request({ ...config, method: 'DELETE' }, options);
|
||||
}
|
||||
|
||||
request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||
let conf: CreateAxiosOptions = cloneDeep(config);
|
||||
// cancelToken 如果被深拷贝,会导致最外层无法使用cancel方法来取消请求
|
||||
if (config.cancelToken) {
|
||||
conf.cancelToken = config.cancelToken;
|
||||
}
|
||||
|
||||
if (config.signal) {
|
||||
conf.signal = config.signal;
|
||||
}
|
||||
|
||||
const transform = this.getTransform();
|
||||
|
||||
const { requestOptions } = this.options;
|
||||
|
||||
const opt: RequestOptions = Object.assign({}, requestOptions, options);
|
||||
|
||||
const { beforeRequestHook, requestCatchHook, transformResponseHook } = transform || {};
|
||||
if (beforeRequestHook && isFunction(beforeRequestHook)) {
|
||||
conf = beforeRequestHook(conf, opt);
|
||||
}
|
||||
conf.requestOptions = opt;
|
||||
|
||||
conf = this.supportFormData(conf);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.axiosInstance
|
||||
.request<any, AxiosResponse<Result>>(conf)
|
||||
.then((res: AxiosResponse<Result>) => {
|
||||
if (transformResponseHook && isFunction(transformResponseHook)) {
|
||||
try {
|
||||
const ret = transformResponseHook(res, opt);
|
||||
resolve(ret);
|
||||
} catch (err) {
|
||||
reject(err || new Error('request error!'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
resolve(res as unknown as Promise<T>);
|
||||
})
|
||||
.catch((e: Error | AxiosError) => {
|
||||
if (requestCatchHook && isFunction(requestCatchHook)) {
|
||||
reject(requestCatchHook(e, opt));
|
||||
return;
|
||||
}
|
||||
if (axios.isAxiosError(e)) {
|
||||
// rewrite error message from axios in here
|
||||
}
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import type { AxiosRequestConfig } from 'axios';
|
||||
|
||||
// 用于存储每个请求的标识和取消函数
|
||||
const pendingMap = new Map<string, AbortController>();
|
||||
|
||||
const getPendingUrl = (config: AxiosRequestConfig): string => {
|
||||
return [config.method, config.url].join('&');
|
||||
};
|
||||
|
||||
export class AxiosCanceler {
|
||||
/**
|
||||
* 添加请求
|
||||
* @param config 请求配置
|
||||
*/
|
||||
public addPending(config: AxiosRequestConfig): void {
|
||||
this.removePending(config);
|
||||
const url = getPendingUrl(config);
|
||||
const controller = new AbortController();
|
||||
config.signal = config.signal || controller.signal;
|
||||
if (!pendingMap.has(url)) {
|
||||
// 如果当前请求不在等待中,将其添加到等待中
|
||||
pendingMap.set(url, controller);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有等待中的请求
|
||||
*/
|
||||
public removeAllPending(): void {
|
||||
pendingMap.forEach((abortController) => {
|
||||
if (abortController) {
|
||||
abortController.abort();
|
||||
}
|
||||
});
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除请求
|
||||
* @param config 请求配置
|
||||
*/
|
||||
public removePending(config: AxiosRequestConfig): void {
|
||||
const url = getPendingUrl(config);
|
||||
if (pendingMap.has(url)) {
|
||||
// 如果当前请求在等待中,取消它并将其从等待中移除
|
||||
const abortController = pendingMap.get(url);
|
||||
if (abortController) {
|
||||
abortController.abort(url);
|
||||
}
|
||||
pendingMap.delete(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
public reset(): void {
|
||||
pendingMap.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { AxiosError, AxiosInstance } from 'axios';
|
||||
/**
|
||||
* 请求重试机制
|
||||
*/
|
||||
|
||||
export class AxiosRetry {
|
||||
/**
|
||||
* 重试
|
||||
*/
|
||||
retry(axiosInstance: AxiosInstance, error: AxiosError) {
|
||||
// @ts-ignore
|
||||
const { config } = error.response;
|
||||
const { waitTime, count } = config?.requestOptions?.retryRequest ?? {};
|
||||
config.__retryCount = config.__retryCount || 0;
|
||||
if (config.__retryCount >= count) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
config.__retryCount += 1;
|
||||
//请求返回后config的header不正确造成重试请求失败,删除返回headers采用默认headers
|
||||
delete config.headers;
|
||||
return this.delay(waitTime).then(() => axiosInstance(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟
|
||||
*/
|
||||
private delay(waitTime: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, waitTime));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Data processing class, can be configured according to the project
|
||||
*/
|
||||
import type {
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
AxiosResponse,
|
||||
InternalAxiosRequestConfig,
|
||||
} from 'axios';
|
||||
import type { RequestOptions, Result } from '#/axios';
|
||||
|
||||
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
||||
authenticationScheme?: string;
|
||||
transform?: AxiosTransform;
|
||||
requestOptions?: RequestOptions;
|
||||
}
|
||||
|
||||
export abstract class AxiosTransform {
|
||||
/**
|
||||
* A function that is called before a request is sent. It can modify the request configuration as needed.
|
||||
* 在发送请求之前调用的函数。它可以根据需要修改请求配置。
|
||||
*/
|
||||
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig;
|
||||
|
||||
/**
|
||||
* @description: 处理响应数据
|
||||
*/
|
||||
transformResponseHook?: (res: AxiosResponse<Result>, options: RequestOptions) => any;
|
||||
|
||||
/**
|
||||
* @description: 请求失败处理
|
||||
*/
|
||||
requestCatchHook?: (e: Error, options: RequestOptions) => Promise<any>;
|
||||
|
||||
/**
|
||||
* @description: 请求之前的拦截器
|
||||
*/
|
||||
requestInterceptors?: (
|
||||
config: InternalAxiosRequestConfig,
|
||||
options: CreateAxiosOptions,
|
||||
) => InternalAxiosRequestConfig;
|
||||
|
||||
/**
|
||||
* @description: 请求之后的拦截器
|
||||
*/
|
||||
responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>;
|
||||
|
||||
/**
|
||||
* @description: 请求之前的拦截器错误处理
|
||||
*/
|
||||
requestInterceptorsCatch?: (error: Error) => void;
|
||||
|
||||
/**
|
||||
* @description: 请求之后的拦截器错误处理
|
||||
*/
|
||||
responseInterceptorsCatch?: (axiosInstance: AxiosInstance, error: Error) => void;
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import type { ErrorMessageMode } from '#/axios';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
import { useI18n } from '@/hooks/web/useI18n';
|
||||
// import router from '@/router';
|
||||
// import { PageEnum } from '@/enums/pageEnum';
|
||||
import { useUserStoreWithOut } from '@/store/modules/user';
|
||||
import projectSetting from '@/settings/projectSetting';
|
||||
import { SessionTimeoutProcessingEnum } from '@/enums/appEnum';
|
||||
|
||||
const { createMessage, createErrorModal } = useMessage();
|
||||
const error = createMessage.error!;
|
||||
const stp = projectSetting.sessionTimeoutProcessing;
|
||||
|
||||
export function checkStatus(
|
||||
status: number,
|
||||
msg: string,
|
||||
errorMessageMode: ErrorMessageMode = 'message',
|
||||
): void {
|
||||
const { t } = useI18n();
|
||||
const userStore = useUserStoreWithOut();
|
||||
let errMessage = '';
|
||||
|
||||
switch (status) {
|
||||
case 400:
|
||||
errMessage = `${msg}`;
|
||||
break;
|
||||
// 401: Not logged in
|
||||
// Jump to the login page if not logged in, and carry the path of the current page
|
||||
// Return to the current page after successful login. This step needs to be operated on the login page.
|
||||
case 401:
|
||||
userStore.setToken(undefined);
|
||||
errMessage = msg || t('sys.api.errMsg401');
|
||||
if (stp === SessionTimeoutProcessingEnum.PAGE_COVERAGE) {
|
||||
userStore.setSessionTimeout(true);
|
||||
} else {
|
||||
userStore.logout(true);
|
||||
}
|
||||
break;
|
||||
case 403:
|
||||
errMessage = t('sys.api.errMsg403');
|
||||
break;
|
||||
// 404请求不存在
|
||||
case 404:
|
||||
errMessage = t('sys.api.errMsg404');
|
||||
break;
|
||||
case 405:
|
||||
errMessage = t('sys.api.errMsg405');
|
||||
break;
|
||||
case 408:
|
||||
errMessage = t('sys.api.errMsg408');
|
||||
break;
|
||||
case 500:
|
||||
errMessage = t('sys.api.errMsg500');
|
||||
break;
|
||||
case 501:
|
||||
errMessage = t('sys.api.errMsg501');
|
||||
break;
|
||||
case 502:
|
||||
errMessage = t('sys.api.errMsg502');
|
||||
break;
|
||||
case 503:
|
||||
errMessage = t('sys.api.errMsg503');
|
||||
break;
|
||||
case 504:
|
||||
errMessage = t('sys.api.errMsg504');
|
||||
break;
|
||||
case 505:
|
||||
errMessage = t('sys.api.errMsg505');
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (errMessage) {
|
||||
if (errorMessageMode === 'modal') {
|
||||
createErrorModal({ title: t('sys.api.errorTip'), content: errMessage });
|
||||
} else if (errorMessageMode === 'message') {
|
||||
error({ content: errMessage, key: `global_error_message_status_${status}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* @Author: 刘妍
|
||||
* @Date: 2024-01-13 13:04:15
|
||||
* @LastEditors: Do not edit
|
||||
* @LastEditTime: 2024-01-22 08:55:09
|
||||
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\utils\http\axios\helper.ts
|
||||
* @Description:
|
||||
*/
|
||||
import { isObject, isString } from '@/utils/is';
|
||||
|
||||
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
||||
|
||||
export function joinTimestamp<T extends boolean>(
|
||||
join: boolean,
|
||||
restful: T,
|
||||
): T extends true ? string : object;
|
||||
|
||||
export function joinTimestamp(join: boolean, restful = false): string | object {
|
||||
if (!join) {
|
||||
return restful ? '' : {};
|
||||
}
|
||||
// const now = new Date().getTime();
|
||||
// if (restful) {
|
||||
// return `?_t=${now}`;
|
||||
// }
|
||||
// return { _t: now };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Format request parameter time
|
||||
*/
|
||||
export function formatRequestDate(params: Recordable) {
|
||||
if (Object.prototype.toString.call(params) !== '[object Object]') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key in params) {
|
||||
const format = params[key]?.format ?? null;
|
||||
if (format && typeof format === 'function') {
|
||||
params[key] = params[key].format(DATE_TIME_FORMAT);
|
||||
}
|
||||
if (isString(key)) {
|
||||
const value = params[key];
|
||||
if (value) {
|
||||
try {
|
||||
params[key] = isString(value) ? value.trim() : value;
|
||||
} catch (error: any) {
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isObject(params[key])) {
|
||||
formatRequestDate(params[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
|
||||
// The axios configuration can be changed according to the project, just change the file, other files can be left unchanged
|
||||
|
||||
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { clone } from 'lodash-es';
|
||||
import type { RequestOptions, Result } from '#/axios';
|
||||
import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform';
|
||||
import { VAxios } from './Axios';
|
||||
import { checkStatus } from './checkStatus';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
import { RequestEnum, ResultEnum, ContentTypeEnum } from '@/enums/httpEnum';
|
||||
import { isString, isUndefined, isNull, isEmpty } from '@/utils/is';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { setObjToUrlParams, deepMerge } from '@/utils';
|
||||
import { useErrorLogStoreWithOut } from '@/store/modules/errorLog';
|
||||
import { useI18n } from '@/hooks/web/useI18n';
|
||||
import { joinTimestamp, formatRequestDate } from './helper';
|
||||
import { useUserStoreWithOut } from '@/store/modules/user';
|
||||
import { AxiosRetry } from '@/utils/http/axios/axiosRetry';
|
||||
import axios from 'axios';
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
const urlPrefix = globSetting.urlPrefix;
|
||||
const { createMessage, createErrorModal, createSuccessModal } = useMessage();
|
||||
/**
|
||||
* @description: 数据处理,方便区分多种处理方式
|
||||
*/
|
||||
const transform: AxiosTransform = {
|
||||
/**
|
||||
* @description: 处理响应数据。如果数据不是预期格式,可直接抛出错误
|
||||
*/
|
||||
transformResponseHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
|
||||
const { t } = useI18n();
|
||||
const { isTransformResponse, isReturnNativeResponse } = options;
|
||||
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
||||
if (isReturnNativeResponse) {
|
||||
return res;
|
||||
}
|
||||
// 不进行任何处理,直接返回
|
||||
// 用于页面代码可能需要直接获取code,data,message这些信息时开启
|
||||
if (!isTransformResponse) {
|
||||
return res.data;
|
||||
}
|
||||
// 错误的时候返回
|
||||
|
||||
const { data } = res;
|
||||
if (!data) {
|
||||
// return '[HTTP] Request has no return value';
|
||||
throw new Error(t('sys.api.apiRequestFailed'));
|
||||
}
|
||||
// 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
|
||||
const { code, result, message } = data;
|
||||
console.log('res',res)
|
||||
// 这里逻辑可以根据项目进行修改
|
||||
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
|
||||
if (hasSuccess) {
|
||||
let successMsg = message;
|
||||
|
||||
if (isNull(successMsg) || isUndefined(successMsg) || isEmpty(successMsg)) {
|
||||
successMsg = t(`sys.api.operationSuccess`);
|
||||
}
|
||||
|
||||
if (options.successMessageMode === 'modal') {
|
||||
createSuccessModal({ title: t('sys.api.successTip'), content: successMsg });
|
||||
} else if (options.successMessageMode === 'message') {
|
||||
createMessage.success(successMsg);
|
||||
}
|
||||
return data.data;
|
||||
}
|
||||
|
||||
// 在此处根据自己项目的实际情况对不同的code执行不同的操作
|
||||
// 如果不希望中断当前请求,请return数据,否则直接抛出异常即可
|
||||
let timeoutMsg = '';
|
||||
switch (code) {
|
||||
case ResultEnum.TIMEOUT:
|
||||
timeoutMsg = t('sys.api.timeoutMessage');
|
||||
const userStore = useUserStoreWithOut();
|
||||
userStore.logout(true);
|
||||
break;
|
||||
default:
|
||||
if (message) {
|
||||
timeoutMsg = message;
|
||||
}
|
||||
}
|
||||
|
||||
// errorMessageMode='modal'的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
|
||||
// errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示
|
||||
if (options.errorMessageMode === 'modal') {
|
||||
createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg });
|
||||
} else if (options.errorMessageMode === 'message') {
|
||||
createMessage.error(timeoutMsg);
|
||||
}
|
||||
|
||||
throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'));
|
||||
},
|
||||
|
||||
// 请求之前处理config
|
||||
beforeRequestHook: (config, options) => {
|
||||
const { lrApi, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options;
|
||||
|
||||
if (joinPrefix) {
|
||||
config.url = `${urlPrefix}${config.url}`;
|
||||
}
|
||||
|
||||
if (lrApi && isString(lrApi)) {
|
||||
config.url = `${lrApi}${config.url}`;
|
||||
}
|
||||
const params = config.params || {};
|
||||
const data = config.data || false;
|
||||
formatDate && data && !isString(data) && formatRequestDate(data);
|
||||
if (config.method?.toUpperCase() === RequestEnum.GET) {
|
||||
if (!isString(params)) {
|
||||
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
|
||||
config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));
|
||||
} else {
|
||||
// 兼容restful风格
|
||||
config.url = config.url + params + `${joinTimestamp(joinTime, true)}`;
|
||||
config.params = undefined;
|
||||
}
|
||||
} else {
|
||||
if (!isString(params)) {
|
||||
formatDate && formatRequestDate(params);
|
||||
if (
|
||||
Reflect.has(config, 'data') &&
|
||||
config.data &&
|
||||
(Object.keys(config.data).length > 0 || config.data instanceof FormData)
|
||||
) {
|
||||
config.data = data;
|
||||
config.params = params;
|
||||
} else {
|
||||
// 非GET请求如果没有提供data,则将params视为data
|
||||
config.data = params;
|
||||
config.params = undefined;
|
||||
}
|
||||
if (joinParamsToUrl) {
|
||||
config.url = setObjToUrlParams(
|
||||
config.url as string,
|
||||
Object.assign({}, config.params, config.data),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 兼容restful风格
|
||||
config.url = config.url + params;
|
||||
config.params = undefined;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
|
||||
/**
|
||||
* @description: 请求拦截器处理
|
||||
*/
|
||||
requestInterceptors: (config, options) => {
|
||||
// 请求之前处理config
|
||||
const token = getToken();
|
||||
if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
|
||||
// jwt token
|
||||
(config as Recordable).headers.Authorization = options.authenticationScheme
|
||||
? `${options.authenticationScheme} ${token}`
|
||||
: token;
|
||||
config.headers['X-Token'] = token;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
|
||||
/**
|
||||
* @description: 响应拦截器处理
|
||||
*/
|
||||
responseInterceptors: (res: AxiosResponse<any>) => {
|
||||
return res;
|
||||
},
|
||||
|
||||
/**
|
||||
* @description: 响应错误处理
|
||||
*/
|
||||
responseInterceptorsCatch: (axiosInstance: AxiosInstance, error: any) => {
|
||||
const { t } = useI18n();
|
||||
const errorLogStore = useErrorLogStoreWithOut();
|
||||
errorLogStore.addAjaxErrorInfo(error);
|
||||
const { response, code, message, config } = error || {};
|
||||
const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none';
|
||||
const msg: string = response?.data?.error?.message ?? '';
|
||||
const err: string = error?.toString?.() ?? '';
|
||||
let errMessage = '';
|
||||
|
||||
if (axios.isCancel(error)) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
try {
|
||||
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
||||
errMessage = t('sys.api.apiTimeoutMessage');
|
||||
}
|
||||
if (err?.includes('Network Error')) {
|
||||
errMessage = t('sys.api.networkExceptionMsg');
|
||||
}
|
||||
|
||||
if (errMessage) {
|
||||
if (errorMessageMode === 'modal') {
|
||||
createErrorModal({ title: t('sys.api.errorTip'), content: errMessage });
|
||||
} else if (errorMessageMode === 'message') {
|
||||
createMessage.error(errMessage);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error as unknown as string);
|
||||
}
|
||||
|
||||
checkStatus(error?.response?.status, msg, errorMessageMode);
|
||||
|
||||
// 添加自动重试机制 保险起见 只针对GET请求
|
||||
const retryRequest = new AxiosRetry();
|
||||
const { isOpenRetry } = config.requestOptions.retryRequest;
|
||||
config.method?.toUpperCase() === RequestEnum.GET &&
|
||||
isOpenRetry &&
|
||||
// @ts-ignore
|
||||
retryRequest.retry(axiosInstance, error);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
};
|
||||
|
||||
function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
||||
return new VAxios(
|
||||
// 深度合并
|
||||
deepMerge(
|
||||
{
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
||||
// authentication schemes,e.g: Bearer
|
||||
// authenticationScheme: 'Bearer',
|
||||
authenticationScheme: '',
|
||||
timeout: 10 * 1000,
|
||||
// 基础接口地址
|
||||
// baseURL: globSetting.lrApi,
|
||||
|
||||
headers: {
|
||||
'Content-Type': ContentTypeEnum.JSON,
|
||||
// 'T-Token':getToken()
|
||||
'Token':'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3MDkzMzk5OTksImV4cCI6MTcwOTM4MzE5OSwiVXNlcklkIjoiU3lzdGVtIiwiVXNlck5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50IjoiU3lzdGVtIn0.u53w_dpsFsmLA6Vq714Am-eu4yoXZC0KitExQ8X8arw'
|
||||
},
|
||||
// 如果是form-data格式
|
||||
// headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
|
||||
// 数据处理方式
|
||||
transform: clone(transform),
|
||||
// 配置项,下面的选项都可以在独立的接口请求中覆盖
|
||||
requestOptions: {
|
||||
// 默认将prefix 添加到url
|
||||
joinPrefix: true,
|
||||
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
||||
isReturnNativeResponse: false,
|
||||
// 需要对返回数据进行处理
|
||||
isTransformResponse: true,
|
||||
// post请求的时候添加参数到url
|
||||
joinParamsToUrl: false,
|
||||
// 格式化提交参数时间
|
||||
formatDate: true,
|
||||
// 消息提示类型
|
||||
errorMessageMode: 'message',
|
||||
// 接口地址
|
||||
lrApi: globSetting.lrApi,
|
||||
// 接口拼接地址
|
||||
urlPrefix: urlPrefix,
|
||||
// 是否加入时间戳
|
||||
joinTime: true,
|
||||
// 忽略重复请求
|
||||
ignoreCancelToken: true,
|
||||
// 是否携带token
|
||||
withToken: true,
|
||||
retryRequest: {
|
||||
isOpenRetry: true,
|
||||
count: 5,
|
||||
waitTime: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
opt || {},
|
||||
),
|
||||
);
|
||||
}
|
||||
export const defHttp = createAxios();
|
||||
|
||||
// other api url
|
||||
// export const otherHttp = createAxios({
|
||||
// requestOptions: {
|
||||
// lrApi: 'xxx',
|
||||
// urlPrefix: 'xxx',
|
||||
// },
|
||||
// });
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<template>
|
||||
<BasicDrawer v-bind="$attrs" @register="registerDrawer" showFooter :title="getTitle" width="50%" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicForm, useForm } from '@/components/Form';
|
||||
import { formSchema } from './menu.data';
|
||||
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
|
||||
|
||||
import { getMenuList, addMenu, editMenu, addButton, editButton } from '@/api/demo/system';
|
||||
|
||||
defineOptions({ name: 'MenuDrawer' });
|
||||
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
|
||||
const isUpdate = ref(true);
|
||||
|
||||
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
|
||||
labelWidth: 100,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
baseColProps: { lg: 12, md: 24 },
|
||||
});
|
||||
|
||||
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
|
||||
resetFields();
|
||||
setDrawerProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
|
||||
if (unref(isUpdate)) {
|
||||
setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
const treeData = await getMenuList();
|
||||
updateSchema({
|
||||
field: 'parentId',
|
||||
componentProps: { treeData },
|
||||
});
|
||||
updateSchema({
|
||||
field: 'moduleId',
|
||||
componentProps: { treeData },
|
||||
});
|
||||
});
|
||||
|
||||
const getTitle = computed(() => (!unref(isUpdate) ? '新增菜单' : '编辑菜单'));
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setDrawerProps({ confirmLoading: true });
|
||||
// TODO custom api
|
||||
console.log(values)
|
||||
if (values.type == '1') {
|
||||
console.log("新增菜单")
|
||||
delete values.type
|
||||
// 新增菜单
|
||||
if (!unref(isUpdate)) {
|
||||
const data = await addMenu(values);
|
||||
} else {
|
||||
const data = await editMenu(values);
|
||||
}
|
||||
closeDrawer();
|
||||
emit('success');
|
||||
} else {
|
||||
console.log("新增按钮")
|
||||
// 新增按钮
|
||||
delete values.type
|
||||
if (!unref(isUpdate)) {
|
||||
const data = await addButton(values);
|
||||
} else {
|
||||
const data = await editButton(values);
|
||||
}
|
||||
closeDrawer();
|
||||
emit('success');
|
||||
}
|
||||
|
||||
} finally {
|
||||
setDrawerProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div class="m-4 mr-0 overflow-hidden bg-white">
|
||||
<BasicTree ref="asyncExpandTreeRef" title="菜单列表" toolbar search
|
||||
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto" loadData :actionList="actionList"
|
||||
:renderIcon="createIcon" :clickRowToExpand="false" :treeData="treeData" :fieldNames="{ key: 'id', title: 'name' }"
|
||||
:defaultExpandAll="true" @select="handleSelect" />
|
||||
<BasicModal @register="register" title="删除" :helpMessage="['提示1', '提示2']" @ok="handleSubmit">
|
||||
确认要删除菜单吗?
|
||||
</BasicModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, h, nextTick, unref } from 'vue';
|
||||
import { BasicTree, TreeItem, TreeActionItem } from '@/components/Tree';
|
||||
import { getMenuList, deleteMenu } from '@/api/demo/system';
|
||||
import { FormOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
||||
import { BasicModal, useModal } from '@/components/Modal';
|
||||
import { router } from '@/router';
|
||||
const [register, { closeModal, openModal }] = useModal();
|
||||
defineOptions({ name: 'DeptTree' });
|
||||
|
||||
const emit = defineEmits(['select', 'edit']);
|
||||
|
||||
const treeData = ref < TreeItem[] > ([]);
|
||||
let selectItemId = ref('')
|
||||
const asyncExpandTreeRef = ref < Nullable < TreeActionType >> (null);
|
||||
|
||||
async function handleSubmit() {
|
||||
var query = [selectItemId.value]
|
||||
const data = await deleteMenu(query);
|
||||
closeModal();
|
||||
|
||||
}
|
||||
|
||||
async function fetch() {
|
||||
treeData.value = (await getMenuList()) as unknown as TreeItem[];
|
||||
// 展开全部
|
||||
nextTick(() => {
|
||||
unref(asyncExpandTreeRef)?.expandAll(true);
|
||||
});
|
||||
}
|
||||
|
||||
function handleSelect(keys) {
|
||||
emit('select', keys[0]);
|
||||
}
|
||||
const btnList = router.currentRoute.value.meta.elements
|
||||
const actionList: TreeActionItem[] = []
|
||||
btnList.forEach(element => {
|
||||
if (element.domId == 'btnEdit') {
|
||||
actionList.push({
|
||||
render: (node) => {
|
||||
return h(FormOutlined, {
|
||||
class: 'ml-2',
|
||||
onClick: () => {
|
||||
emit('edit', node);
|
||||
},
|
||||
});
|
||||
},
|
||||
})
|
||||
} else if (element.domId == 'btnDelete') {
|
||||
actionList.push({
|
||||
render: (node) => {
|
||||
return h(DeleteOutlined, {
|
||||
class: 'ml-2',
|
||||
onClick: () => {
|
||||
selectItemId.value = node.id
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
function createIcon({ level }) {
|
||||
if (level === 1) {
|
||||
return 'ion:git-compare-outline';
|
||||
}
|
||||
if (level === 2) {
|
||||
return 'ion:home';
|
||||
}
|
||||
if (level === 3) {
|
||||
return 'ion:airplane';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
onMounted(() => {
|
||||
fetch();
|
||||
});
|
||||
defineExpose({
|
||||
fetch
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
import { BasicColumn, FormSchema } from '@/components/Table';
|
||||
import { h } from 'vue';
|
||||
import { Tag } from 'ant-design-vue';
|
||||
import { getFormGroupList } from '@/api/formdesign/index';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '部门名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
// {
|
||||
// title: '排序',
|
||||
// dataIndex: 'sortNo',
|
||||
// width: 50,
|
||||
// },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
customRender: ({ record }) => {
|
||||
const status = record.status;
|
||||
const enable = ~~status === 0;
|
||||
const color = enable ? 'green' : 'red';
|
||||
const text = enable ? '启用' : '停用';
|
||||
return h(Tag, { color: color }, () => text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 180,
|
||||
},
|
||||
// {
|
||||
// title: '备注',
|
||||
// dataIndex: 'remark',
|
||||
// },
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'key',
|
||||
label: '关键字',
|
||||
component: 'Input',
|
||||
colProps: { span: 8 },
|
||||
},
|
||||
];
|
||||
export const formGroupSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'posGroupId',
|
||||
component: 'ApiSelect',
|
||||
label: '职级组',
|
||||
required: true,
|
||||
componentProps: ({ formActionType, formModel }) => {
|
||||
return {
|
||||
api: getFormGroupList, // 接口
|
||||
// 接口参数
|
||||
resultField: 'result',
|
||||
labelField: 'name',
|
||||
valueField: 'id',
|
||||
};
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '名称',
|
||||
component: 'Input',
|
||||
ifShow:false
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
label: '部门名称',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'parentId',
|
||||
label: '上级部门',
|
||||
component: 'TreeSelect',
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
key: 'id',
|
||||
value: 'id',
|
||||
},
|
||||
onChange:(value)=>{
|
||||
console.log(value)
|
||||
},
|
||||
getPopupContainer: () => document.body,
|
||||
},
|
||||
// required: true,
|
||||
},
|
||||
// {
|
||||
// field: 'orderNo',
|
||||
// label: '排序',
|
||||
// component: 'InputNumber',
|
||||
// required: true,
|
||||
// },
|
||||
{
|
||||
field: 'status',
|
||||
label: '状态',
|
||||
component: 'RadioButtonGroup',
|
||||
defaultValue: 0,
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '启用', value: 0 },
|
||||
{ label: '停用', value: 1 },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
// {
|
||||
// label: '备注',
|
||||
// field: 'remark',
|
||||
// component: 'InputTextArea',
|
||||
// },
|
||||
];
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<lrlayout class="l-tab-page">
|
||||
<template #left>
|
||||
<lrPanel style="padding-right:0;" >
|
||||
<template #title>
|
||||
{{$t('分类')}}
|
||||
<div class="tree-setting-btn">
|
||||
<Tooltip placement="top" title="设置">
|
||||
<span><SettingOutlined style="color:blue" /></span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<BasicTree ref="asyncExpandTreeRef"
|
||||
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto" loadData
|
||||
:clickRowToExpand="false" :treeData="treeData" :fieldNames="{ key: 'f_ItemId', title: 'f_ItemName' }"
|
||||
:defaultExpandAll="true" @select="handleSelect" />
|
||||
</lrPanel>
|
||||
</template>
|
||||
|
||||
<BasicTable @register="registerTable" :searchInfo="searchInfo">
|
||||
<template #toolbar>
|
||||
<a-button type="primary" @click="handleCreate"> 新增 </a-button>
|
||||
|
||||
<!-- <PermissionBtn @btnEvent="onBtnClicked"></PermissionBtn> -->
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
</lrlayout>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted, ref, nextTick, unref,reactive } from 'vue';
|
||||
|
||||
import { BasicTable, useTable, TableAction } from '@/components/Table';
|
||||
|
||||
import { getMenuList, getOrgList } from '@/api/demo/system';
|
||||
import { getFormGroupList } from '@/api/formdesign/index';
|
||||
import { optionsListApi } from '@/api/formdesign/index';
|
||||
|
||||
|
||||
import { SettingOutlined } from '@ant-design/icons-vue';
|
||||
import lrlayout from '@/components/lrLayout';
|
||||
import lrPanel from '@/components/lrPanel';
|
||||
import { BasicTree, TreeItem, TreeActionItem } from '@/components/Tree';
|
||||
|
||||
import PermissionBtn from '@/components/PermissionBtn/index.vue'
|
||||
|
||||
import { columns, searchFormSchema } from './form.data';
|
||||
|
||||
const [registerTable, { reload, getSelectRows }] = useTable({
|
||||
title: '表单列表',
|
||||
api: getFormGroupList,
|
||||
rowKey: 'id',
|
||||
// columns,
|
||||
formConfig: {
|
||||
labelWidth: 120,
|
||||
// schemas: searchFormSchema,
|
||||
},
|
||||
useSearchForm: true,
|
||||
showTableSetting: true,
|
||||
bordered: true,
|
||||
handleSearchInfoFn(info) {
|
||||
return info;
|
||||
},
|
||||
});
|
||||
|
||||
const searchInfo = reactive < Recordable > ({});
|
||||
|
||||
const treeData = ref < TreeItem[] > ([]);
|
||||
const asyncExpandTreeRef = ref < Nullable < TreeActionType >> (null);
|
||||
|
||||
async function fetch() {
|
||||
treeData.value = (await optionsListApi()) as unknown as TreeItem[];
|
||||
// 展开全部
|
||||
nextTick(() => {
|
||||
unref(asyncExpandTreeRef)?.expandAll(true);
|
||||
});
|
||||
}
|
||||
function handleSelect(keys) {
|
||||
// searchInfo.GroupId = keys[0];
|
||||
// reload();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetch();
|
||||
});
|
||||
defineExpose({
|
||||
fetch
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
import { BasicColumn, FormSchema } from '@/components/Table';
|
||||
import { h } from 'vue';
|
||||
import { Tag } from 'ant-design-vue';
|
||||
import Icon from '@/components/Icon/Icon.vue';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '按钮名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: 'DOMID',
|
||||
dataIndex: 'domId',
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort',
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
const isDir = (type: string) => type === '0';
|
||||
const isMenu = (type: string) => type === '1';
|
||||
const isButton = (type: string) => type === '2';
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'key',
|
||||
label: '关键字',
|
||||
component: 'Input',
|
||||
colProps: { span: 8 },
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'type',
|
||||
label: '类型',
|
||||
component: 'RadioButtonGroup',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
options: [
|
||||
// { label: '目录', value: '0' },
|
||||
{ label: '菜单', value: '1' },
|
||||
{ label: '按钮', value: '2' },
|
||||
],
|
||||
},
|
||||
colProps: { lg: 24, md: 24 },
|
||||
},
|
||||
{
|
||||
field: 'id',
|
||||
label: '名称',
|
||||
component: 'Input',
|
||||
ifShow:false
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
label: '名称',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'parentId',
|
||||
label: '上级',
|
||||
component: 'TreeSelect',
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
key: 'id',
|
||||
value: 'id',
|
||||
},
|
||||
getPopupContainer: () => document.body,
|
||||
},
|
||||
ifShow: ({ values }) => !isButton(values.type),
|
||||
},
|
||||
{
|
||||
field: 'moduleId',
|
||||
label: '菜单',
|
||||
component: 'TreeSelect',
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
key: 'id',
|
||||
value: 'id',
|
||||
},
|
||||
getPopupContainer: () => document.body,
|
||||
},
|
||||
ifShow: ({ values }) => isButton(values.type),
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'domId',
|
||||
label: 'DMOID',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
ifShow: ({ values }) => isButton(values.type),
|
||||
},
|
||||
{
|
||||
field: 'sortNo',
|
||||
label: '排序',
|
||||
component: 'InputNumber',
|
||||
ifShow: ({ values }) => !isButton(values.type),
|
||||
},
|
||||
{
|
||||
field: 'sort',
|
||||
label: '排序',
|
||||
component: 'InputNumber',
|
||||
ifShow: ({ values }) => isButton(values.type),
|
||||
},
|
||||
{
|
||||
field: 'class',
|
||||
helpMessage: ['参考参数值', 'success、warning、error'],
|
||||
label: '样式',
|
||||
component: 'Input',
|
||||
ifShow: ({ values }) => isButton(values.type),
|
||||
},
|
||||
{
|
||||
field: 'iconName',
|
||||
label: '图标',
|
||||
component: 'IconPicker',
|
||||
ifShow: ({ values }) => !isButton(values.type),
|
||||
},
|
||||
|
||||
{
|
||||
field: 'url',
|
||||
label: '路由地址',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
ifShow: ({ values }) => !isButton(values.type),
|
||||
},
|
||||
// {
|
||||
// field: 'component',
|
||||
// label: '组件路径',
|
||||
// component: 'Input',
|
||||
// ifShow: ({ values }) => isMenu(values.type),
|
||||
// },
|
||||
{
|
||||
field: 'code',
|
||||
label: '权限标识',
|
||||
component: 'Input',
|
||||
ifShow: ({ values }) => !isButton(values.type),
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
label: '是否系统',
|
||||
component: 'RadioButtonGroup',
|
||||
defaultValue: 1,
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '是', value: 0 },
|
||||
{ label: '否', value: 1 },
|
||||
],
|
||||
},
|
||||
ifShow: ({ values }) => !isButton(values.type),
|
||||
},
|
||||
// {
|
||||
// field: 'isExt',
|
||||
// label: '是否外链',
|
||||
// component: 'RadioButtonGroup',
|
||||
// defaultValue: '0',
|
||||
// componentProps: {
|
||||
// options: [
|
||||
// { label: '否', value: '0' },
|
||||
// { label: '是', value: '1' },
|
||||
// ],
|
||||
// },
|
||||
// ifShow: ({ values }) => !isButton(values.type),
|
||||
// },
|
||||
|
||||
// {
|
||||
// field: 'keepalive',
|
||||
// label: '是否缓存',
|
||||
// component: 'RadioButtonGroup',
|
||||
// defaultValue: '0',
|
||||
// componentProps: {
|
||||
// options: [
|
||||
// { label: '否', value: '0' },
|
||||
// { label: '是', value: '1' },
|
||||
// ],
|
||||
// },
|
||||
// ifShow: ({ values }) => isMenu(values.type),
|
||||
// },
|
||||
|
||||
// {
|
||||
// field: 'show',
|
||||
// label: '是否显示',
|
||||
// component: 'RadioButtonGroup',
|
||||
// defaultValue: '0',
|
||||
// componentProps: {
|
||||
// options: [
|
||||
// { label: '是', value: '0' },
|
||||
// { label: '否', value: '1' },
|
||||
// ],
|
||||
// },
|
||||
// ifShow: ({ values }) => !isButton(values.type),
|
||||
// },
|
||||
];
|
||||
|
|
@ -74,6 +74,7 @@
|
|||
});
|
||||
}
|
||||
async function editGroup(record: Recordable) {
|
||||
console.log('record',record)
|
||||
openDrawer(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
|
|
|
|||
Loading…
Reference in New Issue