master
zhangliang 9 months ago
commit d19ed21a2d

@ -0,0 +1,36 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'build', // 编译相关修改(新版本发布)
'feat', // 新功能
'fix', // 修复bug
'update', // 更新某功能
'refactor', // 重构
'docs', // 文档
'chore', // 增加依赖或库
'style', // 格式(不影响代码变动)
'revert', // 撤销commit 回滚上一版本
'perf', // 性能优化
'remove', //删除
'release', //
]
],
'scope-case': [0],
},
plugins: [
{
rules: {
"commit-rule": ({ raw }) => {
return [
/^\[(build|feat|fix|update|refactor|docs|chore|style|revert|perf|remove|release)].+/g.test(raw),
`commit备注信息格式错误格式为 <[type] 修改内容>type支持${types.join(",")}`
]
}
}
}
]
}

@ -0,0 +1,3 @@
ENV=develop
VITE_APP_BASE_API=/api
VITE_TOKEN_KEY = X-Access-Token

@ -0,0 +1,3 @@
ENV=production
VITE_APP_BASE_API=/api
VITE_TOKEN_KEY = X-Access-Token

@ -0,0 +1,5 @@
node_modules/
dist/
index.html
.vscode
docker

@ -0,0 +1,26 @@
module.exports = {
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
},
extends: [
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'plugin:prettier/recommended'
],
rules: {
// override/add rules settings here, such as:
},
globals: {
NodeJS: 'readonly'
}
};

28
.gitignore vendored

@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
components.d.ts
# Editor directories and files
.vscode
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.history
du-i18n.config.json

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit ${1}

@ -0,0 +1,2 @@
always-auth=true
registry=https://registry.npmjs.org/

@ -0,0 +1,37 @@
module.exports = {
// 一行最多 80 字符
printWidth: 80,
// 使用 4 个空格缩进
tabWidth: 4,
// 不使用 tab 缩进,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号代替双引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾使用逗号
trailingComma: 'all',
// 大括号内的首尾需要空格 { foo: bar }
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf
endOfLine: 'auto'
}

@ -0,0 +1,6 @@
FROM nginx
ADD nginx.conf /etc/nginx/conf.d/default.conf
ADD docker-entrypoint.sh /docker-entrypoint.sh
COPY dist /usr/share/nginx/html
CMD ["sh","/docker-entrypoint.sh"]
#ADD oauth2 /usr/share/nginx/html/oauth2

