v4 测试

This commit is contained in:
icssoa 2021-12-05 23:09:33 +08:00
parent 2610677c34
commit 8e741ffa41
109 changed files with 3295 additions and 2304 deletions

View File

@ -34,8 +34,8 @@
"",
"<script lang=\"ts\">",
"import { defineComponent, reactive } from \"vue\";",
"import { CrudLoad, Upsert, Table } from \"cl-admin-crud-vue3/types\";",
"import { useCool } from \"/@/core\";",
"import { CrudLoad, Upsert, Table } from \"@cool-vue/crud/types\";",
"import { useCool } from \"/@/cool\";",
"",
"export default defineComponent({",
" setup() {",

187
build/config/rules.ts Normal file
View File

@ -0,0 +1,187 @@
export default [
{
test: ["avatar", "img", "image", "pic", "photo", "picture", "head", "icon"],
table: {
name: "cl-image",
props: {
size: 60
}
},
form: {
name: "cl-upload"
}
},
{
test: ["avatars", "imgs", "images", "pics", "photos", "pictures", "heads", "icons"],
table: {
name: "cl-image",
props: {
size: 60
}
},
form: {
name: "cl-upload",
props: {
listType: "picture-card",
multiple: true
}
}
},
{
test: ["file", "attachment", "attach", "url", "video", "music"],
table: {
name: "cl-link"
},
form: {
name: "cl-upload",
props: {
listType: "text",
limit: 1
}
}
},
{
test: ["files", "attachments", "attachs", "urls", "videos", "musics"],
table: {
name: "cl-link"
},
form: {
name: "cl-upload",
props: {
listType: "text",
multiple: true
}
}
},
{
test: ["enable", "status"],
table: {
name: "cl-switch"
},
form: {
name: "el-switch"
}
},
{
test: ["type", "classify", "category"],
handler: "dict"
},
{
test: ["types", "classifys", "categorys"],
handler: "dict_multiple"
},
{
test: ["date"],
form: {
name: "el-date-picker",
props: {
type: "date"
}
}
},
{
test: ["dates", "dateRange", "dateScope"],
form: {
name: "el-date-picker",
props: {
type: "daterange"
}
}
},
{
test: ["time"],
form: {
name: "el-date-picker",
props: {
type: "datetime"
}
}
},
{
test: ["times", "timeRange", "timeScope"],
form: {
name: "el-date-picker",
props: {
type: "datetimerange"
}
}
},
{
test: ["star", "stars"],
table: {
name: "el-rate",
props: {
disabled: true
}
},
form: {
name: "el-rate"
}
},
{
test: ["progress", "rate", "ratio"],
table: {
name: "el-progress"
},
form: {
name: "el-slider",
props: {
style: {
width: "200px"
}
}
}
},
{
test: ["num", "price", "age", "amount"],
form: {
name: "el-input-number",
props: {
min: 0
}
}
},
{
test: ["remark", "desc"],
table: {
showOverflowTooltip: true
},
form: {
name: "el-input",
props: {
type: "textarea",
rows: 4
}
}
},
{
test: ["rich", "text", "html", "content"],
form: {
name: "el-editor-quill",
props: {
height: 400
}
}
},
{
test: ["code", "codes"],
form: {
name: "el-codemirror",
props: {
height: 400
}
}
},
{
test: ["createTime"],
table: {
sortable: "desc"
}
},
{
test: ["updateTime"],
table: {
sortable: "custom"
}
}
];

396
build/plugins/cool.ts Normal file
View File

@ -0,0 +1,396 @@
import { Plugin } from "vite";
import prettier from "prettier";
import fs from "fs";
import path from "path";
import { isFunction, isRegExp, isString } from "lodash";
import rules from "../config/rules";
// 根路径
const coolPath = path.join(__dirname, `../../src/cool`);
// 格式化
function format(data: any) {
return {
label: data.label,
prop: data.prop,
...data,
component: data.component
};
}
// 颜色
const colors = [
"",
"#409EFF",
"#67C23A",
"#E6A23C",
"#F56C6C",
"#909399",
"#B0CFEB",
"#FF9B91",
"#E6A23C",
"#BFAD6F",
"#FB78F2"
];
// 组件处理器
const handler = {
// 单选
dict({ comment }) {
const [label, ...arr] = comment.split(" ");
// 选择列表
const list = arr.map((e: string, i: number) => {
const [value, label] = e.split("-");
const d: any = {
label,
value: isNaN(Number(value)) ? value : Number(value)
};
if (colors[i]) {
d.color = colors[i];
}
return d;
});
const d = {
table: {
label,
dict: list
},
form: {
label,
value: list[0]?.value,
component: {
name: "",
options: list
}
}
};
// 匹配组件
d.form.component.name = arr.length > 4 ? "el-select" : "el-radio-group";
return d;
},
// 多选
dict_multiple({ comment }) {
const { table, form }: any = handler.dict({ comment });
if (!form.component.props) {
form.component.props = {};
}
if (!form.value) {
form.value = [];
}
switch (form.component.name) {
case "el-select":
form.component.props.multiple = true;
form.component.props.filterable = true;
break;
case "el-radio-group":
form.component.name = "el-checkbox-group";
break;
}
return {
table,
form
};
}
};
// 解析body
function parseJson(req: any) {
return new Promise((resolve, reject) => {
let d = "";
req.on("data", function (chunk: Buffer) {
d += chunk;
});
req.on("end", function () {
try {
resolve(JSON.parse(d));
} catch (e) {
reject(e);
}
});
});
}
// 创建组件
function createComponent(item: any) {
const { propertyName: prop, comment: label } = item;
let d = null;
rules.forEach((r: any) => {
const s = r.test.find((e: any) => {
if (isRegExp(e)) {
return e.test(prop);
}
if (isFunction(e)) {
return e(prop);
}
if (isString(e)) {
const re = new RegExp(`${e}$`);
return re.test(prop.toLocaleLowerCase());
}
return false;
});
if (s) {
if (r.handler) {
const fn = isString(r.handler) ? handler[r.handler] : r.handler;
if (isFunction(fn)) {
d = fn(item);
}
} else {
d = {
...r,
test: undefined
};
}
}
});
function parse(v: any) {
if (v?.name) {
return {
prop,
label,
component: v
};
} else {
return {
prop,
label,
...v
};
}
}
return {
column: parse(d?.table),
item: parse(d?.form)
};
}
// 获取页面标识
function getPageName(router: string) {
if (router.indexOf("/") === 0) {
router = router.substr(1, router.length);
}
return router ? `name: "${router.replace("/", "-")}",` : "";
}
// 创建文件
function createVue({ router, columns, prefix, api, module, filename }: any): void {
const upsert: any = {
items: []
};
const table: any = {
columns: []
};
// 遍历
columns.forEach((e: any) => {
// 组件
const { item, column }: any = createComponent(e);
// 验证规则
if (!e.nullable) {
item.required = true;
}
if (item.component) {
upsert.items.push(format(item));
}
table.columns.push(format(column));
});
// 服务
const service = prefix.replace("/admin", "service").replace(/\//g, ".");
// 请求路径
const paths = api.map((e: any) => e.path);
// 权限
const permission: any = {
add: paths.includes("/add"),
del: paths.includes("/delete"),
update: paths.includes("/info") && paths.includes("/update"),
page: paths.includes("/page"),
upsert: true
};
permission.upsert = permission.add || permission.update;
// 是否有操作栏
if (permission.del || permission.upsert) {
const d: any = {
type: "op",
buttons: []
};
if (permission.upsert) {
d.buttons.push("edit");
}
if (permission.del) {
d.buttons.push("delete");
}
table.columns.push(d);
}
// 是否多选、序号
if (permission.del) {
table.columns.unshift({
type: "selection"
});
} else {
table.columns.unshift({
label: "#",
type: "index"
});
}
// 代码模板
const temp = `<template>
<cl-crud :ref="setRefs('crud')" @load="onLoad">
<el-row type="flex" align="middle">
<!-- -->
<cl-refresh-btn />
${permission.add ? "<!-- 新增按钮 -->\n<cl-add-btn />" : ""}
${permission.del ? "<!-- 删除按钮 -->\n<cl-multi-delete-btn />" : ""}
<cl-flex1 />
<!-- -->
<cl-search-key />
</el-row>
<el-row>
<!-- -->
<cl-table :ref="setRefs('table')" v-bind="table" />
</el-row>
<el-row type="flex">
<cl-flex1 />
<!-- -->
<cl-pagination />
</el-row>
${
permission.update
? '<!-- 新增、编辑 -->\n<cl-upsert :ref="setRefs(\'upsert\')" v-bind="upsert" />'
: ""
}
</cl-crud>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
import { CrudLoad, Table${permission.upsert ? ", Upsert" : ""} } from "@cool-vue/crud/types";
import { useCool } from "/@/cool";
export default defineComponent({
${getPageName(router)}
setup() {
const { refs, setRefs, service } = useCool();
${
permission.upsert
? "// 新增、编辑配置\nconst upsert = reactive<Upsert>(" +
JSON.stringify(upsert) +
");"
: ""
}
// 表格配置
const table = reactive<Table>(${JSON.stringify(table)});
// crud 加载
function onLoad({ ctx, app }: CrudLoad) {
// 绑定 service
ctx.service(${service}).done();
app.refresh();
}
return {
refs,
setRefs,${permission.upsert ? "upsert," : ""}
table,
onLoad
};
}
});
</script>`;
const content = prettier.format(temp, {
parser: "vue",
useTabs: true,
tabWidth: 4,
endOfLine: "lf",
semi: true,
jsxBracketSameLine: true,
singleQuote: false,
printWidth: 100,
trailingComma: "none"
});
// views 目录是否存在
const dir = path.join(coolPath, `modules/${module}/views`);
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
// 创建文件
fs.createWriteStream(path.join(dir, `${filename}.vue`), {
flags: "w"
}).write(content);
}
export const cool = (): Plugin | null => {
return {
name: "vite-cool",
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
function done(data) {
res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
res.end(JSON.stringify(data));
}
if (req.url.includes("/__cool_createMenu")) {
try {
const body: any = await parseJson(req);
await createVue(body);
done({
code: 1000
});
} catch (e) {
done({
code: 1001,
message: e.message
});
}
} else if (req.url.includes("/__cool_modules")) {
const dirs = fs.readdirSync(path.join(coolPath, "modules"));
done({
code: 1000,
data: dirs.filter((e) => !e.includes("."))
});
} else {
next();
}
});
}
};
};

