😎1、集成FastCrud低代码模式 2、升级npm依赖
This commit is contained in:
parent
ce7407a97a
commit
f4fba47aa8
@ -195,6 +195,7 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
new SysMenu{ Id=1310000000621, Pid=1310000000601, Title="代码生成", Path="/develop/codeGen", Name="sysCodeGen", Component="/system/codeGen/index", Icon="ele-Crop", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
|
||||
new SysMenu{ Id=1310000000631, Pid=1310000000601, Title="表单设计", Path="/develop/formDes", Name="sysFormDes", Component="/system/formDes/index", Icon="ele-Edit", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 },
|
||||
new SysMenu{ Id=1310000000641, Pid=1310000000601, Title="系统接口", Path="/develop/api", Name="sysApi", Component="layout/routerView/iframe", IsIframe=true, OutLink="http://localhost:5005", Icon="ele-Help", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
|
||||
new SysMenu{ Id=1310000000681, Pid=1310000000601, Title="FastCrud", Path="/develop/fastCrud", Name="sysFastCrud", Component="/system/fastCrud/index", Icon="ele-CoffeeCup", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=150},
|
||||
|
||||
new SysMenu{ Id=1310000000701, Pid=0, Title="帮助文档", Path="/doc", Name="doc", Component="Layout", Icon="ele-Notebook", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=14000 },
|
||||
new SysMenu{ Id=1310000000711, Pid=1310000000701, Title="框架教程", Path="/doc/admin", Name="sysAdmin", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="http://101.43.53.74:5050/", Icon="ele-Sunny", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
|
||||
@ -65,8 +65,11 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
// 判断密码错误次数(缓存30分钟)
|
||||
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{input.Account}";
|
||||
var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
|
||||
var passwdMaxErrorTimes = await _sysConfigService.GetConfigValue<int>(ConfigConst.SysPasswordMaxErrorTimes);
|
||||
if (passwordErrorTimes >= passwdMaxErrorTimes)
|
||||
var passwordMaxErrorTimes = await _sysConfigService.GetConfigValue<int>(ConfigConst.SysPasswordMaxErrorTimes);
|
||||
// 若未配置或误配置为0、负数, 则正确密码也无法登录
|
||||
if (passwordMaxErrorTimes < 1)
|
||||
passwordMaxErrorTimes = 1;
|
||||
if (passwordErrorTimes >= passwordMaxErrorTimes)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1027);
|
||||
|
||||
// 是否开启验证码
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"name": "admin.net.pro",
|
||||
"type": "module",
|
||||
"version": "2.4.33",
|
||||
"lastBuildTime": "2024.08.06",
|
||||
"lastBuildTime": "2024.08.07",
|
||||
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
||||
"author": "zuohuaijun",
|
||||
"license": "MIT",
|
||||
@ -15,6 +15,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@fast-crud/fast-crud": "^1.21.2",
|
||||
"@fast-crud/fast-extends": "^1.21.2",
|
||||
"@fast-crud/ui-element": "^1.21.2",
|
||||
"@fast-crud/ui-interface": "^1.21.2",
|
||||
"@iconify/vue": "^4.1.2",
|
||||
"@logicflow/core": "^1.2.28",
|
||||
"@logicflow/extension": "^1.2.28",
|
||||
"@microsoft/signalr": "^8.0.7",
|
||||
@ -47,7 +52,7 @@
|
||||
"mqtt": "^4.3.8",
|
||||
"nprogress": "^0.2.0",
|
||||
"ol": "^10.0.0",
|
||||
"pinia": "^2.2.0",
|
||||
"pinia": "^2.2.1",
|
||||
"print-js": "^1.6.0",
|
||||
"push.js": "^1.0.12",
|
||||
"qrcodejs2-fixes": "^0.0.2",
|
||||
@ -59,7 +64,7 @@
|
||||
"splitpanes": "^3.1.5",
|
||||
"vcrontab-3": "^3.3.22",
|
||||
"vform3-builds": "^3.0.10",
|
||||
"vue": "^3.4.35",
|
||||
"vue": "^3.4.36",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-demi": "0.14.6",
|
||||
"vue-draggable-plus": "^0.5.3",
|
||||
@ -70,7 +75,7 @@
|
||||
"vue-router": "^4.4.2",
|
||||
"vue-signature-pad": "^3.0.2",
|
||||
"vue3-tree-org": "^4.2.2",
|
||||
"vxe-pc-ui": "^4.0.88",
|
||||
"vxe-pc-ui": "^4.0.89",
|
||||
"vxe-table": "^4.7.59",
|
||||
"vxe-table-plugin-element": "^4.0.4",
|
||||
"vxe-table-plugin-export-xlsx": "^4.0.5",
|
||||
@ -88,7 +93,7 @@
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitejs/plugin-vue": "^5.1.2",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
||||
"@vue/compiler-sfc": "^3.4.35",
|
||||
"@vue/compiler-sfc": "^3.4.36",
|
||||
"code-inspector-plugin": "^0.15.2",
|
||||
"eslint": "^9.8.0",
|
||||
"eslint-plugin-vue": "^9.27.0",
|
||||
|
||||
@ -30,4 +30,92 @@ const app = createApp(App);
|
||||
directive(app);
|
||||
other.elSvg(app);
|
||||
|
||||
// #region FastCrud配置
|
||||
import { FastCrud } from '@fast-crud/fast-crud';
|
||||
import '@fast-crud/fast-crud/dist/style.css';
|
||||
import ui from '@fast-crud/ui-element';
|
||||
import { FsExtendsUploader, FsExtendsEditor } from '@fast-crud/fast-extends';
|
||||
import '@fast-crud/fast-extends/dist/style.css';
|
||||
app.use(ui);
|
||||
app.use(FastCrud, {
|
||||
i18n,
|
||||
commonOptions() {
|
||||
return {
|
||||
request: {
|
||||
transformQuery: ({ page, form, sort }) => {
|
||||
const order = sort == null ? {} : { orderProp: sort.prop, orderAsc: sort.asc };
|
||||
return { page: page?.currentPage, pageSize: page?.pageSize, ...form, ...order };
|
||||
},
|
||||
// page请求结果转换
|
||||
transformRes: ({ res }) => {
|
||||
const records = res.data.result.items;
|
||||
const total = res.data.result.total;
|
||||
const currentPage = res.data.result.page;
|
||||
const pageSize = res.data.result.pageSize;
|
||||
return {
|
||||
currentPage: currentPage,
|
||||
pageSize: pageSize,
|
||||
total: total,
|
||||
records,
|
||||
};
|
||||
},
|
||||
form: {
|
||||
display: 'flex', // 表单布局
|
||||
labelWidth: '120px', // 表单label宽度
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const baseURL = import.meta.env.VITE_API_URL;
|
||||
import request from '/@/utils/request';
|
||||
import { getToken } from '/@/utils/axios-utils';
|
||||
// 文件上传
|
||||
app.use(FsExtendsUploader, {
|
||||
defaultType: 'form',
|
||||
form: {
|
||||
action: baseURL + '/api/sysFile/uploadFile',
|
||||
name: 'file',
|
||||
withCredentials: false,
|
||||
uploadRequest: async (props) => {
|
||||
const { action, file, onProgress } = props;
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
const token = getToken();
|
||||
const Authorization = token ? `Bearer ${token}` : null;
|
||||
const result = await request({
|
||||
url: action,
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
Authorization: Authorization,
|
||||
},
|
||||
timeout: 60000,
|
||||
onUploadProgress(progress) {
|
||||
onProgress({ percent: Math.round((progress.loaded / progress.total!) * 100) });
|
||||
},
|
||||
});
|
||||
if (result) {
|
||||
return result.data;
|
||||
} else {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
},
|
||||
async successHandle(ret: any) {
|
||||
return {
|
||||
url: baseURL + '/' + ret.result.filePath + '/' + ret.result.id + ret.result.suffix,
|
||||
key: ret.result.fileName,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 富文本编辑器
|
||||
app.use(FsExtendsEditor, {
|
||||
wangEditor: {},
|
||||
});
|
||||
// #endregion
|
||||
|
||||
app.use(pinia).use(router).use(ElementPlus).use(setupVXETable).use(i18n).use(VueGridLayout).use(VForm3).use(VueSignaturePad).use(vue3TreeOrg).mount('#app');
|
||||
|
||||
180
Web/src/views/fastCrud/crud.tsx
Normal file
180
Web/src/views/fastCrud/crud.tsx
Normal file
@ -0,0 +1,180 @@
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { dict, compute, EditReq, DelReq, AddReq } from '@fast-crud/fast-crud';
|
||||
|
||||
import { getAPI } from '/@/utils/axios-utils';
|
||||
import { SysNoticeApi } from '/@/api-services/api';
|
||||
import { PageFileInput } from '/@/api-services/models';
|
||||
|
||||
export default function ({ expose }) {
|
||||
// 分页查询
|
||||
const pageRequest = async (query: any) => {
|
||||
const params = {
|
||||
page: query.currentPage,
|
||||
pageSize: query.pageSize,
|
||||
field: query.field,
|
||||
order: query.order,
|
||||
descStr: 'desc',
|
||||
} as PageFileInput;
|
||||
const result = await getAPI(SysNoticeApi).apiSysNoticePagePost(params);
|
||||
return result;
|
||||
};
|
||||
// 编辑
|
||||
const editRequest = async ({ form, row }: EditReq) => {
|
||||
if (form.id == null) {
|
||||
form.id = row.id;
|
||||
}
|
||||
return await getAPI(SysNoticeApi)
|
||||
.apiSysNoticeUpdatePost(form)
|
||||
.then((rsp: any) => {
|
||||
if (rsp.data.code == 200) {
|
||||
ElMessage.success('修改成功!');
|
||||
} else {
|
||||
ElMessage.error('修改失败:' + rsp.data.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 删除
|
||||
const delRequest = async ({ row }: DelReq) => {
|
||||
return await getAPI(SysNoticeApi).apiSysNoticeDeletePost(row);
|
||||
};
|
||||
// 增加
|
||||
const addRequest = async ({ form }: AddReq) => {
|
||||
return await getAPI(SysNoticeApi).apiSysNoticeAddPost(form);
|
||||
};
|
||||
// 选择
|
||||
const selectedIds = ref([]);
|
||||
const onSelectionChange = (changed: any) => {
|
||||
selectedIds.value = changed;
|
||||
};
|
||||
return {
|
||||
selectedIds,
|
||||
crudOptions: {
|
||||
container: {
|
||||
is: 'fs-layout-card',
|
||||
},
|
||||
form: {
|
||||
wrapper: {
|
||||
// is: 'el-drawer',
|
||||
// width: '80%',
|
||||
draggable: false,
|
||||
closeOnEsc: false,
|
||||
maskClosable: false,
|
||||
},
|
||||
},
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
actionbar: {},
|
||||
toolbar: {
|
||||
show: true,
|
||||
buttons: {
|
||||
search: { show: true },
|
||||
refresh: { show: true },
|
||||
compact: { show: true },
|
||||
export: { show: true },
|
||||
columns: { show: true },
|
||||
},
|
||||
},
|
||||
table: {
|
||||
scrollX: 725,
|
||||
bordered: false,
|
||||
rowKey: (row: any) => row.id,
|
||||
checkedRowKeys: selectedIds,
|
||||
'onUpdate:checkedRowKeys': onSelectionChange,
|
||||
},
|
||||
pagination: {
|
||||
show: true,
|
||||
},
|
||||
request: {
|
||||
pageRequest,
|
||||
addRequest,
|
||||
editRequest,
|
||||
delRequest,
|
||||
},
|
||||
rowHandle: {
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
buttons: {
|
||||
view: { show: true },
|
||||
edit: { show: true },
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
_checked: {
|
||||
title: '选择',
|
||||
form: { show: false },
|
||||
column: {
|
||||
type: 'selection',
|
||||
align: 'center',
|
||||
width: '55px',
|
||||
columnSetDisabled: true,
|
||||
disabled(row: any) {
|
||||
return row.account === 'gvanet';
|
||||
},
|
||||
},
|
||||
},
|
||||
type: {
|
||||
title: '类型',
|
||||
type: 'dict-select',
|
||||
search: { show: true, col: { span: 6 } },
|
||||
column: {
|
||||
align: 'center',
|
||||
width: '120px',
|
||||
},
|
||||
dict: dict({
|
||||
value: 'id',
|
||||
label: 'text',
|
||||
data: [
|
||||
{ id: '1', text: '通知' },
|
||||
{ id: '2', text: '公告' },
|
||||
],
|
||||
}),
|
||||
form: {
|
||||
col: { span: 24 },
|
||||
rule: [{ required: true, message: '请输入类型' }],
|
||||
},
|
||||
},
|
||||
title: {
|
||||
title: '标题',
|
||||
type: 'text',
|
||||
search: { show: true, col: { span: 6 } },
|
||||
column: {
|
||||
align: 'center',
|
||||
width: 'auto',
|
||||
},
|
||||
form: {
|
||||
col: { span: 24 },
|
||||
rule: [{ required: true, message: '请输入标题' }],
|
||||
},
|
||||
},
|
||||
content: {
|
||||
title: '内容',
|
||||
type: 'editor-wang5',
|
||||
search: { show: false, col: { span: 6 } },
|
||||
column: {
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
col: { span: 24 },
|
||||
rule: [{ required: true, message: '请输入内容' }],
|
||||
component: {
|
||||
disabled: compute(({ form }) => {
|
||||
return form.disabled;
|
||||
}),
|
||||
id: '1', // 当同一个页面有多个editor时,需要配置不同的id
|
||||
config: {},
|
||||
uploader: {
|
||||
type: 'form',
|
||||
buildUrl(res: any) {
|
||||
return res.url;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
66
Web/src/views/fastCrud/index.vue
Normal file
66
Web/src/views/fastCrud/index.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div class="h-full">
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||
<template #pagination-left>
|
||||
<fs-button icon="ion:trash-outline" @click="handleBatchDelete" />
|
||||
</template>
|
||||
<template #cell_url="scope">
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-button> 预览 </n-button>
|
||||
</template>
|
||||
<n-image width="120px" height="120px" :src="baseURL + '/' + scope.row.url"></n-image>
|
||||
</n-tooltip>
|
||||
</template>
|
||||
</fs-crud>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref } from 'vue';
|
||||
import { useExpose, useCrud } from '@fast-crud/fast-crud';
|
||||
import createCrudOptions from './crud';
|
||||
|
||||
const baseURL = import.meta.env.VITE_API_URL;
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FastCrud',
|
||||
setup() {
|
||||
const crudRef = ref();
|
||||
const crudBinding = ref();
|
||||
const { expose } = useExpose({ crudRef, crudBinding });
|
||||
const { crudOptions, selectedIds } = createCrudOptions({ expose });
|
||||
const { resetCrudOptions } = useCrud({ expose, crudOptions });
|
||||
|
||||
// 页面初始化
|
||||
onMounted(() => {
|
||||
expose.doRefresh();
|
||||
});
|
||||
// 批量删除
|
||||
const handleBatchDelete = async () => {
|
||||
if (selectedIds.value?.length > 0) {
|
||||
// ElMessageBox.confirm(`确定要批量删除这${selectedIds.value.length}条记录吗`, '确认', {
|
||||
// confirmButtonText: '确定',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'info',
|
||||
// }).then(async () => {
|
||||
// await delBatchSysFile(selectedIds.value);
|
||||
// message.success('删除成功');
|
||||
// selectedIds.value = [];
|
||||
// await expose.doRefresh();
|
||||
// ElMessage.success('删除成功');
|
||||
// })
|
||||
// .catch(() => { });
|
||||
} else {
|
||||
// ElMessage.success('请勾选要删除的记录');
|
||||
}
|
||||
};
|
||||
return {
|
||||
crudBinding,
|
||||
crudRef,
|
||||
handleBatchDelete,
|
||||
baseURL,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
Loading…
Reference in New Issue
Block a user