@ -0,0 +1,261 @@
<h1 align="center"> JetLinks-ui-vue</h1>
## 平台简介
* 本仓库为JetLinks vue版本。
* 前端技术栈[Vue3](https://v3.cn.vuejs.org) + [Jetlinks-ui-components](https://github.com/jetlinks/jetlinks-ui-components) + [Vite 4.x](https://cn.vitejs.dev)
* 本项目采用约定式路由,文件系统即路由,通过目录和文件及其命名分析出路由配置。
## 前端运行
```bash
# 克隆项目
git clone https://github.com/jetlinks/jetlinks-ui-vue.git
# 安装依赖
yarn
# 启动服务
yarn dev
# 更新jetlinks-ui-components
yarn add jetlinks-ui-components@latest
# 更新jetlinks-ui-components之后没有效果时
yarn dev:force
```
## Node
* node >= 18.14.0
## 浏览器兼容
* Chrome >= 100
* Firefox >= 100
* Edge >= 100
不支持IE
### 备注
* 项目在开发模式下,首页加载慢属于正常现象;
* 打开F12后页面卡顿是`vuetools`引起,[https://github.com/vuejs/devtools/issues/1987](https://github.com/vuejs/devtools/issues/1987)
## 更改配置
### 默认图标以及系统名称
#### 1.基础配置
首先启动项目,找到顶部菜单的 系统管理 -> 基础配置
此处可以更改系统名称、主题色、系统logo、浏览器页签等
#### 主题色
```javascript
// src/App.vue
ConfigProvider.config({
theme: {
primaryColor: "#315efb"
}
})
```
#### 2.默认配置
在代码根目录找到`config\config.ts`文件
> 默认图标以及系统名称优先使用基础配置的数据!
```javascript
export default {
...
logo: '/favicon.ico', // 浏览器标签页logo(不要修改如需修改默认图标请在根目录public\favicon.ico替换此文件)
title: 'Jetlinks', // 浏览器标签页title(刷新状态时浏览器标签页名称)
layout: {
title: '物联网平台', // 平台title(默认配置不生效,优先使用基础配置的数据)
logo: '/logo.png', // 平台logo(不要修改如需修改默认logo请在根目录public\logo.png替换此文件)
...
}
}
```
### 去掉或修改备案信息
#### 修改备案信息
在`src\views\user\Login\index.vue`文件
在第16行左右修改以下代码`备案: xxx(自己的备案信息)`
```javascript
<a
href="https://beian.miit.gov.cn/#/Integrated/index"
target="_blank"
rel="noopener noreferrer"
class="records"
>
备案: xxx(自己的备案信息)
</a>
```
### 去掉导航栏右上角jetlinks文档
在`src\components\Layout\BasicLayoutPage.vue`文件
在第23行左右注释以下代码
```javascript
<!-- <AIcon type="QuestionCircleOutlined" @click="toDoc" /> -->
```
### 新增菜单
新增或者修改菜单有两种方式,第一个是代码内的初始化菜单,第二个系统管理的菜单管理
* 初始化菜单
初始化菜单是默认的菜单,在进行系统初始化会使用到。
> 在进行菜单初始化时,如果只在菜单管理新增或修改,但是没有在初始化菜单里新增或者修改,则只会保留初始化菜单!
* 菜单管理
菜单管理是 系统管理 -> 菜单管理 的菜单,可以动态修改,新增或者更改
> 如果需要系统初始化时不丢失,请在`src\views\init-home\data\baseMenu.ts`文件下新增或者修改初始化菜单
**新增或者修改菜单之前,确保`src\views`文件夹下有对应的文件夹以及index.vue入口文件**
#### 1.菜单管理
新建文件夹以及文件`src\views\test\Home\index.vue`
##### 新增顶部菜单 test菜单
1. 启动项目,找到顶部菜单的 系统管理 -> 菜单管理,点击菜单配置旁边的新增按钮。
2. 完成菜单图标、名称、编码、页面地址、权限配置等
> 编码是唯一的,必须和文件路径一致此处是顶级菜单编码填入: test
> 页面地址建议和文件路径保持一致: /test
3. 点击保存,刷新页面后生效
4. 按钮权限 顶级菜单没有页面可以不用添加按钮权限
##### 新增子菜单
1. 在菜单管理 test菜单 新增子菜单
2. 完成菜单图标、名称、编码、页面地址、权限配置等
> 编码是唯一的必须和文件路径一致此处是test菜单下的二级菜单编码填入: test/Home
> 页面地址建议和文件路径保持一致: /test/Home
4. 点击保存,刷新页面后生效
5. 按钮权限 如果有权限控制可以添加对应权限
#### 2.初始化菜单
建议在菜单管理新增或修改菜单之后,再来新增或修改初始化菜单
##### 新增顶部菜单test以及子菜单
**确定有对应的文件夹以及文件`src\views\test\Home\index.vue`**
1. 启动项目,找到顶部菜单的 系统管理 -> 菜单管理
打开控制台(F12),选中网络(Network),点击菜单管理的搜索或者重置,直到有 tree 的接口请求。
点击接口请求 tree , 并选中响应或者预览选项找到刚刚新增code为test的数据复制test菜单的数据
2. 在`src\views\init-home\data\baseMenu.ts`文件中添加配置
把第一步test菜单的数据复制到对应位置即可
```javascript
export default [
// 物联网
...
// 视频中心
...
// 系统管理
...
// 物联卡
...
// test菜单
{
"id": "eb2858ec8dc6d12645a19ee0ed6aba36",
"parentId": "",
"path": "FwY9",
"sortIndex": 5,
"level": 1,
"owner": "iot",
"name": "test菜单",
"code": "test",
"describe": "",
"url": "/test",
"icon": "StepForwardOutlined",
"status": 1,
"permissions": [],
"accessSupport": {
"text": "不支持",
"value": "unsupported"
},
"indirectMenus": [],
"children": [
{
"id": "1995dcd016aaad7c5515f8ead14ca617",
"parentId": "eb2858ec8dc6d12645a19ee0ed6aba36",
"path": "FwY9-T6lF",
"sortIndex": 1,
"level": 2,
"owner": "iot",
"name": "首页",
"code": "test/Home",
"describe": "",
"url": "/test/Home",
"icon": "HeatMapOutlined",
"status": 1,
"permissions": [],
"accessSupport": {
"text": "不支持",
"value": "unsupported"
},
"indirectMenus": [],
"buttons": [
{
"id": "add",
"name": "新增",
"permissions": [
{
"permission": "role",
"actions": [
"query",
"save",
"delete"
]
}
]
}
],
"creatorId": "1199596756811550720",
"createTime": 1688032521555,
"supportDataAccess": false
}
],
"creatorId": "1199596756811550720",
"createTime": 1688032467222,
"supportDataAccess": false
}
]
```
> 新增初始化菜单之后需要进行系统初始化才能生效
##### 修改初始化菜单
同上,在菜单管理修改对应的数据,复制对应的菜单数据,然后替换掉`baseMenu.ts`对应数据即可。
> 修改初始化菜单之后需要进行菜单初始化才能生效
##### 系统初始化
在浏览器顶部修改页面路径,`/#/`后边输入`init-home`,回车进入系统初始化页面
例如: `http://localhost:5174/#/init-home`
填写好基本信息,角色初始化等,点击确定

@ -0,0 +1,3 @@
#!/usr/bin/env bash
docker build -t registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.3.0-SNAPSHOT .
docker push registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.3.0-SNAPSHOT

@ -0,0 +1,13 @@
export default {
theme: {
'primary-color': '#1677FF',
},
logo: '/favicon.ico', // 浏览器标签页logo
title: 'Jetlinks', // 浏览器标签页title
layout: {
title: '物联网平台', // 平台title
logo: '/logo.png', // 平台logo
mode: 'inline',
theme: 'light', // 'dark' 'light'
}
}

@ -0,0 +1,30 @@
#!/usr/bin/env bash
API_BASE_PATH=$API_BASE_PATH;
SERVER_NAME=$SERVER_NAME;
NAMESERVERS=$(cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}' | tr '\n' ' ')
if [ -z "$API_BASE_PATH" ]; then
API_BASE_PATH="http://jetlinks:8844/";
fi
apiUrl="proxy_pass $API_BASE_PATH\$1;"
resolver="resolver $NAMESERVERS ipv6=off;"
sed -i '11c '"$resolver"'' /etc/nginx/conf.d/default.conf
sed -i "s%{API_BASE_PATH}%$API_BASE_PATH%g" /etc/nginx/conf.d/default.conf
if [ -z "$SERVER_NAME" ]; then
serverName="server_name localhost;"
sed -i '4c '"$serverName"'' /etc/nginx/conf.d/default.conf
sed -i "s%{SERVER_NAME}%\"0\"%g" /etc/nginx/conf.d/default.conf
else
serverName="server_name $SERVER_NAME;"
sed -i '4c '"$serverName"'' /etc/nginx/conf.d/default.conf
sed -i "s%{SERVER_NAME}%$SERVER_NAME%g" /etc/nginx/conf.d/default.conf
fi
#cat /etc/nginx/conf.d/default.conf
nginx -g "daemon off;"

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<%- favicon %>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%- title %></title>
<script src="/js/liveplayer-lib.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

@ -0,0 +1,52 @@
server {
listen 80;
listen [::]:80;
server_name _;
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
resolver $NAMESERVERS ipv6=off;
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
set $my_result_code 200;
set $my_server_name {SERVER_NAME};
if ($http_Host !~* ^{SERVER_NAME}) {
set $my_result_code 403;
}
if ($my_server_name ~ "0") {
set $my_result_code 200;
}
if ($my_result_code = 403) {
return 403;
}
location / {
index index.html;
}
location ^~/api/ {
if ($request_uri ~* ^/api/(.*)$) {
proxy_pass {API_BASE_PATH}$1;
}
#proxy_pass http://host.docker.internal:8840/;
proxy_set_header X-Forwarded-Proto $scheme;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 1;
proxy_buffering off;
chunked_transfer_encoding off;
proxy_cache off;
proxy_send_timeout 30m;
proxy_read_timeout 30m;
client_max_body_size 500m;
}
}

13846
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,118 @@
{
"name": "jetlinks-vue",
"private": true,
"version": "2.2.1",
"scripts": {
"dev": "vite --mode develop",
"dev:force": "vite --force --mode develop",
"build": "node --max_old_space_size=1024000 ./node_modules/vite/bin/vite.js build",
"preview": "vite preview",
"eslint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
"prettier": "prettier --write",
"prepare": "husky install"
},
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@fullcalendar/core": "^6.1.13",
"@fullcalendar/daygrid": "^6.1.13",
"@fullcalendar/interaction": "^6.1.13",
"@fullcalendar/vue3": "^6.1.13",
"@liveqing/liveplayer-v3": "^3.7.10",
"@types/axios": "^0.14.0",
"@types/marked": "^4.0.8",
"@vitejs/plugin-vue-jsx": "^3.0.0",
"@vuemap/vue-amap": "^2.1.2",
"@vueuse/core": "^9.10.0",
"ant-design-vue": "^3.2.15",
"async-validator": "^4.2.5",
"axios": "^1.2.1",
"colorpicker-v3": "^2.10.2",
"cronstrue": "^2.50.0",
"dayjs": "^1.11.12",
"driver.js": "^0.9.8",
"echarts": "^5.4.1",
"event-source-polyfill": "^1.0.31",
"global": "^4.4.0",
"jetlinks-store": "^0.0.3",
"jetlinks-ui-components": "^1.0.47",
"jsencrypt": "^3.3.2",
"leaflet": "^1.9.4",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"lodash-es": "^4.17.21",
"markdown-it": "^14.1.0",
"markdown-it-abbr": "^2.0.0",
"markdown-it-anchor": "^8.6.7",
"markdown-it-deflist": "^3.0.0",
"markdown-it-emoji": "^3.0.0",
"markdown-it-footnote": "^4.0.0",
"markdown-it-highlightjs": "^4.0.1",
"markdown-it-ins": "^4.0.0",
"markdown-it-mark": "^4.0.0",
"markdown-it-sub": "^2.0.0",
"markdown-it-sup": "^2.0.0",
"markdown-it-task-lists": "^2.1.1",
"markdown-it-toc-done-right": "^4.2.0",
"marked": "^4.2.12",
"moment": "^2.29.4",
"monaco-editor": "^0.50.0",
"nrm": "^1.2.5",
"pinia": "^2.0.28",
"resize-observer-polyfill": "^1.5.1",
"rollup-plugin-copy": "^3.4.0",
"rxjs": "^7.8.1",
"three": "0.146.0",
"unplugin-auto-import": "^0.12.1",
"unplugin-vue-components": "^0.22.12",
"v-clipboard3": "^0.1.4",
"vite-plugin-monaco-editor": "^1.1.0",
"vue": "3.3.4",
"vue-cropper": "^1.0.9",
"vue-i18n": "^9.13.1",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
"vue3-json-viewer": "^2.2.2",
"vue3-ts-jsoneditor": "^2.7.1",
"xgplayer": "^3.0.19",
"xgplayer-flv": "^3.0.20-beta.0",
"xgplayer-hls": "^3.0.19",
"xgplayer-hls.js": "2.2.2"
},
"devDependencies": {
"@commitlint/cli": "^17.4.1",
"@commitlint/config-conventional": "^17.4.0",
"@types/leaflet": "^1.9.12",
"@types/lodash-es": "^4.17.6",
"@types/moment": "^2.13.0",
"@types/node": "^18.14.0",
"@vitejs/plugin-vue": "^4.0.0",
"@vuemap/unplugin-resolver": "^1.0.4",
"autoprefixer": "^10.4.13",
"commitlint": "^17.4.1",
"husky": "^8.0.0",
"lint-staged": "^13.1.0",
"mrm": "^4.1.13",
"prettier": "^2.8.1",
"typescript": "^4.9.3",
"vite": "^4.0.0",
"vite-plugin-html": "^3.2.0",
"vite-plugin-progress": "^0.0.7",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-tsc": "^1.0.11"
},
"lint-staged": {
"**/*.{vue,js,jsx,ts,tsx}": [
"npm run lint",
"prettier --write"
],
"**/*.{html,css,less,md}": [
"prettier --write"
]
},
"volta": {
"node": "18.14.0",
"yarn": "1.22.0"
}
}

@ -0,0 +1,159 @@
import type { IMatcher } from './jetlinks'
export function kebabCase(key: string) {
const result = key.replace(/([A-Z])/g, ' $1').trim()
return result.split(' ').join('-').toLowerCase()
}
export const AntdMatchComponents: IMatcher[] = [
{
pattern: /^Avatar/,
styleDir: 'avatar',
},
{
pattern: /^AutoComplete/,
styleDir: 'auto-complete',
},
{
pattern: /^Anchor/,
styleDir: 'anchor',
},
{
pattern: /^Badge/,
styleDir: 'badge',
},
{
pattern: /^Breadcrumb/,
styleDir: 'breadcrumb',
},
{
pattern: /^Button/,
styleDir: 'button',
},
{
pattern: /^Checkbox/,
styleDir: 'checkbox',
},
{
pattern: /^Card/,
styleDir: 'card',
},
{
pattern: /^Collapse/,
styleDir: 'collapse',
},
{
pattern: /^Descriptions/,
styleDir: 'descriptions',
},
{
pattern: /^RangePicker|^WeekPicker|^MonthPicker/,
styleDir: 'date-picker',
},
{
pattern: /^Dropdown/,
styleDir: 'dropdown',
},
{
pattern: /^Form/,
styleDir: 'form',
},
{
pattern: /^InputNumber/,
styleDir: 'input-number',
},
{
pattern: /^Input|^Textarea/,
styleDir: 'input',
},
{
pattern: /^Statistic/,
styleDir: 'statistic',
},
{
pattern: /^CheckableTag/,
styleDir: 'tag',
},
{
pattern: /^TimeRangePicker/,
styleDir: 'time-picker',
},
{
pattern: /^Layout/,
styleDir: 'layout',
},
{
pattern: /^Menu|^SubMenu/,
styleDir: 'menu',
},
{
pattern: /^Table/,
styleDir: 'table',
},
{
pattern: /^TimePicker|^TimeRangePicker/,
styleDir: 'time-picker',
},
{
pattern: /^Radio/,
styleDir: 'radio',
},
{
pattern: /^Image/,
styleDir: 'image',
},
{
pattern: /^List/,
styleDir: 'list',
},
{
pattern: /^Tab/,
styleDir: 'tabs',
},
{
pattern: /^Mentions/,
styleDir: 'mentions',
},
{
pattern: /^Step/,
styleDir: 'steps',
},
{
pattern: /^Skeleton/,
styleDir: 'skeleton',
},
{
pattern: /^Select/,
styleDir: 'select',
},
{
pattern: /^TreeSelect/,
styleDir: 'tree-select',
},
{
pattern: /^Tree|^DirectoryTree/,
styleDir: 'tree',
},
{
pattern: /^Typography/,
styleDir: 'typography',
},
{
pattern: /^Timeline/,
styleDir: 'timeline',
},
{
pattern: /^Upload/,
styleDir: 'upload',
},
]

@ -0,0 +1,397 @@
import { AntdMatchComponents, kebabCase } from './antdv'
export interface IMatcher {
pattern: RegExp
styleDir: string
}
const matchComponents: IMatcher[] = [
{
pattern: /^Avatar/,
styleDir: 'Avatar'
},
{
pattern: /^AutoComplete/,
styleDir: 'AutoComplete'
},
{
pattern: /^Anchor/,
styleDir: 'Anchor'
},
{
pattern: /^Badge/,
styleDir: 'Badge'
},
{
pattern: /^Breadcrumb/,
styleDir: 'Breadcrumb'
},
{
pattern: /^Button/,
styleDir: 'Button'
},
{
pattern: /^Checkbox/,
styleDir: 'Checkbox'
},
{
pattern: /^CardSelect/,
styleDir: 'CardSelect'
},
{
pattern: /^Card/,
styleDir: 'Card'
},
{
pattern: /^Collapse/,
styleDir: 'Collapse'
},
{
pattern: /^Descriptions/,
styleDir: 'Descriptions'
},
{
pattern: /^RangePicker|^WeekPicker|^MonthPicker/,
styleDir: 'DatePicker'
},
{
pattern: /^Dropdown/,
styleDir: 'Dropdown'
},
{
pattern: /^Form/,
styleDir: 'Form'
},
{
pattern: /^InputNumber/,
styleDir: 'InputNumber'
},
{
pattern: /^Input|^Textarea/,
styleDir: 'Input'
},
{
pattern: /^Statistic/,
styleDir: 'Statistic'
},
{
pattern: /^CheckableTag/,
styleDir: 'Tag'
},
{
pattern: /^TimeRangePicker/,
styleDir: 'TimePicker'
},
{
pattern: /^Layout/,
styleDir: 'Layout'
},
{
pattern: /^Menu|^SubMenu/,
styleDir: 'Menu'
},
{
pattern: /^Table/,
styleDir: 'Table'
},
{
pattern: /^TimePicker|^TimeRangePicker/,
styleDir: 'TimePicker'
},
{
pattern: /^Radio/,
styleDir: 'Radio'
},
{
pattern: /^Image/,
styleDir: 'Image'
},
{
pattern: /^List/,
styleDir: 'List'
},
{
pattern: /^Tab/,
styleDir: 'Tabs'
},
{
pattern: /^Mentions/,
styleDir: 'Mentions'
},
{
pattern: /^Step/,
styleDir: 'Steps'
},
{
pattern: /^Skeleton/,
styleDir: 'Skeleton'
},
{
pattern: /^Select|^SelectBoolean/,
styleDir: 'Select'
},
{
pattern: /^TreeSelect/,
styleDir: 'TreeSelect'
},
{
pattern: /^Tree|^DirectoryTree/,
styleDir: 'Tree'
},
{
pattern: /^Typography/,
styleDir: 'Typography'
},
{
pattern: /^Timeline/,
styleDir: 'Timeline'
},
{
pattern: /^Upload/,
styleDir: 'Upload'
},
{
pattern: /^ProTable/,
styleDir: 'ProTable'
},
{
pattern: /^Search|^AdvancedSearch/,
styleDir: 'Search'
},
{
pattern: /^Ellipsis/,
styleDir: 'Ellipsis'
},
{
pattern: /^MonacoEditor/,
styleDir: 'MonacoEditor'
},
{
pattern: /^ProLayout/,
styleDir: 'ProLayout'
},
{
pattern: /^ScrollTable/,
styleDir: 'ScrollTable'
},
{
pattern: /^TableCard/,
styleDir: 'TableCard'
},
{
pattern: /^Scrollbar/,
styleDir: 'Scrollbar'
},
{
pattern: /^AIcon/,
styleDir: 'AIcon'
},
{
pattern: /^Tooltip/,
styleDir: 'Tooltip'
},
{
pattern: /^Empty/,
styleDir: 'Empty'
},
{
pattern: /^PopconfirmModal/,
styleDir: 'PopconfirmModal'
},
{
pattern: /^Popconfirm/,
styleDir: 'Popconfirm'
},
{
pattern: /^message/,
styleDir: 'Message'
},
{
pattern: /^Notification/,
styleDir: 'Notification'
},
{
pattern: /^DataTable/,
styleDir: 'DataTable'
},
{
pattern: /^CheckButton/,
styleDir: 'CheckButton'
},
]
export interface JetlinksVueResolverOptions {
/**
* exclude components that do not require automatic import
*
* @default []
*/
exclude?: string[]
/**
* import style along with components
*
* @default 'css'
*/
importStyle?: boolean | 'css' | 'less'
/**
* resolve `ant-design-vue' icons
*
* requires package `@ant-design/icons-vue`
*
* @default false
*/
resolveIcons?: boolean
/**
* @deprecated use `importStyle: 'css'` instead
*/
importCss?: boolean
/**
* @deprecated use `importStyle: 'less'` instead
*/
importLess?: boolean
/**
* use commonjs build default false
*/
cjs?: boolean
packageName?: string
}
function getStyleDir(compName: string, _isAntd = false): string {
let styleDir
const components = _isAntd ? AntdMatchComponents : matchComponents
const total = components.length
for (let i = 0; i < total; i++) {
const matcher = components[i]
if (compName.match(matcher.pattern)) {
styleDir = matcher.styleDir
break
}
}
if (!styleDir)
styleDir = _isAntd ? kebabCase(compName) : compName
return styleDir
}
function getSideEffects(compName: string, options: JetlinksVueResolverOptions, _isAntd = false): any {
const {
importStyle = true,
importLess = false
} = options
if (!importStyle)
return
const lib = options.cjs ? 'lib' : 'es'
const packageName = options?.packageName || 'jetlinks-ui-components'
if (importStyle === 'less' || importLess) {
const styleDir = getStyleDir(compName, _isAntd)
return `${packageName}/${lib}/${styleDir}/style`
} else {
const styleDir = getStyleDir(compName, _isAntd)
return `${packageName}/${lib}/${styleDir}/style/css`
}
}
const filterName = ['message', 'Notification']
const primitiveNames = ['AIcon','Affix', 'Anchor', 'AnchorLink', 'message', 'Notification', 'AutoComplete', 'AutoCompleteOptGroup', 'AutoCompleteOption', 'Alert', 'Avatar', 'AvatarGroup', 'BackTop', 'Badge', 'BadgeRibbon', 'Breadcrumb', 'BreadcrumbItem', 'BreadcrumbSeparator', 'Button', 'ButtonGroup', 'Calendar', 'Card', 'CardGrid', 'CardMeta', 'Collapse', 'CollapsePanel', 'Carousel', 'Cascader', 'Checkbox', 'CheckboxGroup', 'Col', 'Comment', 'ConfigProvider', 'DatePicker', 'MonthPicker', 'WeekPicker', 'RangePicker', 'QuarterPicker', 'Descriptions', 'DescriptionsItem', 'Divider', 'Dropdown', 'DropdownButton', 'Drawer', 'Empty', 'Form', 'FormItem', 'FormItemRest', 'Grid', 'Input', 'InputGroup', 'InputPassword', 'InputSearch', 'Textarea', 'Image', 'ImagePreviewGroup', 'InputNumber', 'Layout', 'LayoutHeader', 'LayoutSider', 'LayoutFooter', 'LayoutContent', 'List', 'ListItem', 'ListItemMeta', 'Menu', 'MenuDivider', 'MenuItem', 'MenuItemGroup', 'SubMenu', 'Mentions', 'MentionsOption', 'Modal', 'Statistic', 'StatisticCountdown', 'PageHeader', 'Pagination', 'Popconfirm', 'Popover', 'Progress', 'Radio', 'RadioButton', 'RadioGroup', 'Rate', 'Result', 'Row', 'Select', 'SelectOptGroup', 'SelectOption', 'SelectBoolean', 'Skeleton', 'SkeletonButton', 'SkeletonAvatar', 'SkeletonInput', 'SkeletonImage', 'Slider', 'Space', 'Spin', 'Steps', 'Step', 'Switch', 'Table', 'TableColumn', 'TableColumnGroup', 'TableSummary', 'TableSummaryRow', 'TableSummaryCell', 'Transfer', 'Tree', 'TreeNode', 'DirectoryTree', 'TreeSelect', 'TreeSelectNode', 'Tabs', 'TabPane', 'Tag', 'CheckableTag', 'TimePicker', 'TimeRangePicker', 'Timeline', 'TimelineItem', 'Tooltip', 'Typography', 'TypographyLink', 'TypographyParagraph', 'TypographyText', 'TypographyTitle', 'Upload', 'UploadDragger', 'LocaleProvider', 'ProTable', 'Search', 'AdvancedSearch', 'Ellipsis', 'MonacoEditor', 'ProLayout', 'ScrollTable', 'TableCard', 'Scrollbar', 'CardSelect', 'PopconfirmModal', 'DataTable',
'DataTableArray',
'DataTableString',
'DataTableInteger',
'DataTableDouble',
'DataTableBoolean',
'DataTableEnum',
'DataTableFile',
'DataTableDate',
'DataTableTypeSelect',
'DataTableObject',
'CheckButton',
]
const prefix = 'J'
const proComponents = [
'ProTable', 'Search', 'AdvancedSearch', 'Ellipsis', 'MonacoEditor', 'ProLayout', 'ScrollTable', 'TableCard', 'Scrollbar', 'CardSelect', 'PopconfirmModal', 'DataTable',
'DataTableArray',
'DataTableString',
'DataTableInteger',
'DataTableDouble',
'DataTableBoolean',
'DataTableEnum',
'DataTableFile',
'DataTableDate',
'DataTableTypeSelect',
'DataTableObject',
'CheckButton',
'ValueItem'
]
let jetlinksNames: Set<string>
function genJetlinksNames(primitiveNames: string[]): void {
jetlinksNames = new Set(primitiveNames.map(name => filterName.includes(name) ? name : `${prefix}${name}`))
}
let antdvNames: Set<string>
function genAntdNames(primitiveNames: string[]): void {
antdvNames = new Set(primitiveNames.map(name => `A${name}`))
}
genAntdNames(primitiveNames.filter(key => !filterName.includes(key)))
genJetlinksNames(primitiveNames)
function isJetlinks(compName: string): boolean {
return jetlinksNames.has(compName)
}
function isAntdv(compName: string): boolean {
return antdvNames.has(compName)
}
export function JetlinksVueResolver(options: JetlinksVueResolverOptions = {}): any {
return {
type: 'component',
resolve: (name: string) => {
if (options.resolveIcons && name.match(/(Outlined|Filled|TwoTone)$/)) {
return {
name,
from: '@ant-design/icons-vue'
}
}
const _isJetlinks = isJetlinks(name)
const _isAntd = isAntdv(name)
if ((_isJetlinks || _isAntd) && !options?.exclude?.includes(name)) {
// const importName = filterName.includes(name) ? name : name.slice(1)
//
// options.packageName = proComponents.includes(importName) ? 'jetlinks-ui-components' : 'ant-design-vue'
//
// const path = `${options.packageName}/${options.cjs ? 'lib' : 'es'}`
// const stylePath = getSideEffects(importName, options, !proComponents.includes(importName))
const importName = filterName.includes(name) ? name : name.slice(1)
options.packageName = _isJetlinks ? 'jetlinks-ui-components' : 'ant-design-vue'
const path = `${options.packageName}/${options.cjs ? 'lib' : 'es'}`
const stylePath = getSideEffects(importName, options, _isAntd)
return {
name: importName,
from: path,
sideEffects: stylePath
}
}
}
}
}

@ -0,0 +1,48 @@
import fs from 'fs'
import path from 'path'
const rootPath = path.resolve(__dirname, '../')
function optimizeAntdComponents(moduleName: string): string[] {
const moduleESPath = `${moduleName}/es`
const nodeModulePath = `./node_modules/${moduleESPath}`
const includes: string[] = [moduleESPath]
const folders = fs.readdirSync(
path.resolve(rootPath, nodeModulePath)
)
folders.map(name => {
const folderName = path.resolve(
rootPath,
nodeModulePath,
name
)
let stat = fs.lstatSync(folderName)
if (stat.isDirectory()) {
let styleFolder = path.resolve(folderName, 'style')
if (fs.existsSync((styleFolder))) {
let _stat = fs.lstatSync(styleFolder)
if (_stat.isDirectory()) {
includes.push(`${moduleESPath}/${name}/style`)
}
}
}
})
return includes
}
export function optimizeDeps() {
return {
name: "optimizeDeps",
configResolved: async (config) => {
const components = [
...optimizeAntdComponents('ant-design-vue'),
...optimizeAntdComponents('jetlinks-ui-components')
]
let concat = config.optimizeDeps.include.concat(components)
config.optimizeDeps.include = Array.from(new Set(concat))
}
}
}

@ -0,0 +1 @@
preview.pro.ant.design

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Loading…
Cancel
Save