Compare commits

...

15 Commits

Author SHA1 Message Date
GitHub Actions Bot
2fd75fe097 🔱: [client] sync upgrade with 6 commits [trident-sync]
build: publish success
perf: antdv示例背景设置为白色
fix: card布局情况下,header-top header-bottom同时跟search显隐的bug
fix: 修复table-select 示例右上角自定义插槽无法设置的bug
feat: 将代码编辑器单独打包到@fast-crud/editor-code,加快不需要code的项目的打包速度,如果您使用了editor-code,请按照文档重新进行editor-code的集成

BREAKING CHANGE: 将代码编辑器单独打包到@fast-crud/editor-code,,如果您使用了editor-code,请按照文档重新进行editor-code的集成
2025-07-28 19:27:48 +00:00
GitHub Actions Bot
76b963f426 🔱: [client] sync upgrade with 2 commits [trident-sync]
fix: 独立使用form表单缺失mode的问题
2025-07-25 19:27:15 +00:00
GitHub Actions Bot
85cbc16c53 🔱: [client] sync upgrade with 3 commits [trident-sync]
build: publish success
fix: 修复fs-values-format组件某些值无法获取自动颜色的bug
2025-06-10 19:25:46 +00:00
GitHub Actions Bot
f802b4c2dd 🔱: [client] sync upgrade with 2 commits [trident-sync]
chore: 增加打开对话框示例
2025-05-28 19:25:49 +00:00
GitHub Actions Bot
957d9d8307 🔱: [client] sync upgrade with 4 commits [trident-sync]
build: publish success
fix: 修复cloneable模式下的dict 无法动态修改data的bug
chore:
2025-05-26 19:25:13 +00:00
GitHub Actions Bot
407b11fdf9 🔱: [client] sync upgrade with 3 commits [trident-sync]
build: publish success
chore:
2025-05-14 19:25:07 +00:00
GitHub Actions Bot
f0b5489e3e 🔱: [client] sync upgrade with 4 commits [trident-sync]
perf: 单元格支持tooltip
Merge remote-tracking branch 'origin/main'

# Conflicts:
#	src/plugin/antdv-async/index.ts
fix: 修复naive-ui下 form-item 的label设置为render会报警告的问题
2025-04-28 19:25:14 +00:00
GitHub Actions Bot
7bb8e9bdc4 🔱: [client] sync upgrade with 3 commits [trident-sync]
build: publish success
perf: 优化antdv单元格合并示例,使用customCell方法,以及增加操作列合并演示
2025-04-25 19:25:06 +00:00
GitHub Actions Bot
c7a3bc9eac 🔱: [client] sync upgrade with 2 commits [trident-sync]
perf: 新增editable-select组件
2025-04-23 19:25:19 +00:00
GitHub Actions Bot
ec01f47b98 🔱: [client] sync upgrade with 4 commits [trident-sync]
build: publish success
fix: 修复yaml workers引入问题
fix: 修复预览大图previewurl错误的bug
2025-04-16 19:25:11 +00:00
GitHub Actions Bot
dde43bbe4d 🔱: [client] sync upgrade with 8 commits [trident-sync]
build: publish success
chore:
chore:
chore:
fix: 修复commonOptions无法覆盖某些参数的bug
chore: yaml-worker挪到外面
fix: fs-editor-code 支持配置schema校验
2025-04-10 19:24:40 +00:00
GitHub Actions Bot
34aea1d398 🔱: [client] sync upgrade with 2 commits [trident-sync]
perf: 添加代码编辑器示例
2025-03-31 19:25:06 +00:00
GitHub Actions Bot
88a4e5051b 🔱: [client] sync upgrade with 6 commits [trident-sync]
chore:
build: publish success
fix: 修复新页面编辑无法正确获取数据的bug

Closes https://github.com/fast-crud/fast-crud/issues/460
fix: 修复antdv4示例没有源码跳转按钮的bug
pref: 添加代码编辑器功能

- 新增 fs-editor-code组件实现代码编辑功能
- 支持 javascript、json、yaml三种语言
- 集成 monaco-editor 并配置相关 worker
- 添加代码格式校验功能
- 在 fast-extends 中引入新功能模块
2025-03-30 19:24:09 +00:00
GitHub Actions Bot
6f30d82394 🔱: [client] sync upgrade with 2 commits [trident-sync]
chore: trace
2025-03-27 19:24:52 +00:00
GitHub Actions Bot
d2652baf22 🔱: [client] sync upgrade with 4 commits [trident-sync]
build: publish success
build: publish success
perf: antdv示例增加保存列宽功能
2025-03-19 19:25:03 +00:00
40 changed files with 667 additions and 79 deletions

View File