View File

@ -1,17 +1,17 @@
{
"name": "front-next",
"version": "0.8.1",
"version": "4.0.0",
"scripts": {
"dev": "vite",
"dev": "vite --host",
"build": "vite build",
"serve": "vite preview",
"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix"
},
"dependencies": {
"@cool-vue/crud": "^1.0.4",
"array.prototype.flat": "^1.2.4",
"axios": "^0.21.1",
"cl-admin-crud-vue3": "^0.9.6",
"clipboard": "^2.0.8",
"clone-deep": "^4.0.1",
"codemirror": "^5.62.0",
@ -22,6 +22,7 @@
"glob": "^7.1.6",
"js-beautify": "^1.13.5",
"merge": "^2.1.1",
"merge-deep": "^3.0.3",
"mitt": "^2.1.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
@ -50,14 +51,16 @@
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.13.0",
"iconv-lite": "^0.6.3",
"prettier": "^2.2.1",
"sass": "^1.42.1",
"sass-loader": "^11.1.1",
"svg-sprite-loader": "^6.0.2",
"typescript": "4.4.3",
"unplugin-vue-components": "0.15.4",
"vite": "^2.6.7",
"vite": "2.6.7",
"vite-plugin-compression": "^0.3.5",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-style-import": "^1.0.1",
"vite-svg-loader": "^2.1.0"
}

View File

@ -2,7 +2,7 @@
<el-config-provider :locale="locale">
<div class="preload" v-if="loading">
<div class="container">
<p class="name">COOL-ADMIN</p>
<p class="name">{{ app.name }}</p>
<div class="loading"></div>
<p class="title">正在加载菜单...</p>
<p class="sub-title">初次加载资源可能需要较多时间 请耐心等待</p>
@ -21,7 +21,7 @@
import { computed, defineComponent } from "vue";
import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
components: {
@ -29,13 +29,14 @@ export default defineComponent({
},
setup() {
const { store } = useCool();
const { store, app } = useCool();
const locale = zhCn;
const loading = computed(() => store.getters.appLoading);
return {
locale,
loading
loading,
app
};
}
});

View File

@ -1,5 +1,5 @@
import store from "store";
import { getUrlParam } from "/@/core/utils";
import { getUrlParam } from "/@/cool/utils";
import { MenuItem } from "/$/base/types";
// 路由模式

View File

@ -1,4 +1,4 @@
import { onBeforeUpdate, ref, inject } from "vue";
import { onBeforeUpdate, ref, inject, computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useStore } from "vuex";
@ -23,6 +23,7 @@ export function useCool() {
const store = useStore();
const route = useRoute();
const router = useRouter();
const app = computed(() => store.getters.app);
return {
store,
@ -31,6 +32,18 @@ export function useCool() {
refs,
setRefs,
service,
mitt
mitt,
app
};
}
export function useModule() {
const store = useStore();
const moduleList = computed(() => store.getters.moduleList);
const modules = computed(() => store.getters.modules);
return {
moduleList,
modules
};
}

View File

@ -1,11 +1,8 @@
import BaseService from "./service/base";
import { Service, Permission, useService } from "./service";
import { useRouter } from "./router";
import { useModule } from "./module";
import router from "/@/router";
import store from "/@/store";
const service = useService();
import { service } from "./service";
import { useRouter } from "./router";
import { useModule } from "./module";
async function bootstrap(app: any) {
app.config.globalProperties.service = store.service = service;
@ -37,5 +34,6 @@ function usePermission(list: any[]) {
deep(service);
}
export { Service, Permission, BaseService, service, bootstrap, usePermission };
export { service, bootstrap, usePermission };
export { BaseService, Service, Permission, useEps } from "./service";
export * from "./hook";

View File

@ -1,11 +1,11 @@
import cool from "/@/cool";
import { modules as mods } from "/@/cool/modules";
import store from "/@/store";
import router from "/@/router";
import { deepMerge, isFunction, isObject, isEmpty } from "../utils";
import { deepFiles } from "../service";
// 模块列表
const modules: any[] = [...cool.modules];
const modules: any[] = [...mods];
function useModule(app: any) {
// 安装模块
@ -78,6 +78,10 @@ function useModule(app: any) {
const value: any = files[i].default;
const fname: string = (cname || "").split(".")[0];
if (name == "index.ts") {
continue;
}
function next(d: any) {
// 配置参数入口
if (fn == "config.ts") {
@ -159,7 +163,8 @@ function useModule(app: any) {
pages: [],
views: [],
store: {},
_services: []
_services: [],
_local: true
})
);
}

View File

@ -1,8 +1,7 @@
import { ElMessage } from "element-plus";
import store from "/@/store";
import router, { ignore } from "/@/router";
import storage from "../utils/storage";
import { cloneDeep } from "../utils";
import { cloneDeep, storage } from "../utils";
const views = import.meta.globEager("/src/**/views/**/*.vue");

View File

@ -3,7 +3,7 @@ import request from "/@/service/request";
import { baseUrl, isDev } from "/@/config/env";
export default class BaseService {
constructor() {
constructor(options: any = {}) {
const crud: any = {
page: "page",
list: "list",
@ -13,6 +13,10 @@ export default class BaseService {
update: "update"
};
if (options?.namespace) {
this.namespace = options?.namespace;
}
if (!this.permission) this.permission = {};
for (const i in crud) {
@ -51,62 +55,50 @@ export default class BaseService {
return request(options);
}
list(params: any) {
list(data: any) {
return this.request({
url: "/list",
method: "POST",
data: {
...params
}
data
});
}
page(params: any) {
page(data: any) {
return this.request({
url: "/page",
method: "POST",
data: {
...params
}
data
});
}
info(params: any) {
return this.request({
url: "/info",
params: {
...params
}
params
});
}
update(params: any) {
update(data: any) {
return this.request({
url: "/update",
method: "POST",
data: {
...params
}
data
});
}
delete(params: any) {
delete(data: any) {
return this.request({
url: "/delete",
method: "POST",
data: {
...params
}
data
});
}
add(params: any) {
add(data: any) {
return this.request({
url: "/add",
method: "POST",
data: {
...params
}
data
});
}
}

View File

@ -1,7 +1,5 @@
import { isObject } from "../utils";
console.log(__PROXY_LIST__);
export function Permission(value: string) {
return function (target: any, key: any, descriptor: any) {
if (!target.permission) {

View File

@ -0,0 +1,141 @@
import BaseService from "./base";
import { Service, Permission } from "./decorator";
import { basename } from "../utils";
function deepFiles(list: any[]) {
const modules: any = {};
list.forEach((e) => {
const arr: any[] = e.path.split("/");
const parents: any[] = arr.slice(0, arr.length - 1);
const name: string = basename(e.path).replace(".ts", "");
let curr: any = modules;
let prev: any = null;
let key: any = null;
parents.forEach((k) => {
if (!curr[k]) {
curr[k] = {};
}
prev = curr;
curr = curr[k];
key = k;
});
if (name == "index") {
prev[key] = e.value;
} else {
curr[name] = e.value;
}
});
return modules;
}
function useService() {
const files = import.meta.globEager("/src/service/**/*.ts");
const d: any = [];
for (const i in files) {
if (!i.includes("request.ts")) {
const value = files[i].default;
d.push({
path: i.replace("/src/service/", ""),
value: new value()
});
}
}
const s = deepFiles(d);
s.request = new BaseService().request;
return s;
}
const service = useService();
function useEps() {
return service.base.common
.eps()
.then((res: any) => {
for (const i in res) {
res[i].forEach((e: any) => {
// 分隔路径
const arr = e.prefix
.replace(/\//, "")
.replace("admin", "")
.split("/")
.filter(Boolean);
function deep(d: any, i: number) {
const k = arr[i];
if (k) {
// 是否最后一个
if (arr[i + 1]) {
if (!d[k]) {
d[k] = {};
}
deep(d[k], i + 1);
} else {
// 本地不存在则创建实例
if (!d[k]) {
d[k] = new BaseService({
namespace: e.prefix.replace("/admin/", "")
});
}
// 创建方法
e.api.forEach((a: any) => {
const n = a.path.replace("/", "");
if (
![
"add",
"info",
"update",
"page",
"list",
"delete"
].includes(n)
) {
// 设置权限
d[k].permission[n] = (
(d[k].namespace ? d[k].namespace + "/" : "") + n
).replace(/\//g, ":");
// 本地不存在则创建
if (!d[k][n]) {
d[k][n] = function (data: any) {
return this.request({
url: a.path,
method: a.method,
[a.method.toLocaleLowerCase() == "post"
? "data"
: "params"]: data
});
};
}
}
});
}
}
}
deep(service, 0);
});
}
console.log(service);
return res;
})
.catch((err: string) => {
console.error("Eps error", err);
});
}
export { BaseService, Service, Permission, service, deepFiles, useService, useEps };

View File

@ -1,22 +1,2 @@
import Crud from "cl-admin-crud-vue3";
import "cl-admin-crud-vue3/dist/index.css";
export default {
modules: [
// crud 模块
{
name: "crud",
value: Crud,
options: {
crud: {
dict: {
sort: {
prop: "order",
order: "sort"
}
}
}
}
}
]
};
export * from "./core";
export * from "./modules";

View File

@ -1,5 +1,5 @@
import { iconfontUrl, app } from "/@/config/env";
import { basename } from "/@/core/utils";
import { basename } from "/@/cool/utils";
import { createLink } from "../utils";
// 主题初始化

View File

@ -1,6 +1,6 @@
<template>
<div class="cl-avatar" :class="[size, shape]" :style="[style]">
<el-image :src="src" alt="">
<el-image :src="src || modelValue" alt="">
<template #error>
<div class="image-slot">
<i class="el-icon-user-solid" :style="{ color }"></i>
@ -12,12 +12,13 @@
<script lang="ts">
import { computed, defineComponent } from "vue";
import { isNumber } from "/@/core/utils";
import { isNumber } from "/@/cool/utils";
export default defineComponent({
name: "cl-avatar",
props: {
modelValue: String,
src: String,
size: {
type: [String, Number],

View File

@ -17,7 +17,7 @@ import "codemirror/addon/hint/show-hint.css";
import "codemirror/theme/hopscotch.css";
import "codemirror/addon/hint/javascript-hint";
import "codemirror/mode/javascript/javascript";
import { deepMerge } from "/@/core/utils";
import { deepMerge } from "/@/cool/utils";
export default defineComponent({
name: "cl-codemirror",

View File

@ -33,10 +33,10 @@
</template>
<script lang="ts">
import { deepTree } from "/@/core/utils";
import { deepTree } from "/@/cool/utils";
import { ElMessage } from "element-plus";
import { defineComponent, inject, nextTick, onMounted, ref, watch } from "vue";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-dept-check",
@ -79,7 +79,7 @@ export default defineComponent({
//
function refresh() {
service.base.system.dept
service.base.sys.department
.list()
.then((res: any[]) => {
list.value = deepTree(res);

View File

@ -1,5 +1,5 @@
import { useCool } from "/@/core";
import { deepTree } from "/@/core/utils";
import { useCool } from "/@/cool";
import { deepTree } from "/@/cool/utils";
import { ElMessage, ElMessageBox } from "element-plus";
import { defineComponent, h, ref } from "vue";
@ -16,7 +16,7 @@ export default defineComponent({
// 刷新列表
async function refresh() {
return await service.base.system.dept.list().then(deepTree);
return await service.base.sys.department.list().then(deepTree);
}
// 转移
@ -51,7 +51,7 @@ export default defineComponent({
type: "warning"
})
.then(() => {
service.base.system.user
service.base.sys.user
.move({
departmentId: id,
userIds: ids

View File

@ -63,9 +63,9 @@
<script lang="ts">
import { defineComponent, inject, onMounted, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { ContextMenu } from "cl-admin-crud-vue3";
import { useCool } from "/@/core";
import { deepTree, isArray, revDeepTree, isPc } from "/@/core/utils";
import { ContextMenu } from "@cool-vue/crud";
import { useCool } from "/@/cool";
import { deepTree, isArray, revDeepTree, isPc } from "/@/cool/utils";
export default defineComponent({
name: "cl-dept-tree",
@ -113,7 +113,7 @@ export default defineComponent({
isDrag.value = false;
loading.value = true;
await service.base.system.dept.list().then((res: any[]) => {
await service.base.sys.department.list().then((res: any[]) => {
list.value = deepTree(res);
emit("list-change", list.value);
});
@ -179,7 +179,7 @@ export default defineComponent({
form: e,
on: {
submit: (data: any, { done, close }: any) => {
service.base.system.dept[method]({
service.base.sys.department[method]({
id: e.id,
parentId: e.parentId,
name: data.name,
@ -202,7 +202,7 @@ export default defineComponent({
//
function rowDel(e: any) {
const del = async (f: boolean) => {
await service.base.system.dept
await service.base.sys.department
.delete({
ids: [e.id],
deleteUser: f
@ -259,7 +259,7 @@ export default defineComponent({
deep(list.value, null);
await service.base.system.dept
await service.base.sys.department
.order(
ids.map((e, i) => {
return {
@ -298,7 +298,7 @@ export default defineComponent({
"suffix-icon": "el-icon-plus",
hidden:
(n && n.level >= props.level) ||
!service.base.system.dept._permission.add,
!service.base.sys.department._permission.add,
callback: (_: any, done: Function) => {
rowEdit({
name: "",
@ -311,7 +311,7 @@ export default defineComponent({
{
label: "编辑",
"suffix-icon": "el-icon-edit",
hidden: !service.base.system.dept._permission.update,
hidden: !service.base.sys.department._permission.update,
callback: (_: any, done: Function) => {
rowEdit(d);
done();
@ -320,7 +320,7 @@ export default defineComponent({
{
label: "删除",
"suffix-icon": "el-icon-delete",
hidden: !d.parentId || !service.base.system.dept._permission.delete,
hidden: !d.parentId || !service.base.sys.department._permission.delete,
callback: (_: any, done: Function) => {
rowDel(d);
done();
@ -329,7 +329,7 @@ export default defineComponent({
{
label: "新增成员",
"suffix-icon": "el-icon-user",
hidden: !service.base.system.user._permission.add,
hidden: !service.base.sys.user._permission.add,
callback: (_: any, done: Function) => {
emit("user-add", d);
done();

View File

@ -15,8 +15,8 @@
import { computed, defineComponent, onMounted, ref, watch } from "vue";
import Quill from "quill";
import "quill/dist/quill.snow.css";
import { isNumber } from "/@/core/utils";
import { useCool } from "/@/core";
import { isNumber } from "/@/cool/utils";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-editor-quill",

View File

@ -6,7 +6,7 @@
<script lang="ts">
import { computed, defineComponent, ref } from "vue";
import { isNumber } from "/@/core/utils";
import { isNumber } from "/@/cool/utils";
export default defineComponent({
name: "icon-svg",

View File

@ -27,12 +27,14 @@
<script lang="ts">
import { computed, defineComponent } from "vue";
import { isArray, isNumber, isString } from "/@/core/utils";
import { isArray, isNumber, isString } from "/@/cool/utils";
export default defineComponent({
name: "cl-image",
props: {
modelValue: [String, Array],
src: [String, Array],
size: {
type: [Number, Array],
default: 100
@ -45,7 +47,6 @@ export default defineComponent({
type: String,
default: "cover"
},
src: [String, Array],
justify: {
type: String,
default: "center"
@ -54,7 +55,7 @@ export default defineComponent({
setup(props) {
const urls = computed(() => {
const urls: any = props.src;
const urls: any = props.modelValue || props.src;
if (isArray(urls)) {
return urls;

View File

@ -0,0 +1,79 @@
<template>
<a v-for="item in urls" :key="item" class="cl-link" :href="item" :target="target">
<el-icon><icon-link /></el-icon>{{ filename(item) }}
</a>
</template>
<script lang="ts">
import { defineComponent, computed } from "vue";
import { isArray, isString, last } from "/@/cool/utils";
import { Link } from "@element-plus/icons";
export default defineComponent({
name: "cl-link",
components: {
"icon-link": Link
},
props: {
modelValue: [String, Array],
href: [String, Array],
text: {
type: String,
default: "查看"
},
target: {
type: String,
default: "_blank"
}
},
setup(props) {
const urls = computed(() => {
const urls: any = props.modelValue || props.href;
if (isArray(urls)) {
return urls;
}
if (isString(urls)) {
return (urls || "").split(",").filter(Boolean);
}
return [];
});
function filename(url: string) {
return last(url.split("/"));
}
return {
urls,
filename
};
}
});
</script>
<style lang="scss" scoped>
.cl-link {
display: inline-flex;
align-items: center;
text-align: left;
background-color: $color-primary;
color: #fff;
padding: 0 5px;
border-radius: 5px;
font-size: 12px;
margin: 2px;
.el-icon {
margin-right: 2px;
}
&:hover {
text-decoration: underline;
}
}
</style>

View File

@ -1,10 +1,10 @@
<template>
<div class="cl-menu-icons">
<div class="cl-menu-icons__wrap">
<el-popover
v-model:visible="visible"
placement="bottom-start"
trigger="click"
width="480px"
popper-class="popper-menu-icon"
popper-class="cl-menu-icons"
>
<el-row :gutter="10" class="list scroller1">
<el-col v-for="(item, index) in list" :key="index" :span="3" :xs="4">
@ -91,7 +91,7 @@ export default defineComponent({
.
<style lang="scss">
.popper-menu-icon {
.cl-menu-icons {
max-width: 90%;
box-sizing: border-box;

View File

@ -0,0 +1,244 @@
<template>
<el-button type="success" size="mini" @click="create">快速创建</el-button>
<cl-form :ref="setRefs('form')" />
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { useModule } from "/@/cool";
import { last, isEmpty } from "/@/cool/utils";
import { ElMessage } from "element-plus";
import { useCool } from "/@/cool/core";
export default defineComponent({
name: "cl-menu-quick",
emits: ["success"],
setup(_, { emit }) {
const { service, refs, setRefs } = useCool();
//
async function create() {
//
const modules = await service.request({
url: "/__cool_modules"
});
//
const eps: any[] = await service.base.common.eps();
const entities: any[] = [];
for (const i in eps) {
eps[i].forEach((e: any) => {
if (!isEmpty(e.columns)) {
entities.push({
label: `${e.name}${e.prefix}`,
value: entities.length,
filename: last(e.prefix.split("/")),
...e
});
}
});
}
//
refs.value.form.open({
title: "快速创建",
width: "900px",
items: [
{
prop: "module",
label: {
text: "模块名称",
tip: "菜单文件存放在所选模块的 views 目录下",
icon: "el-icon-question"
},
span: 9,
component: {
name: "el-select",
props: {
filterable: true,
clearable: true
},
options: modules.map((e: string) => {
return {
label: e,
value: e
};
})
},
required: true
},
{
prop: "entity",
label: {
text: "数据结构",
tip: "所选实体会通过规则配置自动转换",
icon: "el-icon-question"
},
span: 15,
component: {
name: "el-select",
props: {
filterable: true,
clearable: true,
onChange(i: number) {
refs.value.form.setForm(
"router",
"/" +
(refs.value.form.getForm("module") || "test") +
"/" +
entities[i].filename
);
}
},
options: entities
},
required: true
},
{
prop: "name",
label: "菜单名称",
span: 9,
component: {
name: "el-input",
props: {
placeholder: "请输入菜单名称"
}
},
required: true
},
{
prop: "router",
label: "菜单路由",
span: 15,
component: {
name: "el-input",
props: {
placeholder: "请输入菜单路由,如:/test"
}
}
},
{
prop: "parentId",
label: "上级节点",
component: {
name: "cl-menu-tree"
}
},
{
prop: "keepAlive",
value: true,
label: "路由缓存",
component: {
name: "el-radio-group",
options: [
{
label: "开启",
value: true
},
{
label: "关闭",
value: false
}
]
}
},
{
prop: "icon",
label: "菜单图标",
component: {
name: "cl-menu-icons"
}
},
{
prop: "orderNum",
label: "排序号",
component: {
name: "el-input-number",
props: {
placeholder: "请填写排序号",
min: 0,
max: 99,
"controls-position": "right"
}
}
}
],
on: {
submit(data: any, { done, close }: any) {
//
const item = entities[data.entity];
//
service.base.sys.menu
.add({
type: 1,
isShow: true,
viewPath: `cool/modules/${data.module}/views/${item.filename}.vue`,
...data
})
.then((res: any) => {
//
const perms: any[] = [];
item.api.forEach((e: any) => {
const d: any = {
type: 2,
parentId: res.id,
name: e.summary || e.path,
perms: [e.path]
};
if (e.path == "/update") {
if (item.api.find((a: any) => a.path == "/info")) {
d.perms.push("/info");
}
}
d.perms = d.perms
.map((e: string) =>
(item.prefix.replace("/admin/", "") + e).replace(
/\//g,
":"
)
)
.join(";");
perms.push(d);
});
//
service.base.sys.menu.add(perms).then(() => {
emit("success");
close();
service.request({
url: "/__cool_createMenu",
method: "POST",
data: {
...item,
...data
}
});
});
})
.catch((err: string) => {
ElMessage.error(err);
done();
});
}
}
});
}
return {
refs,
setRefs,
create
};
}
});
</script>

View File

@ -1,6 +1,6 @@
import { computed, defineComponent, h, ref, watch } from "vue";
import "./index.scss";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-menu-slider",

View File

@ -17,7 +17,7 @@
<script lang="ts">
import { computed, defineComponent, onMounted, ref } from "vue";
import { firstMenu } from "../../utils";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-menu-topbar",

View File

@ -1,43 +1,45 @@
<template>
<el-popover
:visible="visible"
placement="bottom-start"
trigger="click"
width="500px"
popper-class="cl-menu-tree"
>
<el-input v-model="keyword" size="small">
<template #prefix>
<i class="el-input__icon el-icon-search"></i>
<div class="cl-menu-tree__wrap">
<el-popover
v-model:visible="visible"
placement="bottom-start"
trigger="click"
width="500px"
popper-class="cl-menu-tree"
>
<el-input v-model="keyword" size="small">
<template #prefix>
<i class="el-input__icon el-icon-search"></i>
</template>
</el-input>
<div class="cl-menu-tree__scroller scroller1">
<el-tree
ref="treeRef"
node-key="menuId"
:data="treeList"
:props="{
label: 'name',
children: 'children'
}"
:highlight-current="true"
:expand-on-click-node="false"
:default-expanded-keys="expandedKeys"
:filter-node-method="filterNode"
@current-change="onCurrentChange"
/>
</div>
<template #reference>
<el-input v-model="name" readonly placeholder="请选择" @click="visible = true" />
</template>
</el-input>
<div class="cl-menu-tree__scroller scroller1">
<el-tree
ref="treeRef"
node-key="menuId"
:data="treeList"
:props="{
label: 'name',
children: 'children'
}"
:highlight-current="true"
:expand-on-click-node="false"
:default-expanded-keys="expandedKeys"
:filter-node-method="filterNode"
@current-change="onCurrentChange"
/>
</div>
<template #reference>
<el-input v-model="name" readonly placeholder="请选择" @click="visible = true" />
</template>
</el-popover>
</el-popover>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, inject, onMounted, ref, watch } from "vue";
import { deepTree } from "/@/core/utils";
import { deepTree } from "/@/cool/utils";
export default defineComponent({
name: "cl-menu-tree",
@ -74,7 +76,7 @@ export default defineComponent({
//
function refresh() {
service.base.system.menu.list().then((res: any) => {
service.base.sys.menu.list().then((res: any) => {
const _list = res.filter((e: any) => e.type != 2);
_list.unshift({

View File

@ -32,9 +32,9 @@
<script lang="ts">
import { computed, reactive, watch } from "vue";
import { last } from "/@/core/utils";
import { useCool } from "/@/core";
import { ContextMenu } from "cl-admin-crud-vue3";
import { last } from "/@/cool/utils";
import { useCool } from "/@/cool";
import { ContextMenu } from "@cool-vue/crud";
export default {
name: "cl-process",

View File

@ -26,7 +26,7 @@
<script lang="ts">
import { defineComponent, inject, onMounted, ref, watch } from "vue";
import { ElMessage } from "element-plus";
import { deepTree } from "/@/core/utils";
import { deepTree } from "/@/cool/utils";
export default defineComponent({
name: "cl-role-perms",
@ -85,7 +85,7 @@ export default defineComponent({
//
function refresh() {
service.base.system.menu
service.base.sys.menu
.list()
.then((res: any[]) => {
list.value = deepTree(res);

View File

@ -6,7 +6,7 @@
<script lang="ts">
import { defineComponent, inject, onMounted, ref, watch } from "vue";
import { isArray } from "/@/core/utils";
import { isArray } from "/@/cool/utils";
export default defineComponent({
name: "cl-role-select",
@ -45,7 +45,7 @@ export default defineComponent({
);
onMounted(async () => {
list.value = await service.base.system.role.list();
list.value = await service.base.sys.role.list();
});
return {

View File

@ -18,8 +18,8 @@
<script lang="ts">
import { computed, defineComponent, ref, watch } from "vue";
import _ from "lodash";
import { isEmpty } from "/@/core/utils";
import { useCool } from "/@/core";
import { isEmpty } from "/@/cool/utils";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-route-nav",

View File

@ -21,7 +21,7 @@
<script lang="ts">
import { computed, defineComponent } from "vue";
import { getBrowser } from "/@/core/utils";
import { getBrowser } from "/@/cool/utils";
export default defineComponent({
name: "cl-scrollbar",

View File

@ -0,0 +1,112 @@
<template>
<div class="cl-switch">
<el-switch
:ref="setRefs('switch')"
:model-value="status"
:disabled="disabled"
:loading="loading"
:width="width"
:inline-prompt="inlinePrompt"
:active-icon="activeIcon"
:inactive-icon="inactiveIcon"
:active-text="activeText"
:inactive-text="inactiveText"
:active-value="activeValue"
:inactive-value="inactiveValue"
:active-color="activeColor"
:inactive-color="inactiveColor"
:border-color="borderColor"
:string="string"
:validate-event="validateEvent"
:before-change="beforeChange"
@change="onChange"
/>
</div>
</template>
<script lang="ts">
import { ElMessage } from "element-plus";
import { defineComponent, inject, ref, watch } from "vue";
import { useCool } from "/@/cool/core";
export default defineComponent({
name: "cl-switch",
props: {
scope: null,
column: null,
modelValue: [Boolean, String, Number],
disabled: Boolean,
loading: Boolean,
width: Number,
inlinePrompt: Boolean,
activeIcon: String,
inactiveIcon: String,
activeText: String,
inactiveText: String,
activeValue: {
type: [Boolean, String, Number],
default: 1
},
inactiveValue: {
type: [Boolean, String, Number],
default: 0
},
activeColor: String,
inactiveColor: String,
borderColor: String,
string: String,
validateEvent: {
type: Boolean,
default: true
},
beforeChange: Function
},
emits: ["update:modelValue", "change"],
setup(props, { emit }) {
const { refs, setRefs } = useCool();
const crud = inject<any>("crud");
//
const status = ref<any>(props.modelValue);
watch(
() => props.modelValue,
(val: any) => {
status.value = val;
}
);
function focus() {
refs.value.switch.focus();
}
function onChange(val: boolean | string | number) {
crud.service
.update({
...props.scope,
[props.column.property]: val
})
.then(() => {
emit("update:modelValue", val);
emit("change", val);
status.value = val;
ElMessage.success("更新成功");
})
.catch((err: string) => {
ElMessage.error(err);
});
}
return {
refs,
setRefs,
focus,
onChange,
status
};
}
});
</script>

View File

@ -34,8 +34,8 @@
<script lang="ts">
import { computed, defineComponent, ref } from "vue";
import { href } from "/@/core/utils";
import { useCool } from "/@/core";
import { href } from "/@/cool/utils";
import { useCool } from "/@/cool";
export default defineComponent({
props: {

View File

@ -2,7 +2,7 @@
<div class="page-login">
<div class="box">
<img class="logo" src="../../static/images/logo.png" alt="" />
<p class="desc">COOL ADMIN是一款快速开发后台权限管理系统</p>
<p class="desc">{{ app.name }}是一款快速开发后台权限管理系统</p>
<el-form label-position="top" class="form" size="medium" :disabled="saving">
<el-form-item label="用户名">
@ -57,7 +57,8 @@
import { defineComponent, reactive, ref } from "vue";
import { ElMessage } from "element-plus";
import Captcha from "./components/captcha.vue";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
import { useEps } from "/@/cool/core";
export default defineComponent({
cool: {
@ -71,7 +72,7 @@ export default defineComponent({
},
setup() {
const { refs, setRefs, store, router }: any = useCool();
const { refs, setRefs, store, router, app }: any = useCool();
const saving = ref<boolean>(false);
@ -106,6 +107,9 @@ export default defineComponent({
//
await store.dispatch("userInfo");
// Eps
await useEps();
//
const [first] = await store.dispatch("permMenu");
@ -114,7 +118,7 @@ export default defineComponent({
} else {
router.push("/");
}
} catch (err) {
} catch (err: any) {
ElMessage.error(err);
refs.value.captcha.refresh();
}
@ -124,10 +128,11 @@ export default defineComponent({
return {
refs,
setRefs,
form,
saving,
toLogin,
setRefs
app
};
}
});

View File

@ -1,4 +1,4 @@
import { BaseService, Service } from "/@/core";
import { BaseService, Service } from "/@/cool";
@Service("base/comm")
class Common extends BaseService {
@ -75,6 +75,15 @@ class Common extends BaseService {
url: "/permmenu"
});
}
/**
*
*/
eps() {
return this.request({
url: "/eps"
});
}
}
export default Common;

View File

@ -1,4 +1,4 @@
import { BaseService, Service } from "/@/core";
import { BaseService, Service } from "/@/cool";
@Service("base/open")
class Open extends BaseService {

View File

@ -1,32 +0,0 @@
import { BaseService, Service, Permission } from "/@/core";
@Service("base/plugin/info")
class PluginInfo extends BaseService {
@Permission("config")
config(data: any) {
return this.request({
url: "/config",
method: "POST",
data
});
}
@Permission("getConfig")
getConfig(params: any) {
return this.request({
url: "/getConfig",
params
});
}
@Permission("enable")
enable(data: any) {
return this.request({
url: "/enable",
method: "POST",
data
});
}
}
export default PluginInfo;

View File

@ -1,15 +0,0 @@
import { BaseService, Service, Permission } from "/@/core";
@Service("base/sys/department")
class SysDepartment extends BaseService {
@Permission("order")
order(data: any) {
return this.request({
url: "/order",
method: "POST",
data
});
}
}
export default SysDepartment;

View File

@ -1,32 +0,0 @@
import { BaseService, Service, Permission } from "/@/core";
@Service("base/sys/log")
class SysLog extends BaseService {
@Permission("clear")
clear() {
return this.request({
url: "/clear",
method: "POST"
});
}
@Permission("getKeep")
getKeep() {
return this.request({
url: "/getKeep"
});
}
@Permission("setKeep")
setKeep(value: any) {
return this.request({
url: "/setKeep",
method: "POST",
data: {
value
}
});
}
}
export default SysLog;

View File

@ -1,6 +0,0 @@
import { BaseService, Service } from "/@/core";
@Service("base/sys/menu")
class SysMenu extends BaseService {}
export default SysMenu;

View File

@ -1,6 +0,0 @@
import { BaseService, Service } from "/@/core";
@Service("base/sys/param")
class SysParam extends BaseService {}
export default SysParam;

View File

@ -1,6 +0,0 @@
import { BaseService, Service } from "/@/core";
@Service("base/sys/role")
class SysRole extends BaseService {}
export default SysRole;

View File

@ -1,41 +0,0 @@
import { BaseService, Service, Permission } from "/@/core";
@Service("base/sys/task")
class SysTask extends BaseService {
@Permission("stop")
stop(data: any) {
return this.request({
url: "/stop",
method: "POST",
data
});
}
@Permission("start")
start(data: any) {
return this.request({
url: "/start",
method: "POST",
data
});
}
@Permission("once")
once(data: any) {
return this.request({
url: "/once",
method: "POST",
data
});
}
@Permission("log")
log(params: any) {
return this.request({
url: "/log",
params
});
}
}
export default SysTask;

View File

@ -1,15 +0,0 @@
import { BaseService, Service, Permission } from "/@/core";
@Service("base/sys/user")
class SysUser extends BaseService {
@Permission("move")
move(data: any) {
return this.request({
url: "/move",
method: "POST",
data
});
}
}
export default SysUser;

View File

@ -1,6 +1,7 @@
import store from "store";
import { deepMerge, getBrowser } from "/@/core/utils";
import { deepMerge, getBrowser } from "/@/cool/utils";
import { app } from "/@/config/env";
import { useEps } from "/@/cool";
const browser = getBrowser();
@ -29,8 +30,12 @@ const actions = {
if (getters.token) {
commit("SHOW_LOADING");
// 读取Eps
await useEps();
// 读取菜单权限
await dispatch("permMenu");
// 获取用户信息
dispatch("userInfo");

View File

@ -2,11 +2,11 @@ import { ElMessage } from "element-plus";
import storage from "store";
import store from "/@/store";
import router from "/@/router";
import { deepTree, revDeepTree, isArray, isEmpty } from "/@/core/utils";
import { deepTree, revDeepTree, isArray, isEmpty } from "/@/cool/utils";
import { menuList } from "/@/config/env";
import { revisePath } from "../utils";
import { MenuItem } from "../types";
import { usePermission } from "/@/core";
import { usePermission } from "/@/cool";
const state = {
// 视图路由type=1

View File

@ -1,4 +1,4 @@
import { storage, href } from "/@/core/utils";
import { storage, href } from "/@/cool/utils";
import store from "/@/store";
import { Token } from "../types";

View File

@ -25,8 +25,8 @@
<script lang="ts">
import { ElMessage } from "element-plus";
import { defineComponent, reactive, ref } from "vue";
import { useCool } from "/@/core";
import { cloneDeep } from "/@/core/utils";
import { useCool } from "/@/cool";
import { cloneDeep } from "/@/cool/utils";
export default defineComponent({
name: "sys-info",

View File

@ -4,7 +4,7 @@
<cl-refresh-btn />
<el-button
v-permission="service.base.system.log.permission.clear"
v-permission="service.base.sys.log.permission.clear"
size="mini"
type="danger"
@click="clear"
@ -41,8 +41,8 @@
<script lang="ts">
import { defineComponent, reactive, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { useCool } from "/@/core";
import { CrudLoad, Table } from "cl-admin-crud-vue3/types";
import { useCool } from "/@/cool";
import { CrudLoad, Table } from "@cool-vue/crud/types";
export default defineComponent({
name: "sys-log",
@ -111,13 +111,13 @@ export default defineComponent({
// crud
function onLoad({ ctx, app }: CrudLoad) {
ctx.service(service.base.system.log).done();
ctx.service(service.base.sys.log).done();
app.refresh();
}
//
function saveDay() {
service.base.system.log.setKeep(day.value).then(() => {
service.base.sys.log.setKeep(day.value).then(() => {
ElMessage.success("保存成功");
});
}
@ -128,7 +128,7 @@ export default defineComponent({
type: "warning"
})
.then(() => {
service.base.system.log
service.base.sys.log
.clear()
.then(() => {
ElMessage.success("清空成功");
@ -142,7 +142,7 @@ export default defineComponent({
}
//
service.base.system.log.getKeep().then((res: number) => {
service.base.sys.log.getKeep().then((res: number) => {
day.value = Number(res);
});

View File

@ -3,6 +3,7 @@
<el-row type="flex">
<cl-refresh-btn />
<cl-add-btn />
<cl-menu-quick @success="refresh()" v-if="isDev" />
</el-row>
<el-row>
@ -77,10 +78,11 @@
</template>
<script lang="ts">
import { useCool } from "/@/core";
import { deepTree } from "/@/core/utils";
import { useCool } from "/@/cool";
import { deepTree } from "/@/cool/utils";
import { defineComponent, reactive } from "vue";
import { CrudLoad, Table, Upsert, RefreshOp } from "cl-admin-crud-vue3/types";
import { CrudLoad, Table, Upsert, RefreshOp } from "@cool-vue/crud/types";
import { isDev } from "/@/config/env";
export default defineComponent({
name: "sys-menu",
@ -90,13 +92,13 @@ export default defineComponent({
// crud
function onLoad({ ctx, app }: CrudLoad) {
ctx.service(service.base.system.menu).done();
ctx.service(service.base.sys.menu).done();
app.refresh();
}
//
function onRefresh(_: any, { render }: RefreshOp) {
service.base.system.menu.list().then((list: any[]) => {
service.base.sys.menu.list().then((list: any[]) => {
list.map((e) => {
e.permList = e.perms ? e.perms.split(",") : [];
});
@ -135,6 +137,11 @@ export default defineComponent({
router.push(url);
}
//
function refresh() {
refs.value.crud.refresh();
}
//
const table = reactive<Table>({
props: {
@ -238,7 +245,9 @@ export default defineComponent({
//
const upsert = reactive<Upsert>({
width: "800px",
dialog: {
width: "800px"
},
items: [
{
prop: "type",
@ -273,10 +282,7 @@ export default defineComponent({
placeholder: "请输入节点名称"
}
},
rules: {
required: true,
message: "名称不能为空"
}
required: true
},
{
prop: "parentId",
@ -294,7 +300,7 @@ export default defineComponent({
component: {
name: "el-input",
props: {
placeholder: "请输入节点路由"
placeholder: "请输入节点路由,如:/test"
}
}
},
@ -383,7 +389,9 @@ export default defineComponent({
onRowClick,
upsertAppend,
setPermission,
toUrl
toUrl,
refresh,
isDev
};
}
});

View File

@ -36,8 +36,8 @@
<script lang="ts">
import { ElMessageBox } from "element-plus";
import { defineComponent, nextTick, reactive } from "vue";
import { useCool } from "/@/core";
import { CrudLoad, Table, Upsert } from "cl-admin-crud-vue3/types";
import { useCool } from "/@/cool";
import { CrudLoad, Table, Upsert } from "@cool-vue/crud/types";
export default defineComponent({
name: "sys-param",
@ -158,7 +158,7 @@ export default defineComponent({
// crud
function onLoad({ ctx, app }: CrudLoad) {
ctx.service(service.base.system.param).done();
ctx.service(service.base.sys.param).done();
app.refresh();
}

View File

@ -50,8 +50,8 @@
import { ElMessage } from "element-plus";
import { defineComponent, reactive } from "vue";
import { checkPerm } from "/$/base";
import { useCool } from "/@/core";
import { CrudLoad, RefreshOp, Table } from "cl-admin-crud-vue3/types";
import { useCool } from "/@/cool";
import { CrudLoad, RefreshOp, Table } from "@cool-vue/crud/types";
export default defineComponent({
name: "plugin",

View File

@ -22,7 +22,7 @@
</template>
<script lang="ts">
import { CrudLoad, Table, Upsert } from "cl-admin-crud-vue3/types";
import { CrudLoad, Table, Upsert } from "@cool-vue/crud/types";
import { defineComponent, inject, reactive } from "vue";
export default defineComponent({
@ -153,7 +153,7 @@ export default defineComponent({
// crud
function onLoad({ ctx, app }: CrudLoad) {
ctx.service(service.base.system.role).done();
ctx.service(service.base.sys.role).done();
app.refresh();
}

View File

@ -28,7 +28,7 @@
<cl-add-btn />
<cl-multi-delete-btn />
<el-button
v-permission="service.base.system.user.permission.move"
v-permission="service.base.sys.user.permission.move"
size="mini"
type="success"
:disabled="selects.ids.length == 0"
@ -71,7 +71,7 @@
<!-- 单个转移 -->
<template #slot-move-btn="{ scope }">
<el-button
v-permission="service.base.system.user.permission.move"
v-permission="service.base.sys.user.permission.move"
type="text"
size="mini"
@click="toMove(scope.row)"
@ -103,8 +103,8 @@
<script lang="ts">
import { computed, defineComponent, reactive, ref, watch } from "vue";
import { useCool } from "/@/core";
import { Table, Upsert } from "cl-admin-crud-vue3/types";
import { useCool } from "/@/cool";
import { Table, Upsert } from "@cool-vue/crud/types";
export default defineComponent({
name: "sys-user",
@ -379,7 +379,7 @@ export default defineComponent({
// crud
function onLoad({ ctx, app }: any) {
ctx.service(service.base.system.user).done();
ctx.service(service.base.sys.user).done();
app.refresh();
}

View File

@ -54,7 +54,7 @@ import Session from "./session.vue";
import Message from "./message.vue";
import Input from "./input.vue";
import { parseContent } from "../utils";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
import NotifyMp3 from "../static/notify.mp3";
export default defineComponent({

View File

@ -29,7 +29,7 @@
<script lang="ts">
import { computed, defineComponent, ref } from "vue";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
//
const emoji = {

View File

@ -44,7 +44,7 @@
import { defineComponent, inject, nextTick, reactive, ref } from "vue";
import Emoji from "./emoji.vue";
import Upload from "./upload.vue";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
components: {

View File

@ -113,8 +113,8 @@
import { computed, defineComponent, inject, nextTick, onUnmounted, reactive, ref } from "vue";
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import { isString } from "/@/core/utils";
import { useCool } from "/@/core";
import { isString } from "/@/cool/utils";
import { useCool } from "/@/cool";
import IconVoice from "./icon-voice.vue";
import AvatarUrl from "../static/images/custom-avatar.png";

View File

@ -11,7 +11,7 @@
<script lang="ts">
import { defineComponent, onBeforeMount, ref } from "vue-demi";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-chat-notice",

View File

@ -55,10 +55,10 @@
<script lang="ts">
import { computed, defineComponent, onUnmounted, reactive, ref } from "vue";
import { ElMessage } from "element-plus";
import { isEmpty } from "/@/core/utils";
import { ContextMenu } from "cl-admin-crud-vue3";
import { isEmpty } from "/@/cool/utils";
import { ContextMenu } from "@cool-vue/crud";
import { parseContent } from "../utils";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
setup() {

View File

@ -12,7 +12,7 @@
<script lang="ts">
import { defineComponent, inject } from "vue";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
props: {
@ -85,7 +85,7 @@ export default defineComponent({
}
//
function onUploadProgress(e: any, file: ElFile) {
function onUploadProgress(e: any, file: any) {
store.commit("UPDATE_MESSAGE", {
file,
data: {
@ -95,7 +95,7 @@ export default defineComponent({
}
//
function onUploadSuccess(res: any, file: ElFile) {
function onUploadSuccess(res: any, file: any) {
store.commit("UPDATE_MESSAGE", {
file,
data: {

View File

@ -1,4 +1,4 @@
import { BaseService, Service, Permission } from "/@/core";
import { BaseService, Service, Permission } from "/@/cool";
@Service({
namespace: "im/message",

View File

@ -1,4 +1,4 @@
import { BaseService, Service, Permission } from "/@/core";
import { BaseService, Service, Permission } from "/@/cool";
@Service({
namespace: "im/session",

View File

@ -1,4 +1,4 @@
import { isArray } from "/@/core/utils";
import { isArray } from "/@/cool/utils";
const state = {
list: []

View File

@ -1,4 +1,4 @@
import { isBoolean } from "/@/core/utils";
import { isBoolean } from "/@/cool/utils";
const state = {
list: [],

View File

@ -1,4 +1,4 @@
import { isObject } from "/@/core/utils";
import { isObject } from "/@/cool/utils";
export function parseContent({ content, contentType }: any) {
const data = isObject(content) ? content : JSON.parse(content);

View File

@ -6,7 +6,7 @@
</template>
<script lang="ts">
import { AdvSearchItem } from "cl-admin-crud-vue3/types";
import { AdvSearchItem } from "@cool-vue/crud/types";
import { defineComponent, ref } from "vue";
export default defineComponent({

View File

@ -5,7 +5,7 @@
</template>
<script lang="ts">
import { ContextMenu } from "cl-admin-crud-vue3";
import { ContextMenu } from "@cool-vue/crud";
import { ElMessage } from "element-plus";
import { defineComponent } from "vue";

View File

@ -50,7 +50,7 @@
<script lang="ts">
import { defineComponent, ref, resolveComponent, h } from "vue";
import { CrudLoad, FormItem, FormRef } from "cl-admin-crud-vue3/types";
import { CrudLoad, FormItem, FormRef } from "@cool-vue/crud/types";
import { TestService } from "../../utils/service";
import Test from "./render/test.vue";
import Test2 from "./render/test2";

View File

@ -3,7 +3,7 @@
</template>
<script lang="ts">
import { QueryList } from "cl-admin-crud-vue3/types";
import { QueryList } from "@cool-vue/crud/types";
import { defineComponent, ref } from "vue";
export default defineComponent({

View File

@ -6,8 +6,8 @@
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import { TableColumn } from "cl-admin-crud-vue3/types";
import { useCool } from "/@/core";
import { TableColumn } from "@cool-vue/crud/types";
import { useCool } from "/@/cool";
import Test2 from "./render/test2";
export default defineComponent({
@ -29,7 +29,20 @@ export default defineComponent({
label: "存款",
prop: "price",
sortable: true,
minWidth: 120
minWidth: 120,
component: {
name: "el-progress"
}
},
{
label: "文件",
prop: "urls",
component: {
name: "cl-link",
props: {
size: 50
}
}
},
{
label: "状态",
@ -38,12 +51,11 @@ export default defineComponent({
dict: [
{
label: "启用",
value: 1,
type: "primary"
value: 1
},
{
label: "禁用",
value: 0,
value: 2,
type: "danger"
}
]

View File

@ -5,7 +5,7 @@
</template>
<script lang="ts">
import { UpsertItem, UpsertRef } from "cl-admin-crud-vue3/types";
import { UpsertItem, UpsertRef } from "@cool-vue/crud/types";
import { defineComponent, ref } from "vue";
export default defineComponent({
@ -21,122 +21,32 @@ export default defineComponent({
const items = ref<UpsertItem[]>([
{
label: "测试hook",
prop: "hook",
hook: {
bind: ["split", "number"],
submit: "join"
},
label: "多图",
prop: "imgs",
component: {
name: "el-select",
name: "cl-upload",
props: {
listType: "picture-card",
multiple: true
},
options: [
{
label: "景天",
value: 1
},
{
label: "李逍遥",
value: 2
},
{
label: "宇文拓",
value: 3
}
]
}
},
{
type: "tabs",
props: {
labels: [
{
label: "基本信息",
value: "base"
},
{
label: "金融",
value: "financial"
},
{
label: "工作",
value: "work"
}
]
}
},
{
label: {
text: "姓名",
icon: "el-icon-question",
tip: "姓名是汉语词语,拼音是 xìng míng ,意思是由姓和名组成"
},
prop: "name",
group: "base",
collapse: false,
component: {
name: "el-input"
},
rules: {
required: true,
message: "姓名不能为空"
}
},
{
label: "存款",
prop: "price",
value: 0,
group: "financial",
component: {
name: "el-input-number"
},
append: ({ h }: any) => {
return h("p", "元");
},
rules: {
required: true,
message: "存款不能为空"
}
},
{
label: "公司",
prop: "company",
value: "cool",
group: "work",
component: {
name: "el-input"
}
},
{
label: "状态",
prop: "status",
value: 1,
component: {
name: "el-radio-group",
options: [
{
label: "启用",
value: 1
},
{
label: "禁用",
value: 0
}
],
props: {
onChange(v: any) {
upsertRef.value?.toggleItem("remark", v == 1);
}
}
}
},
{
label: "备注",
prop: "remark",
label: "文件",
prop: "file",
component: {
name: "el-input"
name: "cl-upload",
props: {
listType: "text",
limit: 1
}
}
},
{
label: "开关",
prop: "switch",
component: {
name: "el-switch"
}
}
]);

View File

@ -9,6 +9,7 @@ export const UserList = [
createTime: "2019年09月02日",
price: 75.99,
status: 1,
urls: "https://images.quanjing.com/ojo003/thu/pe0082640.jpg,https://images.quanjing.com/rad005/thu/rad600-02347621.jpg",
hook: "1,2"
},
{
@ -16,28 +17,32 @@ export const UserList = [
name: "陈二",
createTime: "2019年09月05日",
price: 242.1,
status: 1
urls: [
"https://images.quanjing.com/rad005/thu/rad600-02347621.jpg",
"https://images.quanjing.com/ojo003/thu/pe0082640.jpg"
],
status: 2
},
{
id: 3,
name: "张三",
createTime: "2019年09月12日",
price: 74.11,
status: 0
status: 3
},
{
id: 4,
name: "李四",
createTime: "2019年09月13日",
price: 276.64,
status: 0
status: 4
},
{
id: 5,
name: "王五",
createTime: "2019年09月18日",
price: 160.23,
status: 1
status: 5
}
];

View File

@ -36,7 +36,6 @@
<script lang="ts">
import { defineComponent } from "vue";
import { CrudLoad } from "cl-admin-crud-vue3/types";
import { TestService } from "../utils/service";
import Dialog from "../components/crud/dialog.vue";
import ContextMenu from "../components/crud/context-menu.vue";
@ -45,6 +44,7 @@ import AdvSearch from "../components/crud/adv-search.vue";
import Table from "../components/crud/table.vue";
import Upsert from "../components/crud/upsert.vue";
import Form from "../components/crud/form.vue";
import { CrudLoad } from "@cool-vue/crud/types";
export default defineComponent({
name: "crud",

20
src/cool/modules/index.ts Normal file
View File

@ -0,0 +1,20 @@
import Crud from "@cool-vue/crud";
import "@cool-vue/crud/dist/index.css";
export const modules = [
// crud 模块
{
name: "crud",
value: Crud,
options: {
crud: {
dict: {
sort: {
prop: "order",
order: "sort"
}
}
}
}
}
];

View File

@ -1,41 +0,0 @@
import { BaseService, Service, Permission } from "/@/core";
@Service("task/info")
class SysTask extends BaseService {
@Permission("stop")
stop(data: any) {
return this.request({
url: "/stop",
method: "POST",
data
});
}
@Permission("start")
start(data: any) {
return this.request({
url: "/start",
method: "POST",
data
});
}
@Permission("once")
once(data: any) {
return this.request({
url: "/once",
method: "POST",
data
});
}
@Permission("log")
log(params: any) {
return this.request({
url: "/log",
params
});
}
}
export default SysTask;

View File

@ -218,9 +218,9 @@ import { computed, defineComponent, onMounted, reactive } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import Draggable from "vuedraggable/src/vuedraggable";
import { checkPerm } from "/$/base";
import { ContextMenu } from "cl-admin-crud-vue3";
import { ContextMenu } from "@cool-vue/crud";
import Cron from "../components/cron";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
name: "task",

View File

@ -107,7 +107,7 @@
<script>
import { mapGetters } from "vuex";
import { isDev } from "/@/config/env";
import { isArray, cloneDeep } from "/@/core/utils";
import { isArray, cloneDeep } from "/@/cool/utils";
export default {
name: "cl-theme",

View File

@ -108,7 +108,7 @@
<script>
import { mapGetters } from "vuex";
import { clone, last, isArray, isNumber, isBoolean, basename } from "/@/core/utils";
import { clone, last, isArray, isNumber, isBoolean, basename } from "/@/cool/utils";
import { v4 as uuidv4 } from "uuid";
export default {
@ -274,22 +274,23 @@ export default {
},
_urls() {
const format = {
image: ["bmp", "jpg", "jpeg", "png", "tif", "gif", "svg", "webp"]
};
return this.urls
.filter((e) => Boolean(e.url))
.map((e) => {
const arr = e.url.split(".");
const suf = last(arr).toLowerCase();
e.type = format.image.includes(suf) ? "image" : null;
return e;
});
return this.urls.filter((e) => Boolean(e.url));
},
_file() {
return this._urls[0];
const d = this._urls[0];
if (d) {
const suf = last(d.url.split(".")).toLowerCase();
if (["bmp", "jpg", "jpeg", "png", "tif", "gif", "svg", "webp"].includes(suf)) {
d.type = "image";
}
return d;
} else {
return null;
}
},
_style() {
@ -402,15 +403,25 @@ export default {
//
_onPreview(file) {
this.preview.visible = true;
this.preview.url = file.url;
let url = "";
if (!file.url) {
const item = this.urls.find((e) => e.uid == file.uid);
if (file.raw) {
if (file.raw.type.indexOf("image/") == 0) {
const item = this.urls.find((e) => e.uid == file.uid);
if (item) {
this.preview.url = item.url;
if (item) {
url = item.url;
}
}
} else {
if (file.type == "image") {
url = file.url;
}
}
if (url) {
this.preview.visible = true;
this.preview.url = url;
}
},

View File

@ -35,9 +35,9 @@
<script lang="ts">
import { ElMessage, ElMessageBox } from "element-plus";
import { computed, defineComponent, inject, ref, watch } from "vue";
import { isEmpty } from "/@/core/utils";
import { ContextMenu } from "cl-admin-crud-vue3";
import { useCool } from "/@/core";
import { isEmpty } from "/@/cool/utils";
import { ContextMenu } from "@cool-vue/crud";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-upload-space-category",

View File

@ -47,7 +47,7 @@
<script lang="ts">
import { computed, defineComponent, inject } from "vue";
import { ContextMenu } from "cl-admin-crud-vue3";
import { ContextMenu } from "@cool-vue/crud";
import { ElMessage } from "element-plus";
import Clipboard from "clipboard";

View File

@ -140,10 +140,10 @@
<script lang="ts">
import { computed, defineComponent, provide, reactive, ref, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { isEmpty } from "/@/core/utils";
import { isEmpty } from "/@/cool/utils";
import Category from "./category.vue";
import FileItem from "./file-item.vue";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
name: "cl-upload-space",
@ -283,7 +283,7 @@ export default defineComponent({
}
//
function onError(err: string, file: ElFile) {
function onError(err: string, file: any) {
const item = list.value.find((e) => file.uid == e.uid);
if (item) {
@ -305,7 +305,7 @@ export default defineComponent({
}
//
function onProgress({ percent }: any, file: ElFile) {
function onProgress({ percent }: any, file: any) {
const item = list.value.find(({ uid }: any) => uid == file.uid);
if (item) {

View File

@ -1,6 +0,0 @@
import { BaseService, Service } from "/@/core";
@Service("space/info")
class SpaceInfo extends BaseService {}
export default SpaceInfo;

View File

@ -1,6 +0,0 @@
import { BaseService, Service } from "/@/core";
@Service("space/type")
class SpaceType extends BaseService {}
export default SpaceType;

1
src/cool/utils.ts Normal file
View File

@ -0,0 +1 @@
export * from "./core/utils";

View File

@ -1 +0,0 @@
export * from "./core";

View File

@ -1,54 +0,0 @@
import BaseService from "./base";
import { Service, Permission } from "./decorator";
import { basename } from "../utils";
function deepFiles(list: any[]) {
const modules: any = {};
list.forEach((e) => {
const arr: any[] = e.path.split("/");
const parents: any[] = arr.slice(0, arr.length - 1);
const name: string = basename(e.path).replace(".ts", "");
let curr: any = modules;
let prev: any = null;
let key: any = null;
parents.forEach((k) => {
if (!curr[k]) {
curr[k] = {};
}
prev = curr;
curr = curr[k];
key = k;
});
if (name == "index") {
prev[key] = e.value;
} else {
curr[name] = e.value;
}
});
return modules;
}
function useService() {
const files = import.meta.globEager("/src/service/**/*.ts");
const d: any = [];
for (const i in files) {
if (!i.includes("request.ts")) {
const value = files[i].default;
d.push({
path: i.replace("/src/service/", ""),
value: new value()
});
}
}
return deepFiles(d);
}
export { BaseService, Service, Permission, deepFiles, useService };

View File

@ -1,12 +0,0 @@
import { Store } from "vuex";
import { Router } from "vue-router";
export declare class CoolStore<S> extends Store<S> {
service?: any;
}
export declare interface CoolRouter extends Router {
$plugin?: {
addViews(list: any[], options?: any): void;
};
}

View File

@ -2,7 +2,7 @@ import { createApp } from "vue";
import App from "./App.vue";
// cool
import { bootstrap } from "./core";
import { bootstrap } from "./cool";
// router
import router from "./router";
@ -10,6 +10,7 @@ import router from "./router";
// store
import store from "./store";
// mock
import "./mock";
// element-plus
@ -26,10 +27,10 @@ const app = createApp(App);
bootstrap(app)
.then(() => {
// // echarts 可视图表
// echarts 可视图表
app.component("v-chart", VueECharts);
// // 事件通讯
// 事件通讯
app.provide("mitt", mitt());
app.use(store).use(router).use(ElementPlus).mount("#app");

View File

@ -32,7 +32,7 @@
import { computed, defineComponent } from "vue";
import Topbar from "./topbar.vue";
import Slider from "./slider.vue";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
components: {

View File

@ -14,7 +14,7 @@
<script lang="ts">
import { computed, defineComponent } from "vue";
import Logo from "/@/assets/icon/logo/silder-simple.png";
import { useCool } from "/@/core";
import { useCool } from "/@/cool";
export default defineComponent({
setup() {

Some files were not shown because too many files have changed in this diff Show More