This commit is contained in:
icssoa 2023-10-22 20:21:57 +08:00
commit c1b837a0bb
37 changed files with 431 additions and 340 deletions

2
.gitignore vendored
View File

@ -3,4 +3,4 @@ node_modules
dist dist
dist-ssr dist-ssr
*.local *.local
pnpm-lock.yaml pnpm-lock.yaml

55
build/cool/base.ts Normal file
View File

@ -0,0 +1,55 @@
import type { Plugin } from "vite";
import { createSvg } from "./svg";
import { createTag } from "./tag";
import { createEps } from "./eps";
import { createMenu } from "./menu";
import { parseJson } from "./utils";
export function base(): Plugin {
return {
name: "vite-cool-base",
enforce: "pre",
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
function done(data: any) {
res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
res.end(JSON.stringify(data));
}
if (req.url?.includes("__cool")) {
const body = await parseJson(req);
switch (req.url) {
// 快速创建菜单
case "/__cool_createMenu":
await createMenu(body);
break;
// 创建描述文件
case "/__cool_eps":
await createEps(body);
break;
default:
return done({
code: 1001,
message: "未知请求"
});
}
done({
code: 1000
});
} else {
next();
}
});
},
transform(code, id) {
return createTag(code, id);
},
transformIndexHtml(html) {
return createSvg(html);
}
};
}

View File