@@ -3,6 +3,87 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.26.0](https://github.com/fast-crud/fast-crud/compare/v1.25.13...v1.26.0) (2025-07-28)
### Bug Fixes
* 独立使用form表单缺失mode的问题 ([9ed791a](https://github.com/fast-crud/fast-crud/commit/9ed791ad4bb9294f4b9380d858df89fbc32ca2a0))
* 修复table-select 示例右上角自定义插槽无法设置的bug ([54a5d90](https://github.com/fast-crud/fast-crud/commit/54a5d90b86338036474657267de3bd7a74caf1eb))
* card布局情况下header-top header-bottom同时跟search显隐的bug ([3484232](https://github.com/fast-crud/fast-crud/commit/348423280f06f052fb16214e863ba03735ff9042))
### Performance Improvements
* antdv示例背景设置为白色 ([3d74bf4](https://github.com/fast-crud/fast-crud/commit/3d74bf4e7ca76ecad286ec8f1b8fd2cbcb6428eb))
## [1.25.13](https://github.com/fast-crud/fast-crud/compare/v1.25.12...v1.25.13) (2025-06-10)
### Bug Fixes
* 修复fs-values-format组件某些值无法获取自动颜色的bug ([18169fc](https://github.com/fast-crud/fast-crud/commit/18169fc11f37595b8fba96467f0c741fe898ad21))
## [1.25.12](https://github.com/fast-crud/fast-crud/compare/v1.25.11...v1.25.12) (2025-05-26)
### Bug Fixes
* 修复cloneable模式下的dict 无法动态修改data的bug ([1dd5cd1](https://github.com/fast-crud/fast-crud/commit/1dd5cd1e1445b126451c6e1b68f453a70bf920de))
## [1.25.11](https://github.com/fast-crud/fast-crud/compare/v1.25.10...v1.25.11) (2025-05-14)
### Bug Fixes
* 修复naive-ui下 form-item 的label设置为render会报警告的问题 ([45e1bc6](https://github.com/fast-crud/fast-crud/commit/45e1bc6d9cfc408a98dfe628bf3b9bd14af4b2cf))
### Performance Improvements
* 单元格支持tooltip ([44d83ad](https://github.com/fast-crud/fast-crud/commit/44d83ad890589b2b64ff5e9f869fc04863576a3b))
## [1.25.10](https://github.com/fast-crud/fast-crud/compare/v1.25.9...v1.25.10) (2025-04-25)
### Performance Improvements
* 新增editable-select组件 ([8681285](https://github.com/fast-crud/fast-crud/commit/86812851de435cb2406d06898396c368d5eda414))
* 优化antdv单元格合并示例使用customCell方法以及增加操作列合并演示 ([1068f9a](https://github.com/fast-crud/fast-crud/commit/1068f9aaa9b7732acb7082cc2ce3b1fadf1f8521))
## [1.25.9](https://github.com/fast-crud/fast-crud/compare/v1.25.8...v1.25.9) (2025-04-16)
### Bug Fixes
* 修复预览大图previewurl错误的bug ([cfb6554](https://github.com/fast-crud/fast-crud/commit/cfb6554c7c93297ddfcaa206168aceaf4ba2c2ef))
* 修复yaml workers引入问题 ([1c90198](https://github.com/fast-crud/fast-crud/commit/1c90198f6f7df0ac0c9845d1c6af0592b1c34ae3))
## [1.25.8](https://github.com/fast-crud/fast-crud/compare/v1.25.7...v1.25.8) (2025-04-10)
### Bug Fixes
* 修复commonOptions无法覆盖某些参数的bug ([f2ecc03](https://github.com/fast-crud/fast-crud/commit/f2ecc034bf5b38d668ee8366c903a824af34302c))
* fs-editor-code 支持配置schema校验 ([7d342cb](https://github.com/fast-crud/fast-crud/commit/7d342cbe8ebbaebb6ff5b3b80ce977d87aaa9ba5))
### Performance Improvements
* 添加代码编辑器示例 ([7217460](https://github.com/fast-crud/fast-crud/commit/72174604735b90fc57e0fb1ce40cc380b6c0c351))
## [1.25.7](https://github.com/fast-crud/fast-crud/compare/v1.25.6...v1.25.7) (2025-03-30)
### Bug Fixes
* 修复新页面编辑无法正确获取数据的bug ([e0df772](https://github.com/fast-crud/fast-crud/commit/e0df7729d0d8fff7a0bcd81477ec9379f6f23369))
* 修复antdv4示例没有源码跳转按钮的bug ([a8f6486](https://github.com/fast-crud/fast-crud/commit/a8f6486bccc441bb394ae5fb8bbe515de78f83d3))
## [1.25.6](https://github.com/fast-crud/fast-crud/compare/v1.25.5...v1.25.6) (2025-03-19)
**Note:** Version bump only for package @fast-crud/fs-admin-antdv4
## [1.25.5](https://github.com/fast-crud/fast-crud/compare/v1.25.4...v1.25.5) (2025-03-19)
### Bug Fixes
* 修复 antdv 弹出菜单边框过大的问题 ([fe4a044](https://github.com/fast-crud/fast-crud/commit/fe4a0442bf8fcdc3120b6de788ff318933b6bfab))
* 修复 antdv懒加载后dropdown按钮无法点击的bug ([30ee067](https://github.com/fast-crud/fast-crud/commit/30ee067580fb663bbe550d50abf63c1fd89504a1))
### Performance Improvements
* antdv示例增加保存列宽功能 ([a1218b0](https://github.com/fast-crud/fast-crud/commit/a1218b0451eb73fae8e337128e79b6e1fd4184eb))
## [1.25.4](https://github.com/fast-crud/fast-crud/compare/v1.25.3...v1.25.4) (2025-03-04) ## [1.25.4](https://github.com/fast-crud/fast-crud/compare/v1.25.3...v1.25.4) (2025-03-04)
### Performance Improvements ### Performance Improvements

View File

@@ -1,6 +1,6 @@
{ {
"name": "@fast-crud/fs-admin-antdv4", "name": "@fast-crud/fs-admin-antdv4",
"version": "1.25.4", "version": "1.26.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -27,10 +27,11 @@
"@aws-sdk/client-s3": "^3.535.0", "@aws-sdk/client-s3": "^3.535.0",
"@aws-sdk/s3-request-presigner": "^3.535.0", "@aws-sdk/s3-request-presigner": "^3.535.0",
"@ctrl/tinycolor": "^4.1.0", "@ctrl/tinycolor": "^4.1.0",
"@fast-crud/fast-crud": "^1.25.4", "@fast-crud/editor-code": "^1.26.0",
"@fast-crud/fast-extends": "^1.25.4", "@fast-crud/fast-crud": "^1.26.0",
"@fast-crud/ui-antdv4": "^1.25.4", "@fast-crud/fast-extends": "^1.26.0",
"@fast-crud/ui-interface": "^1.25.4", "@fast-crud/ui-antdv4": "^1.26.0",
"@fast-crud/ui-interface": "^1.26.0",
"@iconify/tailwind": "^1.2.0", "@iconify/tailwind": "^1.2.0",
"@iconify/vue": "^4.1.1", "@iconify/vue": "^4.1.1",
"@manypkg/get-packages": "^2.2.2", "@manypkg/get-packages": "^2.2.2",
@@ -56,9 +57,12 @@
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"defu": "^6.1.4", "defu": "^6.1.4",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"js-yaml": "^4.1.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"lucide-vue-next": "^0.477.0", "lucide-vue-next": "^0.477.0",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"monaco-editor": "^0.52.2",
"monaco-yaml": "^5.3.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
"pinia": "2.1.7", "pinia": "2.1.7",
@@ -80,6 +84,7 @@
"vue-router": "^4.3.0", "vue-router": "^4.3.0",
"vuedraggable": "^2.24.3", "vuedraggable": "^2.24.3",
"watermark-js-plus": "^1.5.8", "watermark-js-plus": "^1.5.8",
"yaml-language-server": "^1.17.0",
"zod": "^3.24.2", "zod": "^3.24.2",
"zod-defaults": "^0.1.3" "zod-defaults": "^0.1.3"
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -40,6 +40,7 @@ export default defineComponent({
position: fixed; position: fixed;
right: 3px; right: 3px;
bottom: 20px; bottom: 20px;
z-index: 1000;
.fs-source-link { .fs-source-link {
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { BasicLayout, LockScreen, UserDropdown } from "/@/vben/layouts"; import { BasicLayout, LockScreen, UserDropdown } from "/@/vben/layouts";
import FsSourceLink from "./components/source-link/index.vue";
import { computed } from "vue"; import { computed } from "vue";
import { VBEN_DOC_URL } from "/@/vben/constants"; import { VBEN_DOC_URL } from "/@/vben/constants";
import { BookOpenText } from "/@/vben/icons"; import { BookOpenText } from "/@/vben/icons";
@@ -43,5 +43,8 @@ async function handleLogout() {
<template #lock-screen> <template #lock-screen>
<LockScreen :avatar @to-login="handleLogout" /> <LockScreen :avatar @to-login="handleLogout" />
</template> </template>
<template #extra>
<FsSourceLink />
</template>
</BasicLayout> </BasicLayout>
</template> </template>

View File

@@ -188,7 +188,7 @@ const mockUtil: any = {
handle(req: any) { handle(req: any) {
let id = req.params.id; let id = req.params.id;
id = parseInt(id); id = parseInt(id);
const current = findById(req.body.id, list); const current = findById(id, list);
return { return {
code: 0, code: 0,
msg: "success", msg: "success",

View File

@@ -1,18 +1,30 @@
import { defineAsyncComponent } from "vue"; import { defineAsyncComponent } from "vue";
import Input from "ant-design-vue/es/input/Input"; import Input from "ant-design-vue/es/input";
import Button from "ant-design-vue/es/button/button"; import Button from "ant-design-vue/es/button";
import Divider from "ant-design-vue/es/divider";
import Badge from "ant-design-vue/es/badge";
import Empty from "ant-design-vue/es/empty";
import Avatar from "ant-design-vue/es/avatar";
import Steps from "ant-design-vue/es/steps";
import Select from "ant-design-vue/es/select";
import PageHeader from "ant-design-vue/es/page-header";
import Card from "ant-design-vue/es/card";
export default { export default {
install(app: any) { install(app: any) {
app.component("AInput", Input); app.use(Input);
app.component("AButton", Button); app.use(Button);
app.use(Divider);
app.use(Badge);
app.use(Empty);
app.use(Avatar);
app.use(PageHeader);
app.use(Steps);
app.use(Select);
app.use(Card);
app.component( app.component(
"AInputPassword", "AAutoComplete",
defineAsyncComponent(() => import("ant-design-vue/es/input/Password")) defineAsyncComponent(() => import("ant-design-vue/es/auto-complete/index"))
);
app.component(
"AButtonGroup",
defineAsyncComponent(() => import("ant-design-vue/es/button/button-group"))
); );
app.component( app.component(
"ARadio", "ARadio",
@@ -38,6 +50,11 @@ export default {
"AFormItem", "AFormItem",
defineAsyncComponent(() => import("ant-design-vue/es/form/FormItem")) defineAsyncComponent(() => import("ant-design-vue/es/form/FormItem"))
); );
app.component(
"AFormItemRest",
defineAsyncComponent(() => import("ant-design-vue/es/form/FormItemContext"))
);
app.component( app.component(
"ATabs", "ATabs",
defineAsyncComponent(() => import("ant-design-vue/es/tabs/src/Tabs")) defineAsyncComponent(() => import("ant-design-vue/es/tabs/src/Tabs"))
@@ -55,10 +72,6 @@ export default {
"AInputNumber", "AInputNumber",
defineAsyncComponent(() => import("ant-design-vue/es/input-number/index")) defineAsyncComponent(() => import("ant-design-vue/es/input-number/index"))
); );
app.component(
"ASelect",
defineAsyncComponent(() => import("ant-design-vue/es/select/index"))
);
app.component( app.component(
"ADrawer", "ADrawer",
defineAsyncComponent(() => import("ant-design-vue/es/drawer/index")) defineAsyncComponent(() => import("ant-design-vue/es/drawer/index"))
@@ -98,10 +111,7 @@ export default {
"AInputAutoComplete", "AInputAutoComplete",
defineAsyncComponent(() => import("ant-design-vue/es/auto-complete/index")) defineAsyncComponent(() => import("ant-design-vue/es/auto-complete/index"))
); );
app.component(
"ACard",
defineAsyncComponent(() => import("ant-design-vue/es/card/index"))
);
app.component( app.component(
"ACascader", "ACascader",
defineAsyncComponent(() => import("ant-design-vue/es/cascader/index")) defineAsyncComponent(() => import("ant-design-vue/es/cascader/index"))
@@ -151,8 +161,8 @@ export default {
defineAsyncComponent(() => import("ant-design-vue/es/tree-select")) defineAsyncComponent(() => import("ant-design-vue/es/tree-select"))
); );
app.component( app.component(
"AToar", "ATour",
defineAsyncComponent(() => import("ant-design-vue/es/tree-select")) defineAsyncComponent(() => import("ant-design-vue/es/tour"))
); );
app.component( app.component(
@@ -167,5 +177,67 @@ export default {
"AMenuItem", "AMenuItem",
defineAsyncComponent(() => import("ant-design-vue/es/menu/src/MenuItem")) defineAsyncComponent(() => import("ant-design-vue/es/menu/src/MenuItem"))
); );
app.component(
"AProgress",
defineAsyncComponent(() => import("ant-design-vue/es/progress"))
);
app.component(
"ATimelineItem",
defineAsyncComponent(() => import("ant-design-vue/es/timeline/TimelineItem"))
);
app.component(
"ATimeline",
defineAsyncComponent(() => import("ant-design-vue/es/timeline/Timeline"))
);
app.component(
"APageHeader",
defineAsyncComponent(() => import("ant-design-vue/es/page-header/index"))
);
app.component(
"APopover",
defineAsyncComponent(() => import("ant-design-vue/es/popover"))
);
app.component(
"APopconfirm",
defineAsyncComponent(() => import("ant-design-vue/es/popconfirm"))
);
app.component(
"ACollapse",
defineAsyncComponent(() => import("ant-design-vue/es/collapse"))
);
app.component(
"ADescriptions",
defineAsyncComponent(() => import("ant-design-vue/es/descriptions"))
);
app.component(
"ADescriptionsItem",
defineAsyncComponent(async () => {
const m = await import("ant-design-vue/es/descriptions/");
return m.DescriptionsItem;
})
);
app.component(
"AResult",
defineAsyncComponent(() => import("ant-design-vue/es/result"))
);
app.component(
"ATableSummaryCell",
defineAsyncComponent(() => import("ant-design-vue/es/vc-table/Cell/index"))
);
app.component(
"ATableSummaryRow",
defineAsyncComponent(() => import("ant-design-vue/es/vc-table/Footer/Row"))
);
app.component(
"ATableSummary",
defineAsyncComponent(() => import("ant-design-vue/es/vc-table/Footer/Summary"))
);
app.component(
"ASlider",
defineAsyncComponent(() => import("ant-design-vue/es/slider/index"))
);
} }
}; };

View File

@@ -0,0 +1,33 @@
import { debounce } from "lodash-es";
import { LocalStorage } from "/@/utils/util.storage";
export class ColumnSizeSaver {
save: (key: string, size: number) => void;
constructor() {
this.save = debounce((key: string, size: number) => {
const saveKey = this.getKey();
let data = LocalStorage.get(saveKey);
if (!data) {
data = {};
}
data[key] = size;
LocalStorage.set(saveKey, data);
});
}
getKey() {
const loc = window.location;
const currentUrl = `${loc.pathname}${loc.search}${loc.hash}`;
return `columnSize-${currentUrl}`;
}
get(key: string) {
const saveKey = this.getKey();
const row = LocalStorage.get(saveKey);
return row?.[key];
}
clear() {
const saveKey = this.getKey();
LocalStorage.remove(saveKey);
}
}
export const columnSizeSaver = new ColumnSizeSaver();

View File

@@ -11,11 +11,13 @@ import { useCrudPermission } from "../permission";
import { GetSignedUrl } from "/@/views/crud/component/uploader/s3/api"; import { GetSignedUrl } from "/@/views/crud/component/uploader/s3/api";
import { notification } from "ant-design-vue"; import { notification } from "ant-design-vue";
import { usePreferences } from "/@/vben/preferences"; import { usePreferences } from "/@/vben/preferences";
import { columnSizeSaver } from "/@/plugin/fast-crud/column-size-saver";
import { FsEditorCode } from "@fast-crud/editor-code";
function install(app: any, options: any = {}) { function install(app: any, options: any = {}) {
app.use(UiAntdv); app.use(UiAntdv);
//设置日志级别 //设置日志级别
setLogger({ level: "debug" }); setLogger({ level: "debug" });
app.use(FastCrud, { app.use(FastCrud, {
i18n: options.i18n, i18n: options.i18n,
async dictRequest({ url }: any) { async dictRequest({ url }: any) {
@@ -53,6 +55,7 @@ function install(app: any, options: any = {}) {
onResizeColumn: (w: number, col: any) => { onResizeColumn: (w: number, col: any) => {
if (crudBinding.value?.table?.columnsMap && crudBinding.value?.table?.columnsMap[col.key]) { if (crudBinding.value?.table?.columnsMap && crudBinding.value?.table?.columnsMap[col.key]) {
crudBinding.value.table.columnsMap[col.key].width = w; crudBinding.value.table.columnsMap[col.key].width = w;
columnSizeSaver.save(col.key, w);
} }
}, },
conditionalRender: { conditionalRender: {
@@ -72,6 +75,11 @@ function install(app: any, options: any = {}) {
toolbar: { toolbar: {
export: { export: {
fileType: "excel" fileType: "excel"
},
columnsFilter: {
async onReset() {
columnSizeSaver.clear();
}
} }
}, },
rowHandle: { rowHandle: {
@@ -330,10 +338,12 @@ function install(app: any, options: any = {}) {
toolbarConfig: {} toolbarConfig: {}
} }
}); });
app.use(FsExtendsJson); app.use(FsExtendsJson);
app.use(FsExtendsTime); app.use(FsExtendsTime);
app.use(FsExtendsCopyable); app.use(FsExtendsCopyable);
app.use(FsExtendsInput); app.use(FsExtendsInput);
app.use(FsEditorCode);
const { addTypes, getType } = useTypes(); const { addTypes, getType } = useTypes();
//此处演示修改官方字段类型 //此处演示修改官方字段类型
@@ -381,7 +391,10 @@ function install(app: any, options: any = {}) {
} }
if (columnProps.column.resizable == null) { if (columnProps.column.resizable == null) {
columnProps.column.resizable = true; columnProps.column.resizable = true;
if (!columnProps.column.width) { const savedColumnWidth = columnSizeSaver.get(columnProps.key as string);
if (savedColumnWidth) {
columnProps.column.width = savedColumnWidth;
} else if (!columnProps.column.width) {
columnProps.column.width = 200; columnProps.column.width = 200;
} }
} }

View File

@@ -2,10 +2,11 @@ import "./iconify";
import "./iconfont"; import "./iconfont";
import FastCrud from "./fast-crud"; import FastCrud from "./fast-crud";
import permission from "./permission"; import permission from "./permission";
import { setupMonaco } from "./monaco";
function install(app: any, options: any = {}) { function install(app: any, options: any = {}) {
app.use(FastCrud, options); app.use(FastCrud, options);
app.use(permission); app.use(permission);
setupMonaco();
} }
export default { export default {

View File

@@ -0,0 +1,15 @@
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
import yamlWorker from "./yaml.worker?worker";
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
import { registerWorker } from "@fast-crud/editor-code";
export function setupMonaco() {
registerWorker("json", jsonWorker);
registerWorker(["css", "less", "scss"], cssWorker);
registerWorker(["html", "handlebars", "razor"], htmlWorker);
registerWorker(["yaml", "yml"], yamlWorker);
registerWorker(["typescript", "javascript"], tsWorker);
registerWorker("*", editorWorker);
}

View File

@@ -0,0 +1 @@
export * from "monaco-yaml/yaml.worker.js";

View File

@@ -43,6 +43,10 @@ export function setupCommonGuard(router: Router) {
*/ */
function setupAccessGuard(router: Router) { function setupAccessGuard(router: Router) {
router.beforeEach(async (to, from) => { router.beforeEach(async (to, from) => {
if (to.matched && to.matched.length > 2) {
to.matched.splice(1, to.matched.length - 2);
}
// 基本路由,这些路由不需要进入权限拦截 // 基本路由,这些路由不需要进入权限拦截
const needAuth = to.matched.some((r) => { const needAuth = to.matched.some((r) => {
return r.meta?.auth || r.meta?.permission; return r.meta?.auth || r.meta?.permission;

View File

@@ -304,6 +304,12 @@ export const crudResources = [
path: "/crud/component/editor", path: "/crud/component/editor",
component: "/crud/component/editor/index.vue" component: "/crud/component/editor/index.vue"
}, },
{
title: "代码编辑器",
name: "ComponentCode",
path: "/crud/component/code",
component: "/crud/component/code/index.vue"
},
{ {
title: "图标", title: "图标",
name: "ComponentIcon", name: "ComponentIcon",

View File

@@ -78,7 +78,7 @@ function transformComponent(component: VNode, route: RouteLocationNormalizedLoad
</script> </script>
<template> <template>
<div class="relative h-full"> <div class="relative h-full bg-white dark:bg-black">
<IFrameRouterView /> <IFrameRouterView />
<RouterView v-slot="{ Component, route }"> <RouterView v-slot="{ Component, route }">
<Transition :name="getTransitionName(route)" appear mode="out-in"> <Transition :name="getTransitionName(route)" appear mode="out-in">

View File

@@ -112,7 +112,7 @@ function menuIcon(menu: MenuRecordRaw) {
.vben-normal-menu__name, .vben-normal-menu__name,
.vben-normal-menu__icon { .vben-normal-menu__icon {
@apply text-primary-foreground font-semibold; @apply font-semibold;
} }
} }

View File

@@ -21,6 +21,7 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
return { return {
crudOptions: { crudOptions: {
id: "right-table",
pagination: { pagination: {
showSizeChanger: false, // antdv showSizeChanger: false, // antdv
showQuickJumper: false // antdv showQuickJumper: false // antdv

View File

@@ -31,6 +31,7 @@ export default function ({ crudExpose, context: { asideTableRef } }: CreateCrudO
}; };
return { return {
crudOptions: { crudOptions: {
id: "main-table",
table: { table: {
customRow(record: any, index: number) { customRow(record: any, index: number) {
const clazz = record.id === currentRow.value ? "fs-current-row" : ""; const clazz = record.id === currentRow.value ? "fs-current-row" : "";

View File

@@ -21,6 +21,7 @@ export default function ({ crudExpose, context: { props, ctx } }: CreateCrudOpti
return { return {
crudOptions: { crudOptions: {
id: "sub-table",
table: { table: {
customRow(record: any, index: number) { customRow(record: any, index: number) {
const clazz = record.id === props.modelValue ? "fs-current-row" : ""; const clazz = record.id === props.modelValue ? "fs-current-row" : "";

View File

@@ -133,6 +133,7 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
form: { form: {
helper: "组件本身render", helper: "组件本身render",
render({ form }) { render({ form }) {
console.log("字段组件本身render");
return ( return (
<div> <div>
<a-input v-model={[form.formRender, "value"]} /> <a-input v-model={[form.formRender, "value"]} />

View File

@@ -38,7 +38,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps<FirstRo
search: { show: true }, search: { show: true },
column: { column: {
resizable: true, resizable: true,
width: 200 width: 200,
tooltip: true
} }
}, },
type: { type: {

View File

@@ -51,7 +51,6 @@ const createCrudOptions = async function ({}: CreateCrudOptionsProps): Promise<C
return { return {
//自定义变量返回 //自定义变量返回
customExport: {},
crudOptions: { crudOptions: {
request: { request: {
pageRequest, pageRequest,
@@ -59,6 +58,15 @@ const createCrudOptions = async function ({}: CreateCrudOptionsProps): Promise<C
editRequest, editRequest,
delRequest delRequest
}, },
actionbar: {
buttons: {
add: {
tooltip: {
title: "tooltip演示"
}
}
}
},
columns: { columns: {
name: { name: {
title: "姓名", title: "姓名",
@@ -66,7 +74,10 @@ const createCrudOptions = async function ({}: CreateCrudOptionsProps): Promise<C
search: { show: true }, search: { show: true },
column: { column: {
resizable: true, resizable: true,
width: 200 width: 200,
tooltip: {
title: "tooltip演示"
}
} }
}, },
type: { type: {

View File

@@ -0,0 +1,42 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/ComponentCode";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -0,0 +1,110 @@
import * as api from "./api";
import { FsEditorCodeValidators } from "@fast-crud/editor-code";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, ValueBuilderContext, ValueResolveContext } from "@fast-crud/fast-crud";
export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<CreateCrudOptionsRet> {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
wrapper: {
async onOpened({ mode, formRef }) {
// if (!formRef.form.async) {
// setTimeout(() => {
// formRef.form.async = { aaa: "11", bb: "111" };
// }, 2000);
// }
}
}
},
columns: {
javascript: {
title: "js code",
type: "editor-code",
form: {
show: true,
component: {
language: "javascript"
}
}
},
yaml: {
title: "yaml",
type: "editor-code",
form: {
show: true,
rules: FsEditorCodeValidators.yamlRule,
component: {
language: "yaml",
schema: {
//数据校验提示
type: "object",
properties: {
p1: {
enum: ["v1", "v2"],
description: "数据校验提示"
},
property: {
description: "I have a description"
},
titledProperty: {
title: "I have a title",
description: "I also have a description"
},
markdown: {
markdownDescription: "Even **markdown** _descriptions_ `are` ~~not~~ supported!"
}
}
}
}
}
},
json: {
title: "json",
type: "editor-code",
form: {
show: true,
rules: FsEditorCodeValidators.jsonRule,
component: {
language: "json",
vModel: "modelValue",
schema: {
//校验提示
type: "object",
properties: {
p1: {
enum: ["v1", "v2"],
description: "数据校验示例"
}
}
},
config: {}
}
}
}
}
}
};
}

View File

@@ -0,0 +1,32 @@
<template>
<fs-page>
<fs-crud ref="crudRef" v-bind="crudBinding" />
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import { useFsAsync, useFsRef } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud.js";
export default defineComponent({
name: "ComponentCode",
setup() {
const { crudRef, crudBinding } = useFsRef();
const monacoRef = ref();
// 页面打开后获取列表数据
onMounted(async () => {
const { crudExpose } = await useFsAsync({ crudBinding, crudRef, createCrudOptions });
await crudExpose.doRefresh();
});
return {
crudBinding,
crudRef,
monacoRef
};
}
});
</script>

View File

@@ -0,0 +1,24 @@
import mockUtil from "/src/mock/base";
const options: any = {
name: "ComponentCode",
idGenerator: 0
};
const list: any = [
{
json: '{"p1":1,"b":2}',
yaml: `
property: 1
p1: 3
services:
certd:
container_name: certd
`,
javascript: `console.log(123)`
},
{
json: '{"p1":3,"b":4}'
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -306,7 +306,8 @@ export default async function ({ crudExpose, context }: CreateCrudOptionsProps):
{ value: "wh", label: "武汉" }, { value: "wh", label: "武汉" },
{ value: "sh", label: "上海" }, { value: "sh", label: "上海" },
{ value: "hz", label: "杭州" }, { value: "hz", label: "杭州" },
{ value: "bj", label: "北京", color: "red" } { value: "bj", label: "北京", color: "red" },
{ value: "github", label: "github" }
] ]
}), }),
column: { column: {

View File

@@ -8,7 +8,7 @@ const list = [
statusLocal: "sz", statusLocal: "sz",
customDictUrl: "0", customDictUrl: "0",
statusValue: 1, statusValue: 1,
multiple: ["sz", "bj", "gz", "sh", "hz", "xz", "xg"], multiple: ["sz", "bj", "gz", "sh", "hz", "xz", "xg", "github"],
checkbox: "0", checkbox: "0",
select_local: "sz", select_local: "sz",
statusRemote: "0", statusRemote: "0",

View File

@@ -22,6 +22,9 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
}; };
const crudOptionsOverride = { const crudOptionsOverride = {
container: {
is: "fs-layout-card"
},
table: { table: {
scroll: { scroll: {
x: 2000 x: 2000
@@ -124,7 +127,8 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
placeholder: "点击选择" placeholder: "点击选择"
}, },
createCrudOptions: createCrudOptionsText, createCrudOptions: createCrudOptionsText,
crudOptionsOverride: crudOptionsOverride crudOptionsOverride: crudOptionsOverride,
isSyncCreate: true
} }
}, },
column: { column: {
@@ -250,6 +254,26 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
} }
} }
} }
},
editable: {
title: "可编辑选择",
search: { show: true },
type: "editable-select",
dict: dict({
value: "id",
label: "name",
async getData() {
return await textTableApi.GetAll();
}
}),
form: {
component: {
tableSelect: {
createCrudOptions: createCrudOptionsText,
crudOptionsOverride
}
}
}
} }
} }
} }

View File

@@ -48,3 +48,10 @@ export function GetByIds(ids: any) {
data: { ids } data: { ids }
}); });
} }
export function GetAll() {
return request({
url: apiPrefix + "/all",
method: "get"
});
}

View File

@@ -110,7 +110,7 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
type: "text", type: "text",
column: { column: {
ellipsis: true, ellipsis: true,
showTitle: true tooltip: true
} }
}, },
search: { search: {

View File

@@ -45,5 +45,6 @@ const list = [
} }
]; ];
options.list = list; options.list = list;
options.copyTimes = 5;
const mock = mockUtil.buildMock(options); const mock = mockUtil.buildMock(options);
export default mock; export default mock;

View File

@@ -11,11 +11,11 @@ const list = [
error: ["http://localhost:11111/error_image"], error: ["http://localhost:11111/error_image"],
pictureCard2: [ pictureCard2: [
{ {
url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?1", url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?original1",
previewUrl: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?preview1" previewUrl: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?preview1"
}, },
{ {
url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?2", url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?original2",
previewUrl: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?preview2" previewUrl: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?preview2"
} }
], ],

View File

@@ -1,5 +1,6 @@
import * as api from "./api"; import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, ValueChangeContext } from "@fast-crud/fast-crud"; import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, ValueChangeContext } from "@fast-crud/fast-crud";
import { createUploaderRules } from "@fast-crud/fast-extends";
export default async function createCrudOptions({}: CreateCrudOptionsProps): Promise<CreateCrudOptionsRet> { export default async function createCrudOptions({}: CreateCrudOptionsProps): Promise<CreateCrudOptionsRet> {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => { const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query); return await api.GetList(query);
@@ -53,6 +54,20 @@ export default async function createCrudOptions({}: CreateCrudOptionsProps): Pro
component: { dict: { cache: false } } component: { dict: { cache: false } }
} }
}, },
localSet: {
title: "本地修改",
search: { show: true },
dict: dict({
cloneable: true,
data: [
{
value: 1,
label: "本地字典"
}
]
}),
type: "dict-select"
},
modifyDict: { modifyDict: {
title: "动态修改字典", title: "动态修改字典",
search: { show: false }, search: { show: false },
@@ -65,9 +80,16 @@ export default async function createCrudOptions({}: CreateCrudOptionsProps): Pro
valueChange({ row, getComponentRef }: ValueChangeContext) { valueChange({ row, getComponentRef }: ValueChangeContext) {
// 这里不能使用remoteDict,因为在分发时已经clone到form配置中了 // 这里不能使用remoteDict,因为在分发时已经clone到form配置中了
// 这里dict修改不会影响列里面的数据 // 这里dict修改不会影响列里面的数据
const targetDict = getComponentRef("remote").dict; const targetDict = getComponentRef("remote").getDict();
targetDict.url = row.modifyDict ? "/mock/dicts/moreOpenStatusEnum?remote" : "/mock/dicts/OpenStatusEnum?remote"; targetDict.url = row.modifyDict ? "/mock/dicts/moreOpenStatusEnum?remote" : "/mock/dicts/OpenStatusEnum?remote";
targetDict.reloadDict(); targetDict.reloadDict();
const targetDict2 = getComponentRef("localSet").getDict();
if (row.modifyDict) {
targetDict2.setData([{ value: 1, label: "修改后的字典" }]);
} else {
targetDict2.setData([{ value: 1, label: "原字典" }]);
}
} }
}, },
form: { form: {
@@ -78,11 +100,22 @@ export default async function createCrudOptions({}: CreateCrudOptionsProps): Pro
valueChange({ form, getComponentRef }: ValueChangeContext) { valueChange({ form, getComponentRef }: ValueChangeContext) {
// 这里不能使用remoteDict,因为在分发时已经clone到form配置中了 // 这里不能使用remoteDict,因为在分发时已经clone到form配置中了
// 这里dict修改不会影响列里面的数据 // 这里dict修改不会影响列里面的数据
const targetDict = getComponentRef("remote").dict; const targetDict = getComponentRef("remote").getDict();
targetDict.url = form.modifyDict ? "/mock/dicts/moreOpenStatusEnum?remote" : "/mock/dicts/OpenStatusEnum?remote"; targetDict.url = form.modifyDict ? "/mock/dicts/moreOpenStatusEnum?remote" : "/mock/dicts/OpenStatusEnum?remote";
targetDict.reloadDict(); targetDict.reloadDict();
const targetDict2 = getComponentRef("localSet").getDict();
if (form.modifyDict) {
targetDict2.setData([{ value: 1, label: "修改后的字典" }]);
} else {
targetDict2.setData([{ value: 1, label: "原字典" }]);
}
} }
} }
},
pictureCard: {
title: "照片墙",
type: "image-uploader"
} }
} }
} }

View File

@@ -7,7 +7,8 @@ const list = [
{ {
status: "1", status: "1",
remote: "2", remote: "2",
modifyDict: true modifyDict: true,
localSet: 1
}, },
{ {
status: "2", status: "2",

View File

@@ -121,6 +121,10 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
title: "动态Url", title: "动态Url",
dict: dynamicUrlDict, dict: dynamicUrlDict,
type: "dict-select" type: "dict-select"
},
pictureCard: {
title: "照片墙",
type: "image-uploader"
} }
} }
} }

View File

@@ -26,6 +26,8 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
] ]
}); });
console.log("dict", statusDict.data);
const remoteDict = dict({ const remoteDict = dict({
url: "/mock/dicts/OpenStatusEnum", url: "/mock/dicts/OpenStatusEnum",
immediate: false immediate: false
@@ -131,6 +133,10 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
cache: true cache: true
}), }),
type: "dict-select" type: "dict-select"
},
pictureCard: {
title: "test",
type: "image-uploader"
} }
} }
} }

View File

@@ -52,6 +52,19 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
} }
} }
}, },
rowHandle: {
fixed: null,
title: "操作列行合并",
customCell: (_: any, index: any) => {
if (index === 4) {
return { rowSpan: 2 };
} else if (index === 5) {
return { rowSpan: 0 };
} else {
return { rowSpan: 1 };
}
}
},
columns: { columns: {
id: { id: {
title: "id", title: "id",
@@ -69,57 +82,55 @@ export default async function ({ crudExpose }: CreateCrudOptionsProps): Promise<
title: "上下合并", title: "上下合并",
type: "text", type: "text",
column: { column: {
customRender: ({ text, index }: any, cellRender: any) => { customCell: (_: any, index: any) => {
const obj: any = {
props: {}
};
if (index === 2) { if (index === 2) {
obj.children = text + "(我合并了)"; return {
obj.props.rowSpan = 2; rowSpan: 2
};
} else if (index === 3) { } else if (index === 3) {
obj.props.rowSpan = 0; return {
} else { rowSpan: 0
obj.children = cellRender(); };
} }
return obj; },
formatter({ value, index }) {
if (index === 2) {
return value + "(我上下合并了)";
}
return value;
} }
} }
}, },
colMerge1: { colMerge1: {
title: "左右合并", title: "左右合并1",
type: "text", type: "text",
column: { column: {
align: "center", align: "center",
customRender({ text, index, record, dataIndex }: any, cellRender: any) { customCell(value: any, index: any) {
if (index !== 4) { if (index === 4) {
return { return {
children: cellRender() colSpan: 2
}; };
} }
return { },
children: text + "(我合并了)", formatter({ value, index }) {
props: { if (index === 4) {
colSpan: 2 return value + "(我左右合并了)";
} }
}; return value;
} }
} }
}, },
colMerge2: { colMerge2: {
title: "左右合并", title: "左右合并2",
type: "text", type: "text",
column: { column: {
customRender({ text, index, record, dataIndex }: any, cellRender: any) { customCell(_: any, index: any) {
if (index !== 4) { if (index === 4) {
return { return {
children: cellRender() colSpan: 0
}; };
} }
return {
props: {
colSpan: 0
}
};
} }
} }
}, },

View File

@@ -20,7 +20,7 @@
label: '上置' label: '上置'
}, },
{ {
value: '', value: 'horizontal',
label: '左置' label: '左置'
} }
]" ]"
@@ -41,7 +41,7 @@ export default defineComponent({
name: "FormBase", name: "FormBase",
setup() { setup() {
const labelWidthRef = ref(100); const labelWidthRef = ref(100);
const labelLayoutRef = ref(); const labelLayoutRef = ref("horizontal");
const context = { const context = {
labelWidthRef, labelWidthRef,
labelLayoutRef labelLayoutRef

View File

@@ -72,13 +72,17 @@
</template> </template>
</fs-form-wrapper> </fs-form-wrapper>
</a-card> </a-card>
<a-card class="mt-10" title="打开对话框">
<a-button @click="openDialogOnly"> 打开对话框 </a-button>
</a-card>
</a-col> </a-col>
</a-row> </a-row>
</div> </div>
</fs-page> </fs-page>
</template> </template>
<script lang="ts"> <script lang="tsx">
import { defineComponent, ref } from "vue"; import { defineComponent, ref } from "vue";
import { message } from "ant-design-vue"; import { message } from "ant-design-vue";
import { CreateCrudOptionsProps, useColumns, useFormWrapper, useFs, utils } from "@fast-crud/fast-crud"; import { CreateCrudOptionsProps, useColumns, useFormWrapper, useFs, utils } from "@fast-crud/fast-crud";
@@ -268,6 +272,42 @@ function useFormProvider() {
}; };
} }
function useOpenDialogOnly() {
const { openDialog } = useFormWrapper();
function openDialogOnly() {
openDialog({
wrapper: {
title: "自定义对话框",
is: "a-modal",
footer: false,
buttons: {
cancel: {
show: false
},
reset: {
show: false
},
ok: {
show: false
}
},
slots: {
"form-body-top": () => {
return (
<div>
<a-alert type="warning" message="form-body-top 插槽" />
</div>
);
}
}
}
});
}
return {
openDialogOnly
};
}
export default defineComponent({ export default defineComponent({
name: "FormIndependent", name: "FormIndependent",
setup() { setup() {
@@ -276,7 +316,8 @@ export default defineComponent({
...useFormWrapperUsingTag(), ...useFormWrapperUsingTag(),
...useCrudBindingForm(), ...useCrudBindingForm(),
...useCrudOptions(), ...useCrudOptions(),
...useFormProvider() ...useFormProvider(),
...useOpenDialogOnly()
}; };
} }
}); });