merge from cool-admin-vue-5.x
5
.dockerignore
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
11
.editorconfig
Normal file
@ -0,0 +1,11 @@
|
||||
# 🎨 editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
||||
vite.config.ts
|
64
.eslintrc.js
Normal file
@ -0,0 +1,64 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true
|
||||
},
|
||||
parser: "vue-eslint-parser",
|
||||
parserOptions: {
|
||||
parser: "@typescript-eslint/parser",
|
||||
ecmaVersion: 2020,
|
||||
sourceType: "module",
|
||||
jsxPragma: "React",
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
tsx: true
|
||||
}
|
||||
},
|
||||
extends: [
|
||||
"plugin:vue/vue3-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
rules: {
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"vue/component-name-in-template-casing": ["error", "kebab-case"],
|
||||
"vue/component-definition-name-casing": ["error", "kebab-case"],
|
||||
"no-use-before-define": "off",
|
||||
"@typescript-eslint/no-use-before-define": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^h$",
|
||||
varsIgnorePattern: "^h$"
|
||||
}
|
||||
],
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^h$",
|
||||
varsIgnorePattern: "^h$"
|
||||
}
|
||||
],
|
||||
"space-before-function-paren": "off",
|
||||
"vue/attributes-order": "off",
|
||||
"vue/one-component-per-file": "off",
|
||||
"vue/html-closing-bracket-newline": "off",
|
||||
"vue/max-attributes-per-line": "off",
|
||||
"vue/multiline-html-element-content-newline": "off",
|
||||
"vue/singleline-html-element-content-newline": "off",
|
||||
"vue/attribute-hyphenation": "off",
|
||||
"vue/html-self-closing": "off",
|
||||
"vue/require-default-prop": "off"
|
||||
}
|
||||
};
|
4
.gitattributes
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.js text eol=lf
|
||||
*.json text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.vue text eol=lf
|
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
8
.prettierrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"useTabs": true,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
67
.vscode/crud.code-snippets
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"cl-crud": {
|
||||
"prefix": "cl-crud",
|
||||
"body": [
|
||||
"<template>",
|
||||
" <cl-crud ref=\"Crud\">",
|
||||
" <el-row>",
|
||||
" <!-- 刷新按钮 -->",
|
||||
" <cl-refresh-btn />",
|
||||
" <!-- 新增按钮 -->",
|
||||
" <cl-add-btn />",
|
||||
" <!-- 删除按钮 -->",
|
||||
" <cl-multi-delete-btn />",
|
||||
" <cl-flex1 />",
|
||||
" <!-- 关键字搜索 -->",
|
||||
" <cl-search-key />",
|
||||
" </el-row>",
|
||||
"",
|
||||
" <el-row>",
|
||||
" <!-- 数据表格 -->",
|
||||
" <cl-table ref=\"Table\" />",
|
||||
" </el-row>",
|
||||
"",
|
||||
" <el-row>",
|
||||
" <cl-flex1 />",
|
||||
" <!-- 分页控件 -->",
|
||||
" <cl-pagination />",
|
||||
" </el-row>",
|
||||
"",
|
||||
" <!-- 新增、编辑 -->",
|
||||
" <cl-upsert ref=\"Upsert\" />",
|
||||
" </cl-crud>",
|
||||
"</template>",
|
||||
"",
|
||||
"<script lang=\"ts\" setup>",
|
||||
"import { useCrud, useTable, useUpsert } from \"@cool-vue/crud\";",
|
||||
"import { useCool } from \"/@/cool\";",
|
||||
"",
|
||||
"const { service, named } = useCool();",
|
||||
"",
|
||||
"named(\"菜单名称\");",
|
||||
"",
|
||||
"// cl-upsert 配置",
|
||||
"const Upsert = useUpsert({",
|
||||
" items: []",
|
||||
"});",
|
||||
"",
|
||||
"// cl-table 配置",
|
||||
"const Table = useTable({",
|
||||
" columns: []",
|
||||
"});",
|
||||
"",
|
||||
"// cl-crud 配置",
|
||||
"const Crud = useCrud(",
|
||||
" {",
|
||||
" service: service.demo.goods",
|
||||
" },",
|
||||
" (app) => {",
|
||||
" app.refresh();",
|
||||
" }",
|
||||
");",
|
||||
"</script>",
|
||||
""
|
||||
],
|
||||
"description": "cl-crud snippets"
|
||||
}
|
||||
}
|
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"editor.cursorSmoothCaretAnimation": true
|
||||
}
|
16
Dockerfile
Normal file
@ -0,0 +1,16 @@
|
||||
FROM node:lts-alpine
|
||||
WORKDIR /build
|
||||
# 设置Node-Sass的镜像地址
|
||||
RUN npm config set sass_binary_site https://repo.huaweicloud.com/node-sass
|
||||
# 设置npm镜像
|
||||
RUN npm config set registry https://repo.huaweicloud.com/repository/npm/
|
||||
COPY package.json /build/package.json
|
||||
RUN npm install
|
||||
COPY ./ /build
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx
|
||||
RUN mkdir /app
|
||||
COPY --from=0 /build/dist /app
|
||||
COPY --from=0 /build/nginx.conf /etc/nginx/nginx.conf
|
||||
EXPOSE 80
|
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 cool-team-official
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
96
README.md
Normal file
@ -0,0 +1,96 @@
|
||||
# cool-admin [vue3 - ts - vite]
|
||||
|
||||
<p align="center">
|
||||
<a href="https://show.cool-admin.com/" target="blank"><img src="https://admin.cool-js.com/logo.png" width="200" alt="cool-admin Logo" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">cool-admin 一个很酷的后台权限管理系统,开源免费,模块化、插件化、极速开发 CRUD,方便快速构建迭代后台管理系统, 到<a href="https://cool-js.com" target="_blank">文档</a> 进一步了解</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/cool-team-official/cool-admin-vue/blob/master/LICENSE" target="_blank"><img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="GitHub license" />
|
||||
<a href=""><img src="https://img.shields.io/github/package-json/v/cool-team-official/cool-admin-vue?style=flat-square" alt="GitHub tag"></a>
|
||||
<img src="https://img.shields.io/github/last-commit/cool-team-official/cool-admin-vue?style=flat-square" alt="GitHub tag"></a>
|
||||
</p>
|
||||
|
||||
## 地址
|
||||
|
||||
- [⚡️ vue2.x + element-ui](https://github.com/cool-team-official/cool-admin-vue)
|
||||
|
||||
- [⚡️ vue3.x + element-plus + ts + webpack](https://github.com/cool-team-official/cool-admin-vue/tree/vue3-ts-webpack)
|
||||
|
||||
- [📌 vue3.x + element-plus + ts + vite](https://github.com/cool-team-official/cool-admin-vue/tree/vue3-ts-vite)
|
||||
|
||||
- [🌐 码云仓库地址](https://gitee.com/cool-team-official/cool-admin-vue)
|
||||
|
||||
## 演示
|
||||
|
||||
[https://show.cool-admin.com](https://show.cool-admin.com)
|
||||
|
||||
账户:admin,密码:123456
|
||||
|
||||
<img src="https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/home-mini.png" alt="Admin Home" ></a>
|
||||
|
||||
## 项目后端
|
||||
|
||||
[https://github.com/cool-team-official/cool-admin-midway](https://github.com/cool-team-official/cool-admin-midway)
|
||||
|
||||
## 微信群
|
||||
|
||||
<img width="260" src="https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/wechat.jpeg" alt="Admin Wechat"></a>
|
||||
|
||||
## 微信公众号
|
||||
|
||||
<img width="260" src="https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/mp.jpg" alt="Admin Wechat"></a>
|
||||
|
||||
## 在线社区
|
||||
|
||||
[https://bbs.cool-js.com/](https://bbs.cool-js.com/)
|
||||
|
||||
## 安装项目依赖
|
||||
|
||||
推荐使用 `yarn`:
|
||||
|
||||
```shell
|
||||
yarn
|
||||
```
|
||||
|
||||
解决 `node-sass` 网络慢的方法:
|
||||
|
||||
```shell
|
||||
yarn config set sass-binary-site http://npm.taobao.org/mirrors/node-sass
|
||||
```
|
||||
|
||||
## 运行应用程序
|
||||
|
||||
安装过程完成后,运行以下命令启动服务。您可以在浏览器中预览网站 [http://localhost:9000](http://localhost:9000)
|
||||
|
||||
```shell
|
||||
yarn dev
|
||||
```
|
||||
|
||||
### 服务器
|
||||
|
||||
#### 腾讯云特供
|
||||
|
||||
不限新老用户,注册过买过都可以享受
|
||||
|
||||
|配置|价格|条件|备注|
|
||||
|---------|-------|-------|-------|
|
||||
|2核2g2M|一年240|个人企业限一台(不限新老用户)||
|
||||
|2核4g2M|一年260、两年380|个人企业限一台(不限新老用户)||
|
||||
|2核4g3M|一年260、三年600|企业(不限新老用户)||
|
||||
|2核4g5M|一年280、三年660|企业(不限新老用户)||
|
||||
|4核8g5M|一年320、三年720|企业(不限新老用户)||
|
||||
|4核8g10M|一年560、三年1520|企业(不限新老用户)||
|
||||
|8核16g5M|一年1800、三年3800|限企业新用户|送独立数据库|
|
||||
|8核16g10M|一年2200、三年6600|限企业新用户|送独立数据库|
|
||||
|16核32g5M|一年2600、三年6900|限企业新用户|送独立数据库|
|
||||
|16核32g10M|一年2900、三年9600|限企业新用户|送独立数据库|
|
||||
|
||||
#### 购买咨询,数量有限!!!
|
||||
|
||||
<img width="260" src="https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/wechat.jpeg?v=1" alt="Admin Wechat"></a>
|
||||
|
||||
#### 阿里云
|
||||
|
||||
[点击链接购买](https://www.aliyun.com/minisite/goods?userCode=pw6cig1f)
|
65
build/cool/index.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { Plugin } from "vite";
|
||||
import { parseJson } from "./utils";
|
||||
import { getModules } from "./lib/modules";
|
||||
import { createEps, getEps } from "./lib/eps";
|
||||
import { createMenu } from "./lib/menu";
|
||||
|
||||
export const cool = (): Plugin | null => {
|
||||
return {
|
||||
name: "vite-cool",
|
||||
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);
|
||||
let next: any = null;
|
||||
|
||||
switch (req.url) {
|
||||
// 快速创建菜单
|
||||
case "/__cool_createMenu":
|
||||
next = createMenu(body);
|
||||
break;
|
||||
|
||||
// 获取模块列表
|
||||
case "/__cool_modules":
|
||||
next = getModules();
|
||||
break;
|
||||
|
||||
// 创建描述文件
|
||||
case "/__cool_eps":
|
||||
next = createEps(body);
|
||||
break;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
next.then((data: any) => {
|
||||
done({
|
||||
code: 1000,
|
||||
data
|
||||
});
|
||||
}).catch((message: string) => {
|
||||
done({
|
||||
code: 1001,
|
||||
message
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
},
|
||||
config() {
|
||||
return {
|
||||
define: {
|
||||
__EPS__: getEps()
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
219
build/cool/lib/eps/index.ts
Normal file
@ -0,0 +1,219 @@
|
||||
import prettier from "prettier";
|
||||
import { isEmpty, last } from "lodash";
|
||||
import { createDir, firstUpperCase, readFile, toCamel } from "../../utils";
|
||||
import { createWriteStream } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
// 临时目录路径
|
||||
const tempPath = join(__dirname, "../../temp");
|
||||
|
||||
// 创建描述文件
|
||||
export async function createEps({ list, service }: any) {
|
||||
const t0 = [
|
||||
[
|
||||
`
|
||||
declare interface Crud {
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data: any): Promise<any>;
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data: { ids?: number[] | string[]; [key: string]: any }): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data: { id?: number | string; [key: string]: any }): Promise<any>;
|
||||
/**
|
||||
* 详情
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data: { id?: number | string; [key: string]: any }): Promise<any>;
|
||||
/**
|
||||
* 全部
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: { page?: number | string; size?: number | string; [key: string]: any }): Promise<PageResponse>;
|
||||
}
|
||||
`,
|
||||
|
||||
`
|
||||
declare interface PageResponse {
|
||||
list: any[];
|
||||
pagination: { size: number; page: number; total: number };
|
||||
[key: string]: any;
|
||||
}
|
||||
`,
|
||||
|
||||
`
|
||||
declare interface RequestOptions {
|
||||
params?: any;
|
||||
data?: any;
|
||||
url: string;
|
||||
method?: "GET" | "get" | "POST" | "post" | string;
|
||||
[key: string]: any;
|
||||
}
|
||||
`
|
||||
]
|
||||
];
|
||||
|
||||
const t1 = [`declare type Service = {`, `request(data: RequestOptions): Promise<any>;`];
|
||||
|
||||
// 处理数据
|
||||
function deep(d: any, k?: string) {
|
||||
if (!k) k = "";
|
||||
|
||||
for (const i in d) {
|
||||
const name = k + toCamel(firstUpperCase(i.replace(/[:]/g, "")));
|
||||
|
||||
if (d[i].namespace) {
|
||||
// 查找配置
|
||||
const item = list.find((e: any) => (e.prefix || "").includes(d[i].namespace));
|
||||
|
||||
if (item) {
|
||||
const t = [
|
||||
`declare interface ${name} ${item.extendCrud ? " extends Crud" : ""} {`
|
||||
];
|
||||
|
||||
t1.push(`${i}: ${name};`);
|
||||
|
||||
// 插入方法
|
||||
if (item.api) {
|
||||
// 权限列表
|
||||
const permission: string[] = [];
|
||||
|
||||
item.api.forEach((a: any) => {
|
||||
// 方法名
|
||||
const n = toCamel(a.name || last(a.path.split("/"))).replace(
|
||||
/[:\/-]/g,
|
||||
""
|
||||
);
|
||||
|
||||
if (n) {
|
||||
// 参数类型
|
||||
let q: string[] = [];
|
||||
|
||||
// 参数列表
|
||||
const { parameters = [] } = a.dts || {};
|
||||
|
||||
parameters.forEach((p: any) => {
|
||||
if (p.description) {
|
||||
q.push(`\n/** ${p.description} */\n`);
|
||||
}
|
||||
|
||||
if (p.name.includes(":")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const a = `${p.name}${p.required ? "" : "?"}`;
|
||||
const b = `${p.schema.type || "string"}`;
|
||||
|
||||
q.push(`${a}: ${b},`);
|
||||
});
|
||||
|
||||
if (isEmpty(q)) {
|
||||
q = ["any"];
|
||||
} else {
|
||||
q.unshift("{");
|
||||
q.push("}");
|
||||
}
|
||||
|
||||
// 返回类型
|
||||
let res = "";
|
||||
|
||||
switch (a.path) {
|
||||
case "/page":
|
||||
res = "PageResponse";
|
||||
break;
|
||||
default:
|
||||
res = "any";
|
||||
break;
|
||||
}
|
||||
|
||||
// 描述
|
||||
t.push("\n");
|
||||
t.push("/**\n");
|
||||
t.push(` * ${a.summary || n}\n`);
|
||||
t.push(` * @returns Promise<${res}>\n`);
|
||||
t.push(" */\n");
|
||||
|
||||
t.push(
|
||||
`${n}(data${q.length == 1 ? "?" : ""}: ${q.join(
|
||||
""
|
||||
)}): Promise<${res}>;`
|
||||
);
|
||||
}
|
||||
|
||||
permission.push(`${n}: string;`);
|
||||
});
|
||||
|
||||
// 添加权限
|
||||
t.push("\n");
|
||||
t.push("/**\n");
|
||||
t.push(" * 权限\n");
|
||||
t.push(" */\n");
|
||||
t.push(`permission: { ${permission.join("\n")} }`);
|
||||
}
|
||||
|
||||
t.push("}");
|
||||
t0.push(t);
|
||||
}
|
||||
} else {
|
||||
t1.push(`${i}: {`);
|
||||
deep(d[i], name);
|
||||
t1.push(`},`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deep(service);
|
||||
t1.push("}");
|
||||
|
||||
// 追加
|
||||
t0.push(t1);
|
||||
|
||||
// 文本内容
|
||||
const content = prettier.format(t0.map((e) => e.join("")).join("\n\n"), {
|
||||
parser: "typescript",
|
||||
useTabs: true,
|
||||
tabWidth: 4,
|
||||
endOfLine: "lf",
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
printWidth: 100,
|
||||
trailingComma: "none"
|
||||
});
|
||||
|
||||
// 创建 temp 目录
|
||||
createDir(tempPath);
|
||||
|
||||
// 创建 service 描述文件
|
||||
createWriteStream(join(tempPath, "service.d.ts"), {
|
||||
flags: "w"
|
||||
}).write(content);
|
||||
|
||||
// 创建 eps 文件
|
||||
createWriteStream(join(tempPath, "eps.json"), {
|
||||
flags: "w"
|
||||
}).write(
|
||||
JSON.stringify(
|
||||
list.map((e: any) => {
|
||||
return [e.prefix, e.api.map((a: any) => [a.method || "", a.path, a.name || ""])];
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// 获取描述
|
||||
export function getEps() {
|
||||
return JSON.stringify(readFile(join(tempPath, "eps.json")));
|
||||
}
|
360
build/cool/lib/menu/index.ts
Normal file
@ -0,0 +1,360 @@
|
||||
import { createWriteStream } from "fs";
|
||||
import prettier from "prettier";
|
||||
import { join } from "path";
|
||||
import { createDir } from "../../utils";
|
||||
import rules from "./rules";
|
||||
import { isFunction, isRegExp, isString } from "lodash";
|
||||
|
||||
// 格式化
|
||||
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 (i > 0 && colors[i]) {
|
||||
d.color = colors[i];
|
||||
}
|
||||
|
||||
return d;
|
||||
});
|
||||
|
||||
const d: any = {
|
||||
table: {
|
||||
label,
|
||||
dict: list
|
||||
},
|
||||
form: {
|
||||
label,
|
||||
component: {
|
||||
name: "",
|
||||
options: list
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 默认值
|
||||
if (list[0]) {
|
||||
d.form.value = list[0].value;
|
||||
}
|
||||
|
||||
// 匹配组件
|
||||
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
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 创建组件
|
||||
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 ? router.replace("/", "-") : "";
|
||||
}
|
||||
|
||||
// 时间合并
|
||||
function datetimeMerge({ columns, item }: any) {
|
||||
if (["startTime", "startDate"].includes(item.prop)) {
|
||||
const key = item.prop.replace("start", "");
|
||||
|
||||
if (columns.find((e: any) => e.propertyName == "end" + key)) {
|
||||
item.prop = key.toLocaleLowerCase();
|
||||
const isTime = item.prop == "time";
|
||||
item.label = isTime ? "时间范围" : "日期范围";
|
||||
item.hook = "datetimeRange";
|
||||
item.component = {
|
||||
name: "el-date-picker",
|
||||
props: {
|
||||
type: isTime ? "datetimerange" : "daterange",
|
||||
valueFormat: isTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD 00:00:00",
|
||||
defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建文件
|
||||
export async function createMenu({ 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 (!["createTime", "updateTime", "id", "endTime", "endDate"].includes(item.prop)) {
|
||||
datetimeMerge({ columns, item });
|
||||
|
||||
if (!item.component) {
|
||||
item.component = {
|
||||
name: "el-input"
|
||||
};
|
||||
}
|
||||
|
||||
upsert.items.push(format(item));
|
||||
}
|
||||
|
||||
if (!["cl-codemirror", "cl-editor-quill"].includes(column.component?.name)) {
|
||||
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="Crud">
|
||||
<el-row>
|
||||
<!-- 刷新按钮 -->
|
||||
<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="Table" />
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<cl-flex1 />
|
||||
<!-- 分页控件 -->
|
||||
<cl-pagination />
|
||||
</el-row>
|
||||
|
||||
<!-- 新增、编辑 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
</cl-crud>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useCrud, useTable, useUpsert } from "@cool-vue/crud";
|
||||
import { useCool } from "/@/cool";
|
||||
|
||||
const { service, named } = useCool();
|
||||
|
||||
named("${getPageName(router)}");
|
||||
|
||||
// cl-upsert 配置
|
||||
const Upsert = useUpsert(${JSON.stringify(upsert)});
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable(${JSON.stringify(table)});
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: ${service}
|
||||
},
|
||||
(app) => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
</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 = join(__dirname, `../../../../src/modules/${module}/views`);
|
||||
|
||||
// 创建目录
|
||||
createDir(dir);
|
||||
|
||||
// 创建文件
|
||||
createWriteStream(join(dir, `${filename}.vue`), {
|
||||
flags: "w"
|
||||
}).write(content);
|
||||
}
|
214
build/cool/lib/menu/rules.ts
Normal file
@ -0,0 +1,214 @@
|
||||
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"],
|
||||
table: {
|
||||
name: "cl-date-text",
|
||||
props: {
|
||||
format: "YYYY-MM-DD"
|
||||
}
|
||||
},
|
||||
form: {
|
||||
name: "el-date-picker",
|
||||
props: {
|
||||
type: "date",
|
||||
valueFormat: "YYYY-MM-DD"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: ["dates", "dateRange", "dateScope"],
|
||||
table: {
|
||||
name: "cl-date-text",
|
||||
props: {
|
||||
format: "YYYY-MM-DD"
|
||||
}
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
name: "el-date-picker",
|
||||
props: {
|
||||
type: "daterange",
|
||||
valueFormat: "YYYY-MM-DD"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: ["time"],
|
||||
form: {
|
||||
name: "el-date-picker",
|
||||
props: {
|
||||
type: "datetime",
|
||||
valueFormat: "YYYY-MM-DD HH:mm:ss"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: ["times", "timeRange", "timeScope"],
|
||||
form: {
|
||||
component: {
|
||||
name: "el-date-picker",
|
||||
props: {
|
||||
type: "datetimerange",
|
||||
valueFormat: "YYYY-MM-DD HH:mm:ss",
|
||||
defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
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", "introduce", "description", "desc"],
|
||||
table: {
|
||||
name: "cl-editor-quill"
|
||||
},
|
||||
form: {
|
||||
name: "cl-editor-quill",
|
||||
props: {
|
||||
height: 400
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: ["code", "codes"],
|
||||
table: {
|
||||
name: "cl-codemirror"
|
||||
},
|
||||
form: {
|
||||
name: "cl-codemirror",
|
||||
props: {
|
||||
height: 400
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: ["createTime"],
|
||||
table: {
|
||||
sortable: "desc"
|
||||
}
|
||||
},
|
||||
{
|
||||
test: ["updateTime"],
|
||||
table: {
|
||||
sortable: "custom"
|
||||
}
|
||||
}
|
||||
];
|
11
build/cool/lib/modules/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import fs from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
export function getModules() {
|
||||
try {
|
||||
const dirs = fs.readdirSync(join(__dirname, "../../../../src/modules"));
|
||||
return Promise.resolve(dirs.filter((e) => !e.includes(".")));
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}
|
1
build/cool/temp/eps.json
Normal file
@ -0,0 +1 @@
|
||||
[["/admin/base/comm",[["post","/personUpdate",""],["get","/uploadMode",""],["get","/permmenu",""],["get","/person",""],["post","/upload",""],["post","/logout",""],["","/list",""],["","/page",""],["","/info",""],["","/update",""],["","/delete",""],["","/add",""]]],["/admin/base/open",[["get","/refreshToken",""],["get","/captcha",""],["post","/login",""],["get","/html",""],["get","/eps",""],["","/list",""],["","/page",""],["","/info",""],["","/update",""],["","/delete",""],["","/add",""]]],["/admin/base/sys/department",[["post","/delete",""],["post","/update",""],["post","/order",""],["post","/list",""],["post","/add",""],["","/page",""],["","/info",""]]],["/admin/base/sys/log",[["post","/setKeep",""],["get","/getKeep",""],["post","/clear",""],["post","/page",""],["","/list",""],["","/info",""],["","/update",""],["","/delete",""],["","/add",""]]],["/admin/base/sys/menu",[["post","/delete",""],["post","/update",""],["get","/info",""],["post","/list",""],["post","/page",""],["post","/add",""]]],["/admin/base/sys/param",[["post","/delete",""],["post","/update",""],["get","/html",""],["get","/info",""],["post","/page",""],["post","/add",""],["","/list",""]]],["/admin/base/sys/role",[["post","/delete",""],["post","/update",""],["get","/info",""],["post","/list",""],["post","/page",""],["post","/add",""]]],["/admin/base/sys/user",[["post","/delete",""],["post","/update",""],["post","/move",""],["get","/info",""],["post","/list",""],["post","/page",""],["post","/add",""]]],["/admin/demo/goods",[["post","/delete",""],["post","/update",""],["get","/info",""],["post","/page",""],["post","/list",""],["post","/add",""]]],["/admin/space/info",[["post","/delete",""],["post","/update",""],["get","/info",""],["post","/list",""],["post","/page",""],["post","/add",""]]],["/admin/space/type",[["post","/delete",""],["post","/update",""],["get","/info",""],["post","/list",""],["post","/page",""],["post","/add",""]]],["/admin/task/info",[["post","/delete",""],["post","/update",""],["post","/start",""],["post","/once",""],["post","/stop",""],["get","/info",""],["post","/page",""],["get","/log",""],["post","/add",""],["","/list",""]]],["/test",[["","/list",""],["","/page",""],["","/info",""],["","/update",""],["","/delete",""],["","/add",""]]]]
|
768
build/cool/temp/service.d.ts
vendored
Normal file
@ -0,0 +1,768 @@
|
||||
declare interface Crud {
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data: any): Promise<any>;
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data: { ids?: number[] | string[]; [key: string]: any }): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data: { id?: number | string; [key: string]: any }): Promise<any>;
|
||||
/**
|
||||
* 详情
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data: { id?: number | string; [key: string]: any }): Promise<any>;
|
||||
/**
|
||||
* 全部
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: {
|
||||
page?: number | string;
|
||||
size?: number | string;
|
||||
[key: string]: any;
|
||||
}): Promise<PageResponse>;
|
||||
}
|
||||
|
||||
declare interface PageResponse {
|
||||
list: any[];
|
||||
pagination: { size: number; page: number; total: number };
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
declare interface RequestOptions {
|
||||
params?: any;
|
||||
data?: any;
|
||||
url: string;
|
||||
method?: "GET" | "get" | "POST" | "post" | string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
declare interface BaseComm {
|
||||
/**
|
||||
* 修改个人信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
personUpdate(data?: any): Promise<any>;
|
||||
/**
|
||||
* 文件上传模式
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
uploadMode(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限与菜单
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
permmenu(data?: any): Promise<any>;
|
||||
/**
|
||||
* 个人信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
person(data?: any): Promise<any>;
|
||||
/**
|
||||
* 文件上传
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
upload(data?: any): Promise<any>;
|
||||
/**
|
||||
* 退出
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
logout(data?: any): Promise<any>;
|
||||
/**
|
||||
* list
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* page
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* info
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* update
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* delete
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* add
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
personUpdate: string;
|
||||
uploadMode: string;
|
||||
permmenu: string;
|
||||
person: string;
|
||||
upload: string;
|
||||
logout: string;
|
||||
list: string;
|
||||
page: string;
|
||||
info: string;
|
||||
update: string;
|
||||
delete: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface BaseOpen {
|
||||
/**
|
||||
* 刷新token
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
refreshToken(data?: any): Promise<any>;
|
||||
/**
|
||||
* 验证码
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
captcha(data?: any): Promise<any>;
|
||||
/**
|
||||
* 登录
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
login(data?: any): Promise<any>;
|
||||
/**
|
||||
* 获得网页内容的参数值
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
html(data?: any): Promise<any>;
|
||||
/**
|
||||
* 实体信息与路径
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
eps(data?: any): Promise<any>;
|
||||
/**
|
||||
* list
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* page
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* info
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* update
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* delete
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* add
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
refreshToken: string;
|
||||
captcha: string;
|
||||
login: string;
|
||||
html: string;
|
||||
eps: string;
|
||||
list: string;
|
||||
page: string;
|
||||
info: string;
|
||||
update: string;
|
||||
delete: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface BaseSysDepartment {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 排序
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
order(data?: any): Promise<any>;
|
||||
/**
|
||||
* 列表查询
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* page
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* info
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
order: string;
|
||||
list: string;
|
||||
add: string;
|
||||
page: string;
|
||||
info: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface BaseSysLog {
|
||||
/**
|
||||
* 日志保存时间
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
setKeep(data?: any): Promise<any>;
|
||||
/**
|
||||
* 获得日志保存时间
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
getKeep(data?: any): Promise<any>;
|
||||
/**
|
||||
* 清理
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
clear(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* list
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* info
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* update
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* delete
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* add
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
setKeep: string;
|
||||
getKeep: string;
|
||||
clear: string;
|
||||
page: string;
|
||||
list: string;
|
||||
info: string;
|
||||
update: string;
|
||||
delete: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface BaseSysMenu {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 列表查询
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
info: string;
|
||||
list: string;
|
||||
page: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface BaseSysParam {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 获得网页内容的参数值
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
html(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* list
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
html: string;
|
||||
info: string;
|
||||
page: string;
|
||||
add: string;
|
||||
list: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface BaseSysRole {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 列表查询
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
info: string;
|
||||
list: string;
|
||||
page: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface BaseSysUser {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 移动部门
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
move(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 列表查询
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
move: string;
|
||||
info: string;
|
||||
list: string;
|
||||
page: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface DemoGoods {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 列表查询
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
info: string;
|
||||
page: string;
|
||||
list: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface SpaceInfo {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 列表查询
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
info: string;
|
||||
list: string;
|
||||
page: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface SpaceType {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 列表查询
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
info: string;
|
||||
list: string;
|
||||
page: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface TaskInfo {
|
||||
/**
|
||||
* 删除
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* 修改
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* 开始
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
start(data?: any): Promise<any>;
|
||||
/**
|
||||
* 执行一次
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
once(data?: any): Promise<any>;
|
||||
/**
|
||||
* 停止
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
stop(data?: any): Promise<any>;
|
||||
/**
|
||||
* 单个信息
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* 分页查询
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* 日志
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
log(data?: any): Promise<any>;
|
||||
/**
|
||||
* 新增
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* list
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
delete: string;
|
||||
update: string;
|
||||
start: string;
|
||||
once: string;
|
||||
stop: string;
|
||||
info: string;
|
||||
page: string;
|
||||
log: string;
|
||||
add: string;
|
||||
list: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare interface Test {
|
||||
/**
|
||||
* list
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
list(data?: any): Promise<any>;
|
||||
/**
|
||||
* page
|
||||
* @returns Promise<PageResponse>
|
||||
*/
|
||||
page(data?: any): Promise<PageResponse>;
|
||||
/**
|
||||
* info
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
info(data?: any): Promise<any>;
|
||||
/**
|
||||
* update
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
update(data?: any): Promise<any>;
|
||||
/**
|
||||
* delete
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
delete(data?: any): Promise<any>;
|
||||
/**
|
||||
* add
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
add(data?: any): Promise<any>;
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
permission: {
|
||||
list: string;
|
||||
page: string;
|
||||
info: string;
|
||||
update: string;
|
||||
delete: string;
|
||||
add: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare type Service = {
|
||||
request(data: RequestOptions): Promise<any>;
|
||||
base: {
|
||||
comm: BaseComm;
|
||||
open: BaseOpen;
|
||||
sys: {
|
||||
department: BaseSysDepartment;
|
||||
log: BaseSysLog;
|
||||
menu: BaseSysMenu;
|
||||
param: BaseSysParam;
|
||||
role: BaseSysRole;
|
||||
user: BaseSysUser;
|
||||
};
|
||||
};
|
||||
demo: { goods: DemoGoods };
|
||||
space: { info: SpaceInfo; type: SpaceType };
|
||||
task: { info: TaskInfo };
|
||||
test: Test;
|
||||
};
|
46
build/cool/utils/index.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import fs from "fs";
|
||||
|
||||
// 首字母大写
|
||||
export function firstUpperCase(value: string): string {
|
||||
return value.replace(/\b(\w)(\w*)/g, function ($0, $1, $2) {
|
||||
return $1.toUpperCase() + $2;
|
||||
});
|
||||
}
|
||||
|
||||
// 横杠转驼峰
|
||||
export function toCamel(str: string): string {
|
||||
return str.replace(/([^-])(?:-+([^-]))/g, function ($0, $1, $2) {
|
||||
return $1 + $2.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
// 创建目录
|
||||
export function createDir(path: string) {
|
||||
if (!fs.existsSync(path)) fs.mkdirSync(path);
|
||||
}
|
||||
|
||||
// 读取文件
|
||||
export function readFile(name: string) {
|
||||
try {
|
||||
return fs.readFileSync(name, "utf8");
|
||||
} catch (e) {}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// 解析body
|
||||
export function parseJson(req: any) {
|
||||
return new Promise((resolve) => {
|
||||
let d = "";
|
||||
req.on("data", function (chunk: Buffer) {
|
||||
d += chunk;
|
||||
});
|
||||
req.on("end", function () {
|
||||
try {
|
||||
resolve(JSON.parse(d));
|
||||
} catch {
|
||||
resolve({});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
71
build/svg/index.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { Plugin } from "vite";
|
||||
import { readFileSync, readdirSync } from "fs";
|
||||
|
||||
let idPerfix = "";
|
||||
const svgTitle = /<svg([^>+].*?)>/;
|
||||
const clearHeightWidth = /(width|height)="([^>+].*?)"/g;
|
||||
|
||||
const hasViewBox = /(viewBox="[^>+].*?")/g;
|
||||
|
||||
const clearReturn = /(\r)|(\n)/g;
|
||||
|
||||
function findSvgFile(dir: string): string[] {
|
||||
const svgRes = [];
|
||||
const dirents = readdirSync(dir, {
|
||||
withFileTypes: true
|
||||
});
|
||||
for (const dirent of dirents) {
|
||||
if (dirent.isDirectory()) {
|
||||
svgRes.push(...findSvgFile(dir + dirent.name + "/"));
|
||||
} else {
|
||||
const svg = readFileSync(dir + dirent.name)
|
||||
.toString()
|
||||
.replace(clearReturn, "")
|
||||
.replace(svgTitle, (_: any, $2: any) => {
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
let content = $2.replace(clearHeightWidth, (_: any, s2: any, s3: any) => {
|
||||
if (s2 === "width") {
|
||||
width = s3;
|
||||
} else if (s2 === "height") {
|
||||
height = s3;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
if (!hasViewBox.test($2)) {
|
||||
content += `viewBox="0 0 ${width} ${height}"`;
|
||||
}
|
||||
return `<symbol id="${idPerfix}-${dirent.name.replace(
|
||||
".svg",
|
||||
""
|
||||
)}" ${content}>`;
|
||||
})
|
||||
.replace("</svg>", "</symbol>");
|
||||
svgRes.push(svg);
|
||||
}
|
||||
}
|
||||
return svgRes;
|
||||
}
|
||||
|
||||
export const svgBuilder = (path: string, perfix = "icon"): Plugin | null => {
|
||||
if (path !== "") {
|
||||
idPerfix = perfix;
|
||||
const res = findSvgFile(path);
|
||||
return {
|
||||
name: "svg-transform",
|
||||
transformIndexHtml(html): string {
|
||||
return html.replace(
|
||||
"<body>",
|
||||
`
|
||||
<body>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
|
||||
${res.join("")}
|
||||
</svg>
|
||||
`
|
||||
);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
163
index.html
Normal file
@ -0,0 +1,163 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="referer" content="never" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"
|
||||
/>
|
||||
<title>COOL-ADMIN</title>
|
||||
<link rel="icon" href="favicon.ico" />
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
|
||||
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.preload__wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
letter-spacing: 1px;
|
||||
background-color: #2f3447;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.preload__container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.preload__name {
|
||||
font-size: 30px;
|
||||
color: #fff;
|
||||
letter-spacing: 5px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.preload__title {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
margin: 30px 0 20px 0;
|
||||
}
|
||||
|
||||
.preload__sub-title {
|
||||
color: #ababab;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.preload__footer {
|
||||
text-align: center;
|
||||
padding: 10px 0 20px 0;
|
||||
}
|
||||
|
||||
.preload__footer a {
|
||||
font-size: 12px;
|
||||
color: #ababab;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.preload__loading {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border-radius: 30px;
|
||||
border: 7px solid currentColor;
|
||||
border-bottom-color: #2f3447 !important;
|
||||
position: relative;
|
||||
animation: r 1s infinite cubic-bezier(0.17, 0.67, 0.83, 0.67),
|
||||
bc 2s infinite ease-in;
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
@keyframes r {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.preload__loading::after,
|
||||
.preload__loading::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
height: 7px;
|
||||
width: 7px;
|
||||
border-radius: 10px;
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
.preload__loading::after {
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
.preload__loading::before {
|
||||
right: -1px;
|
||||
}
|
||||
|
||||
@keyframes bc {
|
||||
0% {
|
||||
color: #689cc5;
|
||||
}
|
||||
|
||||
25% {
|
||||
color: #b3b7e2;
|
||||
}
|
||||
|
||||
50% {
|
||||
color: #93dbe9;
|
||||
}
|
||||
|
||||
75% {
|
||||
color: #abbd81;
|
||||
}
|
||||
|
||||
100% {
|
||||
color: #689cc5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="preload__wrap">
|
||||
<div class="preload__container">
|
||||
<p class="preload__name">COOL-ADMIN</p>
|
||||
<div class="preload__loading"></div>
|
||||
<p class="preload__title">正在加载资源...</p>
|
||||
<p class="preload__sub-title">初次加载资源可能需要较多时间 请耐心等待</p>
|
||||
</div>
|
||||
|
||||
<div class="preload__footer">
|
||||
<a href="https://cool-js.com/" target="_blank"> https://cool-js.com </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
123
nginx.conf
Normal file
@ -0,0 +1,123 @@
|
||||
user nginx;
|
||||
worker_processes 1;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
access_log /var/log/nginx/access.log main;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
upstream backend {
|
||||
server midway:7001;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
location / {
|
||||
root /app;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
location /api/
|
||||
{
|
||||
proxy_pass http://backend/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
|
||||
#缓存相关配置
|
||||
#proxy_cache cache_one;
|
||||
#proxy_cache_key $host$request_uri$is_args$args;
|
||||
#proxy_cache_valid 200 304 301 302 1h;
|
||||
|
||||
#持久化连接相关配置
|
||||
proxy_connect_timeout 3000s;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 3000s;
|
||||
#proxy_http_version 1.1;
|
||||
#proxy_set_header Upgrade $http_upgrade;
|
||||
#proxy_set_header Connection "upgrade";
|
||||
|
||||
add_header X-Cache $upstream_cache_status;
|
||||
|
||||
#expires 12h;
|
||||
}
|
||||
location /im {
|
||||
proxy_pass http://backend/im;
|
||||
proxy_connect_timeout 3600s; #配置点1
|
||||
proxy_read_timeout 3600s; #配置点2,如果没效,可以考虑这个时间配置长一点
|
||||
proxy_send_timeout 3600s; #配置点3
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
#proxy_bind $remote_addr transparent;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
# rewrite /socket/(.*) /$1 break;
|
||||
proxy_redirect off;
|
||||
|
||||
}
|
||||
|
||||
location /socket {
|
||||
proxy_pass http://backend/socket;
|
||||
proxy_connect_timeout 3600s; #配置点1
|
||||
proxy_read_timeout 3600s; #配置点2,如果没效,可以考虑这个时间配置长一点
|
||||
proxy_send_timeout 3600s; #配置点3
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
#proxy_bind $remote_addr transparent;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
rewrite /socket/(.*) /$1 break;
|
||||
proxy_redirect off;
|
||||
|
||||
}
|
||||
|
||||
|
||||
location /adminer/
|
||||
{
|
||||
proxy_pass http://adminer:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
|
||||
#缓存相关配置
|
||||
#proxy_cache cache_one;
|
||||
#proxy_cache_key $host$request_uri$is_args$args;
|
||||
#proxy_cache_valid 200 304 301 302 1h;
|
||||
|
||||
#持久化连接相关配置
|
||||
proxy_connect_timeout 3000s;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 3000s;
|
||||
#proxy_http_version 1.1;
|
||||
#proxy_set_header Upgrade $http_upgrade;
|
||||
#proxy_set_header Connection "upgrade";
|
||||
|
||||
add_header X-Cache $upstream_cache_status;
|
||||
|
||||
#expires 12h;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
70
package.json
Normal file
@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "front-next",
|
||||
"version": "5.2.1",
|
||||
"scripts": {
|
||||
"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": "^5.0.7",
|
||||
"@element-plus/icons-vue": "^1.1.3",
|
||||
"@vueuse/core": "^8.2.5",
|
||||
"axios": "^0.27.2",
|
||||
"codemirror": "^5.62.0",
|
||||
"core-js": "^3.6.5",
|
||||
"echarts": "^5.0.2",
|
||||
"element-plus": "^2.2.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"js-beautify": "^1.13.5",
|
||||
"lodash": "^4.17.21",
|
||||
"mitt": "^3.0.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.12",
|
||||
"quill": "^1.3.7",
|
||||
"store": "^2.0.12",
|
||||
"unocss": "^0.31.0",
|
||||
"vue": "^3.2.32",
|
||||
"vue-echarts": "^6.0.2",
|
||||
"vue-router": "^4.0.14",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"xlsx": "^0.16.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/node": "^16.10.2",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/quill": "^2.0.9",
|
||||
"@types/store": "^2.0.2",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@typescript-eslint/eslint-plugin": "^4.20.0",
|
||||
"@typescript-eslint/parser": "^4.20.0",
|
||||
"@unocss/preset-uno": "^0.31.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"@vitejs/plugin-vue-jsx": "^1.3.9",
|
||||
"@vue/cli-plugin-babel": "^5.0.1",
|
||||
"@vue/cli-plugin-typescript": "^5.0.1",
|
||||
"@vue/compiler-sfc": "^3.2.31",
|
||||
"@vue/composition-api": "^1.4.9",
|
||||
"eslint": "^7.23.0",
|
||||
"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.4.1",
|
||||
"sass": "^1.49.9",
|
||||
"sass-loader": "^11.1.1",
|
||||
"svg-sprite-loader": "^6.0.2",
|
||||
"typescript": "^4.6.2",
|
||||
"unplugin-vue-components": "^0.17.21",
|
||||
"vite": "^2.9.8",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-dts": "^0.9.9",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
"vite-plugin-style-import": "^1.0.1",
|
||||
"vite-svg-loader": "^2.1.0"
|
||||
}
|
||||
}
|
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 66 KiB |
28
src/App.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<el-config-provider :locale="zhCn">
|
||||
<div class="preload__wrap" v-if="app.loading">
|
||||
<div class="preload__container">
|
||||
<p class="preload__name">{{ app.info.name }}</p>
|
||||
<div class="preload__loading"></div>
|
||||
<p class="preload__title">正在加载菜单...</p>
|
||||
<p class="preload__sub-title">初次加载资源可能需要较多时间 请耐心等待</p>
|
||||
</div>
|
||||
|
||||
<div class="preload__footer">
|
||||
<a href="https://cool-js.com" target="_blank"> https://cool-js.com </a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<router-view />
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElConfigProvider } from "element-plus";
|
||||
import zhCn from "element-plus/lib/locale/lang/zh-cn";
|
||||
import { useBaseStore } from "/$/base";
|
||||
|
||||
const { app } = useBaseStore();
|
||||
</script>
|
||||
|
||||
<style lang="scss" src="./assets/css/index.scss"></style>
|
44
src/assets/css/index.scss
Normal file
@ -0,0 +1,44 @@
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
|
||||
"微软雅黑", Arial, sans-serif;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(144, 147, 153, 0.3);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:root {
|
||||
--view-bg-color: #f7f7f7;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input {
|
||||
&:-webkit-autofill {
|
||||
box-shadow: 0 0 0px 1000px white inset;
|
||||
}
|
||||
}
|
BIN
src/assets/logo-text.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
src/assets/logo.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
49
src/cool/bootstrap.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { createPinia } from "pinia";
|
||||
import { App } from "vue";
|
||||
import { useModule } from "./module";
|
||||
import { router, viewer } from "./router";
|
||||
import { useBaseStore } from "/$/base";
|
||||
import mitt from "mitt";
|
||||
import VueECharts from "vue-echarts";
|
||||
import ElementPlus from "element-plus";
|
||||
import "element-plus/theme-chalk/src/index.scss";
|
||||
import "uno.css";
|
||||
|
||||
export async function bootstrap(Vue: App) {
|
||||
// 缓存
|
||||
Vue.use(createPinia());
|
||||
|
||||
// ui库
|
||||
Vue.use(ElementPlus);
|
||||
|
||||
// 事件通讯
|
||||
Vue.provide("mitt", mitt());
|
||||
|
||||
// 可视图表
|
||||
Vue.component("v-chart", VueECharts);
|
||||
|
||||
// 基础
|
||||
const { app, user, menu } = useBaseStore();
|
||||
|
||||
// 加载模块
|
||||
useModule(Vue);
|
||||
|
||||
// 取缓存视图
|
||||
viewer.add(menu.routes);
|
||||
|
||||
// 路由
|
||||
Vue.use(router);
|
||||
|
||||
// 开启
|
||||
app.showLoading();
|
||||
|
||||
if (user.token) {
|
||||
// 获取用户信息
|
||||
user.get();
|
||||
|
||||
// 获取菜单权限
|
||||
await menu.get();
|
||||
}
|
||||
|
||||
app.hideLoading();
|
||||
}
|
20
src/cool/config/dev.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { getUrlParam, storage } from "../utils";
|
||||
import { proxy } from "./proxy";
|
||||
|
||||
export default {
|
||||
// 根地址
|
||||
host: proxy["/dev"].target,
|
||||
|
||||
// 请求地址
|
||||
get baseUrl() {
|
||||
let proxy = getUrlParam("proxy");
|
||||
|
||||
if (proxy) {
|
||||
storage.set("proxy", proxy);
|
||||
} else {
|
||||
proxy = storage.get("proxy") || "dev";
|
||||
}
|
||||
|
||||
return `/${proxy}`;
|
||||
}
|
||||
};
|
61
src/cool/config/index.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import dev from "./dev";
|
||||
import prod from "./prod";
|
||||
|
||||
// 是否开发模式
|
||||
export const isDev = import.meta.env.MODE === "development";
|
||||
|
||||
// 配置
|
||||
export const config = {
|
||||
// 项目信息
|
||||
app: {
|
||||
name: "COOL-ADMIN",
|
||||
|
||||
// 菜单
|
||||
menu: {
|
||||
list: []
|
||||
},
|
||||
|
||||
// 路由
|
||||
router: {
|
||||
// 模式
|
||||
mode: "history",
|
||||
// 页面
|
||||
pages: [],
|
||||
// 视图 / 路由下的 children
|
||||
views: []
|
||||
},
|
||||
|
||||
// 主题
|
||||
theme: {
|
||||
// 主色
|
||||
color: "",
|
||||
// 样式地址
|
||||
url: "",
|
||||
// 显示一级菜单
|
||||
showAMenu: false
|
||||
},
|
||||
|
||||
// 字体图标库
|
||||
iconfont: []
|
||||
},
|
||||
|
||||
// 忽略规则
|
||||
ignore: {
|
||||
// 不显示请求进度条
|
||||
NProgress: ["/sys/info/record"],
|
||||
// 页面不需要登录验证
|
||||
token: ["/login", "/401", "/403", "/404", "/500", "/502"]
|
||||
},
|
||||
|
||||
// 调试
|
||||
test: {
|
||||
token: "",
|
||||
mock: false,
|
||||
eps: true
|
||||
},
|
||||
|
||||
// 当前环境
|
||||
...(isDev ? dev : prod)
|
||||
};
|
||||
|
||||
export * from "./proxy";
|
9
src/cool/config/prod.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { proxy } from "./proxy";
|
||||
|
||||
export default {
|
||||
// 根地址
|
||||
host: proxy["/prod"].target,
|
||||
|
||||
// 请求地址
|
||||
baseUrl: "/api"
|
||||
};
|
13
src/cool/config/proxy.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export const proxy = {
|
||||
"/dev": {
|
||||
target: "http://127.0.0.1:8001",
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/dev/, "")
|
||||
},
|
||||
|
||||
"/prod": {
|
||||
target: "https://show.cool-admin.com",
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/prod/, "/api")
|
||||
}
|
||||
};
|
49
src/cool/hook/index.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { onBeforeUpdate, ref, inject, getCurrentInstance } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useService } from "../service";
|
||||
|
||||
export function useRefs() {
|
||||
const refs: any = ref<any[]>([]);
|
||||
|
||||
onBeforeUpdate(() => {
|
||||
refs.value = [];
|
||||
});
|
||||
|
||||
const setRefs = (index: string) => (el: any) => {
|
||||
refs.value[index] = el;
|
||||
};
|
||||
|
||||
return { refs, setRefs };
|
||||
}
|
||||
|
||||
// 服务
|
||||
const service = useService();
|
||||
|
||||
// 组件命名
|
||||
function named(name: string) {
|
||||
const { proxy }: any = getCurrentInstance();
|
||||
proxy.$.type.name = name;
|
||||
}
|
||||
|
||||
export function useCool() {
|
||||
const { refs, setRefs } = useRefs();
|
||||
|
||||
// 通信
|
||||
const mitt = inject<any>("mitt");
|
||||
|
||||
// 路由
|
||||
const route = useRoute();
|
||||
|
||||
// 路由器
|
||||
const router = useRouter();
|
||||
|
||||
return {
|
||||
route,
|
||||
router,
|
||||
refs,
|
||||
setRefs,
|
||||
service,
|
||||
mitt,
|
||||
named
|
||||
};
|
||||
}
|
6
src/cool/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from "./service";
|
||||
export * from "./bootstrap";
|
||||
export * from "./hook";
|
||||
export * from "./router";
|
||||
export * from "./config";
|
||||
export { storage } from "./utils";
|
162
src/cool/module/index.ts
Normal file
@ -0,0 +1,162 @@
|
||||
import { App } from "vue";
|
||||
import modules from "/@/modules";
|
||||
import { router, viewer } from "../router";
|
||||
import { filename, module } from "../utils";
|
||||
import { isFunction, isObject } from "lodash";
|
||||
|
||||
// 扫描文件
|
||||
const files = import.meta.globEager("/src/modules/**/*");
|
||||
|
||||
// 模块列表
|
||||
const list: any[] = [...modules];
|
||||
|
||||
function main() {
|
||||
for (const i in files) {
|
||||
// 模块名
|
||||
const [, , , name, action] = i.split("/");
|
||||
|
||||
// 文件内容
|
||||
let value: any = null;
|
||||
|
||||
try {
|
||||
value = files[i].default;
|
||||
} catch (err) {
|
||||
console.error(err, i);
|
||||
value = files[i];
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 文件名
|
||||
const fname: string = filename(i);
|
||||
|
||||
// 配置参数
|
||||
function next(d: any) {
|
||||
// 配置参数入口
|
||||
if (action == "config.ts") {
|
||||
d.options = value || {};
|
||||
}
|
||||
|
||||
// 模块入口
|
||||
if (action == "index.ts") {
|
||||
d.value = value || {};
|
||||
}
|
||||
|
||||
// 其他功能
|
||||
switch (action) {
|
||||
case "service":
|
||||
const s = new value();
|
||||
|
||||
d.service.push({
|
||||
path: s.namespace,
|
||||
value: s
|
||||
});
|
||||
break;
|
||||
|
||||
case "pages":
|
||||
case "views":
|
||||
if (value.cool) {
|
||||
d[action].push({
|
||||
...value.cool.route,
|
||||
component: value
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "components":
|
||||
d.components[value.name] = value;
|
||||
break;
|
||||
|
||||
case "directives":
|
||||
d.directives[fname] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
// 是否存在
|
||||
const item: any = list.find((e) => e.name === name);
|
||||
|
||||
if (item) {
|
||||
if (!item.isLoaded) {
|
||||
next(item);
|
||||
}
|
||||
} else {
|
||||
list.push(
|
||||
next({
|
||||
name,
|
||||
options: {},
|
||||
directives: {},
|
||||
components: {},
|
||||
pages: [],
|
||||
views: [],
|
||||
service: []
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.set(list);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
export function useModule(app: App) {
|
||||
// 模块安装
|
||||
list.forEach((e: any) => {
|
||||
if (isObject(e.value)) {
|
||||
if (isFunction(e.value.install)) {
|
||||
Object.assign(e, e.value.install(app, e.options));
|
||||
} else {
|
||||
Object.assign(e, e.value);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// 注册组件
|
||||
if (e.components) {
|
||||
for (const i in e.components) {
|
||||
if (e.components[i]) {
|
||||
if (e.components[i].cool?.global || i.indexOf("cl-") === 0) {
|
||||
app.component(e.components[i].name, e.components[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册指令
|
||||
if (e.directives) {
|
||||
for (const i in e.directives) {
|
||||
app.directive(i, e.directives[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 注册页面
|
||||
if (e.pages) {
|
||||
e.pages.forEach((e: any) => {
|
||||
router.addRoute(e);
|
||||
});
|
||||
}
|
||||
|
||||
// 注册视图
|
||||
if (e.views) {
|
||||
e.views.forEach((e: any) => {
|
||||
if (!e.meta) {
|
||||
e.meta = {};
|
||||
}
|
||||
|
||||
if (e.path) {
|
||||
viewer.add([e]);
|
||||
} else {
|
||||
console.error(`[${name}-views]:缺少 path 参数`);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`模块 ${name} 异常`, err);
|
||||
}
|
||||
});
|
||||
}
|
144
src/cool/router/index.ts
Normal file
@ -0,0 +1,144 @@
|
||||
// @ts-nocheck
|
||||
import { ElMessage } from "element-plus";
|
||||
import {
|
||||
createRouter,
|
||||
createWebHashHistory,
|
||||
createWebHistory,
|
||||
NavigationGuardNext,
|
||||
RouteRecordRaw
|
||||
} from "vue-router";
|
||||
import { storage, config } from "/@/cool";
|
||||
import { useBaseStore } from "/$/base";
|
||||
import { cloneDeep, isArray } from "lodash";
|
||||
|
||||
// 视图文件
|
||||
const views = import.meta.globEager("/src/**/views/**/*.vue");
|
||||
|
||||
for (const i in views) {
|
||||
views[i.slice(5)] = views[i];
|
||||
delete views[i];
|
||||
}
|
||||
|
||||
// 默认路由
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "/",
|
||||
name: "index",
|
||||
component: () => import("/$/base/pages/layout/index.vue"),
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
name: "数据统计",
|
||||
component: () => import("/@/views/home/index.vue")
|
||||
},
|
||||
...config.app.router.views
|
||||
]
|
||||
},
|
||||
...config.app.router.pages,
|
||||
{
|
||||
path: "/:catchAll(.*)",
|
||||
name: "404",
|
||||
redirect: "/404"
|
||||
}
|
||||
];
|
||||
|
||||
// 创建
|
||||
const router = createRouter({
|
||||
history: config.app.router.mode == "history" ? createWebHistory() : createWebHashHistory(),
|
||||
routes
|
||||
}) as CoolRouter;
|
||||
|
||||
// 路由守卫
|
||||
router.beforeEach((to: any, _: any, next: NavigationGuardNext) => {
|
||||
const { user, process } = useBaseStore();
|
||||
|
||||
if (user.token) {
|
||||
if (to.path.includes("/login")) {
|
||||
// 登录成功且 token 未过期,回到首页
|
||||
if (!storage.isExpired("token")) {
|
||||
return next("/");
|
||||
}
|
||||
} else {
|
||||
// 添加路由进程
|
||||
process.add({
|
||||
keepAlive: to.meta?.keepAlive,
|
||||
label: to.meta?.label || to.name,
|
||||
value: to.fullPath
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!config.ignore.token.find((e: string) => to.path == e)) {
|
||||
return next("/login");
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
// 自定义
|
||||
router.href = function (path: string) {
|
||||
const url = import.meta.env.BASE_URL + path;
|
||||
|
||||
if (url != location.pathname) {
|
||||
location.href = url;
|
||||
}
|
||||
};
|
||||
|
||||
let lock = false;
|
||||
|
||||
// 错误监听
|
||||
router.onError((err: any) => {
|
||||
if (!lock) {
|
||||
lock = true;
|
||||
|
||||
ElMessage.error("页面不存在或者未配置!");
|
||||
console.error(err);
|
||||
|
||||
setTimeout(() => {
|
||||
lock = false;
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// 视图
|
||||
const viewer = {
|
||||
add(data: any[] | any) {
|
||||
// 列表
|
||||
const list = isArray(data) ? data : [data];
|
||||
|
||||
list.forEach((e: any) => {
|
||||
const d: any = cloneDeep(e);
|
||||
|
||||
// 命名
|
||||
d.name = d.router;
|
||||
|
||||
if (!d.component) {
|
||||
const url = d.viewPath;
|
||||
|
||||
if (url) {
|
||||
if (
|
||||
/^(http[s]?:\/\/)([0-9a-z.]+)(:[0-9]+)?([/0-9a-z.]+)?(\?[0-9a-z&=]+)?(#[0-9-a-z]+)?/i.test(
|
||||
url
|
||||
)
|
||||
) {
|
||||
d.meta.iframeUrl = url;
|
||||
d.component = () => import(`/$/base/pages/iframe/index.vue`);
|
||||
} else {
|
||||
d.component = () => Promise.resolve(views[url.replace("cool/", "")]);
|
||||
}
|
||||
} else {
|
||||
d.redirect = "/404";
|
||||
}
|
||||
}
|
||||
|
||||
// 批量添加
|
||||
router.addRoute("index", d);
|
||||
});
|
||||
},
|
||||
|
||||
get() {
|
||||
return router.getRoutes().find((e) => e.name == "index")?.children;
|
||||
}
|
||||
};
|
||||
|
||||
export { router, viewer };
|
132
src/cool/service/base.ts
Normal file
@ -0,0 +1,132 @@
|
||||
// @ts-nocheck
|
||||
import { isDev, config, proxy } from "../config";
|
||||
import { isObject } from "lodash";
|
||||
import request from "./request";
|
||||
|
||||
export function Service(
|
||||
value:
|
||||
| string
|
||||
| {
|
||||
namespace?: string;
|
||||
url?: string;
|
||||
mock?: boolean;
|
||||
}
|
||||
) {
|
||||
return function (target: any) {
|
||||
// 命名
|
||||
if (typeof value == "string") {
|
||||
target.prototype.namespace = value;
|
||||
}
|
||||
|
||||
// 复杂项
|
||||
if (isObject(value)) {
|
||||
target.prototype.namespace = value.namespace;
|
||||
target.prototype.mock = value.mock;
|
||||
|
||||
// 代理
|
||||
if (value.proxy) {
|
||||
target.prototype.url = proxy[value.proxy].target;
|
||||
} else {
|
||||
if (value.url) {
|
||||
target.prototype.url = value.url;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class BaseService {
|
||||
constructor(
|
||||
options = {} as {
|
||||
namespace?: string;
|
||||
}
|
||||
) {
|
||||
if (options?.namespace) {
|
||||
this.namespace = options.namespace;
|
||||
}
|
||||
}
|
||||
|
||||
request(
|
||||
options = {} as {
|
||||
params?: any;
|
||||
data?: any;
|
||||
url: string;
|
||||
method?: "GET" | "get" | "POST" | "post" | string;
|
||||
[key: string]: any;
|
||||
}
|
||||
) {
|
||||
if (!options.params) options.params = {};
|
||||
|
||||
let ns = "";
|
||||
|
||||
// 是否 mock 模式
|
||||
if (this.mock || config.test.mock) {
|
||||
// 测试
|
||||
} else {
|
||||
if (isDev) {
|
||||
ns = this.proxy || config.baseUrl;
|
||||
} else {
|
||||
ns = this.proxy ? this.url : config.baseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// 拼接前缀
|
||||
if (this.namespace) {
|
||||
ns += "/" + this.namespace;
|
||||
}
|
||||
|
||||
// 处理地址
|
||||
if (options.proxy === undefined || options.proxy) {
|
||||
options.url = ns + options.url;
|
||||
}
|
||||
|
||||
return request(options);
|
||||
}
|
||||
|
||||
list(data: any) {
|
||||
return this.request({
|
||||
url: "/list",
|
||||
method: "POST",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
page(data: { page?: number; size?: number; [key: string]: any }) {
|
||||
return this.request({
|
||||
url: "/page",
|
||||
method: "POST",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
info(params: { id?: number | string; [key: string]: any }) {
|
||||
return this.request({
|
||||
url: "/info",
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
update(data: { id?: number | string; [key: string]: any }) {
|
||||
return this.request({
|
||||
url: "/update",
|
||||
method: "POST",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
delete(data: { ids?: number[] | string[]; [key: string]: any }) {
|
||||
return this.request({
|
||||
url: "/delete",
|
||||
method: "POST",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
add(data: any) {
|
||||
return this.request({
|
||||
url: "/add",
|
||||
method: "POST",
|
||||
data
|
||||
});
|
||||
}
|
||||
}
|
213
src/cool/service/eps.ts
Normal file
@ -0,0 +1,213 @@
|
||||
import { isDev, config } from "../config";
|
||||
import { BaseService } from "./base";
|
||||
import { storage, toCamel } from "../utils";
|
||||
import { isArray, isEmpty } from "lodash";
|
||||
|
||||
// 获取标签名
|
||||
function getNames(v: any) {
|
||||
return [...Object.getOwnPropertyNames(v.constructor.prototype), ...Object.keys(v)].filter(
|
||||
(e) => !["namespace", "constructor", "request", "permission"].includes(e)
|
||||
);
|
||||
}
|
||||
|
||||
// 标签名
|
||||
const names = getNames(new BaseService());
|
||||
|
||||
export function useEps(service: Service) {
|
||||
// 创建描述文件
|
||||
function createDts(list: any[]) {
|
||||
function deep(v: any) {
|
||||
for (const i in v) {
|
||||
if (v[i].namespace) {
|
||||
v[i].namespace = v[i].namespace;
|
||||
|
||||
// 模块
|
||||
const item: any = list.find((e: any) => e.prefix.includes(v[i].namespace));
|
||||
|
||||
// 接口
|
||||
const api: any[] = item ? item.api : [];
|
||||
|
||||
// 获取方法集合
|
||||
[...names, ...getNames(v[i])].forEach((e) => {
|
||||
if (!api.find((a) => a.path.includes(e))) {
|
||||
api.push({
|
||||
path: `/${e}`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (item) {
|
||||
item.api = api;
|
||||
} else {
|
||||
list.push({
|
||||
prefix: `/${v[i].namespace}`,
|
||||
api
|
||||
});
|
||||
}
|
||||
} else {
|
||||
deep(v[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deep(service);
|
||||
|
||||
// 本地服务
|
||||
return service.request({
|
||||
url: "/__cool_eps",
|
||||
method: "POST",
|
||||
proxy: false,
|
||||
data: {
|
||||
service,
|
||||
list
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取 eps
|
||||
function getEps() {
|
||||
if (isDev && config.test.eps) {
|
||||
service
|
||||
.request({
|
||||
url: "/admin/base/open/eps"
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (!isEmpty(res)) {
|
||||
const isLoaded: boolean = storage.get("eps");
|
||||
storage.set("eps", res);
|
||||
|
||||
if (!isLoaded) {
|
||||
location.reload();
|
||||
} else {
|
||||
set(res, true);
|
||||
console.log("[Eps] 初始化成功。");
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("[Eps] 获取失败!", err.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 设置
|
||||
async function set(d: any, c?: boolean) {
|
||||
const list: any[] = [];
|
||||
|
||||
if (!d) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isArray(d)) {
|
||||
d = { d };
|
||||
}
|
||||
|
||||
for (const i in d) {
|
||||
if (isArray(d[i])) {
|
||||
d[i].forEach((e: any) => {
|
||||
// 分隔路径
|
||||
const arr = e.prefix
|
||||
.replace(/\//, "")
|
||||
.replace("admin", "")
|
||||
.split("/")
|
||||
.filter(Boolean)
|
||||
.map(toCamel);
|
||||
|
||||
// 遍历
|
||||
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.substr(1, e.prefix.length - 1)
|
||||
});
|
||||
}
|
||||
|
||||
// 创建方法
|
||||
e.api.forEach((a: any) => {
|
||||
// 方法名
|
||||
const n = (a.name || a.path).replace("/", "");
|
||||
|
||||
// 过滤
|
||||
if (!names.includes(n)) {
|
||||
// 本地不存在则创建
|
||||
if (!d[k][n]) {
|
||||
if (n && !/[-:]/g.test(n)) {
|
||||
d[k][n] = function (data: any) {
|
||||
return this.request({
|
||||
url: a.path,
|
||||
method: a.method,
|
||||
[a.method.toLocaleLowerCase() == "post"
|
||||
? "data"
|
||||
: "params"]: data
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 创建权限
|
||||
if (!d[k].permission) {
|
||||
d[k].permission = {};
|
||||
|
||||
const ks = Array.from(new Set([...names, ...getNames(d[k])]));
|
||||
|
||||
ks.forEach((e) => {
|
||||
d[k].permission[e] = `${d[k].namespace.replace(
|
||||
"admin/",
|
||||
""
|
||||
)}/${e}`.replace(/\//g, ":");
|
||||
});
|
||||
}
|
||||
|
||||
list.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deep(service, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (isDev && c) {
|
||||
await createDts(list);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析
|
||||
try {
|
||||
const eps =
|
||||
storage.get("eps") ||
|
||||
JSON.parse(__EPS__ || "[]").map(([prefix, api]: any[]) => {
|
||||
return {
|
||||
prefix,
|
||||
api: api.map(([method, path, name]: string[]) => {
|
||||
return {
|
||||
method,
|
||||
path,
|
||||
name
|
||||
};
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
set(eps);
|
||||
} catch (err) {
|
||||
console.error("[Eps] 解析失败!", err);
|
||||
}
|
||||
|
||||
// 获取
|
||||
getEps();
|
||||
}
|
23
src/cool/service/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { deepFiles, deepMerge, module } from "../utils";
|
||||
import { BaseService } from "./base";
|
||||
import { useEps } from "./eps";
|
||||
|
||||
// 基础服务
|
||||
export const service: Service = {
|
||||
request: new BaseService().request
|
||||
};
|
||||
|
||||
export function useService() {
|
||||
// 接口内容
|
||||
useEps(service);
|
||||
|
||||
// 模块内容
|
||||
module.list.forEach((e) => {
|
||||
deepMerge(service, deepFiles(e.service || []));
|
||||
});
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
export * from "./base";
|
||||
export * from "./request";
|
146
src/cool/service/request.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import axios from "axios";
|
||||
import NProgress from "nprogress";
|
||||
import "nprogress/nprogress.css";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { isDev, config } from "/@/cool";
|
||||
import { storage } from "/@/cool/utils";
|
||||
import { useBaseStore } from "/$/base";
|
||||
import { router } from "../router";
|
||||
|
||||
axios.defaults.timeout = 30000;
|
||||
axios.defaults.withCredentials = false;
|
||||
|
||||
NProgress.configure({
|
||||
showSpinner: true
|
||||
});
|
||||
|
||||
// 请求队列
|
||||
let requests: Array<Function> = [];
|
||||
|
||||
// Token 是否刷新中
|
||||
let isRefreshing = false;
|
||||
|
||||
// @ts-ignore
|
||||
axios.interceptors.request.eject(axios._req);
|
||||
|
||||
// @ts-ignore
|
||||
axios._req = axios.interceptors.request.use(
|
||||
(req: any) => {
|
||||
const { user } = useBaseStore();
|
||||
|
||||
if (req.url) {
|
||||
// 请求进度条
|
||||
if (!config.ignore.NProgress.some((e: string) => req.url.includes(e))) {
|
||||
NProgress.start();
|
||||
}
|
||||
}
|
||||
|
||||
// 请求信息
|
||||
if (isDev) {
|
||||
console.group(req.url);
|
||||
console.log("method:", req.method);
|
||||
console.table("data:", req.method == "get" ? req.params : req.data);
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
// 验证 token
|
||||
if (user.token) {
|
||||
// 请求标识
|
||||
req.headers["Authorization"] = user.token;
|
||||
|
||||
if (req.url.includes("refreshToken")) {
|
||||
return req;
|
||||
}
|
||||
|
||||
// 判断 token 是否过期
|
||||
if (storage.isExpired("token")) {
|
||||
// 判断 refreshToken 是否过期
|
||||
if (storage.isExpired("refreshToken")) {
|
||||
return user.logout();
|
||||
}
|
||||
|
||||
// 是否在刷新中
|
||||
if (!isRefreshing) {
|
||||
isRefreshing = true;
|
||||
|
||||
user.refreshToken()
|
||||
.then((token: string) => {
|
||||
requests.forEach((cb) => cb(token));
|
||||
requests = [];
|
||||
isRefreshing = false;
|
||||
})
|
||||
.catch(() => {
|
||||
user.clear();
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
// 继续请求
|
||||
requests.push((token: string) => {
|
||||
// 重新设置 token
|
||||
req.headers["Authorization"] = token;
|
||||
resolve(req);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return req;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应
|
||||
axios.interceptors.response.use(
|
||||
(res) => {
|
||||
NProgress.done();
|
||||
|
||||
if (!res?.data) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const { code, data, message } = res.data;
|
||||
|
||||
switch (code) {
|
||||
case 1000:
|
||||
return data;
|
||||
default:
|
||||
return Promise.reject({ code, message });
|
||||
}
|
||||
},
|
||||
async (error) => {
|
||||
NProgress.done();
|
||||
|
||||
if (error.response) {
|
||||
const { status, config } = error.response;
|
||||
|
||||
if (isDev) {
|
||||
ElMessage.error(`${config.url} ${status}`);
|
||||
} else {
|
||||
switch (status) {
|
||||
case 401:
|
||||
router.href("401");
|
||||
break;
|
||||
|
||||
case 403:
|
||||
router.href("403");
|
||||
break;
|
||||
|
||||
case 500:
|
||||
router.href("500");
|
||||
break;
|
||||
|
||||
case 502:
|
||||
router.href("502");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject({ message: error.message });
|
||||
}
|
||||
);
|
||||
|
||||
export default axios;
|
272
src/cool/utils/index.ts
Normal file
@ -0,0 +1,272 @@
|
||||
import { isArray, orderBy } from "lodash";
|
||||
import storage from "./storage";
|
||||
import module from "./module";
|
||||
|
||||
// 首字母大写
|
||||
export function firstUpperCase(value: string): string {
|
||||
return value.replace(/\b(\w)(\w*)/g, function ($0, $1, $2) {
|
||||
return $1.toUpperCase() + $2;
|
||||
});
|
||||
}
|
||||
|
||||
// 获取方法名
|
||||
export function getNames(value: any) {
|
||||
return Object.getOwnPropertyNames(value.constructor.prototype);
|
||||
}
|
||||
|
||||
// 深度合并
|
||||
export function deepMerge(a: any, b: any) {
|
||||
let k;
|
||||
for (k in b) {
|
||||
a[k] =
|
||||
a[k] && a[k].toString() === "[object Object]" ? deepMerge(a[k], b[k]) : (a[k] = b[k]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// 获取地址栏参数
|
||||
export function getUrlParam(name: string): string | null {
|
||||
const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
|
||||
const r = window.location.search.substr(1).match(reg);
|
||||
if (r != null) return decodeURIComponent(r[2]);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 文件路径转对象
|
||||
export function deepFiles(list: any[]) {
|
||||
const modules: any = {};
|
||||
|
||||
list.forEach((e) => {
|
||||
const arr = e.path.split("/");
|
||||
const parents = arr.slice(0, arr.length - 1);
|
||||
const name = basename(e.path).replace(".ts", "");
|
||||
|
||||
let curr: any = modules;
|
||||
let prev: any = null;
|
||||
let key: any = null;
|
||||
|
||||
parents.forEach((k: string) => {
|
||||
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;
|
||||
}
|
||||
|
||||
// 文件名
|
||||
export function filename(path: string): string {
|
||||
return basename(path.substring(0, path.lastIndexOf(".")));
|
||||
}
|
||||
|
||||
// 路径名称
|
||||
export function basename(path: string): string {
|
||||
let index = path.lastIndexOf("/");
|
||||
index = index > -1 ? index : path.lastIndexOf("\\");
|
||||
if (index < 0) {
|
||||
return path;
|
||||
}
|
||||
return path.substring(index + 1);
|
||||
}
|
||||
|
||||
// 文件扩展名
|
||||
export function extname(path: string): string {
|
||||
return path.substring(path.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
// 横杠转驼峰
|
||||
export function toCamel(str: string): string {
|
||||
return str.replace(/([^-])(?:-+([^-]))/g, function ($0, $1, $2) {
|
||||
return $1 + $2.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
// uuid
|
||||
export function uuid(): string {
|
||||
const s: any[] = [];
|
||||
const hexDigits = "0123456789abcdef";
|
||||
for (let i = 0; i < 36; i++) {
|
||||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||
}
|
||||
s[14] = "4";
|
||||
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
|
||||
s[8] = s[13] = s[18] = s[23] = "-";
|
||||
|
||||
return s.join("");
|
||||
}
|
||||
|
||||
// 浏览器信息
|
||||
export function getBrowser() {
|
||||
const { clientHeight, clientWidth } = document.documentElement;
|
||||
|
||||
// 浏览器信息
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
|
||||
// 浏览器类型
|
||||
let type = (ua.match(/firefox|chrome|safari|opera/g) || "other")[0];
|
||||
|
||||
if ((ua.match(/msie|trident/g) || [])[0]) {
|
||||
type = "msie";
|
||||
}
|
||||
|
||||
// 平台标签
|
||||
let tag = "";
|
||||
|
||||
const isTocuh =
|
||||
"ontouchstart" in window || ua.indexOf("touch") !== -1 || ua.indexOf("mobile") !== -1;
|
||||
if (isTocuh) {
|
||||
if (ua.indexOf("ipad") !== -1) {
|
||||
tag = "pad";
|
||||
} else if (ua.indexOf("mobile") !== -1) {
|
||||
tag = "mobile";
|
||||
} else if (ua.indexOf("android") !== -1) {
|
||||
tag = "androidPad";
|
||||
} else {
|
||||
tag = "pc";
|
||||
}
|
||||
} else {
|
||||
tag = "pc";
|
||||
}
|
||||
|
||||
// 浏览器内核
|
||||
let prefix = "";
|
||||
|
||||
switch (type) {
|
||||
case "chrome":
|
||||
case "safari":
|
||||
case "mobile":
|
||||
prefix = "webkit";
|
||||
break;
|
||||
case "msie":
|
||||
prefix = "ms";
|
||||
break;
|
||||
case "firefox":
|
||||
prefix = "Moz";
|
||||
break;
|
||||
case "opera":
|
||||
prefix = "O";
|
||||
break;
|
||||
default:
|
||||
prefix = "webkit";
|
||||
break;
|
||||
}
|
||||
|
||||
// 操作平台
|
||||
const plat = ua.indexOf("android") > 0 ? "android" : navigator.platform.toLowerCase();
|
||||
|
||||
// 屏幕信息
|
||||
let screen = "full";
|
||||
|
||||
if (clientWidth < 768) {
|
||||
screen = "xs";
|
||||
} else if (clientWidth < 992) {
|
||||
screen = "sm";
|
||||
} else if (clientWidth < 1200) {
|
||||
screen = "md";
|
||||
} else if (clientWidth < 1920) {
|
||||
screen = "xl";
|
||||
} else {
|
||||
screen = "full";
|
||||
}
|
||||
|
||||
// 是否 ios
|
||||
const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
|
||||
|
||||
// 浏览器版本
|
||||
const version = (ua.match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1];
|
||||
|
||||
// 是否 PC 端
|
||||
const isPC = tag === "pc";
|
||||
|
||||
// 是否移动端
|
||||
const isMobile = isPC ? false : true;
|
||||
|
||||
// 是否移动端 + 屏幕宽过小
|
||||
const isMini = screen === "xs" || isMobile;
|
||||
|
||||
return {
|
||||
height: clientHeight,
|
||||
width: clientWidth,
|
||||
version,
|
||||
type,
|
||||
plat,
|
||||
tag,
|
||||
prefix,
|
||||
isMobile,
|
||||
isIOS,
|
||||
isPC,
|
||||
isMini,
|
||||
screen
|
||||
};
|
||||
}
|
||||
|
||||
// 列表转树形
|
||||
export function deepTree(list: any[]): any[] {
|
||||
const newList: Array<any> = [];
|
||||
const map: any = {};
|
||||
|
||||
list.forEach((e) => (map[e.id] = e));
|
||||
|
||||
list.forEach((e) => {
|
||||
const parent = map[e.parentId];
|
||||
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(e);
|
||||
} else {
|
||||
newList.push(e);
|
||||
}
|
||||
});
|
||||
|
||||
const fn = (list: Array<any>) => {
|
||||
list.map((e) => {
|
||||
if (e.children instanceof Array) {
|
||||
e.children = orderBy(e.children, "orderNum");
|
||||
|
||||
fn(e.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
fn(newList);
|
||||
|
||||
return orderBy(newList, "orderNum");
|
||||
}
|
||||
|
||||
// 树形转列表
|
||||
export function revDeepTree(list: Array<any> = []) {
|
||||
const d: Array<any> = [];
|
||||
let id = 0;
|
||||
|
||||
const deep = (list: Array<any>, parentId: any) => {
|
||||
list.forEach((e) => {
|
||||
if (!e.id) {
|
||||
e.id = id++;
|
||||
}
|
||||
|
||||
e.parentId = parentId;
|
||||
|
||||
d.push(e);
|
||||
|
||||
if (e.children && isArray(e.children)) {
|
||||
deep(e.children, e.id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
deep(list || [], null);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
export { storage, module };
|
31
src/cool/utils/module.ts
Normal file
@ -0,0 +1,31 @@
|
||||
// @ts-nocheck
|
||||
|
||||
interface Item {
|
||||
name: string;
|
||||
options: {
|
||||
[key: string]: any;
|
||||
};
|
||||
value: any;
|
||||
service?: any[];
|
||||
pages?: any[];
|
||||
views?: any[];
|
||||
components?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
const module = {
|
||||
get list(): Item[] {
|
||||
return window.__modules__ || [];
|
||||
},
|
||||
|
||||
set(list: Item[]) {
|
||||
window.__modules__ = list;
|
||||
},
|
||||
|
||||
get(name: string) {
|
||||
return name ? window.__modules__.find((e) => e.name == name) : window.__modules__;
|
||||
}
|
||||
};
|
||||
|
||||
export default module;
|
81
src/cool/utils/storage.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import store from "store";
|
||||
|
||||
export default {
|
||||
// 后缀标识
|
||||
suffix: "_deadtime",
|
||||
|
||||
/**
|
||||
* 获取
|
||||
* @param {string} key 关键字
|
||||
*/
|
||||
get(key: string) {
|
||||
return store.get(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取全部
|
||||
*/
|
||||
info() {
|
||||
const d: any = {};
|
||||
|
||||
store.each(function (value: any, key: any) {
|
||||
d[key] = value;
|
||||
});
|
||||
|
||||
return d;
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置
|
||||
* @param {string} key 关键字
|
||||
* @param {*} value 值
|
||||
* @param {number} expires 过期时间
|
||||
*/
|
||||
set(key: string, value: any, expires?: any) {
|
||||
store.set(key, value);
|
||||
|
||||
if (expires) {
|
||||
store.set(`${key}${this.suffix}`, Date.parse(String(new Date())) + expires * 1000);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 是否过期
|
||||
* @param {string} key 关键字
|
||||
*/
|
||||
isExpired(key: string) {
|
||||
return (this.getExpiration(key) || 0) - Date.parse(String(new Date())) <= 2000;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取到期时间
|
||||
* @param {string} key 关键字
|
||||
*/
|
||||
getExpiration(key: string) {
|
||||
return this.get(key + this.suffix);
|
||||
},
|
||||
|
||||
/**
|
||||
* 移除
|
||||
* @param {string} key 关键字
|
||||
*/
|
||||
remove(key: string) {
|
||||
store.remove(key);
|
||||
this.removeExpiration(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* 移除到期时间
|
||||
* @param {string} key 关键字
|
||||
*/
|
||||
removeExpiration(key: string) {
|
||||
store.remove(key + this.suffix);
|
||||
},
|
||||
|
||||
/**
|
||||
* 清理
|
||||
*/
|
||||
clearAll() {
|
||||
store.clearAll();
|
||||
}
|
||||
};
|
4
src/env.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/// <reference types="@cool-vue/crud" />
|
||||
/// <reference types="../build/cool/temp/service" />
|
||||
|
||||
declare const __EPS__: string;
|
1
src/icons/svg/icon-activity.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441341007" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11418" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M848.896 132.192c-10.048-5.664-22.4-5.408-32.352 0.544-0.448 0.288-45.664 27.328-98.688 27.328-53.184 0-99.776-27.232-100.16-27.424a29.488 29.488 0 0 0-3.456-1.792c-3.2-1.408-79.008-34.752-149.696-34.752-70.08 0-151.936 32.96-155.36 34.368-12.032 4.896-19.936 16.64-19.936 29.632v416a32.041 32.041 0 0 0 14.24 26.624c8.928 5.984 20.192 7.04 30.08 2.912 19.68-8.224 80.992-29.536 127.68-29.536 51.52 0 115.776 24.768 126.208 28.928 11.712 6.304 68.544 35.072 133.088 35.072 72.032 0 127.776-35.616 130.08-37.152 9.088-5.92 14.592-16 14.592-26.848v-416c0.032-11.584-6.24-22.208-16.32-27.904z m-271.68 763.744H224.768V128.064c0-17.664-14.336-32-32-32s-32 14.336-32 32v768c0 0.064 0.032 0.096 0.032 0.16-16.96 0.8-30.56 14.528-30.56 31.712 0 17.696 14.336 32 32 32h414.976c17.696 0 32-14.304 32-32s-14.304-32-32-32z" p-id="11419"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/icons/svg/icon-app.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441249036" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4552" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M364.8 590.62857143H182.85714286c-60.34285714 0-109.71428571-49.37142857-109.71428572-109.71428572V182.85714286c0-60.34285714 49.37142857-109.71428571 109.71428572-109.71428572h181.94285714c60.34285714 0 109.71428571 49.37142857 109.71428571 109.71428572v298.05714285c0 60.34285714-49.37142857 109.71428571-109.71428571 109.71428572zM841.14285714 358.4H659.2c-60.34285714 0-109.71428571-49.37142857-109.71428571-109.71428571V182.85714286c0-60.34285714 49.37142857-109.71428571 109.71428571-109.71428572H841.14285714c60.34285714 0 109.71428571 49.37142857 109.71428572 109.71428572v65.82857143c0 60.34285714-49.37142857 109.71428571-109.71428572 109.71428571zM364.8 950.85714286H182.85714286c-60.34285714 0-109.71428571-49.37142857-109.71428572-109.71428572v-65.82857143c0-60.34285714 49.37142857-109.71428571 109.71428572-109.71428571h181.94285714c60.34285714 0 109.71428571 49.37142857 109.71428571 109.71428571v65.82857143c0 60.34285714-49.37142857 109.71428571-109.71428571 109.71428572z m476.34285714 0H659.2c-60.34285714 0-109.71428571-49.37142857-109.71428571-109.71428572V543.08571429c0-60.34285714 49.37142857-109.71428571 109.71428571-109.71428572H841.14285714c60.34285714 0 109.71428571 49.37142857 109.71428572 109.71428572V841.14285714c0 60.34285714-49.37142857 109.71428571-109.71428572 109.71428572z" p-id="4553"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
1
src/icons/svg/icon-approve.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441250987" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4692" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M825.42250667 584.80298667H628.39239111l-29.53557333-99.30865778c74.05568-33.86026667 125.62545778-108.54172445 125.62545777-195.44291556 0-118.69297778-95.98862222-214.90005333-214.37553777-214.90005333-118.40170667 0-214.37553778 96.22186667-214.37553778 214.90005333 0 86.91484445 51.56977778 161.59744 125.62545778 195.44291556l-29.53557333 99.30865778h-197.02897778a70.59000889 70.59000889 0 0 0-70.59000889 70.59000888v131.0572089c0 17.31697778 14.03904 31.34122667 31.34008889 31.34122666h709.05628444a31.36967111 31.36967111 0 0 0 31.36967111-31.37080889V655.36341333a70.54563555 70.54563555 0 0 0-70.54563555-70.56042666z m48.71509333 291.24266666h-728.07537778a21.84533333 21.84533333 0 0 0-21.84533333 21.84533334v29.12711111a21.84533333 21.84533333 0 0 0 21.84533333 21.84533333h728.09016889a21.84533333 21.84533333 0 0 0 21.84533334-21.84533333v-29.12711111a21.84533333 21.84533333 0 0 0-21.86012445-21.84533334z" p-id="4693"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
src/icons/svg/icon-auth.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441301181" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8337" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M864.35351563 176.78515625c-22.93945313 3.95507813-46.40625 6.06445313-70.48828126 6.06445313-101.42578125 0-194.32617188-36.82617188-265.95703124-97.73437501-9.31640625-7.91015625-23.02734375-7.91015625-32.34375001 0-71.63085938 60.99609375-164.53125 97.734375-265.95703124 97.734375-23.73046875 0-47.02148438-2.02148438-69.60937501-5.88867187-15.1171875-2.54882813-28.91601563 9.140625-29.00390625 24.52148437-0.17578125 95.88867188-0.3515625 209.26757813-0.3515625 213.13476563 0 413.96484375 346.72851563 520.92773438 378.80859376 529.98046875 1.58203125 0.43945313 3.1640625 0.43945313 4.74609374 0C546.18945313 935.6328125 890.80859375 829.28515625 893.00585938 418.57226562l0.35156249-217.08984374c0-15.46875-13.88671875-27.33398438-29.00390625-24.69726563zM541.8828125 562.00976563v135.79101562c0 16.5234375-13.359375 29.8828125-29.8828125 29.8828125s-29.8828125-13.359375-29.8828125-29.8828125V562.00976563c-59.94140625-13.62304688-104.67773438-67.1484375-104.67773438-131.22070313 0-74.26757813 60.20507813-134.56054688 134.56054688-134.56054688S646.56054688 356.43359375 646.56054688 430.7890625c0 64.07226563-44.73632813 117.68554688-104.67773438 131.22070313z" p-id="8338"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
1
src/icons/svg/icon-ban.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441322440" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10017" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M509.27 62.598c-248.668 0-450.254 199.753-450.254 446.161s201.586 446.162 450.255 446.162 450.255-199.754 450.255-446.162S757.939 62.598 509.27 62.598z m0 148.72c55.666 0 107.78 15.033 152.468 41.2L250.676 659.842c-26.404-44.281-41.575-95.922-41.575-151.084 0-164.27 134.386-297.441 300.17-297.441z m0 594.883c-55.666 0-107.78-15.033-152.469-41.198l411.062-407.326C794.27 401.96 809.44 453.6 809.44 508.76c0 164.277-134.394 297.442-300.17 297.442z" p-id="10018"></path></svg>
|
After Width: | Height: | Size: 853 B |
1
src/icons/svg/icon-camera.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441302655" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8477" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M284.22599111 249.97250845c11.41782755-31.32742163 22.64147437-62.24099555 33.94279348-93.11573334 5.90309452-16.13035141 16.45317689-23.63907792 33.554432-23.65121422 106.48871822-0.05218608 212.97743645-0.05218608 319.46615466 0 17.70928355 0.0121363 28.54456889 7.85703822 34.61635793 24.69979022 10.16172089 28.2338797 20.42781392 56.42892325 30.26549571 84.76596148 1.99399348 5.76109985 4.88121837 7.46989037 10.84863526 7.43105423 45.03779555-0.25971675 90.06102755-0.1432083 135.09760948-0.1432083 46.33152475 0 84.05477452 36.93317689 84.11909689 83.25256533 0.19418075 158.4126483 0.44054755 316.81194667-0.12864474 475.22459497-0.19418075 53.15333689-45.21862637 83.49771852-83.951616 83.43339615-247.67025303-0.46603378-495.35506963-0.23301689-743.02532267-0.23301689-43.83387497 0-81.34959408-37.54241897-81.36173036-81.46610253-0.02669985-159.4612243-0.01334992-318.93458489 0-478.39580918 0-44.29990875 37.55455525-81.7767917 81.90543643-81.80227792 47.92380682-0.0121363 95.85974992 0 144.65130193 0z m395.04129897 308.73524147c0.75123675-92.05502103-75.58849422-164.60094578-163.6555283-166.58280295-93.00043852-2.09593837-171.21522725 72.74131911-171.65577481 165.14465185-0.42719763 88.27456475 69.05067141 167.64351525 167.87531851 167.43598459 100.13293985-0.21966697 167.90201837-80.54617125 167.4359846-165.99904711z" p-id="8478"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
1
src/icons/svg/icon-card.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441255776" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4972" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M891.733 170.667H132.267c-38.4 0-68.267 29.866-68.267 68.266v102.4h896v-102.4c0-38.4-29.867-68.266-68.267-68.266z m0 704c38.4 0 68.267-29.867 68.267-68.267V426.667H64V806.4c0 38.4 29.867 68.267 68.267 68.267h759.466zM192 554.667h253.867c19.2 0 32 12.8 32 32s-12.8 32-32 32H187.733c-17.066-2.134-27.733-14.934-27.733-32 0-19.2 12.8-32 32-32z m0 128h128c19.2 0 32 12.8 32 32s-12.8 32-32 32H187.733c-17.066-2.134-27.733-14.934-27.733-32 0-19.2 12.8-32 32-32z" p-id="4973"></path></svg>
|
After Width: | Height: | Size: 859 B |
1
src/icons/svg/icon-cart.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441257585" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5112" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M259.2 896a64 64 0 1 0 128 0 64 64 0 1 0-128 0zM768 896a64 64 0 1 0 128 0 64 64 0 1 0-128 0zM940.8 284.8c-16-19.2-38.4-28.8-64-28.8H249.6l-22.4-112c-6.4-44.8-44.8-80-92.8-80H96c-19.2 0-32 16-32 32s12.8 32 32 32h38.4c12.8 0 25.6 9.6 28.8 25.6L192 310.4l51.2 371.2c6.4 48 44.8 86.4 89.6 86.4h486.4c44.8 0 83.2-32 89.6-73.6L960 355.2c3.2-25.6-3.2-51.2-19.2-70.4z" p-id="5113"></path></svg>
|
After Width: | Height: | Size: 763 B |
1
src/icons/svg/icon-command.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441314533" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9317" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M478.176 454.848c-17.12 0-33.184 6.656-45.248 18.72-24.928 24.96-24.928 65.568 0 90.592 24.128 24.096 66.304 24.064 90.496-0.032 12.096-12.096 18.752-28.16 18.752-45.28s-6.656-33.184-18.752-45.28c-12.064-12.096-28.096-18.72-45.248-18.72zM512 63.968c-247.04 0-448 172.256-448 384 0 116.48 63.008 226.048 170.592 298.944l87.328 71.52c-3.904 19.328-17.408 60.096-32.64 97.536-4.928 12.096-1.984 25.984 7.36 35.072a32.049 32.049 0 0 0 22.272 8.992c4.384 0 8.8-0.896 12.992-2.752 36.416-16.224 147.488-68.96 187.584-125.376C763.104 828.448 960 657.568 960 447.968c0-211.744-200.96-384-448-384z m214.624 334.656c12.512 12.512 12.512 32.736 0 45.248-6.24 6.24-14.432 9.376-22.624 9.376s-16.384-3.136-22.624-9.376l-39.84-39.84-52.288 52.288c10.688 18.944 16.896 40.128 16.928 62.496 0.032 34.24-13.312 66.4-37.504 90.592-24.16 24.16-56.288 37.472-90.496 37.472-34.176 0-66.336-13.312-90.496-37.472-49.888-49.984-49.888-131.2 0-181.056 24.16-24.16 56.288-37.472 90.496-37.472 24.032 0 46.912 6.912 66.848 19.2l136.352-136.352c12.512-12.512 32.736-12.512 45.248 0s12.512 32.736 0 45.248l-39.84 39.84 39.84 39.808z" p-id="9318"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
1
src/icons/svg/icon-common.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441297938" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8056" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 65.984C266.08 65.984 65.984 266.08 65.984 512c0 245.952 200.064 446.016 446.016 446.016 245.952 0 446.016-200.064 446.016-446.016 0-245.92-200.064-446.016-446.016-446.016zM512 672c-88.224 0-160-71.776-160-160s71.776-160 160-160 160 71.776 160 160-71.776 160-160 160z" p-id="8057"></path></svg>
|
After Width: | Height: | Size: 675 B |
1
src/icons/svg/icon-count.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441329307" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10578" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M517.46416016 442.25V126.28583984A64.28583984 64.28583984 0 0 1 592.35839844 62.96416016a450 450 0 0 1 368.67832031 368.67832031 64.28583984 64.28583984 0 0 1-63.32167969 74.89335937H581.75a64.28583984 64.28583984 0 0 1-64.28583984-64.28583984z m-21.53583985 117.96416016h299.08916016a64.28583984 64.28583984 0 0 1 64.28583984 75.21416015A401.78583984 401.78583984 0 1 1 388.57167969 165.5a64.28583984 64.28583984 0 0 1 75.21416015 64.28583984v298.28583985a32.14248047 32.14248047 0 0 0 32.14248047 32.14248047z" p-id="10579"></path></svg>
|
After Width: | Height: | Size: 917 B |
1
src/icons/svg/icon-crown.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441339081" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11278" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M960.14 330.74c0-57.69-46.92-104.61-104.64-104.61S750.86 273.05 750.86 330.74c0 49.41 34.5 90.69 80.64 101.61-41.46 82.65-96.24 159.48-125.58 159.48-28.56 0-86.13-83.31-144.36-242.94 41.88-18.42 70.41-59.97 70.41-107.94 0-65.28-53.13-118.38-118.41-118.38-65.31 0-118.44 53.13-118.44 118.38 0 48.09 28.65 89.7 70.65 108.03C403.79 520.7 349.85 583.97 327.71 583.97c-41.13 0-98.25-79.98-135.42-151.65 46.17-10.89 80.73-52.2 80.73-101.64 0-57.69-46.95-104.61-104.64-104.61S63.74 273.05 63.74 330.74c0 39.54 22.32 73.62 54.78 91.41L139.25 839.81a29.955 29.955 0 0 0 13.86 23.82c4.35 2.79 109.41 67.65 360.45 67.65s356.1-65.1 360.45-67.86a30.1209375 30.1209375 0 0 0 13.86-24l18.48-417.81c31.92-17.88 53.79-51.69 53.79-90.87z" p-id="11279"></path></svg>
|
After Width: | Height: | Size: 1.1 KiB |
1
src/icons/svg/icon-dept.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441317794" class="icon" viewBox="0 0 1096 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9597" xmlns:xlink="http://www.w3.org/1999/xlink" width="137" height="128"><defs><style type="text/css"></style></defs><path d="M415.24 190.419A128.774 128.774 0 1 0 544.014 62 128.774 128.774 0 0 0 415.24 190.419zM254.806 544.014h578.417a32.016 32.016 0 0 1 32.016 32.016v32.015a32.016 32.016 0 0 0 32.015 32.372 32.016 32.016 0 0 0 32.016-32.372v-96.402a32.016 32.016 0 0 0-32.016-32.016H608.046a32.016 32.016 0 0 1-32.016-32.016V415.24a32.016 32.016 0 0 0-32.016-32.016 32.371 32.371 0 0 0-32.371 32.016v32.371a32.016 32.016 0 0 1-32.016 32.016H190.42a32.016 32.016 0 0 0-32.016 32.016v96.402a32.016 32.016 0 0 0 32.016 32.372 32.371 32.371 0 0 0 32.371-32.372V576.03a32.016 32.016 0 0 1 32.016-32.016zM62 833.223A128.774 128.774 0 1 0 190.42 704.448 128.419 128.419 0 0 0 62 833.223z m706.836 0a128.419 128.419 0 1 0 128.418-128.775 128.419 128.419 0 0 0-128.418 128.775z m-353.596 0a128.774 128.774 0 1 0 128.774-128.775A128.774 128.774 0 0 0 415.24 833.223z" p-id="9598"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/icons/svg/icon-discover.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441331528" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10718" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M928.768 87.232c-0.032-7.456-1.216-13.696-2.848-19.328-31.328-8.288-72.128 1.248-106.624 17.984-7.072 3.424-23.84 13.632-48.672 28.736-10.272 6.272-19.328 11.776-23.328 14.048-0.384 0.224-0.608 0.64-0.96 0.864C678.56 88.256 599.296 64 514.272 64c-247.04 0-448 200.96-448 448 0 82.816 22.976 160.192 62.304 226.784C82.112 810.4 59.072 862.112 65.088 897.152c1.248 7.168 13.6 8.32 20.384 8.32 138.432 0 454.848-303.776 494.208-342.496C753.504 392 928.864 182.976 928.768 87.232zM306.272 610.688c-44.096 0-80-35.872-80-80 0-44.096 35.904-80 80-80s80 35.904 80 80c0 44.128-35.904 80-80 80z m140.8-224c-52.928 0-96-43.072-96-96s43.072-96 96-96 96 43.072 96 96-43.072 96-96 96zM895.904 278.56C828.8 378.208 723.296 497.856 618.048 601.344c-28.64 28.192-202.272 196.448-348.096 286.112 0.128-0.096 0.224-0.16 0.352-0.224C340.576 933.088 424.288 960 514.272 960c247.04 0 448-200.96 448-448-0.032-85.6-24.544-165.344-66.368-233.44zM640.032 800c-35.296 0-64-28.704-64-64s28.704-64 64-64 64 28.704 64 64-28.704 64-64 64z" p-id="10719"></path></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
src/icons/svg/icon-emoji.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441239241" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4412" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 960.00035C264.5696 960.00035 63.99965 759.4304 63.99965 512S264.5696 63.99965 512 63.99965 960.00035 264.5696 960.00035 512 759.4304 960.00035 512 960.00035z m-179.20035-403.2a179.20035 179.20035 0 1 0 358.4007 0H332.79965z m0-89.6007a67.2 67.2 0 1 0 0-134.4 67.2 67.2 0 0 0 0 134.4z m358.4007 0a67.2 67.2 0 1 0 0-134.4 67.2 67.2 0 0 0 0 134.4z" p-id="4413"></path></svg>
|
After Width: | Height: | Size: 753 B |
1
src/icons/svg/icon-favor.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441342980" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11558" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M957.216 404.32c-3.808-11.36-13.632-19.68-25.504-21.504l-270.336-41.728-120.8-258.624C535.328 71.232 524.032 64.032 511.648 64h-0.064a31.968 31.968 0 0 0-28.928 18.336L360.8 340.352l-270.72 40.8a32.014 32.014 0 0 0-25.568 21.408c-3.84 11.36-0.992 23.936 7.36 32.512l196.448 202.08-46.88 284.8a31.997 31.997 0 0 0 13.12 31.328c9.984 7.072 23.168 7.808 33.888 1.92l241.824-133.024 241.312 133.856a32.547 32.547 0 0 0 15.52 3.968h0.64c17.696 0 32-14.304 32-32 0-3.968-0.704-7.776-2.016-11.296l-44.896-278.688L949.76 436.768c8.32-8.544 11.232-21.088 7.456-32.448z" p-id="11559"></path></svg>
|
After Width: | Height: | Size: 965 B |
1
src/icons/svg/icon-goods.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441261013" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5392" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M898.133 341.333c0-10.666-10.666-21.333-21.333-21.333h-128v-8.533C746.667 185.6 646.4 85.333 520.533 85.333h-17.066c-123.734 0-226.134 100.267-226.134 226.134V320h-128C138.667 320 128 328.533 128 341.333l-17.067 518.4v2.134C115.2 917.333 162.133 960 217.6 960h595.2c55.467 0 102.4-42.667 106.667-98.133v-2.134l-21.334-518.4zM320 311.467C320 209.067 403.2 128 503.467 128h17.066C620.8 128 704 211.2 704 311.467V320H320v-8.533z m-21.333 243.2C275.2 554.667 256 535.467 256 512c0-14.933 8.533-29.867 21.333-36.267V384c0-12.8 8.534-21.333 21.334-21.333S320 371.2 320 384v91.733c12.8 6.4 21.333 21.334 21.333 36.267 0 23.467-19.2 42.667-42.666 42.667z m426.666 0c-23.466 0-42.666-19.2-42.666-42.667 0-14.933 8.533-29.867 21.333-36.267V384c0-12.8 8.533-21.333 21.333-21.333S746.667 371.2 746.667 384v91.733C759.467 482.133 768 497.067 768 512c0 23.467-19.2 42.667-42.667 42.667z" p-id="5393"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/icons/svg/icon-home.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441323970" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10157" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M947.2 422.4L572.8 115.2c-32-25.6-86.4-25.6-118.4 0L76.8 425.6c-12.8 6.4-16 22.4-9.6 35.2 3.2 12.8 16 19.2 28.8 19.2h32v364.8c0 48 35.2 83.2 83.2 83.2H416c19.2 0 32-12.8 32-32V748.8c0-22.4 35.2-44.8 64-44.8 28.8 0 67.2 22.4 67.2 44.8V896c0 19.2 12.8 32 32 32h208c48 0 80-32 80-83.2V480h32c12.8 0 25.6-9.6 28.8-22.4 3.2-12.8 0-25.6-12.8-35.2z" p-id="10158"></path></svg>
|
After Width: | Height: | Size: 747 B |
1
src/icons/svg/icon-hot.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441312875" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9177" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M713 221c-12-9-27-6-36 0-9 9-15 24-9 36 6 12 9 27 12 42C599 110 464 68 458 65c-9-3-21 0-27 6-9 6-12 18-9 27 12 81-24 177-108 291-6-24-15-48-30-75-9-9-21-15-33-12-15 3-24 12-24 27-3 45-24 87-48 132C158 500 137 542 128 587c-30 141 93 309 219 357 9 3 18 6 30 9-24-18-39-48-45-90C308 680 506 632 515 464c144 99 210 315 129 474 3 0 6-3 9-3 0 0 3 0 3-3 153-84 237-195 243-324 15-198-153-366-186-387z" p-id="9178"></path></svg>
|
After Width: | Height: | Size: 797 B |
1
src/icons/svg/icon-info.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441311089" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9037" xmlns:xlink="http://www.w3.org/1999/xlink" width="128.125" height="128"><defs><style type="text/css"></style></defs><path d="M512.26455078 82.10585938C263.58681641 82.10585938 62.52910156 258.29667969 62.52910156 475.22744141c0 11.11113281 0.52910156 22.22226562 1.58730469 33.33339843C74.6984375 619.14306641 137.66152344 716.49775391 231.3125 782.10546875v147.61933594c0 22.75136719 24.86777344 36.50800781 43.91542969 24.86777343l152.90947265-92.59277343c27.51328125 4.2328125 55.55566406 6.87832031 84.12714844 6.87832031 235.45019531 0 428.57138672-158.20048828 448.14814453-359.78818359 1.05820312-11.11113281 2.11640625-22.22226562 2.11640625-33.33339844C962 258.29667969 760.41230469 82.10585938 512.26455078 82.10585938zM286.86728516 458.29619141c0-15.34394531 12.6984375-28.04238281 28.04238281-28.04238282h41.26992187c15.34394531 0 28.04238281 12.6984375 28.04238282 28.04238282s-12.6984375 28.04238281-28.04238282 28.04238281h-41.26992187c-15.34394531 0.52910156-28.04150391-12.16933594-28.04150391-28.04238281z m365.60917968 157.67226562H371.52353516c-15.34394531 0-28.04238281-12.6984375-28.04238282-28.04238281s12.6984375-28.04238281 28.04238282-28.04238281h281.48203125c15.34394531 0 28.04238281 12.6984375 28.04238281 28.04238281-0.52910156 15.34394531-12.6984375 28.04238281-28.57148438 28.04238281z m56.61386719-129.10078125H462.52900391c-15.34394531 0-28.04238281-12.6984375-28.04238282-28.04238281s12.6984375-28.04238281 28.04238282-28.04238281h246.03222656c15.34394531 0 28.04238281 12.6984375 28.04238281 28.04238281 0.52822266 15.34394531-12.16933594 28.04238281-27.51328125 28.04238281z" p-id="9038"></path></svg>
|
After Width: | Height: | Size: 1.8 KiB |
1
src/icons/svg/icon-like.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441333584" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10858" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M722 136c-61.83 0-120.54 23.46-165.36 66.06-4.29 4.05-26.88 26.94-44.37 44.7L467.9 202.6C423.05 159.64 364.13 136 302 136 169.67 136 62 243.67 62 376c0 77.28 38.61 135.27 71.7 171.09l297.09 300.12C454.31 870.7 480.41 886 512 886s57.72-15.3 81.33-38.91l296.94-300 2.07-2.31C928.16 500.11 962 457.93 962 376c0-132.33-107.67-240-240-240z" p-id="10859"></path></svg>
|
After Width: | Height: | Size: 740 B |
1
src/icons/svg/icon-living.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441325978" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10297" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M407.467 488.533a106.667 106.667 0 1 0 213.333 0 106.667 106.667 0 1 0-213.333 0z" p-id="10298"></path><path d="M512 64C264.533 64 64 264.533 64 512c0 236.8 183.467 428.8 416 445.867v-134.4c-53.333-59.734-200.533-230.4-200.533-334.934 0-130.133 104.533-234.666 234.666-234.666S748.8 358.4 748.8 488.533c0 61.867-49.067 153.6-145.067 270.934L544 827.733V960c232.533-17.067 416-211.2 416-448 0-247.467-200.533-448-448-448z" p-id="10299"></path></svg>
|
After Width: | Height: | Size: 826 B |
1
src/icons/svg/icon-log.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441337115" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11138" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M871.616 64H152.384c-31.488 0-60.416 25.28-60.416 58.24v779.52c0 32.896 26.24 58.24 60.352 58.24h719.232c34.112 0 60.352-25.344 60.352-58.24V122.24c0.128-32.96-28.8-58.24-60.288-58.24zM286.272 512c-23.616 0-44.672-20.224-44.672-43.008 0-22.784 20.992-43.008 44.608-43.008 23.616 0 44.608 20.224 44.608 43.008A43.328 43.328 0 0 1 286.272 512z m0-202.496c-23.616 0-44.608-20.224-44.608-43.008 0-22.784 20.992-43.008 44.608-43.008 23.616 0 44.608 20.224 44.608 43.008a43.456 43.456 0 0 1-44.608 43.008zM737.728 512H435.904c-23.68 0-44.672-20.224-44.672-43.008 0-22.784 20.992-43.008 44.608-43.008h299.264c23.616 0 44.608 20.224 44.608 43.008A42.752 42.752 0 0 1 737.728 512z m0-202.496H435.904c-23.616 0-44.608-20.224-44.608-43.008 0-22.784 20.992-43.008 44.608-43.008h299.264c23.616 0 44.608 20.224 44.608 43.008a42.88 42.88 0 0 1-42.048 43.008z" p-id="11139"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/icons/svg/icon-menu.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441316068" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9457" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M910.93333334 214.1088H116.55786667a37.23733333 37.23733333 0 0 1 0-74.47253333H910.93333334a37.23733333 37.23733333 0 0 1 0 74.47253333z m0 695.07946667H116.55786667a37.23733333 37.23733333 0 0 1 0-74.4736H910.93333334a37.23733333 37.23733333 0 0 1 0 74.4736zM712.33920001 561.648H116.55786667a37.23733333 37.23733333 0 0 1 0-74.47253333h595.78133334a37.23733333 37.23733333 0 0 1 0 74.47253333z" p-id="9458"></path></svg>
|
After Width: | Height: | Size: 800 B |
1
src/icons/svg/icon-message.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441267509" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5815" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 67.168c-247.04 0-448 172.256-448 384 0 116.512 63.04 226.048 174.048 301.408l84.16 52.032c-3.68 23.552-18.752 74.496-33.44 115.936-4.256 12.064-0.928 25.504 8.448 34.176a32.006 32.006 0 0 0 21.728 8.512c4.416 0 8.832-0.896 13.024-2.752 36.416-16.224 147.456-68.96 187.584-125.376C763.136 831.616 960 660.704 960 451.168c0-211.744-200.96-384-448-384z m68.224 476.8H384.96c-17.664 0-32-14.336-32-32s14.336-32 32-32h195.264c17.696 0 32 14.336 32 32s-14.304 32-32 32z m60.704-128H384.96c-17.664 0-32-14.336-32-32s14.336-32 32-32h255.968c17.696 0 32 14.336 32 32s-14.304 32-32 32z" p-id="5816"></path></svg>
|
After Width: | Height: | Size: 984 B |
1
src/icons/svg/icon-monitor.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441278876" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6655" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 133.12c208.896 0 378.88 169.984 378.88 378.88S720.896 890.88 512 890.88 133.12 720.896 133.12 512 303.104 133.12 512 133.12m0-71.68C262.144 61.44 61.44 262.144 61.44 512S264.192 962.56 512 962.56 962.56 759.808 962.56 512 761.856 61.44 512 61.44z" p-id="6656"></path><path d="M602.112 784.384h-2.048c-14.336-2.048-24.576-12.288-28.672-24.576l-67.584-356.352-36.864 129.024c-4.096 12.288-16.384 20.48-28.672 20.48h-36.864l-36.864 92.16c-4.096 12.288-16.384 20.48-28.672 20.48s-24.576-8.192-28.672-20.48l-45.056-135.168-14.336 28.672c-4.096 10.24-16.384 18.432-28.672 18.432H184.32c-16.384 0-30.72-14.336-30.72-30.72s14.336-34.816 30.72-34.816h16.384l38.912-81.92c6.144-12.288 16.384-18.432 30.72-18.432 12.288 0 22.528 8.192 26.624 20.48l40.96 126.976 12.288-30.72c4.096-12.288 16.384-20.48 28.672-20.48h34.816l67.584-229.376c4.096-14.336 16.384-22.528 30.72-22.528s26.624 10.24 28.672 24.576l71.68 374.784 92.16-260.096c4.096-12.288 16.384-20.48 28.672-20.48s24.576 8.192 28.672 20.48l40.96 116.736h36.864c16.384 0 30.72 12.288 30.72 30.72 0 16.384-12.288 30.72-30.72 30.72h-59.392c-14.336 0-24.576-8.192-28.672-20.48l-20.48-55.296-100.352 286.72c-4.096 12.288-16.384 20.48-28.672 20.48z" p-id="6657"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
src/icons/svg/icon-new.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441271889" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6095" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 63.68c-247.04 0-448 172.256-448 384 0 116.48 63.008 226.048 170.592 298.944l87.328 71.52c-3.904 19.328-17.408 60.096-32.64 97.536-4.928 12.096-1.984 25.984 7.36 35.072a32.049 32.049 0 0 0 22.272 8.992c4.384 0 8.8-0.896 12.992-2.752 36.416-16.224 147.488-68.96 187.616-125.376C763.136 828.16 960 657.248 960 447.68c0-211.712-200.96-384-448-384z m219.136 342.88l-128.8 188.864c-5.984 8.736-15.872 13.984-26.432 13.984h-0.448c-10.72-0.16-20.672-5.664-26.464-14.688l-91.584-142.208L385.824 592c-5.664 11.072-16.864 17.408-28.512 17.408-4.896 0-9.92-1.12-14.592-3.52-15.712-8.064-21.92-27.328-13.856-43.072L425.76 373.92a31.925 31.925 0 0 1 26.912-17.344c11.52-0.416 22.272 5.024 28.48 14.656l95.456 148.288L678.24 370.528c9.984-14.592 29.856-18.336 44.48-8.416 14.592 9.92 18.368 29.856 8.416 44.448z" p-id="6096"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/icons/svg/icon-news.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441270012" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5955" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M867.2 160H160c-54.4 0-96 44.8-96 96v512c0 54.4 41.6 96 96 96h707.2c54.4 0 96-41.6 96-96V256c0-51.2-41.6-96-96-96z m-672 163.2c0-19.2 12.8-32 32-32H416c19.2 0 32 12.8 32 32V512c0 19.2-12.8 32-32 32H227.2c-19.2 0-32-12.8-32-32V323.2zM800 736H224c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM512 448c0-19.2 12.8-32 32-32h128c19.2 0 32 12.8 32 32s-12.8 32-32 32H544c-19.2 0-32-12.8-32-32z m288-96H544c-19.2 0-32-12.8-32-32s12.8-32 32-32h256c19.2 0 32 12.8 32 32s-12.8 32-32 32z" p-id="5956"></path></svg>
|
After Width: | Height: | Size: 910 B |
1
src/icons/svg/icon-pending.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441252941" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4832" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M736 96c31.04 0 51.712 25.856 51.712 62.08v304.96c-129.28 0-232.64 103.36-227.456 232.576 0 113.728 77.504 206.784 180.928 227.456H115.712c-31.04 0-51.712-25.856-51.712-67.2V158.08c0-36.16 20.672-62.016 51.712-62.016z m43.072 413.568l10.88 0.32C883.328 515.392 960 591.872 960 687.808c0 99.648-82.688 183.552-180.928 183.552h-5.12a179.2 179.2 0 0 1-124.16-52.416c-10.24-10.496-15.424-15.744-20.608-26.24a5.888 5.888 0 0 0-0.832-3.072l-3.52-4.288-0.832-3.136a16 16 0 0 1-3.072-4.736l-4.224-11.52-3.072-4.672c0-5.248-5.12-10.496-5.12-15.744l-1.344-5.248c-1.536-3.52-3.84-7.04-3.84-10.496-5.12-10.496-5.12-26.24-5.12-36.736 0-26.24 5.12-47.168 15.424-68.16v-5.248c0-5.248 5.184-15.744 10.368-20.928 0-1.344 0.32-2.304 0.832-3.2l3.52-4.224 0.832-3.072c30.976-47.232 82.688-78.72 149.888-78.72z m0 52.416c-15.488 0-25.856 10.496-25.856 26.24v125.824c0 15.744 10.368 26.24 25.856 26.24H892.8c10.368 0 25.856-10.496 25.856-26.24 0-15.744-10.368-26.24-25.856-26.24h-87.872v-99.584c0-15.744-10.368-26.24-25.856-26.24zM394.88 468.16H198.4a40.768 40.768 0 0 0-41.344 41.408c0 20.672 15.488 41.344 36.16 41.344h196.48c25.792 0 46.464-15.552 46.464-41.344a40.768 40.768 0 0 0-41.344-41.408z m165.44-206.72H198.4a40.768 40.768 0 0 0-41.344 41.344c0 20.672 15.488 41.344 36.16 41.344h361.856a40.768 40.768 0 0 0 41.344-41.344c0-25.856-15.488-41.344-36.16-41.344z" p-id="4833"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
1
src/icons/svg/icon-pic.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441277399" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6515" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M842.688 128H181.312C116.64 128 64 180.64 64 245.312v533.376C64 843.36 116.64 896 181.312 896h661.376C907.36 896 960 843.36 960 778.688V245.312C960 180.64 907.36 128 842.688 128zM288 288c35.36 0 64 28.64 64 64s-28.64 64-64 64c-35.328 0-64-28.64-64-64s28.672-64 64-64z m544 448c0 17.696-14.304 31.488-32 31.488L225.92 768h-0.352c-10.08 0-19.616-4.288-25.664-12.384-6.112-8.192-7.936-18.56-4.896-28.352 2.304-7.488 58.272-183.552 180.064-183.552 38.08 0.896 67.424 9.824 95.776 18.336 35.712 10.72 70.528 19.936 109.664 13.76 20.448-3.296 28.896-23.808 43.328-69.952 19.04-60.8 47.808-152.736 174.656-152.736 17.536 0 31.776 14.08 32 31.616L832 511.616V736z" p-id="6516"></path></svg>
|
After Width: | Height: | Size: 1.0 KiB |
1
src/icons/svg/icon-question.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441273689" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6235" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 64C264.96 64 64 264.96 64 512s200.96 448 448 448 448-200.96 448-448S759.04 64 512 64z m0 768.352c-26.496 0-48-21.504-48-48s21.504-48 48-48 48 21.504 48 48-21.504 48-48 48z m88.576-327.168C572.736 532.992 544 561.728 544 587.552v54.112c0 17.664-14.336 32-32 32s-32-14.336-32-32v-54.112c0-52.352 40-92.352 75.328-127.648C581.216 434.016 608 407.264 608 385.92c0-53.344-43.072-96.736-96-96.736-53.824 0-96 41.536-96 94.56 0 17.664-14.336 32-32 32s-32-14.336-32-32c0-87.424 71.776-158.56 160-158.56S672 297.28 672 385.92c0 47.872-36.32 84.16-71.424 119.264z" p-id="6236"></path></svg>
|
After Width: | Height: | Size: 962 B |
1
src/icons/svg/icon-rank.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441308883" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8897" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M228.255 913.307H66.103V672.523h162.152v240.784z m243.21 0H309.319V351.483h162.146v561.824z m243.216 0h-162.14v-321.04h162.14v321.04z m243.215 0H795.744V110.693h162.152v802.614z" p-id="8898"></path></svg>
|
After Width: | Height: | Size: 581 B |
1
src/icons/svg/icon-scan.svg
Normal file
After Width: | Height: | Size: 5.9 KiB |
1
src/icons/svg/icon-search.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441284945" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7076" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M699.498496 793.02322252c-102.60024889 65.24472889-212.6764563 85.28175408-330.3135763 55.12305778-99.9424-25.61972148-178.67055408-82.76954075-236.59709629-167.90565927-113.18309925-166.34007703-85.29389037-393.90776889 64.40732444-529.93137778 150.44152889-136.70324148 376.79559111-142.24952889 534.40967112-13.84751407 156.78881185 127.72238222 206.19567408 369.53808592 71.21578666 557.56572445 2.20880592 2.34230518 4.50256592 4.86665482 6.90555259 7.26964148 42.9382163 42.96248889 85.96138667 85.8400237 128.81464889 128.87533037 26.06876445 26.19012741 31.72427852 59.41930667 15.44950519 88.61923555-22.9497363 41.19058963-78.49756445 49.23695408-112.20005927 15.83786667-45.21984-44.79506963-90.06345482-89.96636445-135.08911406-134.96775111-2.24521482-2.23307852-4.5996563-4.35693037-7.00264297-6.63855407z m-227.22787555-639.58281482c-165.40558222 0-300.19128889 134.48229925-300.02138075 299.34174815 0.16990815 164.58031408 134.87066075 299.30533925 299.32961185 299.41456593 165.33276445 0.10922667 300.08206222-134.16675555 300.21556148-299.1597037 0.15777185-165.29635555-134.11821037-299.59661037-299.52379258-299.59661038z" p-id="7077"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
1
src/icons/svg/icon-system.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441320870" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9877" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M956.17988281 446.79003906c-3.50683594-19.66376953-22.35234375-39.46289063-41.85175781-43.92597656l-14.45800781-3.34248047c-34.29140625-10.35351563-64.74550781-33.27539063-84.08232422-66.74589844-19.49941406-33.71132813-23.93789063-72-15.49863281-107.05693359l4.27148437-13.72060547c5.86230469-19.08984375-1.75253906-45.38144531-16.92421875-58.31103515 0 0-13.74873047-11.61035156-52.47949219-34.01367188-38.72460938-22.37519531-55.53896484-28.48535156-55.53896484-28.48535156-18.78925781-6.79130859-45.30146484-0.32607422-58.88408203 14.35253906l-10.19003906 10.95380859c-26.07363281 24.64892578-61.21142578 39.740625-99.83056641 39.740625-38.80546875 0-74.05488281-15.20068359-100.15488281-40.01396484l-9.83320313-10.62773437C387.1953125 90.94199219 360.65498047 84.44951172 341.86748047 91.24433594c0 0-16.81523438 6.07851562-55.62597656 28.48095703-38.66923828 22.40419922-52.33623047 33.9609375-52.33623047 33.9609375-15.22792969 12.92871094-22.86914063 39.11132813-16.95410156 58.28291016l4.24423828 13.85947265c8.32763672 35.02792969 3.83554687 73.23574219-15.49863282 106.92246094-19.39130859 33.60585937-50.146875 56.58398438-84.57539062 66.82324219l-14.1328125 3.23261718c-19.41503906 4.43847656-38.28955078 24.26572266-41.79550781 43.90136719 0 0-3.17548828 17.66601563-3.17548829 62.49902344 0 44.83564453 3.17548828 62.41992188 3.17548829 62.41992187 3.53320313 19.71826172 22.37871094 39.49189453 41.7946289 44.03759766l13.80761719 3.06914063c34.56298828 10.29550781 65.39941406 33.35712891 84.90234375 67.09921875 19.41503906 33.68671875 23.85351563 71.97539063 15.44414062 107.03320312l-4.18974609 13.69335938c-5.91503906 19.06083984 1.72529297 45.3515625 17.00683594 58.27939453 0 0 13.66699219 11.61298828 52.42148437 34.01542968 38.75361328 22.4578125 55.51611328 28.48623047 55.51611328 28.48623047 18.815625 6.79130859 45.27158203 0.27421875 58.85771485-14.29980468l9.72246094-10.45986329c26.10087891-24.92226562 61.37402344-40.09394531 100.23662109-40.09394531 38.83886719 0 74.16914062 15.28154297 100.37988281 40.09394531h0.02460938l9.61523437 10.46074219c13.58261719 14.57226563 39.98408203 21.09023438 58.82519531 14.29980469 0 0 16.7625-6.13476563 55.65410157-28.48710938 38.67363281-22.40332031 52.36523438-34.01542969 52.36523437-34.01542968 15.2296875-12.92695313 22.78828125-39.10869141 16.98310547-58.28027344l-4.27236328-14.1328125c-8.21777344-34.94619141-3.7265625-73.07226563 15.49863281-106.59287109 19.55566406-33.79658203 50.34111328-56.75097656 84.84785156-67.09921875v-0.05712891l13.80410157-3.17460938c19.50029297-4.43935547 38.34580078-24.21035156 41.84912109-43.93125 0 0 3.17636719-17.63789062 3.17636719-62.49902343-0.10898438-44.64316406-3.28447266-62.28105469-3.28447266-62.28105469z m-445.49121093 207.05449219c-79.61923828 0-144.20039063-64.74462891-144.20039063-144.60820312 0-79.75371094 64.58027344-144.44208984 144.20039063-144.44208985 79.61484375 0 144.11425781 64.71650391 144.11425781 144.55195313 0 79.86357422-64.49941406 144.49833984-144.11425781 144.49833984z" p-id="9878"></path></svg>
|
After Width: | Height: | Size: 3.3 KiB |
1
src/icons/svg/icon-tag.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441259332" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5252" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M926.54933333 370.9952L645.9392 97.8944c-38.87786667-37.6832-112.81066667-37.75146667-151.79093333 0.1024l-348.84266667 341.23093333c-60.17706667 58.368-75.43466667 81.8176-75.43466667 161.04106667v153.53173333c0 141.6192 28.7744 204.8 199.3728 204.8h140.66346667c86.528 0 137.0112-49.7664 206.88213333-118.6816l309.3504-317.5424c19.83146667-19.18293333 31.19786667-46.8992 31.19786667-76.01493333 0-28.91093333-11.22986667-56.38826667-30.78826667-75.3664zM310.40853333 805.0688c-56.45653333 0-102.4-45.94346667-102.4-102.4s45.94346667-102.4 102.4-102.4 102.4 45.94346667 102.4 102.4-45.94346667 102.4-102.4 102.4z" p-id="5253"></path></svg>
|
After Width: | Height: | Size: 1018 B |
1
src/icons/svg/icon-task.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441304345" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8617" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M672 491.968c-83.648 68.288-160 142.208-160 142.208L373.504 467.2l-67.2 67.2s59.392 68.352 112 134.4C471.104 735.104 512 797.12 512 797.12s108.416-123.968 216.448-224.448c60.736-56.448 135.104-121.728 190.784-169.984v458.88c0 54.336-44.096 98.432-98.432 98.432H203.136c-54.336 0-98.432-44.096-98.432-98.432V310.144c0-12.352 4.8-24.256 13.44-33.088l193.92-198.784C321.024 69.184 333.248 64 345.984 64H820.8c54.336 0 98.432 44.096 98.432 98.432V312.64C861.056 352.128 746.176 431.36 672 491.968z" p-id="8618"></path></svg>
|
After Width: | Height: | Size: 897 B |
12
src/icons/svg/icon-theme.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<svg t="1615283148941" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5045"
|
||||
width="64" height="64">
|
||||
<path
|
||||
d="M552.75 563.239c44.4 26.348 99.1 26.348 143.5 0C740.65 536.89 768 488.197 768 435.5c0-81.462-64.247-147.5-143.5-147.5S481 354.038 481 435.5c0 52.697 27.35 101.39 71.75 127.739z"
|
||||
p-id="5046"></path>
|
||||
<path
|
||||
d="M471.264 952c-18.842 0-38.581-1.796-60.115-4.49l-5.384-0.899c-152.533-23.352-256.614-171.55-261.1-177.837-147.149-224.541-73.574-451.777 65.5-577.52C348.34 65.511 578.934 11.621 780.814 174.19c130.102 105.085 169.58 250.588 171.375 256.875v1.797c18.843 102.39 3.59 177.836-45.76 226.337-75.368 72.752-200.086 49.4-217.134 45.807-23.328-2.695-40.376 4.49-52.938 19.76-13.458 17.064-16.15 39.518-11.664 52.991 12.562 37.723 14.356 66.464 5.384 88.02C604.058 922.361 551.12 952 471.264 952z m-51.973-80.488l5.083 0.849c82.179 12.72 132.164-3.393 152.497-49.188 0-0.849 4.236-11.873-6.778-45.796-11.013-30.53-2.541-70.39 19.486-97.528 22.875-28.834 56.763-41.556 96.581-37.315l2.542 0.848c0.847 0 105.9 22.898 160.122-29.683 33.04-32.226 43.207-88.199 28.805-166.221-3.39-11.025-39.819-130.603-144.872-214.562-166.053-135.69-356.674-90.743-471.894 13.57-105.9 96.68-183.843 280.71-53.374 480.007 0.848 0 89.804 127.21 211.802 145.02z"
|
||||
p-id="5047"></path>
|
||||
<path
|
||||
d="M203 529c0-29.823 24.177-54 54-54s54 24.177 54 54-24.177 54-54 54-54-24.177-54-54z m90-115.235A54 54 0 0 1 266 367c0-29.823 24.177-54 54-54s54 24.177 54 54a54 54 0 0 1-81 46.765zM427 278c0-29.823 24.177-54 54-54s54 24.177 54 54-24.177 54-54 54-54-24.177-54-54z m180 44c0-29.823 24.177-54 54-54s54 24.177 54 54-24.177 54-54 54-54-24.177-54-54z m90 144c0-29.823 24.177-54 54-54s54 24.177 54 54-24.177 54-54 54-54-24.177-54-54z"
|
||||
p-id="5048"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
1
src/icons/svg/icon-time.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441281314" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6796" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 64C264.96 64 64 264.96 64 512s200.96 448 448 448 448-200.96 448-448S759.04 64 512 64z m159.264 512H480.16c-17.664 0-32.16-14.464-32.16-32.16V289.088c0-17.664 14.336-32 32-32s32 14.336 32 32V512h159.264c17.696 0 32 14.336 32 32 0 17.696-14.336 32-32 32z" p-id="6797"></path></svg>
|
After Width: | Height: | Size: 661 B |
1
src/icons/svg/icon-user.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441265116" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5675" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512.13653333 899.75239111H98.48604445c-17.72657778 0-23.19928889-5.24515555-22.96035556-22.8352 0.32995555-25.14488889-0.9216-50.49457778 1.8432-75.38915556 9.92142222-89.15626667 78.21084445-161.57582222 164.27235556-174.54648888 11.42328889-1.71804445 23.08551111-2.63964445 34.64533333-2.65102222 157.16124445-0.17066667 314.31111111-0.11377778 471.47235555-0.11377778 100.16995555 0 183.10257778 69.95057778 197.56373334 169.19893333 4.33493333 29.7984 2.62826667 60.49564445 3.16302222 90.79466667 0.14791111 8.23751111-6.98595555 14.57493333-15.29173334 15.37137778-2.93546667 0.28444445-5.92782222 0.17066667-8.88604444 0.17066666H512.13653333z m201.18186667-560.44657778c0 121.05955555-97.60995555 218.30542222-219.63662222 217.69102222-123.0848-0.6144-218.16888889-102.33173333-216.73528889-220.88817777 1.39946667-115.87128889 97.05244445-217.30417778 222.50382222-215.08551111 121.32124445 2.1504 215.26755555 102.68444445 213.86808889 218.28266666z" p-id="5676"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
src/icons/svg/icon-video.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441283344" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6936" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 64C265.6 64 64 265.6 64 512s201.6 448 448 448 448-201.6 448-448S758.4 64 512 64z m179.2 480l-256 156.8c-6.4 3.2-12.8 3.2-19.2 3.2-6.4 0-9.6 0-16-3.2-9.6-6.4-16-16-16-28.8V352c0-12.8 6.4-22.4 16-28.8 9.6-6.4 22.4-6.4 32 0l256 166.4c9.6 6.4 16 16 16 28.8 0 9.6-3.2 22.4-12.8 25.6z" p-id="6937"></path></svg>
|
After Width: | Height: | Size: 687 B |
1
src/icons/svg/icon-wallet.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441288344" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7356" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M677 339.66666667c36-36 75-90 75-147 0-33-9-60-30-81C683 72.66666667 614 72.66666667 536 72.66666667h-57c-75 0-135 0-174 36-21 21-30 48-30 84 0 60 39 111 72 147C215 408.66666667 125 546.66666667 125 687.66666667c0 261 264 261 390 261s390 0 390-261c0-144-93-279-228-348z m-72 246c18 0 30 12 30 30s-12 30-30 30h-60v30h60c18 0 30 12 30 30s-12 30-30 30h-60v63c0 18-12 30-30 30s-30-12-30-30v-63h-60c-18 0-30-12-30-30s12-30 30-30h60v-30h-60c-18 0-30-12-30-30s12-30 30-30h60V567.66666667l-84-81c-12-12-12-30 0-42 12-12 30-12 42 0l75 72 75-72c12-12 30-12 42 0 12 12 12 30 0 42l-90 87v12h60z" p-id="7357"></path></svg>
|
After Width: | Height: | Size: 986 B |
1
src/icons/svg/icon-warn.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441293293" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7776" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M942.656 769.376L602.112 159.584c-22.144-39.712-55.104-62.496-90.304-62.496-35.232 0-68.16 22.784-90.368 62.528L81.312 769.344C59.296 808.8 57.056 848.8 75.2 879.744 93.344 910.624 129.664 928 174.88 928h674.24c45.184 0 81.536-17.376 99.648-48.256 18.176-30.944 15.904-70.912-6.112-110.368zM480 320c0-17.664 14.336-32 32-32s32 14.336 32 32v288c0 17.696-14.336 32-32 32s-32-14.304-32-32V320z m32 512.128c-26.528 0-48-21.504-48-48s21.472-48 48-48 48 21.504 48 48-21.472 48-48 48z" p-id="7777"></path></svg>
|
After Width: | Height: | Size: 881 B |
1
src/icons/svg/icon-workbench.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1614441286553" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7216" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M897.8 93.32H126.26c-35.52 0-64.26 28.8-64.26 64.32v548.1c0 35.52 28.74 64.2 64.26 64.2h321.42v96.42H287a32.1 32.1 0 0 0-32.1 32.1v32.1h514.2v-32.1a32.04 32.04 0 0 0-32.1-32.1H576.26V770h321.36c35.52 0 64.32-28.74 64.32-64.2V157.7a64.2 64.2 0 0 0-64.14-64.38zM512 737.9a32.1 32.1 0 1 1 0-64.2 32.1 32.1 0 0 1 0 64.2z m360-95.88H152V180.74h720v461.28z" p-id="7217"></path></svg>
|
After Width: | Height: | Size: 754 B |
17
src/main.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import { bootstrap } from "./cool";
|
||||
|
||||
// mock
|
||||
// import "./mock";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
// 启动
|
||||
bootstrap(app)
|
||||
.then(() => {
|
||||
app.mount("#app");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("COOL-ADMIN 启动失败", err);
|
||||
});
|
3
src/mock/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
// @ts-nocheck
|
||||
const xhr = new window._XMLHttpRequest();
|
||||
window.XMLHttpRequest.prototype.upload = xhr.upload;
|
4
src/modules/base/common/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import "./resize";
|
||||
|
||||
export * from "./theme";
|
||||
export * from "./permission";
|
30
src/modules/base/common/permission.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { useBaseStore } from "../store";
|
||||
import { isObject } from "lodash";
|
||||
|
||||
function parse(value: any) {
|
||||
const { menu } = useBaseStore();
|
||||
|
||||
if (typeof value == "string") {
|
||||
return value ? menu.perms.some((e: any) => e.includes(value.replace(/\s/g, ""))) : false;
|
||||
} else {
|
||||
return Boolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkPerm(value: any) {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isObject(value)) {
|
||||
if (value.or) {
|
||||
return value.or.some(parse);
|
||||
}
|
||||
|
||||
if (value.and) {
|
||||
return value.and.some((e: any) => !parse(e)) ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
return parse(value);
|
||||
}
|
13
src/modules/base/common/resize.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { useEventListener } from "@vueuse/core";
|
||||
import { useBaseStore } from "../store";
|
||||
|
||||
function resize() {
|
||||
const { app } = useBaseStore();
|
||||
app.setBrowser();
|
||||
app.isFold = app.browser.isMini;
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
useEventListener(window, "resize", resize);
|
||||
resize();
|
||||
};
|
39
src/modules/base/common/theme.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { config } from "/@/cool";
|
||||
import { basename } from "/@/cool/utils";
|
||||
import { createLink } from "../utils";
|
||||
|
||||
// 主题初始化
|
||||
if (config.app.theme) {
|
||||
const { url, color } = config.app.theme;
|
||||
|
||||
if (url) {
|
||||
createLink(url, "theme-style");
|
||||
}
|
||||
|
||||
document.getElementsByTagName("body")[0].style.setProperty("--color-primary", color);
|
||||
}
|
||||
|
||||
// 字体图标库加载
|
||||
if (config.app.iconfont) {
|
||||
config.app.iconfont.forEach((e: string) => {
|
||||
createLink(e);
|
||||
});
|
||||
}
|
||||
|
||||
// 默认
|
||||
createLink("//at.alicdn.com/t/font_3254019_60a2xxj8uus.css");
|
||||
|
||||
// svg 图标加载
|
||||
const svgFiles = import.meta.globEager("/src/icons/svg/**/*.svg");
|
||||
|
||||
function iconList() {
|
||||
const list: string[] = [];
|
||||
|
||||
for (const i in svgFiles) {
|
||||
list.push(basename(i).replace(".svg", ""));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
export { iconList };
|
110
src/modules/base/components/avatar/index.vue
Normal file
@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="cl-avatar" :class="[size, shape]" :style="[style]">
|
||||
<el-image :src="src || modelValue" alt="头像">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<el-icon :size="20" :color="color"><user /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from "vue";
|
||||
import { isNumber } from "lodash";
|
||||
import { User } from "@element-plus/icons-vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "cl-avatar",
|
||||
|
||||
components: {
|
||||
User
|
||||
},
|
||||
|
||||
props: {
|
||||
modelValue: String,
|
||||
src: String,
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: 36
|
||||
},
|
||||
shape: {
|
||||
type: String as PropType<"square" | "circle">,
|
||||
default: "square"
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: "#f7f7f7"
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "#ccc"
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const size = isNumber(props.size) ? props.size + "px" : props.size;
|
||||
|
||||
const style = computed(() => {
|
||||
return {
|
||||
height: size,
|
||||
width: size,
|
||||
backgroundColor: props.backgroundColor
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
style
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cl-avatar {
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
|
||||
&.large {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
&.small {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
&.circle {
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
&.square {
|
||||
border-radius: 10%;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.image-slot {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
142
src/modules/base/components/codemirror/index.vue
Normal file
@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div ref="editorRef" class="cl-codemirror">
|
||||
<textarea id="editor" class="cl-code" :height="height" :width="width"></textarea>
|
||||
|
||||
<div class="cl-codemirror__tools">
|
||||
<el-button @click="formatCode">格式化</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, nextTick, onMounted, ref, watch } from "vue";
|
||||
import CodeMirror from "codemirror";
|
||||
import beautifyJs from "js-beautify";
|
||||
import "codemirror/lib/codemirror.css";
|
||||
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 "/@/cool/utils";
|
||||
|
||||
export default defineComponent({
|
||||
name: "cl-codemirror",
|
||||
|
||||
props: {
|
||||
modelValue: null,
|
||||
height: String,
|
||||
width: String,
|
||||
options: Object
|
||||
},
|
||||
|
||||
emits: ["update:modelValue", "load"],
|
||||
|
||||
setup(props, { emit }) {
|
||||
const editorRef = ref<any>(null);
|
||||
|
||||
let editor: any = null;
|
||||
|
||||
// 获取内容
|
||||
function getValue() {
|
||||
if (editor) {
|
||||
return editor.getValue();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// 设置内容
|
||||
function setValue(val?: string) {
|
||||
if (editor) {
|
||||
editor.setValue(val || "");
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化
|
||||
function formatCode() {
|
||||
if (editor) {
|
||||
editor.setValue(beautifyJs(getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
// 监听内容变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string) => {
|
||||
if (editor && val != getValue()) {
|
||||
setValue(val);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(function () {
|
||||
nextTick(() => {
|
||||
// 实例化
|
||||
editor = CodeMirror.fromTextArea(
|
||||
editorRef.value.querySelector("#editor"),
|
||||
deepMerge(
|
||||
{
|
||||
mode: "javascript",
|
||||
theme: "hopscotch",
|
||||
styleActiveLine: true,
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
indentWithTabs: true,
|
||||
indentUnit: 4,
|
||||
extraKeys: { Ctrl: "autocomplete" },
|
||||
foldGutter: true,
|
||||
autofocus: true,
|
||||
matchBrackets: true,
|
||||
autoCloseBrackets: true,
|
||||
gutters: [
|
||||
"CodeMirror-linenumbers",
|
||||
"CodeMirror-foldgutter",
|
||||
"CodeMirror-lint-markers"
|
||||
]
|
||||
},
|
||||
props.options
|
||||
)
|
||||
);
|
||||
|
||||
// 输入监听
|
||||
editor.on("change", (e: any) => {
|
||||
emit("update:modelValue", e.getValue());
|
||||
});
|
||||
|
||||
// 设置内容
|
||||
setValue(props.modelValue);
|
||||
|
||||
// 格式化
|
||||
formatCode();
|
||||
|
||||
// 加载回调
|
||||
emit("load", editor);
|
||||
|
||||
// 设置编辑框大小
|
||||
editor.setSize(props.width || "auto", props.height || "auto");
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
editorRef,
|
||||
formatCode
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.cl-codemirror {
|
||||
border-radius: 3px;
|
||||
border: 1px solid #dcdfe6;
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
line-height: 150%;
|
||||
|
||||
&__tools {
|
||||
background-color: #322931;
|
||||
padding: 10px;
|
||||
border-top: 1px solid #444;
|
||||
}
|
||||
}
|
||||
</style>
|
30
src/modules/base/components/date/text.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<span class="cl-date-text">{{ value }}</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export default defineComponent({
|
||||
name: "cl-date-text",
|
||||
|
||||
props: {
|
||||
modelValue: [String, Number],
|
||||
format: {
|
||||
type: String,
|
||||
default: "YYYY-MM-DD HH:mm:ss"
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const value = computed(() => {
|
||||
return props.modelValue ? dayjs(props.modelValue).format(props.format) : "";
|
||||
});
|
||||
|
||||
return {
|
||||
value
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
256
src/modules/base/components/editor-quill/index.vue
Normal file
@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<div class="cl-editor-quill">
|
||||
<div ref="Editor" class="editor" :style="style"></div>
|
||||
<cl-upload-space ref="Upload" :show-btn="false" @confirm="onUploadConfirm" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, ref, watch } from "vue";
|
||||
import Quill from "quill";
|
||||
import "quill/dist/quill.snow.css";
|
||||
import { isNumber } from "lodash";
|
||||
|
||||
export default defineComponent({
|
||||
name: "cl-editor-quill",
|
||||
|
||||
props: {
|
||||
modelValue: null,
|
||||
options: Object,
|
||||
height: [String, Number],
|
||||
width: [String, Number]
|
||||
},
|
||||
|
||||
emits: ["update:modelValue", "load"],
|
||||
|
||||
setup(props, { emit }) {
|
||||
let quill: any = null;
|
||||
|
||||
const Editor = ref<any>();
|
||||
const Upload = ref<any>();
|
||||
|
||||
// 文本内容
|
||||
const content = ref<string>("");
|
||||
|
||||
// 光标位置
|
||||
const cursorIndex = ref<number>(0);
|
||||
|
||||
// 上传处理
|
||||
function uploadFileHandler() {
|
||||
const selection = quill.getSelection();
|
||||
|
||||
if (selection) {
|
||||
cursorIndex.value = selection.index;
|
||||
}
|
||||
|
||||
Upload.value.open();
|
||||
}
|
||||
|
||||
// 文件确认
|
||||
function onUploadConfirm(files: any[]) {
|
||||
if (files.length > 0) {
|
||||
// 批量插入图片
|
||||
files.forEach((file, i) => {
|
||||
if (file.type == "image") {
|
||||
quill.insertEmbed(
|
||||
cursorIndex.value + i,
|
||||
file.type,
|
||||
file.url,
|
||||
Quill.sources.USER
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// 移动光标到图片后一位
|
||||
quill.setSelection(cursorIndex.value + files.length);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置内容
|
||||
function setContent(val: string) {
|
||||
quill.root.innerHTML = val || "";
|
||||
}
|
||||
|
||||
// 编辑框样式
|
||||
const style = computed<any>(() => {
|
||||
const height = isNumber(props.height) ? props.height + "px" : props.height;
|
||||
const width = isNumber(props.width) ? props.width + "px" : props.width;
|
||||
|
||||
return {
|
||||
height,
|
||||
width
|
||||
};
|
||||
});
|
||||
|
||||
// 监听绑定值
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string) => {
|
||||
if (val) {
|
||||
if (val !== content.value) {
|
||||
setContent(val);
|
||||
}
|
||||
} else {
|
||||
setContent("");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(function () {
|
||||
// 实例化
|
||||
quill = new Quill(Editor.value, {
|
||||
theme: "snow",
|
||||
placeholder: "输入内容",
|
||||
modules: {
|
||||
toolbar: [
|
||||
["bold", "italic", "underline", "strike"],
|
||||
["blockquote", "code-block"],
|
||||
[{ header: 1 }, { header: 2 }],
|
||||
[{ list: "ordered" }, { list: "bullet" }],
|
||||
[{ script: "sub" }, { script: "super" }],
|
||||
[{ indent: "-1" }, { indent: "+1" }],
|
||||
[{ direction: "rtl" }],
|
||||
[{ size: ["small", false, "large", "huge"] }],
|
||||
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||
[{ color: [] }, { background: [] }],
|
||||
[{ font: [] }],
|
||||
[{ align: [] }],
|
||||
["clean"],
|
||||
["link", "image"]
|
||||
]
|
||||
},
|
||||
...props.options
|
||||
});
|
||||
|
||||
// 添加图片工具
|
||||
quill.getModule("toolbar").addHandler("image", uploadFileHandler);
|
||||
|
||||
// 监听输入
|
||||
quill.on("text-change", () => {
|
||||
content.value = quill.root.innerHTML;
|
||||
emit("update:modelValue", content.value);
|
||||
});
|
||||
|
||||
// 设置内容
|
||||
setContent(props.modelValue);
|
||||
|
||||
// 加载回调
|
||||
emit("load", quill);
|
||||
});
|
||||
|
||||
return {
|
||||
Editor,
|
||||
Upload,
|
||||
content,
|
||||
quill,
|
||||
cursorIndex,
|
||||
style,
|
||||
setContent,
|
||||
onUploadConfirm
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cl-editor-quill {
|
||||
background-color: #fff;
|
||||
|
||||
.ql-snow {
|
||||
line-height: 22px !important;
|
||||
}
|
||||
|
||||
.el-upload,
|
||||
#quill-upload-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ql-snow {
|
||||
border: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode="link"]::before {
|
||||
content: "请输入链接地址:";
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||
border-right: 0px;
|
||||
content: "保存";
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode="video"]::before {
|
||||
content: "请输入视频地址:";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||
content: "14px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
|
||||
content: "10px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
|
||||
content: "18px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
|
||||
content: "32px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||
content: "文本";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||
content: "标题1";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||
content: "标题2";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||
content: "标题3";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||
content: "标题4";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||
content: "标题5";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||
content: "标题6";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||
content: "标准字体";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
|
||||
content: "衬线字体";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
|
||||
content: "等宽字体";
|
||||
}
|
||||
}
|
||||
</style>
|