2025-04-12 23:59:03 +08:00
|
|
|
|
import { request } from "/src/api/service";
|
2024-06-15 18:32:36 +00:00
|
|
|
|
// import "/src/mock";
|
2025-03-09 23:51:53 +08:00
|
|
|
|
import { ColumnCompositionProps, CrudOptions, FastCrud, PageQuery, PageRes, setLogger, TransformResProps, useColumns, UseCrudProps, UserPageQuery, useTypes, utils } from "@fast-crud/fast-crud";
|
2023-01-29 15:26:45 +08:00
|
|
|
|
import "@fast-crud/fast-crud/dist/style.css";
|
2025-03-09 23:51:53 +08:00
|
|
|
|
import { FsExtendsCopyable, FsExtendsEditor, FsExtendsJson, FsExtendsTime, FsExtendsUploader, FsExtendsInput, FsUploaderS3SignedUrlType, FsUploaderGetAuthContext, FsUploaderAliossSTS } from "@fast-crud/fast-extends";
|
2023-01-29 15:26:45 +08:00
|
|
|
|
import "@fast-crud/fast-extends/dist/style.css";
|
2024-03-08 17:07:53 +08:00
|
|
|
|
import UiAntdv from "@fast-crud/ui-antdv4";
|
2024-06-15 18:32:36 +00:00
|
|
|
|
import "@fast-crud/ui-antdv4/dist/style.css";
|
2025-03-18 10:00:16 +08:00
|
|
|
|
import { debounce, merge } from "lodash-es";
|
2023-01-29 15:26:45 +08:00
|
|
|
|
import { useCrudPermission } from "../permission";
|
2023-06-29 17:19:05 +08:00
|
|
|
|
import { App } from "vue";
|
2023-06-07 19:24:02 +00:00
|
|
|
|
import { notification } from "ant-design-vue";
|
2025-03-03 19:24:51 +00:00
|
|
|
|
import { usePreferences } from "/@/vben/preferences";
|
2025-03-18 10:00:16 +08:00
|
|
|
|
import { LocalStorage } from "/@/utils/util.storage";
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
const columnSizeSaver = new ColumnSizeSaver();
|
2023-01-29 15:26:45 +08:00
|
|
|
|
|
2023-06-29 17:19:05 +08:00
|
|
|
|
function install(app: App, options: any = {}) {
|
2023-01-29 15:26:45 +08:00
|
|
|
|
app.use(UiAntdv);
|
|
|
|
|
|
//设置日志级别
|
2023-06-29 17:19:05 +08:00
|
|
|
|
setLogger({ level: "info" });
|
2025-03-18 10:00:16 +08:00
|
|
|
|
|
2023-01-29 15:26:45 +08:00
|
|
|
|
app.use(FastCrud, {
|
|
|
|
|
|
i18n: options.i18n,
|
2023-03-09 19:24:01 +00:00
|
|
|
|
async dictRequest({ url }: any) {
|
2023-01-29 15:26:45 +08:00
|
|
|
|
return await request({ url, method: "post" });
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
|
|
|
* useCrud时会被执行
|
2023-03-17 19:23:57 +00:00
|
|
|
|
* @param props,useCrud的参数
|
2023-01-29 15:26:45 +08:00
|
|
|
|
*/
|
2023-03-17 19:23:57 +00:00
|
|
|
|
commonOptions(props: UseCrudProps): CrudOptions {
|
2024-06-15 18:32:36 +00:00
|
|
|
|
utils.logger.debug("commonOptions:", props);
|
2023-03-17 19:23:57 +00:00
|
|
|
|
const crudBinding = props.crudExpose?.crudBinding;
|
2025-03-03 19:24:51 +00:00
|
|
|
|
const { isMobile } = usePreferences();
|
2023-01-29 15:26:45 +08:00
|
|
|
|
const opts: CrudOptions = {
|
2025-03-03 19:24:51 +00:00
|
|
|
|
settings: {
|
|
|
|
|
|
plugins: {
|
|
|
|
|
|
mobile: {
|
|
|
|
|
|
enabled: true,
|
|
|
|
|
|
props: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
isMobile: isMobile,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2025-03-03 19:24:51 +00:00
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
table: {
|
2024-06-15 18:32:36 +00:00
|
|
|
|
scroll: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
x: 960,
|
2024-06-15 18:32:36 +00:00
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
size: "small",
|
|
|
|
|
|
pagination: false,
|
2025-03-18 10:00:16 +08:00
|
|
|
|
onResizeColumn: (w: number, col: any) => {
|
2023-03-09 19:24:01 +00:00
|
|
|
|
if (crudBinding.value?.table?.columnsMap && crudBinding.value?.table?.columnsMap[col.key]) {
|
|
|
|
|
|
crudBinding.value.table.columnsMap[col.key].width = w;
|
2025-03-18 10:00:16 +08:00
|
|
|
|
columnSizeSaver.save(col.key, w);
|
2023-03-09 19:24:01 +00:00
|
|
|
|
}
|
2023-04-06 19:24:11 +00:00
|
|
|
|
},
|
|
|
|
|
|
conditionalRender: {
|
|
|
|
|
|
match(scope) {
|
2024-10-07 03:21:16 +08:00
|
|
|
|
if (scope.column.conditionalRenderDisabled) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-10-01 23:34:01 +08:00
|
|
|
|
if (scope.key === "__blank__") {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-10-07 03:21:16 +08:00
|
|
|
|
|
2023-04-07 19:23:58 +00:00
|
|
|
|
//不能用 !scope.value , 否则switch组件设置为关之后就消失了
|
2024-06-15 18:32:36 +00:00
|
|
|
|
const { value, key, props } = scope;
|
2023-04-19 19:24:05 +00:00
|
|
|
|
return !value && key != "_index" && value != false;
|
2023-04-06 19:24:11 +00:00
|
|
|
|
},
|
|
|
|
|
|
render() {
|
|
|
|
|
|
return "-";
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
2023-07-04 19:24:06 +00:00
|
|
|
|
toolbar: {
|
|
|
|
|
|
export: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
fileType: "excel",
|
|
|
|
|
|
},
|
|
|
|
|
|
columnsFilter: {
|
|
|
|
|
|
async onReset() {
|
|
|
|
|
|
columnSizeSaver.clear();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2025-06-03 10:23:28 +08:00
|
|
|
|
buttons: {
|
|
|
|
|
|
export: {
|
|
|
|
|
|
show: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
|
|
|
|
|
rowHandle: {
|
2024-09-10 19:24:33 +00:00
|
|
|
|
fixed: "right",
|
2023-01-29 15:26:45 +08:00
|
|
|
|
buttons: {
|
2025-06-04 17:26:56 +08:00
|
|
|
|
view: { type: "link", text: null, icon: "ion:eye-outline", tooltip: { title: "查看" } },
|
|
|
|
|
|
copy: { show: true, type: "link", text: null, icon: "ion:copy-outline", tooltip: { title: "复制" } },
|
|
|
|
|
|
edit: { type: "link", text: null, icon: "ion:create-outline", tooltip: { title: "编辑" } },
|
|
|
|
|
|
remove: { type: "link", style: { color: "red" }, text: null, icon: "ion:trash-outline", tooltip: { title: "删除" } },
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
|
|
|
|
|
dropdown: {
|
|
|
|
|
|
more: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
type: "link",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
resizable: true,
|
|
|
|
|
|
width: 200,
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
|
|
|
|
|
request: {
|
2023-03-09 19:24:01 +00:00
|
|
|
|
transformQuery: ({ page, form, sort }: PageQuery): UserPageQuery => {
|
2023-01-29 15:26:45 +08:00
|
|
|
|
const limit = page.pageSize;
|
|
|
|
|
|
const currentPage = page.currentPage ?? 1;
|
|
|
|
|
|
const offset = limit * (currentPage - 1);
|
|
|
|
|
|
|
|
|
|
|
|
sort = sort == null ? {} : sort;
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
page: {
|
|
|
|
|
|
limit,
|
2025-03-18 10:00:16 +08:00
|
|
|
|
offset,
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
|
|
|
|
|
query: form,
|
2025-03-18 10:00:16 +08:00
|
|
|
|
sort,
|
2023-01-29 15:26:45 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
2023-03-09 19:24:01 +00:00
|
|
|
|
transformRes: ({ res }: TransformResProps): PageRes => {
|
2023-01-29 15:26:45 +08:00
|
|
|
|
const pageSize = res.limit;
|
|
|
|
|
|
let currentPage = res.offset / pageSize;
|
|
|
|
|
|
if (res.offset % pageSize === 0) {
|
|
|
|
|
|
currentPage++;
|
|
|
|
|
|
}
|
2024-06-15 18:32:36 +00:00
|
|
|
|
return { currentPage, pageSize, records: res.records, total: res.total, ...res };
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
2024-12-24 17:52:03 +08:00
|
|
|
|
search: {
|
|
|
|
|
|
formItem: {
|
|
|
|
|
|
wrapperCol: {
|
|
|
|
|
|
style: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
width: "50%",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2024-12-24 17:52:03 +08:00
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
form: {
|
|
|
|
|
|
display: "flex",
|
|
|
|
|
|
labelCol: {
|
|
|
|
|
|
//固定label宽度
|
|
|
|
|
|
span: null,
|
|
|
|
|
|
style: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
width: "145px",
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
2023-05-23 19:24:05 +00:00
|
|
|
|
async afterSubmit({ mode }) {
|
|
|
|
|
|
if (mode === "add") {
|
|
|
|
|
|
notification.success({ message: "添加成功" });
|
|
|
|
|
|
} else if (mode === "edit") {
|
|
|
|
|
|
notification.success({ message: "保存成功" });
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
wrapperCol: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
span: null,
|
2024-06-15 18:32:36 +00:00
|
|
|
|
},
|
|
|
|
|
|
wrapper: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
saveRemind: true,
|
2024-06-15 18:32:36 +00:00
|
|
|
|
// inner: true,
|
|
|
|
|
|
// innerContainerSelector: "main.fs-framework-content"
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
2024-06-15 18:32:36 +00:00
|
|
|
|
},
|
|
|
|
|
|
columns: {
|
2024-09-25 19:23:59 +00:00
|
|
|
|
//最后一列空白,用于自动伸缩列宽
|
|
|
|
|
|
__blank__: {
|
|
|
|
|
|
title: "",
|
|
|
|
|
|
type: "text",
|
|
|
|
|
|
form: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
show: false,
|
2024-09-25 19:23:59 +00:00
|
|
|
|
},
|
|
|
|
|
|
column: {
|
|
|
|
|
|
order: 99999,
|
|
|
|
|
|
width: -1,
|
|
|
|
|
|
columnSetShow: false,
|
2025-03-18 10:00:16 +08:00
|
|
|
|
resizable: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 从 useCrud({permission}) 里获取permission参数,去设置各个按钮的权限
|
2023-03-17 19:23:57 +00:00
|
|
|
|
const permission = props.context?.permission || null;
|
|
|
|
|
|
const crudPermission = useCrudPermission({ permission });
|
2023-01-29 15:26:45 +08:00
|
|
|
|
return crudPermission.merge(opts);
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// fast-extends里面的扩展组件均为异步组件,只有在使用时才会被加载,并不会影响首页加载速度
|
|
|
|
|
|
//安装uploader 公共参数
|
2023-06-29 17:19:05 +08:00
|
|
|
|
|
2024-07-26 21:42:25 +08:00
|
|
|
|
// @ts-ignore
|
2023-01-29 15:26:45 +08:00
|
|
|
|
app.use(FsExtendsUploader, {
|
2023-06-29 17:19:05 +08:00
|
|
|
|
// @ts-ignore
|
2024-10-14 00:19:55 +08:00
|
|
|
|
defaultType: "form",
|
2023-01-29 15:26:45 +08:00
|
|
|
|
form: {
|
2023-09-13 19:24:15 +00:00
|
|
|
|
keepName: true,
|
2024-10-27 00:52:26 +08:00
|
|
|
|
type: "form",
|
|
|
|
|
|
action: "/basic/file/upload",
|
2023-01-29 15:26:45 +08:00
|
|
|
|
name: "file",
|
|
|
|
|
|
withCredentials: false,
|
2025-02-20 19:24:20 +00:00
|
|
|
|
test: 22,
|
|
|
|
|
|
custom: { aaa: 22 },
|
2025-01-24 19:24:01 +00:00
|
|
|
|
uploadRequest: async (opts: any) => {
|
|
|
|
|
|
console.log("uploadRequest:", opts);
|
|
|
|
|
|
const { action, file, onProgress } = opts;
|
2023-01-29 15:26:45 +08:00
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
const data = new FormData();
|
|
|
|
|
|
data.append("file", file);
|
|
|
|
|
|
return await request({
|
|
|
|
|
|
url: action,
|
|
|
|
|
|
method: "post",
|
|
|
|
|
|
headers: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
"Content-Type": "multipart/form-data",
|
2023-01-29 15:26:45 +08:00
|
|
|
|
},
|
|
|
|
|
|
timeout: 60000,
|
|
|
|
|
|
data,
|
2023-06-29 17:19:05 +08:00
|
|
|
|
onUploadProgress: (p: any) => {
|
2023-01-29 15:26:45 +08:00
|
|
|
|
onProgress({ percent: Math.round((p.loaded / p.total) * 100) });
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
2024-10-27 00:52:26 +08:00
|
|
|
|
successHandle(res: any) {
|
|
|
|
|
|
return res;
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
//安装editor
|
|
|
|
|
|
app.use(FsExtendsEditor, {
|
|
|
|
|
|
//编辑器的公共配置
|
2023-03-16 19:24:01 +00:00
|
|
|
|
wangEditor: {
|
|
|
|
|
|
editorConfig: {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
MENU_CONF: {},
|
2023-03-16 19:24:01 +00:00
|
|
|
|
},
|
2025-03-18 10:00:16 +08:00
|
|
|
|
toolbarConfig: {},
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
});
|
|
|
|
|
|
app.use(FsExtendsJson);
|
|
|
|
|
|
app.use(FsExtendsTime);
|
|
|
|
|
|
app.use(FsExtendsCopyable);
|
2024-06-15 18:32:36 +00:00
|
|
|
|
app.use(FsExtendsInput);
|
2023-01-29 15:26:45 +08:00
|
|
|
|
|
2023-09-16 19:24:09 +00:00
|
|
|
|
const { addTypes, getType } = useTypes();
|
|
|
|
|
|
//此处演示修改官方字段类型
|
|
|
|
|
|
const textType = getType("text");
|
2024-06-15 18:32:36 +00:00
|
|
|
|
textType.search.autoSearchTrigger = "change"; //修改官方的字段类型,变化就触发 , "enter"=回车键触发
|
2024-10-14 00:19:55 +08:00
|
|
|
|
if (!textType.column) {
|
|
|
|
|
|
textType.column = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
textType.column.ellipsis = true;
|
|
|
|
|
|
textType.column.showTitle = true;
|
2023-09-16 19:24:09 +00:00
|
|
|
|
|
2023-01-29 15:26:45 +08:00
|
|
|
|
// 此处演示自定义字段类型
|
|
|
|
|
|
addTypes({
|
|
|
|
|
|
time2: {
|
|
|
|
|
|
//如果与官方字段类型同名,将会覆盖官方的字段类型
|
|
|
|
|
|
form: { component: { name: "a-date-picker" } },
|
|
|
|
|
|
column: { component: { name: "fs-date-format", format: "YYYY-MM-DD" } },
|
2023-06-29 17:19:05 +08:00
|
|
|
|
valueBuilder(context: any) {
|
2023-01-29 15:26:45 +08:00
|
|
|
|
console.log("time2,valueBuilder", context);
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 此处演示自定义字段合并插件
|
|
|
|
|
|
const { registerMergeColumnPlugin } = useColumns();
|
|
|
|
|
|
registerMergeColumnPlugin({
|
|
|
|
|
|
name: "readonly-plugin",
|
|
|
|
|
|
order: 1,
|
|
|
|
|
|
handle: (columnProps: ColumnCompositionProps) => {
|
|
|
|
|
|
// 你可以在此处做你自己的处理
|
|
|
|
|
|
// 比如你可以定义一个readonly的公共属性,处理该字段只读,不能编辑
|
|
|
|
|
|
if (columnProps.readonly) {
|
|
|
|
|
|
// 合并column配置
|
2025-03-04 19:24:24 +00:00
|
|
|
|
merge(columnProps, {
|
2023-01-29 15:26:45 +08:00
|
|
|
|
form: { show: false },
|
2025-03-18 10:00:16 +08:00
|
|
|
|
viewForm: { show: true },
|
2023-01-29 15:26:45 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
return columnProps;
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
2023-01-29 15:26:45 +08:00
|
|
|
|
});
|
2024-08-03 23:32:50 +08:00
|
|
|
|
|
2024-08-04 19:24:18 +00:00
|
|
|
|
//默认宽度,支持自动拖动调整列宽
|
2024-08-03 23:32:50 +08:00
|
|
|
|
registerMergeColumnPlugin({
|
|
|
|
|
|
name: "resize-column-plugin",
|
|
|
|
|
|
order: 2,
|
|
|
|
|
|
handle: (columnProps: ColumnCompositionProps) => {
|
|
|
|
|
|
if (!columnProps.column) {
|
|
|
|
|
|
columnProps.column = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
columnProps.column.resizable = true;
|
2025-03-18 10:00:16 +08:00
|
|
|
|
const savedColumnWidth = columnSizeSaver.get(columnProps.key as string);
|
|
|
|
|
|
if (savedColumnWidth) {
|
|
|
|
|
|
columnProps.column.width = savedColumnWidth;
|
|
|
|
|
|
} else if (columnProps.column.width == null) {
|
2024-10-07 03:21:16 +08:00
|
|
|
|
columnProps.column.width = 200;
|
2024-08-04 02:35:45 +08:00
|
|
|
|
} else if (typeof columnProps.column?.width === "string" && columnProps.column.width.indexOf("px") > -1) {
|
|
|
|
|
|
columnProps.column.width = parseInt(columnProps.column.width.replace("px", ""));
|
2024-08-03 23:32:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
return columnProps;
|
2025-03-18 10:00:16 +08:00
|
|
|
|
},
|
2024-08-03 23:32:50 +08:00
|
|
|
|
});
|
2023-01-29 15:26:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
2025-03-18 10:00:16 +08:00
|
|
|
|
install,
|
2023-01-29 15:26:45 +08:00
|
|
|
|
};
|