@ -2,56 +2,27 @@ import { createDir, error, firstUpperCase, readFile, toCamel } from "../utils";
import { join } from "path"; import { join } from "path";
import { Entity, DistPath } from "./config"; import { Entity, DistPath } from "./config";
import axios from "axios"; import axios from "axios";
import { isArray, isEmpty, last } from "lodash"; import { isArray, isEmpty, last, merge } from "lodash";
import { createWriteStream } from "fs"; import { createWriteStream } from "fs";
import prettier from "prettier"; import prettier from "prettier";
import { proxy } from "../../../src/config/proxy"; import { proxy } from "../../../src/config/proxy";
import type { Eps } from "../types";
// 实体类型
type Entity = {
api: {
dts: {
parameters?: {
description: string;
name: string;
required: boolean;
schema: {
type: string;
};
}[];
};
name: string;
method: string;
path: string;
prefix: string;
summary: string;
tag: string;
}[];
columns: {
comment: string;
length: string;
nullable: boolean;
propertyName: string;
type: string;
}[];
module: string;
name: string;
prefix: string;
};
// 获取方法名 // 获取方法名
function getNames(v: any) { function getNames(v: any) {
return Object.keys(v).filter((e) => !["namespace", "permission"].includes(e)); return Object.keys(v).filter((e) => !["namespace", "permission"].includes(e));
} }
// 获取数据 // 数据
async function getData(temps: any[]) { let service = {};
let list: Entity[] = []; let list: Eps.Entity[] = [];
// 获取数据
async function getData(temps?: Eps.Entity[]) {
// 本地文件 // 本地文件
try { try {
list = JSON.parse(readFile(join(DistPath, "eps.json")) || "[]"); list = JSON.parse(readFile(join(DistPath, "eps.json")) || "[]");
} catch (err) { } catch (err: any) {
error(`[eps] ${join(DistPath, "eps.json")} 文件异常, ${err.message}`); error(`[eps] ${join(DistPath, "eps.json")} 文件异常, ${err.message}`);
} }
@ -68,60 +39,55 @@ async function getData(temps: any[]) {
if (code === 1000) { if (code === 1000) {
if (!isEmpty(data) && data) { if (!isEmpty(data) && data) {
// @ts-ignore list = Object.values(data).flat() as Eps.Entity[];
list = Object.values(data).flat();
} }
} else { } else {
error(`[eps] ${message}`); error(`[eps] ${message}`);
} }
}) })
.catch(() => { .catch(() => {
error(`[eps] 获取失败, ${url} 无法访问`); error(`[eps] ${url} 服务未启动!!`);
}); });
// 判断是否重复项 // 合并本地 service 数据
if (isArray(temps)) { if (isArray(temps)) {
temps.forEach((e) => { temps.forEach((e) => {
const d = list.find((a) => e.prefix === a.prefix); const d = list.find((a) => e.prefix === a.prefix);
if (d) { if (d) {
Object.assign(d, e); merge(d, e);
} else { } else {
list.push(e); list.push(e);
} }
}); });
} }
return list;
} }
// 创建数据文件 // 创建 json 文件
function createJson(eps: Entity[]) { function createJson() {
createWriteStream(join(DistPath, "eps.json"), { const d = list.map((e) => {
flags: "w" return {
}).write( prefix: e.prefix,
JSON.stringify( name: e.name || "",
eps.map((e) => { api: e.api.map((e) => {
return { return {
prefix: e.prefix, name: e.name,
name: e.name || "", method: e.method,
api: e.api.map((e) => { path: e.path
return {
name: e.name,
method: e.method,
path: e.path
};
})
}; };
}) })
) };
); });
createWriteStream(join(DistPath, "eps.json"), {
flags: "w"
}).write(JSON.stringify(d));
} }
// 创建描述文件 // 创建描述文件
async function createDescribe({ list, service }: { list: Entity[]; service: any }) { async function createDescribe({ list, service }: { list: Eps.Entity[]; service: any }) {
// 获取类型 // 获取类型
function getType({ propertyName, type }) { function getType({ propertyName, type }: any) {
for (const map of Entity.mapping) { for (const map of Entity.mapping) {
if (map.custom) { if (map.custom) {
const resType = map.custom({ propertyName, type }); const resType = map.custom({ propertyName, type });
@ -355,7 +321,7 @@ async function createDescribe({ list, service }: { list: Entity[]; service: any
`; `;
// 文本内容 // 文本内容
const content = await prettier.format(text, { const content = prettier.format(text, {
parser: "typescript", parser: "typescript",
useTabs: true, useTabs: true,
tabWidth: 4, tabWidth: 4,
@ -372,93 +338,82 @@ async function createDescribe({ list, service }: { list: Entity[]; service: any
}).write(content); }).write(content);
} }
// 创建服务 // 创建 service
function createService(data: Entity[]) { function createService() {
const list: Entity[] = []; list.forEach((e) => {
const service = {}; // 分隔路径
const d = { data }; const arr = e.prefix
.replace(/\//, "")
.replace("admin", "")
.split("/")
.filter(Boolean)
.map(toCamel);
for (const i in d) { // 遍历
if (isArray(d[i])) { function deep(d: any, i: number) {
d[i].forEach((e: Entity) => { const k = arr[i];
// 分隔路径
const arr = e.prefix
.replace(/\//, "")
.replace("admin", "")
.split("/")
.filter(Boolean)
.map(toCamel);
// 遍历 if (k) {
function deep(d: any, i: number) { // 是否最后一个
const k = arr[i]; if (arr[i + 1]) {
if (!d[k]) {
if (k) { d[k] = {};
// 是否最后一个
if (arr[i + 1]) {
if (!d[k]) {
d[k] = {};
}
deep(d[k], i + 1);
} else {
// 本地不存在则创建实例
if (!d[k]) {
d[k] = {
namespace: e.prefix.substring(1, e.prefix.length),
permission: {}
};
}
// 创建方法
e.api.forEach((a) => {
// 方法名
const n = a.path.replace("/", "");
if (n && !/[-:]/g.test(n)) {
d[k][n] = a;
}
});
// 创建权限
getNames(d[k]).forEach((e) => {
d[k].permission[e] = `${d[k].namespace.replace(
"admin/",
""
)}/${e}`.replace(/\//g, ":");
});
list.push(e);
}
} }
deep(d[k], i + 1);
} else {
// 不存在则创建
if (!d[k]) {
d[k] = {
namespace: e.prefix.substring(1, e.prefix.length),
permission: {}
};
}
// 创建方法
e.api.forEach((a) => {
// 方法名
const n = a.path.replace("/", "");
if (n && !/[-:]/g.test(n)) {
d[k][n] = a;
}
});
// 创建权限
getNames(d[k]).forEach((e) => {
d[k].permission[e] = `${d[k].namespace.replace("admin/", "")}/${e}`.replace(
/\//g,
":"
);
});
} }
}
deep(service, 0);
});
} }
}
return { service, list }; deep(service, 0);
});
} }
// 创建 eps // 创建 eps
export async function createEps(query?: { list: any[] }) { export async function createEps(query?: { list: any[] }) {
// 获取数据 // 获取数据
const data = await getData(query?.list || []); await getData(query?.list || []);
// 生成数据 // 创建 service
const { service, list } = createService(data); createService();
// 创建临时目录 // 创建临时目录
createDir(DistPath); createDir(DistPath);
// 创建数据文件 // 创建 json 文件
createJson(data); createJson();
// 创建描述文件 // 创建描述文件
createDescribe({ service, list }); createDescribe({ service, list });
return ` return {
export const eps = ${JSON.stringify({ service, list })} service,
`; list
};
} }

View File

@ -1,73 +1,6 @@
import { Plugin } from "vite"; import { base } from "./base";
import { createSvg } from "./svg"; import { virtual } from "./virtual";
import { createTag } from "./tag";
import { createEps } from "./eps";
import { createModule } from "./module";
import { createMenu } from "./menu";
import { parseJson } from "./utils";
export function cool(): Plugin { export function cool() {
// 虚拟模块 return [base(), virtual()];
const virtualModuleIds = ["virtual:eps", "virtual:module"];
return {
name: "vite-cool",
enforce: "pre",
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
function done(data: any) {
res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
res.end(JSON.stringify(data));
}
if (req.url?.includes("__cool")) {
const body = await parseJson(req);
switch (req.url) {
// 快速创建菜单
case "/__cool_createMenu":
await createMenu(body);
break;
// 创建描述文件
case "/__cool_eps":
await createEps(body);
break;
default:
return done({
code: 1001,
message: "未知请求"
});
}
done({
code: 1000
});
} else {
next();
}
});
},
transform(code, id) {
return createTag(code, id);
},
transformIndexHtml(html) {
return createSvg(html);
},
resolveId(id) {
if (virtualModuleIds.includes(id)) {
return "\0" + id;
}
},
async load(id) {
if (id === "\0virtual:eps") {
return createEps();
}
if (id === "\0virtual:module") {
return createModule();
}
}
};
} }

View File

@ -8,7 +8,5 @@ export function createModule() {
dirs = dirs.filter((e) => !e.includes(".")); dirs = dirs.filter((e) => !e.includes("."));
} catch (err) {} } catch (err) {}
return ` return { dirs };
export const dirs = ${JSON.stringify(dirs)}
`;
} }

32
build/cool/types/index.d.ts vendored Normal file
View File

@ -0,0 +1,32 @@
export namespace Eps {
interface Entity {
api: {
dts: {
parameters?: {
description: string;
name: string;
required: boolean;
schema: {
type: string;
};
}[];
};
name: string;
method: string;
path: string;
prefix: string;
summary: string;
tag: string;
}[];
columns: {
comment: string;
length: string;
nullable: boolean;
propertyName: string;
type: string;
}[];
module: string;
name: string;
prefix: string;
}
}

61
build/cool/virtual.ts Normal file
View File

@ -0,0 +1,61 @@
import type { Plugin, ViteDevServer } from "vite";
import { createEps } from "./eps";
import { createModule } from "./module";
export function virtual(): Plugin {
const virtualModuleIds = ["virtual:eps", "virtual:module"];
// 使虚拟模块失效,重新加载
function buildEps(server: ViteDevServer) {
virtualModuleIds.forEach((vm) => {
const mod = server.moduleGraph.getModuleById(`\0${vm}`);
if (mod) {
server.moduleGraph.invalidateModule(mod);
}
});
}
return {
name: "vite-cool-virtual",
enforce: "pre",
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
// 页面刷新时触发 eps 刷新
if (req.url == "/@vite/client") {
buildEps(server);
}
next();
});
},
handleHotUpdate({ file, server }) {
// 代码保存时触发 eps 刷新
if (!file.includes("build/cool/dist")) {
buildEps(server);
}
},
resolveId(id) {
if (virtualModuleIds.includes(id)) {
return "\0" + id;
}
},
async load(id) {
if (id === "\0virtual:eps") {
const { service, list } = await createEps();
return `
export const eps = ${JSON.stringify({ service, list })}
`;
}
if (id === "\0virtual:module") {
const { dirs } = createModule();
return `
export const dirs = ${JSON.stringify(dirs)}
`;
}
}
};
}

View File

@ -9,7 +9,7 @@
"lint:eslint": "eslint \"{src}/**/*.{vue,ts,tsx}\" --fix" "lint:eslint": "eslint \"{src}/**/*.{vue,ts,tsx}\" --fix"
}, },
"dependencies": { "dependencies": {
"@cool-vue/crud": "^7.0.1-beta2", "@cool-vue/crud": "^7.0.1-beta9",
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@vueuse/core": "^10.4.0", "@vueuse/core": "^10.4.0",
"@wangeditor/editor": "^5.1.23", "@wangeditor/editor": "^5.1.23",

View File

@ -56,8 +56,8 @@ declare type List<T> = Array<DeepPartial<T> | (() => DeepPartial<T>)>;
// 字典选项 // 字典选项
declare type DictOptions = { declare type DictOptions = {
label: string; label?: string;
value: any; value?: any;
color?: string; color?: string;
type?: string; type?: string;
[key: string]: any; [key: string]: any;
@ -703,7 +703,7 @@ declare interface Config {
size: ElementPlus.Size; size: ElementPlus.Size;
colors: string[]; colors: string[];
form: { form: {
labelPostion: ElementPlus.FormProps["labelPosition"]; labelPosition: ElementPlus.FormProps["labelPosition"];
labelWidth: ElementPlus.FormProps["labelWidth"]; labelWidth: ElementPlus.FormProps["labelWidth"];
span: number; span: number;
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "@cool-vue/crud", "name": "@cool-vue/crud",
"version": "7.0.1-beta2", "version": "7.0.1-beta9",
"private": false, "private": false,
"main": "./dist/index.umd.min.js", "main": "./dist/index.umd.min.js",
"typings": "types/index.d.ts", "typings": "types/index.d.ts",

View File

@ -1,7 +1,8 @@
import { ElMessageBox, ElMessage } from "element-plus"; import { ElMessageBox, ElMessage } from "element-plus";
import { Mitt } from "../../utils/mitt"; import { Mitt } from "../../utils/mitt";
import { ref } from "vue"; import { ref } from "vue";
import { isArray, isFunction, merge } from "lodash-es"; import { isArray, isFunction } from "lodash-es";
import { merge } from "../../utils";
interface Options { interface Options {
mitt: Mitt; mitt: Mitt;

View File

@ -463,9 +463,6 @@ export default defineComponent({
<el-form <el-form
ref={Form} ref={Form}
size={style.size} size={style.size}
label-position={
browser.isMini && !props.inline ? "top" : style.form.labelPostion
}
label-width={style.form.labelWidth} label-width={style.form.labelWidth}
inline={props.inline} inline={props.inline}
disabled={saving.value} disabled={saving.value}
@ -476,7 +473,13 @@ export default defineComponent({
e.preventDefault(); e.preventDefault();
}} }}
/>, />,
config.props, {
...config.props,
labelPosition:
browser.isMini && !props.inline
? "top"
: config.props.labelPosition || style.form.labelPosition
},
{ {
default: () => { default: () => {
return ( return (

View File

@ -15,7 +15,7 @@ export function useHeight({ config, Table }: { Table: Vue.Ref<any>; config: ClTa
let vm = Table.value; let vm = Table.value;
if (vm) { if (vm) {
while (!vm.$parent?.$el.className.includes("cl-crud")) { while (!vm.$parent?.$el.className?.includes("cl-crud")) {
vm = vm.$parent; vm = vm.$parent;
} }

View File

@ -405,7 +405,7 @@
grid-template-rows: 0fr; grid-template-rows: 0fr;
> .cl-form-item__children { > .cl-form-item__children {
margin: 10px 10px 10px 0px; margin: 10px;
min-height: 0; min-height: 0;
overflow: hidden; overflow: hidden;
} }

View File

@ -29,15 +29,16 @@ export function parseTableDict(value: any, item: ClTable.Column) {
// 设置颜色 // 设置颜色
if (item.dictColor) { if (item.dictColor) {
options.forEach((e, i) => { options.forEach((e, i) => {
e.color = style.colors[i]; if (!e.color) {
e.color = style.colors[i];
}
}); });
} }
// 格式化方法 // 绑定值
const formatter = item.dictFormatter; const values = (isArray(value) ? value : [value]).filter(
(e) => e !== undefined && e !== null && e !== ""
// 多个值 );
const values = isArray(value) ? value : [value];
// 返回值 // 返回值
const list = values.map((v) => { const list = values.map((v) => {
@ -48,8 +49,8 @@ export function parseTableDict(value: any, item: ClTable.Column) {
}); });
// 是否格式化 // 是否格式化
if (formatter) { if (item.dictFormatter) {
return formatter(list); return item.dictFormatter(list);
} else { } else {
return list.map((e) => { return list.map((e) => {
return h( return h(
@ -66,14 +67,14 @@ export function parseTableDict(value: any, item: ClTable.Column) {
/** /**
* table.op.buttons * table.op.buttons
*/ */
export function parseTableOpButtons(buttons: any, { scope }: any) { export function parseTableOpButtons(buttons: any[], { scope }: any) {
const { crud } = useCore(); const { crud } = useCore();
const { style } = useConfig(); const { style } = useConfig();
const slots = useSlots(); const slots = useSlots();
const list = getValue(buttons, { scope }) || ["edit", "delete"]; const list: any[] = getValue(buttons, { scope }) || ["edit", "delete"];
return list.map((vnode: any) => { return list.map((vnode) => {
if (vnode === "info") { if (vnode === "info") {
return ( return (
<el-button <el-button

View File

@ -7,7 +7,7 @@ declare const _default: import("vue").DefineComponent<{
}; };
title: StringConstructor; title: StringConstructor;
size: { size: {
type: (StringConstructor | NumberConstructor)[]; type: (NumberConstructor | StringConstructor)[];
default: string; default: string;
}; };
op: { op: {
@ -22,7 +22,7 @@ declare const _default: import("vue").DefineComponent<{
}; };
title: StringConstructor; title: StringConstructor;
size: { size: {
type: (StringConstructor | NumberConstructor)[]; type: (NumberConstructor | StringConstructor)[];
default: string; default: string;
}; };
op: { op: {

View File

@ -1,6 +1,6 @@
import { PropType } from "vue"; import { PropType } from "vue";
declare const _default: import("vue").DefineComponent<{ declare const _default: import("vue").DefineComponent<{
modelValue: (StringConstructor | NumberConstructor)[]; modelValue: (NumberConstructor | StringConstructor)[];
labels: { labels: {
type: ArrayConstructor; type: ArrayConstructor;
default: () => never[]; default: () => never[];
@ -14,7 +14,7 @@ declare const _default: import("vue").DefineComponent<{
default: string; default: string;
}; };
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("change" | "update:modelValue")[], "change" | "update:modelValue", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{ }, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("change" | "update:modelValue")[], "change" | "update:modelValue", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
modelValue: (StringConstructor | NumberConstructor)[]; modelValue: (NumberConstructor | StringConstructor)[];
labels: { labels: {
type: ArrayConstructor; type: ArrayConstructor;
default: () => never[]; default: () => never[];

View File

@ -74,15 +74,15 @@ export declare function useForm(): {
name?: string | undefined; name?: string | undefined;
options?: { options?: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[] | { }[] | {
value: { value: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[]; }[];
@ -105,15 +105,15 @@ export declare function useForm(): {
name?: string | undefined; name?: string | undefined;
options?: { options?: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[] | { }[] | {
value: { value: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[]; }[];
@ -136,15 +136,15 @@ export declare function useForm(): {
name?: string | undefined; name?: string | undefined;
options?: { options?: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[] | { }[] | {
value: { value: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[]; }[];

View File

@ -15,7 +15,7 @@ declare const _default: import("vue").DefineComponent<{
onSearch: FunctionConstructor; onSearch: FunctionConstructor;
placeholder: StringConstructor; placeholder: StringConstructor;
width: { width: {
type: (StringConstructor | NumberConstructor)[]; type: (NumberConstructor | StringConstructor)[];
default: number; default: number;
}; };
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("change" | "update:modelValue" | "field-change")[], "change" | "update:modelValue" | "field-change", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{ }, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("change" | "update:modelValue" | "field-change")[], "change" | "update:modelValue" | "field-change", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
@ -34,7 +34,7 @@ declare const _default: import("vue").DefineComponent<{
onSearch: FunctionConstructor; onSearch: FunctionConstructor;
placeholder: StringConstructor; placeholder: StringConstructor;
width: { width: {
type: (StringConstructor | NumberConstructor)[]; type: (NumberConstructor | StringConstructor)[];
default: number; default: number;
}; };
}>> & { }>> & {

View File

@ -13,15 +13,15 @@ export declare function useTable(props: any): {
name?: string | undefined; name?: string | undefined;
options?: { options?: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[] | { }[] | {
value: { value: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[]; }[];
@ -41,15 +41,15 @@ export declare function useTable(props: any): {
}; };
dict: { dict: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[] | { }[] | {
value: { value: {
[x: string]: any; [x: string]: any;
label: string; label?: string | undefined;
value: any; value?: any;
color?: string | undefined; color?: string | undefined;
type?: string | undefined; type?: string | undefined;
}[]; }[];

View File

@ -12,7 +12,7 @@ export declare function parseTableDict(value: any, item: ClTable.Column): string
/** /**
* table.op.buttons * table.op.buttons
*/ */
export declare function parseTableOpButtons(buttons: any, { scope }: any): any; export declare function parseTableOpButtons(buttons: any[], { scope }: any): any[];
/** /**
* *
*/ */

View File

@ -200,34 +200,26 @@ export function deepPaths(paths: string[], splitor?: string) {
} }
// 列表转树形 // 列表转树形
export function deepTree(list: any[], order?: "asc" | "desc"): any[] { export function deepTree(list: any[], sort?: "desc" | "asc"): any[] {
const newList: any[] = []; const newList: any[] = [];
const map: any = {}; const map: any = {};
list.forEach((e) => (map[e.id] = e)); orderBy(list, "orderNum", sort)
.map((e) => {
map[e.id] = e;
return e;
})
.forEach((e) => {
const parent = map[e.parentId];
list.forEach((e) => { if (parent) {
const parent = map[e.parentId]; (parent.children || (parent.children = [])).push(e);
} else {
if (parent) { newList.push(e);
(parent.children || (parent.children = [])).push(e);
} else {
newList.push(e);
}
});
const fn = (list: Array<any>) => {
list.map((e) => {
if (isArray(e.children)) {
e.children = orderBy(e.children, "orderNum", order);
fn(e.children);
} }
}); });
};
fn(newList); return newList;
return orderBy(newList, "orderNum", order);
} }
// 树形转列表 // 树形转列表

View File

@ -78,8 +78,8 @@ export default defineComponent({
) : ( ) : (
<el-option <el-option
disabled={e.disabled} disabled={e.disabled}
label={e[props.labelKey] || ""} label={e[props.labelKey]}
value={e[props.valueKey] || ""} value={e[props.valueKey]}
/> />
); );
})} })}

View File

@ -0,0 +1,52 @@
<template>
<div class="cl-view-head">
<el-icon class="cl-view-head__back" @click="router.back()">
<ArrowLeft />
</el-icon>
<span class="cl-view-head__title">{{ title }}</span>
</div>
</template>
<script setup lang="ts" name="cl-view-head">
import { computed } from "vue";
import { useCool } from "/@/cool";
import { ArrowLeft } from "@element-plus/icons-vue";
const props = defineProps({
title: String
});
const { route, router } = useCool();
//
const title = computed(() => props.title || route.query.title);
</script>
<style lang="scss" scoped>
.cl-view-head {
display: flex;
align-items: center;
margin-bottom: 10px;
height: 30px;
&__back {
cursor: pointer;
height: 30px;
width: 30px;
font-size: 16px;
border-radius: 4px;
margin-right: 10px;
background-color: var(--el-fill-color-lighter);
&:hover {
color: var(--color-primary);
}
}
&__title {
font-size: 14px;
line-height: 1;
}
}
</style>

View File

@ -68,9 +68,7 @@
<cl-svg name="bg"></cl-svg> <cl-svg name="bg"></cl-svg>
</div> </div>
<a href="https://beian.miit.gov.cn" class="copyright"> <a href="https://cool-js.com" class="copyright"> Copyright © COOL </a>
Copyright © 2023 COOL | ICP 2022012608
</a>
</div> </div>
</template> </template>

View File

@ -143,12 +143,7 @@ export const useMenuStore = defineStore("menu", function () {
}); });
} else { } else {
// 动态菜单 // 动态菜单
await service.base.comm await service.base.comm.permmenu().then(next);
.permmenu()
.then(next)
.catch(() => {
ElMessage.error("菜单加载异常!");
});
} }
} }

View File

@ -9,13 +9,7 @@
</cl-row> </cl-row>
<cl-row> <cl-row>
<cl-table <cl-table ref="Table" />
ref="Table"
:default-sort="{
prop: 'createTime',
order: 'descending'
}"
/>
</cl-row> </cl-row>
<cl-row> <cl-row>
@ -154,7 +148,7 @@ const Table = useTable({
{ {
prop: "createTime", prop: "createTime",
label: "创建时间", label: "创建时间",
sortable: "custom", sortable: "desc",
minWidth: 160 minWidth: 160
}, },
{ {

View File

@ -129,6 +129,9 @@ function open() {
} }
} }
], ],
op: {
// buttons: ["save"]
},
on: { on: {
open() { open() {
refs.name.focus(); refs.name.focus();

View File

@ -13,7 +13,7 @@ const useDictStore = defineStore("dict", () => {
// 获取 // 获取
function get(name: string) { function get(name: string) {
return computed(() => data[name]); return computed(() => data[name] || []);
} }
// 查找 // 查找

View File

@ -1,12 +1,13 @@
export namespace Dict { export namespace Dict {
type List = { interface Item {
id: string; id: string;
label: string; label: string;
value: any; value: any;
children?: Item[];
[key: string]: any; [key: string]: any;
}[]; }
interface Data { interface Data {
[key: string]: List; [key: string]: Item[];
} }
} }

View File

@ -19,7 +19,7 @@ import { useFormat } from "./format";
import { parsePx } from "/@/cool/utils"; import { parsePx } from "/@/cool/utils";
import { useTypes } from "./types"; import { useTypes } from "./types";
import { useCool } from "/@/cool"; import { useCool } from "/@/cool";
import { merge } from "lodash-es"; import { isObject, merge } from "lodash-es";
const props = defineProps({ const props = defineProps({
modelValue: String, modelValue: String,
@ -61,9 +61,15 @@ function getContent() {
} }
// //
function setContent(value?: string) { function setContent(value: string = "") {
if (isObject(value)) {
value = JSON.stringify(value);
} else {
value = value.toString();
}
if (value != getContent()) { if (value != getContent()) {
editor?.setValue(value || ""); editor?.setValue(value);
} }
} }
@ -74,7 +80,7 @@ async function formatCode() {
} }
// //
function init() { function create() {
const options = merge( const options = merge(
{ {
theme: "default", theme: "default",
@ -148,7 +154,7 @@ watch(
); );
onMounted(() => { onMounted(() => {
init(); create();
}); });
onUnmounted(() => { onUnmounted(() => {

View File

@ -1,10 +1,15 @@
<template> <template>
<div> <div>
<slot>
<el-button @click="open()">{{ text }}</el-button>
</slot>
<cl-dialog width="1000px" :title="title" append-to-body v-model="visible"> <cl-dialog width="1000px" :title="title" append-to-body v-model="visible">
<cl-editor <cl-editor
:name="`cl-editor-${name}`" :name="`cl-editor-${name}`"
:ref="setRefs('editor')" :ref="setRefs('editor')"
:height="600" :height="600"
preview
v-bind="props.props" v-bind="props.props"
v-model="text" v-model="text"
/> />
@ -25,6 +30,7 @@ import { nextTick, PropType, ref } from "vue";
import { useCool } from "/@/cool"; import { useCool } from "/@/cool";
const props = defineProps({ const props = defineProps({
modelValue: String,
title: { title: {
type: String, type: String,
default: "文本预览" default: "文本预览"
@ -33,6 +39,10 @@ const props = defineProps({
type: String as PropType<"monaco" | "quill" | "wang">, type: String as PropType<"monaco" | "quill" | "wang">,
required: true required: true
}, },
text: {
type: String,
default: "点击查看"
},
props: Object props: Object
}); });
@ -45,7 +55,11 @@ const visible = ref(false);
// //
const text = ref(""); const text = ref("");
async function open(data: string) { async function open(data?: string) {
if (!data) {
data = props.modelValue;
}
if (isString(data)) { if (isString(data)) {
text.value = data; text.value = data;
} }

View File

@ -1,13 +1,16 @@
<template> <template>
<div class="cl-editor-wang" :class="{ disabled }" :ref="setRefs('editor')"> <div class="cl-editor-wang" :class="{ disabled }" :ref="setRefs('editor')">
<!-- 工具栏 --> <!-- 工具栏 -->
<toolbar :editor="Editor" :mode="mode" /> <toolbar :editor="Editor" :mode="mode" v-if="!preview" />
<!-- 编辑框 --> <!-- 编辑框 -->
<editor <editor
v-model="value" v-model="value"
:defaultConfig="editorConfig" :defaultConfig="editorConfig"
:mode="mode" :mode="mode"
:style="{
height: parsePx(height)
}"
@onCreated="onCreated" @onCreated="onCreated"
@onFocus="onFocus" @onFocus="onFocus"
@onBlur="onBlur" @onBlur="onBlur"
@ -58,8 +61,8 @@ export default defineComponent({
type: [String, Number], type: [String, Number],
default: 400 default: 400
}, },
maxHeight: [String, Number], disabled: Boolean,
disabled: Boolean preview: Boolean
}, },
emits: ["update:modelValue", "change", "focus", "blur"], emits: ["update:modelValue", "change", "focus", "blur"],
@ -106,20 +109,23 @@ export default defineComponent({
} }
}; };
//
function onCreated(editor: any) { function onCreated(editor: any) {
Editor.value = editor; Editor.value = editor;
onDisabled(); onDisabled();
onHeight();
} }
//
function onFocus(editor: any) { function onFocus(editor: any) {
emit("focus", editor); emit("focus", editor);
} }
//
function onBlur(editor: any) { function onBlur(editor: any) {
emit("blur", editor); emit("blur", editor);
} }
//
function onChange() { function onChange() {
if (value.value == "<p><br></p>") { if (value.value == "<p><br></p>") {
value.value = ""; value.value = "";
@ -129,6 +135,7 @@ export default defineComponent({
emit("change", value.value); emit("change", value.value);
} }
//
function onFileConfirm(files: any[]) { function onFileConfirm(files: any[]) {
if (files.length > 0) { if (files.length > 0) {
files.forEach((file) => { files.forEach((file) => {
@ -141,30 +148,14 @@ export default defineComponent({
// //
function onDisabled() { function onDisabled() {
if (props.disabled) { if (props.disabled || props.preview) {
Editor.value?.disable(); Editor.value?.disable();
} else { } else {
Editor.value?.enable(); Editor.value?.enable();
} }
} }
watch(() => props.disabled, onDisabled); watch(() => [props.disabled, props.preview], onDisabled);
//
function onHeight() {
const scroll = refs.editor.querySelector(".w-e-scroll");
scroll.style.maxHeight = parsePx(props.maxHeight || "auto");
scroll.style.height = parsePx(props.height);
}
watch(
() => {
return [props.height, props.maxHeight];
},
() => {
onHeight();
}
);
onBeforeUnmount(() => { onBeforeUnmount(() => {
const editor = Editor.value; const editor = Editor.value;
@ -182,7 +173,8 @@ export default defineComponent({
onBlur, onBlur,
onChange, onChange,
editorConfig, editorConfig,
onFileConfirm onFileConfirm,
parsePx
}; };
} }
}); });

View File

@ -71,7 +71,6 @@ export function useCode() {
// 编辑器处理 // 编辑器处理
if (item.component?.name?.includes("cl-editor-")) { if (item.component?.name?.includes("cl-editor-")) {
table.columns.push(column);
column.component = { column.component = {
name: "cl-editor-preview", name: "cl-editor-preview",
props: { props: {

View File

@ -92,7 +92,7 @@
</el-icon> </el-icon>
</template> </template>
<el-icon @click.stop="remove"> <el-icon @click.stop="remove" v-if="!disabled">
<delete /> <delete />
</el-icon> </el-icon>
</div> </div>
@ -125,7 +125,8 @@ const props = defineProps({
list: { list: {
type: Array as PropType<Upload.Item[]>, type: Array as PropType<Upload.Item[]>,
default: () => [] default: () => []
} },
disabled: Boolean
}); });
const emit = defineEmits(["remove"]); const emit = defineEmits(["remove"]);

View File

@ -111,7 +111,12 @@
> >
<slot name="item" :item="item" :index="index"> <slot name="item" :item="item" :index="index">
<div class="cl-upload__item"> <div class="cl-upload__item">
<upload-item :item="item" :list="list" @remove="remove(index)" /> <upload-item
:item="item"
:list="list"
:disabled="disabled"
@remove="remove(index)"
/>
</div> </div>
</slot> </slot>
</el-upload> </el-upload>

View File

@ -282,10 +282,10 @@
"@babel/helper-validator-identifier" "^7.22.20" "@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@cool-vue/crud@^7.0.1-beta2": "@cool-vue/crud@^7.0.1-beta9":
version "7.0.1-beta2" version "7.0.1-beta9"
resolved "https://registry.yarnpkg.com/@cool-vue/crud/-/crud-7.0.1-beta2.tgz#1c43ad0d5af3fe009bfcfa312c71d8b99a676213" resolved "https://registry.yarnpkg.com/@cool-vue/crud/-/crud-7.0.1-beta9.tgz#caacb1eab03f48bc6789209242b198ebd06435f5"
integrity sha512-CN9hlfsWKOU/qf7E1COjgLqEqJBOd3v8v8bHeivFt7BHdDmwxrgqGZWXvZ6zp4LXSBq7dacF7dqn1FOe7TYzCQ== integrity sha512-PnukV6Q1sPsXZS2li2BrmCDmYKJdqFumE/wA2kaSTOcrIgmjYmrS/oa2c3C5BKXrwDD9561kq0q8vsKBTpGQxQ==
dependencies: dependencies:
array.prototype.flat "^1.2.4" array.prototype.flat "^1.2.4"
core-js "^3.21.1" core-js "^3.21.1"